P0 Drift Triage — 2026-05-25
Source: 29 P0 drifts surfaced by Phase 1 of the RTM reconciliation pass (see
RTM-DASHBOARD.md§"Highlighted launch-critical P0 drifts surfaced", lines 70-100). Companion: cross-references the Master Pending Tracker to separate already-tracked work from brand-new findings. Outcome: 11 actionable engineering clusters with owner + sprint placement + remediation summary, ready for operator accept/defer.
Aggregate
| Metric | Count |
|---|---|
| Total P0 drifts surfaced by RTM | 29 |
| Already tracked in master pending tracker (full or partial) | 7 |
| Brand-new P0s the RTM pass surfaced | 22 |
| Sprint-0 prerequisites (re-measure) | 1 cluster, 1 drift |
| Sprint-1 Property #1 launch-blockers | 7 clusters, 18 drifts |
| Sprint-2 post-launch hardening | 3 clusters, 10 drifts |
The "brand-new" finding count is the single most important number on this page. ~75% of the launch-critical P0 drifts surfaced by the RTM pass are NOT in the existing audit tracker — they came from the SME deep-dive layer (Indian GST slab logic, DPDPA §9, TRAI DLT, B2B IRN GSTIN capture, dual-implementation ownership, etc.) that the original AP-T## audit did not exercise.
Cluster 0 — Test-pass re-measurement (sprint-0 prerequisite)
Drifts (1): EP-005A D-008.
Three of the P0s (EP-005A D-008, EP-007 D-005, EP-015 D-007) cite the 2026-05-16 flow-demo-readiness snapshot ("0/15 PASS", "0/10 PASS"). Several upstream fixes have landed since (frontdesk nationality fallback, AP-CC-4 EINVOICE_MOCK=false, AP-T08-001/006/007 IRN pipeline, AP-T07-001/002 KDS rewrite). Some of those 0-pass scores may already be 60-90%.
Action: re-run flow-tests/src/flows/flow-7-pos-to-folio.spec.ts, flow-8-check-out.spec.ts, check-out-einvoice.flow.spec.ts against the latest test+QA env and update each EPIC RTM's pass-rate citation in the same commit. If they pass, the drift collapses and the clusters that wrap them (5, 1) shrink accordingly.
Owner: QA/Eng (any engineer, ~½ day). Master tracker linkage: indirect — pipeline 29940 reference in EP-007 RTM line 192.
Cluster 1 — INDIA GST + E-INVOICE COMPLIANCE (8 P0s — Property #1 GO-LIVE gate)
Drifts (8): EP-002 D-008, EP-005A D-009, EP-005B D-008, EP-005B D-003, EP-007 D-004, EP-011 D-003 (showstopper), EP-012C D-003, EP-012C D-004 (= BF-012 D-009).
| Drift | Severity | What |
|---|---|---|
| EP-011 D-003 | SHOWSTOPPER | Booking-engine hardcodes 12% GST flat. Files: hmp-booking-engine/src/pages/checkout/CheckoutPage.tsx:220 (const taxRate = 0.12;), lib/api/mockApi.ts:26, lib/api/mockData.ts:225. Mis-charges rooms ≥₹7,501/night by 6pp (should be 18% per Indian GST slab {≤₹1,000:0%, ₹1,001-7,500:12%, ≥₹7,501:18%}). Direct revenue mis-statement risk on every premium-room booking. |
| EP-002 D-008 | P0 | RatePlan story silent on GST-inclusive-vs-exclusive + CGST+SGST (intra-state) vs IGST (inter-state). Without explicit AC, two property admins configuring the same rate produce different bills. |
| EP-005A D-009 | P0 | Buyer GSTIN cannot be captured at check-in/check-out. Blocks B2B e-invoice IRN for corporate stays. AP-T08-003 wired GuestServiceClient.getCompany() ✅ DONE on the backend; UI capture surface still missing. |
| EP-005B D-008 | P0 | EPIC AC says "IRN generated within 30s of check-out" but actual flow is a 5-min retry-backoff EInvoiceJob queue. AC needs updating OR queue needs an SLA fast-path. |
| EP-005B D-003 | P0 | TDS adjustment not in story body → Indian books won't tie to Form 26AS at FY close. |
| EP-007 D-004 | P0 | MenuItem.gstRate silently falls back to outlet taxRate when null. Sin-goods (liquor/beer/cigarettes) must reject null and force an explicit GST entry (alcohol = state excise + 5%/12%/18% varies; cigarettes = 28% + cess). Today they bill at outlet default. |
| EP-012C D-003 | P0 | Two GSTR-1 implementations exist: one in hmp-frontdesk-service/src/gst/, another in hmp-analytics-service/src/gstr/. They aggregate from different sources and don't agree on totals. |
| EP-012C D-004 / BF-012 D-009 | P0 | Zero validation against NIC e-invoice portal schema v3.4 (IRN + GSTR-1 payloads). Property #1 cannot file GSTR-1 from HMP today — schema mismatches fail at GSTN upload. |
Owner cluster: cross-team (booking-engine, frontdesk, pos, property-service, analytics). Suggested lead: 1 senior FE + 1 senior BE engineer + finance/compliance SME. Effort: L (2 weeks for the booking-engine fix + GSTIN capture + schema validator; remaining items 3-5 days each). Master tracker linkage: AP-T02-005 (inclusive Boolean ✅ DONE) covers part of EP-002 D-008. AP-T08-003 (GuestServiceClient B2B ✅ DONE) covers backend side of EP-005A D-009. Rest is net-new and not tracked. Sprint placement: SP1 — go-live gate. Property #1 cannot legally invoice in India without these.
Cluster 2 — DPDPA + TRAI INDIAN COMPLIANCE (3 P0s — regulator-enforced)
Drifts (3): EP-010 D-013, EP-014 D-002, EP-014 D-003.
| Drift | Severity | What |
|---|---|---|
| EP-014 D-003 | P0 | TRAI DLT registration absent + no 9 AM-9 PM IST promotional-SMS window enforcement + no STOP/START opt-out handling. TRAI fines ₹1L/violation; sustained non-compliance gets the sender ID blocked. |
| EP-014 D-002 | P0 | GST e-invoice PDF attachments silent-dropped by AWS SESv2 Simple-Content mode (must use Raw mode for attachments). Customer never receives IRN-stamped invoice → opens for refund disputes. |
| EP-010 D-013 | P0 | DPDPA §9 minor / guardian-consent absent across all dispatch paths (SMS / email / WhatsApp / push). Under-18 guests get marketing material with no guardian-consent flag. |
Owner cluster: notification-service + crm-service. Suggested lead: 1 BE engineer + compliance SME for TRAI DLT registration paperwork. Effort: M-L (TRAI DLT process has external lead time; STOP/START handler + 9-9 window + SES Raw mode + guardian-consent flag = ~5 days code, but TRAI DLT cert procurement is 1-2 weeks external). Master tracker linkage: none — net-new. Sprint placement: SP1 — regulator-enforced launch blocker. Start TRAI DLT procurement immediately (external lead time).
Cluster 3 — OTA CHANNEL SECURITY (2 P0s — tenant-isolation breach)
Drifts (2): EP-009 D-001, EP-009 D-002.
| Drift | Severity | What |
|---|---|---|
| EP-009 D-001 | P0 | ConnectionsService.create stamps caller tenantId from JWT but trusts dto.propertyId unchecked → a malicious actor with one tenant's JWT can attach a channel connection to another tenant's property. Same pattern as the recently-closed property-service drift. |
| EP-009 D-002 | P0 | No role guard on POST/PUT/PATCH /channels. GET /channels/:id returns decrypted ResAvenue / Booking.com / Expedia credentials in the response body. Anyone with a non-admin JWT can extract OTA passwords. |
Owner cluster: channel-service.
Suggested lead: 1 senior BE engineer; should pair with security reviewer.
Effort: S-M (3-5 days for both: @Roles decorator on the controller methods + assertPropertyTenant(propertyId, tenantId) + DTO transformer that strips credentials from response payloads + 1 cross-tenant denial spec on each endpoint).
Master tracker linkage: none — net-new.
Sprint placement: SP1 — pre-launch security gate. ResAvenue credentials are live in prod RDS right now (LOTUS LEAF RESORT).
Cluster 4 — CRM SECURITY (1 P0)
Drifts (1): EP-010 D-007.
CampaignService.create doesn't verify the propertyId or templateId belong to the caller's tenant. findOne returns 403 with an info-leaky body that distinguishes "doesn't exist" from "exists but wrong tenant" — confirms IDs to attackers.
Owner cluster: crm-service. Pair with Cluster 3 engineer (same pattern).
Effort: S (~2 days: assertPropertyTenant + template-tenant assertion + 403-body sanitisation + 2 cross-tenant denial specs).
Master tracker linkage: none — net-new.
Sprint placement: SP1 — pair with Cluster 3 as one ~1-week security batch.
Cluster 5 — POS LAUNCH-BLOCKERS + INTEGRITY (2 P0s)
Drifts (2): EP-007 D-005, EP-007 D-009.
| Drift | Severity | What |
|---|---|---|
| EP-007 D-005 | P0 | flow-7-pos-to-folio.spec.ts 0/10 PASS as of 2026-05-16. EP-007 RTM notes "Root cause is downstream (frontdesk nationality fallback, pipeline 29940)" — needs re-measure (see Cluster 0). |
| EP-007 D-009 | P0 | Room-charge from POS posts onto a folio without checking: (a) the guest is currently checked-in, (b) credit-limit not exceeded, (c) no identity-verification holds. Risk: room-charges accumulate on a folio that has already checked out, with no recovery path. |
Owner cluster: pos-service + frontdesk-service.
Effort: M (~5 days: add assertCheckedInGuest() + assertCreditLimitAvailable() + integration test of the full POS→folio path).
Master tracker linkage: EP-007 D-005 indirect via pipeline 29940; EP-007 D-009 net-new.
Sprint placement: SP1 (D-009) + SP0 (D-005 re-measure).
Cluster 6 — BOOKING-ENGINE PAYMENT TAMPERING (1 P0)
Drifts (1): EP-011 D-005.
VITE_FEATURE_PAYMENT_SERVICE_ENABLED=false in the production booking-engine build means guest payments don't go through the backend payment-service proxy — the guest browser computes the amount, the legacy direct-Razorpay path accepts it. Client-side amount tampering is possible today on prod.
Owner: ops (env flag flip) + booking-engine engineer (verify the v2 proxy path works end-to-end against the live merchant account).
Effort: S (~½ day for the flag + a flow-test asserting /payments/initiate-v2 is the only code path that calls Razorpay).
Master tracker linkage: related to AP-T12-002 (Razorpay LIVE creds 🛑 BLOCKED on Finance procurement). The flag flip is a different issue — it can be done with sandbox creds. AP-T12-002 unblocks the LIVE creds; this drift unblocks the proxy.
Sprint placement: SP1. Cheap fix, big risk reduction.
Cluster 7 — DPDPA RETENTION CONFLICT (1 P0)
Drifts (1): BF-013 D-005.
DSAR cascade scrubs guest PII at 90 days post-checkout (AP-T08-004 ✅ DONE). But the cascade today also scrubs: (a) CBIC-mandated 7-year GST records (folios.guestName, folio_transactions.guestGstin), (b) RBI-mandated 10-year payment records (payments.payerName, merchant_accounts.payerIdentity). DPDPA right-to-erasure does not override these statutory retention periods.
Owner: guest-service + payment-service + analytics-service. Legal/DPO + CISO sign-off needed before code change (this is a policy conflict, not a code bug).
Effort: M-L. Legal review: 1-2 weeks. Implementation (after policy decision): pseudonymise (replace with [ERASED-${hash}]) instead of NULL on retained-statutory fields, ~3-5 days code.
Master tracker linkage: net-new. Conflicts with AP-T08-004 90d erasure (already shipped ✅) — that AC needs a carve-out.
Sprint placement: SP1 for policy decision + statute-aware erasure implementation. Block on Q5 (backup retention sign-off) stakeholder gate — same Legal/DPO + CISO approvers.
Cluster 8 — ARCHITECTURE / MULTI-IMPLEMENTATION OWNERSHIP (3 P0s)
Drifts (3): EP-002 D-006, EP-013 D-004, EP-012C D-008.
| Drift | Severity | What |
|---|---|---|
| EP-002 D-006 | P0 | Room status state machine — 3 services PATCH /rooms/:id/status with no central guard: frontdesk (check-in/out), housekeeping (clean→inspected→vacant), property (admin override). State machine invariant (Vacant→Occupied requires reservation; Occupied→Vacant requires checkout) is not enforced anywhere. |
| EP-013 D-004 | P0 | Three live dynamic-pricing implementations: hmp-revenue-strategy/src/decisions/, hmp-property-service/src/rate-plans/ (auto-suggest), hmp-booking-engine/src/lib/api/mockApi.ts (demo path). No documented ownership → ambiguity on whose price wins at booking time. |
| EP-012C D-008 | P0 | EPIC catalog says "Hash-chain AuditLog — Built" but code search finds no append-only hash-chain implementation. There's an audit_logs table, but rows can be UPDATE'd / DELETE'd. CERT-In + DPDPA expect tamper-evident logs. |
Owner cluster: architecture team (cross-service redesign). Effort: L-XL. Each item needs a design doc before code. Room status state machine → one canonical service must own writes (recommendation: housekeeping-service, with property + frontdesk going through HTTP). Dynamic pricing → revenue-strategy owns; property + booking-engine consume. Hash-chain → either build it or revise the AuditLog AC to remove the claim. Master tracker linkage: none — net-new. Sprint placement: SP2 — post-launch hardening. Not strict launch-blockers, but the room-status race will produce wrong reports on every concurrent staff write.
Cluster 9 — CROSS-EPIC HANDOFF GAPS (3 P0s)
Drifts (3): BF-006 D-009, BF-008 D-002, BF-010 D-013.
| Drift | Severity | What |
|---|---|---|
| BF-010 D-013 | P0 | Banquet → folio → IRN handoff entirely missing. Banquet events today get manual Word-doc GST invoices outside HMP. No flow test exists. |
| BF-006 D-009 | P0 | Night audit has no closing folio-reconciliation invariant — at 23:59:59, sum-of-charges should equal sum-of-payments + outstanding-balance. Today the rollover happens with no integrity check. |
| BF-008 D-002 | P0 | payment.refunded consumer (in folio + analytics) has no documented contract — producer and consumer can drift silently. |
Owner cluster: banquet + frontdesk (night-audit) + payment.
Effort: M each (~3-5 days). BF-010 is the largest: needs banquet.event.confirmed → folio publisher + IRN trigger.
Master tracker linkage: net-new.
Sprint placement: SP2 — Property #1 is rooms-only at launch; banquet onboards later.
Cluster 10 — REPORTING / BENCHMARK ACCURACY (1 P0)
Drifts (1): EP-012A D-004.
STR-benchmark divergence — MvDailyKpi.revpar is computed as total_room_revenue / total_rooms_available_for_sale, but Hotelogix / IDS Next / STR Global use total_room_revenue / rooms_sold. KPIs won't match industry benchmarks → Property #1 sales team can't quote against competitive set.
Owner: analytics.
Effort: S (~1 day: add MvDailyKpi.revpar_str column with the industry formula; UI labels both; analytics CLAUDE.md notes the convention).
Master tracker linkage: net-new.
Sprint placement: SP2 — accuracy concern, not gate.
Operator decision queue
Stack-rank with owner; decide accept-into-sprint or defer.
| Cluster | Total P0s | Sprint | Owner | Effort | Decision (accept / defer / reject) |
|---|---|---|---|---|---|
| 0 — Flow-test re-measure | 1 | SP0 | QA | ½ day | ☐ |
| 1 — India GST + E-invoice | 8 | SP1 | FE+BE+Finance SME | 2 weeks | ☐ |
| 2 — DPDPA + TRAI | 3 | SP1 | notification+crm | M-L | ☐ |
| 3 — OTA channel security | 2 | SP1 | channel | 3-5 days | ☐ |
| 4 — CRM security | 1 | SP1 | crm (pair w/3) | 2 days | ☐ |
| 5 — POS launch-blockers | 2 | SP0+SP1 | pos+frontdesk | 5 days | ☐ |
| 6 — Booking-engine payment tampering | 1 | SP1 | ops+BE | ½ day | ☐ |
| 7 — DPDPA retention conflict | 1 | SP1 | legal+payment+guest | 2 weeks | ☐ |
| 8 — Architecture multi-impl | 3 | SP2 | architecture | L-XL | ☐ |
| 9 — Cross-EPIC handoff gaps | 3 | SP2 | banquet+frontdesk+payment | M each | ☐ |
| 10 — STR benchmark | 1 | SP2 | analytics | 1 day | ☐ |
Hard launch-gate clusters (Property #1 cannot ship without these)
- Cluster 1 (India GST + E-invoice) — direct revenue mis-statement + GSTR-1 filing blocker
- Cluster 2 (DPDPA + TRAI) — regulator-enforced; TRAI DLT has 1-2 week external procurement lead time
- Cluster 3 (OTA channel security) — live OTA creds on prod RDS; tenant-isolation breach
- Cluster 4 (CRM security) — same pattern as Cluster 3
- Cluster 6 (booking-engine payment tampering) — client-side amount tampering possible today
- Cluster 7 (DPDPA retention conflict) — needs Legal/DPO sign-off before any first DSAR is processed in prod
Soft launch-gate clusters
- Cluster 0 (re-measure) — may shrink some hard-gate clusters
- Cluster 5 (POS integrity) — only critical if Property #1's POS goes live at launch (vs Day-2)
Defer-able to SP2
- Cluster 8 (architecture multi-impl) — design work; not strict gate
- Cluster 9 (cross-EPIC handoffs) — Property #1 is rooms-only at launch
- Cluster 10 (STR benchmark) — accuracy concern, not gate
Linkage back to master tracker
For each P0 already-tracked in 2026-05-20-master-pending-tracker.md:
| RTM Drift | Master tracker row | Status |
|---|---|---|
| EP-002 D-008 (partial) | AP-T02-005 inclusive Boolean | ✅ DONE — 1cec19a |
| EP-005A D-009 (backend) | AP-T08-003 B2B IRN | ✅ DONE — verified 2026-05-20 |
| EP-005B D-008 | AP-T08-001 + 006 + 007 IRN pipeline | ✅ DONE — story-AC drift only |
| EP-007 D-005 | pipeline 29940 reference | re-measure pending (Cluster 0) |
| EP-011 D-005 | AP-T12-002 Razorpay LIVE creds | 🛑 BLOCKED on Finance procurement |
| EP-012C D-004 / BF-012 D-009 | AP-T10-005 GSTR-3B | partial — GSTR-3B ✅; GSTR-1 net-new |
| EP-015 D-007 | AP-CC-4 + AP-T08-002 | partial — env flipped ✅; NIC creds 🟡 |
For the other 22 P0s: no master tracker row exists. The RTM pass is the first time they've been formally surfaced.
Next steps
- Operator reads this triage doc + decides accept/defer per cluster
- Accepted clusters get rolled into
2026-05-20-master-pending-tracker.mdas newRTM-CLUSTER-Nrows (or merged into existing AP-T## rows where overlap exists) - Cluster 0 (re-measure) executes first — outcomes may shrink Cluster 5
- Cluster 1 starts the GST/e-invoice 2-week batch with a TRAI DLT procurement kick-off in parallel (Cluster 2)
- Sprint 1 capacity sanity-check: clusters 1+2+3+4+6+7 total ~3.5-4 weeks of engineering effort + 1-2 weeks external dependencies (TRAI DLT, Legal sign-off). Property #1 launch window (currently ~2026-06-15 per master tracker §1) is tight; consider deferring Cluster 5 to Day-2 if POS isn't a launch-day requirement.