Skip to content

Phase 9 — cross-cutting invariants, conformance, and the shrink-and-run guard - #54

Merged
Wahbeh-Mohammad merged 1 commit into
mvpfrom
24-phase-9-cross-cutting-invariants-conformance
Aug 29, 2026
Merged

Phase 9 — cross-cutting invariants, conformance, and the shrink-and-run guard#54
Wahbeh-Mohammad merged 1 commit into
mvpfrom
24-phase-9-cross-cutting-invariants-conformance

Conversation

@Wahbeh-Mohammad

@Wahbeh-Mohammad Wahbeh-Mohammad commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

Closes #24

What changed

Phase 9 audits Phases 0-8 against §19 (XCUT-1..XCUT-24) and §20 (NFR-1..NFR-17). It is the
first systematic tabulation of the XCUT family: before this phase no source file cited an XCUT-N
at all.

New package

  • @dexpace/shrink-test — private, unpublished, a devDependency of the workspace root only. It
    bundles a synthetic consumer of @dexpace/core, @dexpace/transport-fetch and
    @dexpace/codec-json through esbuild with minify and tree-shaking, asserts a size budget, then
    runs the artifact in a child process so the check measures the shipped bytes rather than this
    process's warm module graph. NFR-9.
  • The budget is 24 KiB against a measured 16,671 bytes. The plan guessed 50 KB; a budget that never
    fires catches nothing, so the figure, the toolchain version and the headroom are recorded in
    shrink-test.config.ts.
  • NFR-8's keep-configuration ships nothing, deliberately. This port has no reflection-driven
    discovery surface to keep-configure, so the guard targets the dual-package hazard instead
    (deliberate-deviations.md:32). The hazard is real, not assumed: a separately bundled IoError
    has a different class identity and instanceof is false across the boundary.

New conformance suite

  • tests/conformance/xcut/ — six suites, 36 tests. Every row drives the real
    standardResilience() pipeline over a live two-origin node:http fixture, never a fake of a
    subsystem the row is meant to prove.
  • Cancellation and timeout (XCUT-1, 3), error taxonomy (4, 6, 7, 9), retry safety
    (10), concurrency and lifecycle (11, 13), security by default (16, 17), diagnostic
    previews (24).
  • The dispatch counter wraps the transport, not Runtime.send. Wrapping the runtime counts
    caller invocations and reads 1 whether retry re-issued four times or none, which inverts every
    XCUT-10 row.
  • The cross-origin hop uses two real listeners. The server binds 127.0.0.1 explicitly, so one port
    under a second hostname is not reliably resolvable.

Requirement citations

  • 17 retrofit citations across 12 existing test files, comment-only. XCUT-2, 5, 8, 12, 14,
    15, 16, 18, 19, 20, 21, 22 are satisfied by earlier phases and are cited where they
    are actually asserted rather than restated here.
  • XCUT-14 stays a retrofit on purpose: neither bounded map is reachable from a consumer-shaped
    test, so a burst driven from tests/ could assert liveness but never a cap. context/store.test.ts
    and auth/digest.test.ts assert the cap where it is observable.
  • XCUT-23 is not applicable by construction. Every seam this port ships is explicit-call-only, so
    the explicit-install ordering holds vacuously.

Gates and toolchain

  • build:deps gains codec-json and transport-fetch. This phase made them the third and fourth
    packages imported by name with exports pointing at dist/. A warm tree hid it; a clean
    preflight failed typecheck and lint exactly as Phase 8a — the fetch and undici transport adapters, and the file-backed body #52 did.
  • bunfig.toml pins [test] root = "packages", so a bare bun test never sees tests/. The root
    test script now passes both trees (bun test ./packages ./tests) and CI's Test step is
    bun run test --coverage. One process, one coverage report, one exit code.
  • typecheck gains tests/tsconfig.json and packages/shrink-test. The tests/ tree was being
    linted with the type-aware tier but never typechecked.
  • NFR-13 SPDX sweep across every tracked source file: 3 offenders fixed, now 0.

Docs

  • A phase checklist mapping all 24 XCUT and all 17 NFR IDs to their evidence, plus ten plan
    amendments — the plan predates the packages and several code blocks assume APIs that shipped
    differently.
  • docs/open-items.md §N, and CLAUDE.md for the two-tree split, the bare-bun test trap and the
    grown build:deps list.

Open and deferred items

Four findings, filed rather than patched. Phase 9 audits; it does not edit another phase's code, and
the plan says a failure found here belongs to the phase that shipped it.

  • N1 — cancellation surfaces CancellationError from the transport but a bare AbortError
    under a SuppressedError from a retry backoff wait, so e instanceof CancellationError handles
    one path and silently misses the other. Not an XCUT-3 violation on its own terms: a cancellation
    is surfaced, it aborts near-immediately, nothing is re-dispatched, and it is not a timeout. The
    defect is cross-layer consistency. Owner 5a.
  • N2HttpStatusError's public constructor accepts a 200, fabricating the "successful
    exception" XCUT-8 names and contradicting the class's own TSDoc. toHttpError itself is
    correct. Owner 3b.
  • N3 — the plan's grep "unresolved 2026-07-25" docs/knowledge/ step cannot return empty. Two
    markers live outside the file the design scoped. Owner Phase 10.
  • N4rxjs is restated in three places against NFR-14. The peer range is legitimate; the
    two devDependencies are not. Owner Phase 10.

No changeset: bun run api reports no drift in any of the nine etc/*.api.md, and
@dexpace/shrink-test is private. Nothing consumer-facing changed.

Verification

node .claude/skills/ci-preflight/run-ci.mjs --clean — all 14 steps pass on .bun-version's Bun
1.3.14. test:node also passes on the 20.3.0 engines.node floor, and the shrink guard holds there
too. 2171 tests, 99.72% line coverage against the 80% floor.

The coverage floor was verified live rather than assumed: raising coverageThreshold to 0.999 exits
1, and a single file at 66.67% function coverage failed the run on its own while the aggregate stayed
at 98.5% — so Bun enforces the floor per file, not only in aggregate.

…k guard.

Audits what Phases 0-8 built against product spec §19 (XCUT-1..24) and §20
(NFR-1..17). This is the first systematic tabulation of the XCUT family:
before this phase, zero XCUT-N citations existed in any source file.

Ships:

- @dexpace/shrink-test (NFR-9) — private, unpublished. esbuild
  bundle+minify+tree-shake of a synthetic consumer, a 24 KiB budget against
  a measured 16,671 bytes, then a child-process round trip. NFR-8's keep
  configuration ships nothing, deliberately: this port has no reflective
  discovery surface to keep-configure, so the guard targets the
  dual-package hazard instead (deliberate-deviations.md:32). Verified
  non-vacuous — a separately bundled IoError has a different class identity
  and instanceof is false across the boundary.

- tests/conformance/xcut/ — six suites, 36 tests driving the real
  standardResilience() pipeline over live sockets, plus 17 retrofit
  citations across 12 existing test files. All 24 XCUT and 17 NFR IDs are
  dispositioned with evidence in a new phase checklist; no silent gaps.

- NFR-13 SPDX sweep across every tracked source file: 3 offenders fixed,
  now 0.

Four findings filed as docs/open-items.md Section N, not patched here —
Phase 9 audits rather than edits another phase's code:

  N1  cancellation surfaces CancellationError from the transport but a bare
      AbortError under a SuppressedError from a retry backoff wait, so
      `e instanceof CancellationError` handles one path and silently misses
      the other (owner 5a)
  N2  HttpStatusError's public constructor accepts a 200, fabricating the
      "successful exception" XCUT-8 names and contradicting its own TSDoc
      (owner 3b)
  N3  the plan's `grep unresolved 2026-07-25 docs/knowledge/` step cannot
      return empty as written (owner Phase 10)
  N4  rxjs restated in three places against NFR-14's single source of truth
      (owner Phase 10)

Toolchain:

- build:deps gains codec-json and transport-fetch. Phase 9 made them the
  third and fourth packages imported by name with exports pointing at
  dist/, from shrink-test/src/ and from tests/. A warm tree hid this; a
  clean preflight failed typecheck and lint exactly as PR #52 did.
- bunfig pins [test] root = "packages", so a bare `bun test` never sees
  tests/. The root `test` script now passes both trees
  (bun test ./packages ./tests) and CI runs `bun run test --coverage`.
  typecheck gains tests/tsconfig.json, which was linted but never
  typechecked.
- CLAUDE.md documents the two-tree split, the bare-`bun test` trap, and the
  grown build:deps list.

Ten plan amendments are recorded in the checklist — the plan predates the
packages and several of its code blocks assume APIs that shipped
differently. The two that would otherwise have produced silently-passing
tests: the dispatch counter belongs on the transport rather than
Runtime.send, and Runtime.close() is a documented no-op (PIPE-27).

Gates: ci-preflight --clean green, all 14 steps, on .bun-version's Bun
1.3.14; test:node also green on the 20.3.0 engines.node floor; 2171 tests
passing at 99.72% line coverage against the 80% floor.
@Wahbeh-Mohammad Wahbeh-Mohammad self-assigned this Aug 29, 2026
@Wahbeh-Mohammad
Wahbeh-Mohammad merged commit d8217af into mvp Aug 29, 2026
3 checks passed
@Wahbeh-Mohammad
Wahbeh-Mohammad deleted the 24-phase-9-cross-cutting-invariants-conformance branch August 29, 2026 13:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant