Skip to content

ci(fork-sync): fork-boundary mock baseline in check-stub-debt.mjs (H8) #2436

@alexey-pelykh

Description

@alexey-pelykh

Status update (2026-04-20)

Originally scoped as three new baselines in `scripts/check-stub-debt.mjs`:

  1. `.never-return-baseline` — count of `: never` return types
  2. `.fork-boundary-stub-baseline` — count of fork-attributed throw stubs
  3. `.fork-boundary-mock-baseline` — count of `vi.mock` of `src/agents/` + `src/middleware/`

Re-scoped per 360 evaluation on 2026-04-20. H7 (PR #2444) now catches throwing-stub exports with live callers via AST classification including `: never` return type. This makes Counters 1 & 2 redundant or noise-heavy:

Decision: Implement Counter 3 only. Bundle the stale `.throwing-stub-callers-allowlist` cleanup for `resolveAgentRuntimeOrThrow` (surfaced by H7 inventory mode; the function was restored to a real implementation in commit `d4a01b9190`, making the allowlist entry vestigial). Both live in the throwing-stub gate family; natural to bundle.

Problem

Tests that mock fork-boundary modules (`src/agents/`, `src/middleware/`) can mask production stubs — the test exercises the mock, production exercises a broken stub. This is the underlying cause of #2408 and the #2337 cascade.

H7 catches production-side throwing stubs at PR time. Counter 3 creates a test-side friction point: any PR that adds a new `vi.mock` of a fork-boundary module must bump the baseline and justify in the PR description. The justification prompt catches the "mock-to-mask-a-stub" anti-pattern that H7 cannot see.

Solution

Extend `scripts/check-stub-debt.mjs` with one new baseline:

  • `.fork-boundary-mock-baseline`: count of `vi.mock("...")` calls in `src/` + `extensions/` + `ui/` test files where the specifier resolves to a module under `src/agents/` or `src/middleware/`
  • Same decrement-tolerated / increment-requires-justification semantics as existing `@ts-expect-error` baseline
  • Seed with current count (~99)
  • PR-description prompt clarifies categorization: isolation / performance / stub-placeholder (the last being a red flag)

Additionally, in the same PR:

Acceptance criteria

  • `scripts/check-stub-debt.mjs` extended with fork-boundary-mock counter
  • `.fork-boundary-mock-baseline` file seeded with current count
  • CI gate fails on increment without justification; tolerates decrement
  • CONTRIBUTING.md or CLAUDE.md note on the three mock-reason categories (isolation / performance / stub-placeholder)
  • Stale `resolveAgentRuntimeOrThrow` entry removed from `.throwing-stub-callers-allowlist`
  • `node scripts/check-throwing-stub-callers.mjs --inventory` reports zero stale entries after this PR
  • `node scripts/check-stub-debt.mjs` exits 0 on main post-merge
  • `pnpm check` passes

Out of scope

  • Counter 1 (`.never-return-baseline`) — superseded by H7 + H9
  • Counter 2 (`.fork-boundary-stub-baseline`) — superseded by H7
  • Per-mock-category enforcement (manual review only; no auto-categorization)
  • Expanding mock-baseline scope beyond `src/agents/` + `src/middleware/` (follow-up if needed)

Effort

~0.5 day.

Dependencies

Blocked by: — (no longer depends on an ADR file; HQ ADR 0005 H8 description updated to reflect the narrower scope)
Tracked under: #2433

References

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions