Zero-assertion remediation — 27 cases, 9 suites
Round: sentinel-2026-08-06-05-46 · TEST · freshly onboarded property · pod-verified build
Status: plan, not defects. Do not file these as bugs.
What this is
The Sentinel ZERO-ASSERTION gate fails any case in which expect() never ran. A case
that asserts nothing cannot fail for the behaviour it is named after — it only fails if the
code under test throws. Any catalogue row pointing at such a case is a FALSE GREEN
(CERTIFICATION-METHODOLOGY §4.2).
These are coverage gaps, not breakage. Every one of them was passing before this round, because it asserted nothing. Nothing regressed; the measurement improved.
The count, and why it is not 92
The gate fires in two situations, and only one is a coverage gap:
| Situation | Count | Meaning |
|---|---|---|
expect() never ran, no other error | 27 | genuinely vacuous — this plan |
expect() never ran because the case threw first | 65 | downstream of a real error (mostly ROOM_ALREADY_ASSIGNED contention); fixing the throw restores the assertions |
The raw gate hit 92 cases across 32 suites. Counting all 92 as hollow tests would overstate the gap by 3.4x. The gate's own message says so explicitly — "this gate only observes that no expect() ran, which is expected when a case throws before its first assertion" — and the distinction has to be computed, not assumed.
The 27, by suite
| Cases | Suite | Why it matters |
|---|---|---|
| 8 | pms-j-night-audit | Highest priority. The most financially consequential nightly operation. TC-694b (folio has ROOM charge), TC-697 (no-show status + charge), TC-702 (business date advances), TC-704 (duplicate start returns 400), TC-708 (rollback voids charges) each NAME a behaviour they never assert. |
| 5 | folio-void-creditnote | §34 credit notes — a money path with statutory meaning. |
| 4 | cash-refund | Cash out of the drawer. |
| 3 | room-move-suite | Mid-stay category change; repricing crosses the ₹7,500 GST slab. |
| 2 | advance-deposit-split | Deposit allocation. |
| 2 | folio-discount | Discount posting. |
| 1 | reservation-amend | |
| 1 | concurrency | |
| 1 | checkin-id-document-validation |
Seven of the nine suites are money paths. That is the finding: the areas with the most financial consequence carried the most assertion-free certification.
Remediation rule
For each case, add the assertion the case's own NAME promises — and it must be a read-back in a separate request, not a re-read of the response body that was just returned. The GOLD-GREEN bar: separate-request read-back + positive-data assertion + state-transition + money-conserves.
Regression-first: each added assertion must be shown to FAIL against a build where the behaviour is absent before it is trusted. An assertion that has never been red is not yet known to catch anything — which is precisely how these 27 got here.
Order of work
pms-j-night-audit(8) — money, nightly, irreversiblefolio-void-creditnote(5) +cash-refund(4) — money outroom-move-suite(3) +advance-deposit-split(2) +folio-discount(2) — money moved- The remaining 3 singletons
Do not
- File these as Bug work items. They are coverage debt, and a bug queue is the wrong ledger.
- Register any catalogue row against a suite in this list until its cases assert.
- Count the 65 throw-before-assert cases here. Fix the throw; the assertions come back on their own.
⚠ RE-MEASURED 2026-08-07 — this plan's counts are STALE and its framing was wrong
Do not scope work off the per-suite table above. Measured against a live sweep:
1. Four of the five suites this plan names are ALREADY CLEAN
room-move-suite, advance-deposit-split, reservation-amend and
checkin-id-document-validation all run green with zero vacuous cases.
cash-refund passed 11/11 across isolation and multi-suite contexts.
2. The vacuous total is mostly CASCADE, not debt
A first pass counted ~256 vacuous cases and I reported that as "5-6x the plan". That was wrong. Partitioning by SUITE instead of by case:
| suites with failures | 105 |
| suites where EVERY failure is vacuous, ≥3 cases | 20 |
| cases inside those 20 suites | 126 |
A suite-level beforeAll failure makes every case in the file report zero
assertions. uat/pms-g-folio contributed 17 "vacuous cases" that collapse to
ONE line:
[beforeAll] G2 check-in 409 {"message":"Room is already occupied"}
TC-420 SKIP: G1 check-in failed in beforeAll
Count root causes, not failures — the rule this programme already had, applied to its own backlog.
3. The dominant root is ROOM CONTENTION, and half of it is now fixed
23 contention setup failures (10 Room is already occupied, 13 Room is not ready) across 8 suites.
FIXED — claimedRoomIds was per-SPEC-FILE while the onboarded property is
per-RUN, so spec B re-issued a room spec A had checked into. Now process-wide.
Verified by running the collision-prone suites together:
rooms-in-house-checked-in-count and company-ar-open-item-application both
FAIL → PASS.
STILL OPEN — a DIFFERENT root, and the next real work item:
35
uat/*specs, ZERO of them releasing rooms, contending over 11 hardcoded room keys (68 references) on a property seeded with 100 rooms.
They select by static constant (UAT_ROOMS['R-201']), so the claim set cannot see
them, and nothing checks out — occupancy accumulates until later specs find every
one of the 11 occupied. This is why pms-g-folio reports "all rooms failed".
Fixing it is NOT a de-vacuuming exercise. The candidate approaches, in order of
leverage: (a) make the UAT_ROOMS accessor claim-aware so each spec file draws
from the unused 89 rooms; (b) add the existing assertNoResidualHolds teardown to
the uat suites; (c) both. Option (a) alone should reclaim most of the 126 cases,
because the rooms exist — they are simply never handed out.
Estimated real vacuous debt after the cascades are removed: far below 256, and not yet measurable until the contention root is closed. Re-measure then; do not carry a number forward from this document.
Full-sweep raw facts (2026-08-07) — and why NO root-cause number is published here
The complete L1 sweep finished: 409 suites · 1274 passed · 449 failed · 3344s. 14 suites hit room contention or OVERBOOKED.
Two caveats that make the failure count non-comparable, both stated rather than adjusted for:
- The sweep STARTED BEFORE two of the day's fixes landed — the process-wide room-claim fix and the deployed night-audit closing-date fix. It measures a build that no longer exists.
- Mechanical partition of these results is NOT trustworthy. Two rules were tried: treating every non-cascade vacuous case as a root gave 442; treating every real failure as a root gave 348 in-scope. Both are wrong in opposite directions — the first counts symptoms, the second splits one cause across many failures.
The programme's own rule is to classify by READING each failure message, and that is what produced the trustworthy reductions earlier in the day (126 → 15 distinct signals; 249 → ~4). A regex does not substitute for it. Do not quote a root-cause figure from this sweep. Re-run after the room-contention root is closed, and partition by reading.