Files
2026-05-27 23:29:53 +01:00

4.8 KiB

OpenSpec Change: testing-spec-conformance

  • Change ID: testing-spec-conformance
  • Package: @suaveplan/testing
  • Status: PROPOSED
  • Date: 2026-04-26

Summary

Close five drift items uncovered by bun scripts/openspec-conformance.ts @suaveplan/testing:

  1. **Verified by:** lines on every requirement in openspec/specs/testing/spec.md (15 reqs, all owned by this package).
  2. Thread a <TBody = unknown> generic through RequestBuilder, ResponseBuilder, TestRequest, TestResponse, and the corresponding *BuilderState types so consumers can pin the body type at the call site instead of the public d.ts leaking five : unknown positions.
  3. Add a tests/spec-conformance.spec-conformance.test.ts pinning the new generic threading via expectTypeOf, the dual-runner / sideEffects / subpath-export package-shape assertions, the schemas-leaf-isolation check, and the module-scope determinism scan (Math.random / Date.now / performance.now allow-list).
  4. Replace the wall-clock fallback in measureTime and withObservability with the existing injectable Clock substrate (defaultClock by default, FakeClock when injected). Removes the last two non-deterministic call sites in src/ outside the allow list.
  5. Tighten scripts/openspec-conformance.ts: stop matching change folders by token-substring on the folder name (which over-matched 226 reqs across enterprise-testing-dom, enterprise-testing-e2e, enterprise-ab-testing, enterprise-network-testing, etc.). Match only via **Package**: @suaveplan/<pkg> in proposal.md frontmatter, and only pull active-change specs/<cap>/spec.md deltas from changes whose proposal explicitly names this package.

After this change, bun scripts/openspec-conformance.ts @suaveplan/testing exits 0.

Current state

@suaveplan/testing is structurally solid (Layer 0, zero @suaveplan/* workspace deps, 295 passing tests, structured TestingError hierarchy with stable TESTING.<DOMAIN>.<REASON> codes, dual-runner subpath exports, sideEffects: false, fast-check property tests, mitata bench harness). Conformance gaps are documentary plus two real drift items:

  • 35/35 requirements lacked **Verified by:** lines (down from 226 once the conformance script's over-matching was fixed).
  • 5 public d.ts positions resolved to : unknown (request-builder.types.d.ts, response-builder.types.d.ts, http.types.d.ts x2, fixture-manager-internals.d.ts).
  • 2 wall-clock fallback sites (measureTime, withObservability) bypassed the Clock substrate documented by the spec's "Module-scope non-determinism absent" scenario.
  • The conformance script over-matched on folder-name tokens, pulling in unrelated testing-* change folders.

What changes

  1. Add **Verified by:** lines under every ### Requirement: block in openspec/specs/testing/spec.md. Citations name real it(...) test titles in src/**/*.test.ts and tests/*.test.ts.
  2. Thread <TBody = unknown> through RequestBuilder, ResponseBuilder, RequestBuilderState, ResponseBuilderState, TestRequest, and TestResponse. Default generic preserves the existing unknown surface for zero-config callers.
  3. Add tests/spec-conformance.spec-conformance.test.ts:
    • expectTypeOf assertions over RequestBuilder<UserPayload> / ResponseBuilder<UserPayload> so the generic threading regresses loudly.
    • package.json shape: sideEffects === false, every public surface has a subpath export.
    • Module-scope determinism: scan src/ for Math.random( / Date.now( / performance.now( outside the allow list (context, fake-clock, memory-store).
    • Schema-bundle isolation: *.schemas.ts files do not import their sibling implementation file.
  4. measureTime(fn, { clock }) and withObservability({ ..., clock }) now route every wall-clock read through defaultClock (default) or a caller-supplied Clock. Behaviour identical for zero-config callers.
  5. scripts/openspec-conformance.ts swaps the folder-name token regex for a frontmatter check and only pulls active-change specs/<cap>/spec.md deltas from changes explicitly tagged **Package**: @suaveplan/<pkg>.

Impact

  • Public API: additive — RequestBuilder, ResponseBuilder, TestRequest, TestResponse gain an optional <TBody> generic with unknown default. measureTime and withObservability gain an optional clock option.
  • Tests: 7 new it blocks under tests/spec-conformance.spec-conformance.test.ts. Existing 295 tests unchanged.
  • Spec: 15 **Verified by:** lines folded into openspec/specs/testing/spec.md. Two stale packages/universal/testing/ path references corrected to packages/dev/testing/.
  • Tooling: scripts/openspec-conformance.ts matching tightened. Affects every package's audit but downward-only (fewer false-positive folders).