Problem
The AST gate and baseline counters (Phase 1 child issues of #2433) catch throwing-stub regressions and drift. Neither catches semantic stubs — functions whose return type stays valid (boolean, object) but whose implementation has been gutted to return constant values.
#2337 instance 1: modelSupportsVision returns false (always). Type is boolean, body has no throw, no : never. AST gate doesn't fire. Baselines don't fire. Telegram vision is silently disabled.
Solution
Each fork-boundary module exports a MODULE_ATTESTATIONS constant declaring each export's status:
// src/agents/agent-scope.ts
export const MODULE_ATTESTATIONS = {
resolveAgentRuntime: "live",
resolveAgentRuntimeOrThrow: "live",
resolveAgentAuth: "live",
// ...
} as const;
CI verifier (scripts/check-attestations.mjs):
- Imports each fork-boundary module
- Reads
MODULE_ATTESTATIONS
- Verifies (a) every export listed; (b)
"live" exports don't match throwing-stub patterns; (c) "stub" exports have zero non-test importers
- Sync PRs that change
MODULE_ATTESTATIONS show diffs clearly in PR review
- CODEOWNERS rule for files containing
MODULE_ATTESTATIONS
Scope (initial rollout)
Limit to src/agents/* for first iteration to bound rollout cost. Expand to src/middleware/* and other fork-boundary directories in follow-up issues if pattern proves valuable.
Acceptance criteria
Effort
3-5 days
Open questions (needs-discussion)
- "live" / "stub" / "deprecated" — sufficient classification, or do we need "partial"?
- Where exactly should
MODULE_ATTESTATIONS live in the file (top, bottom, separate sibling file)?
- CODEOWNERS scope — repo maintainers or sync-PR specialists?
- Should
MODULE_ATTESTATIONS be tree-shakable (it is exported runtime data — small but non-zero bundle cost)?
Dependencies
Blocked by: #2434 (ADR 0005)
Recommended after: AST gate and baseline counters (other Phase 1 child issues of #2433) land first to validate lighter-weight gates
Tracked under: #2433
References
Problem
The AST gate and baseline counters (Phase 1 child issues of #2433) catch throwing-stub regressions and drift. Neither catches semantic stubs — functions whose return type stays valid (
boolean,object) but whose implementation has been gutted to return constant values.#2337 instance 1:
modelSupportsVisionreturnsfalse(always). Type isboolean, body has no throw, no: never. AST gate doesn't fire. Baselines don't fire. Telegram vision is silently disabled.Solution
Each fork-boundary module exports a
MODULE_ATTESTATIONSconstant declaring each export's status:CI verifier (
scripts/check-attestations.mjs):MODULE_ATTESTATIONS"live"exports don't match throwing-stub patterns; (c)"stub"exports have zero non-test importersMODULE_ATTESTATIONSshow diffs clearly in PR reviewMODULE_ATTESTATIONSScope (initial rollout)
Limit to
src/agents/*for first iteration to bound rollout cost. Expand tosrc/middleware/*and other fork-boundary directories in follow-up issues if pattern proves valuable.Acceptance criteria
MODULE_ATTESTATIONSconvention documented in CONTRIBUTING.mdsrc/agents/*.tsfiles with exportsscripts/check-attestations.mjsimplemented and wired into CI"live"attestation for a function matching throwing-stub patterns"stub"attestation for a function with non-test importerssrc/agents/**/*.ts(or files containingMODULE_ATTESTATIONS)MODULE_ATTESTATIONSwould have flagged thelive-vs-actual-stub mismatchEffort
3-5 days
Open questions (
needs-discussion)MODULE_ATTESTATIONSlive in the file (top, bottom, separate sibling file)?MODULE_ATTESTATIONSbe tree-shakable (it is exported runtime data — small but non-zero bundle cost)?Dependencies
Blocked by: #2434 (ADR 0005)
Recommended after: AST gate and baseline counters (other Phase 1 child issues of #2433) land first to validate lighter-weight gates
Tracked under: #2433
References
modelSupportsVision)