Skip to main content

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​

MetricCount
Total P0 drifts surfaced by RTM29
Already tracked in master pending tracker (full or partial)7
Brand-new P0s the RTM pass surfaced22
Sprint-0 prerequisites (re-measure)1 cluster, 1 drift
Sprint-1 Property #1 launch-blockers7 clusters, 18 drifts
Sprint-2 post-launch hardening3 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).

DriftSeverityWhat
EP-011 D-003SHOWSTOPPERBooking-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-008P0RatePlan 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-009P0Buyer 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-008P0EPIC 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-003P0TDS adjustment not in story body → Indian books won't tie to Form 26AS at FY close.
EP-007 D-004P0MenuItem.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-003P0Two 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-009P0Zero 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.

DriftSeverityWhat
EP-014 D-003P0TRAI 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-002P0GST 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-013P0DPDPA §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.

DriftSeverityWhat
EP-009 D-001P0ConnectionsService.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-002P0No 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.

DriftSeverityWhat
EP-007 D-005P0flow-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-009P0Room-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.

DriftSeverityWhat
EP-002 D-006P0Room 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-004P0Three 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-008P0EPIC 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.

DriftSeverityWhat
BF-010 D-013P0Banquet → folio → IRN handoff entirely missing. Banquet events today get manual Word-doc GST invoices outside HMP. No flow test exists.
BF-006 D-009P0Night 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-002P0payment.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.

ClusterTotal P0sSprintOwnerEffortDecision (accept / defer / reject)
0 — Flow-test re-measure1SP0QA½ day☐
1 — India GST + E-invoice8SP1FE+BE+Finance SME2 weeks☐
2 — DPDPA + TRAI3SP1notification+crmM-L☐
3 — OTA channel security2SP1channel3-5 days☐
4 — CRM security1SP1crm (pair w/3)2 days☐
5 — POS launch-blockers2SP0+SP1pos+frontdesk5 days☐
6 — Booking-engine payment tampering1SP1ops+BE½ day☐
7 — DPDPA retention conflict1SP1legal+payment+guest2 weeks☐
8 — Architecture multi-impl3SP2architectureL-XL☐
9 — Cross-EPIC handoff gaps3SP2banquet+frontdesk+paymentM each☐
10 — STR benchmark1SP2analytics1 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 DriftMaster tracker rowStatus
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-008AP-T08-001 + 006 + 007 IRN pipeline✅ DONE — story-AC drift only
EP-007 D-005pipeline 29940 referencere-measure pending (Cluster 0)
EP-011 D-005AP-T12-002 Razorpay LIVE creds🛑 BLOCKED on Finance procurement
EP-012C D-004 / BF-012 D-009AP-T10-005 GSTR-3Bpartial — GSTR-3B ✅; GSTR-1 net-new
EP-015 D-007AP-CC-4 + AP-T08-002partial — 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​

  1. Operator reads this triage doc + decides accept/defer per cluster
  2. Accepted clusters get rolled into 2026-05-20-master-pending-tracker.md as new RTM-CLUSTER-N rows (or merged into existing AP-T## rows where overlap exists)
  3. Cluster 0 (re-measure) executes first — outcomes may shrink Cluster 5
  4. Cluster 1 starts the GST/e-invoice 2-week batch with a TRAI DLT procurement kick-off in parallel (Cluster 2)
  5. 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.