ci(fork-sync): MODULE_ATTESTATIONS manifest for src/agents/* (#2437)#2446
Merged
alexey-pelykh merged 1 commit intomainfrom Apr 21, 2026
Merged
ci(fork-sync): MODULE_ATTESTATIONS manifest for src/agents/* (#2437)#2446alexey-pelykh merged 1 commit intomainfrom
alexey-pelykh merged 1 commit intomainfrom
Conversation
Implements H9 of ADR 0005 — semantic-stub detection that H7 (throwing-stub AST gate) and H8 (test-side mock baseline) cannot see. Every runtime export in src/agents/ depth-1 now carries an attestation declaring the implementation status: "live" / "stub" / "partial" / "deprecated". The attestation-gate CI job enforces structural invariants; CODEOWNERS enforces semantic review. Design decisions (per user direction to proceed as issue describes): - 4-category set including "partial" for legitimately-gutted-to-default functions that work in the narrow case - Inline placement (top of file, after imports) to prevent drift - Plain object with `as const` for tree-shakability (zero bundle cost) - CODEOWNERS /src/agents/ → @alexey-pelykh (solo maintainer project) - Initial scope: src/agents/* depth-1. Expand to src/middleware/, etc., in follow-up issues if the pattern proves valuable Rollout: - 93 attested modules, 319 attestations across src/agents/* depth-1 - Auto-classified "live" by default; 11 semantic-stub exports manually classified "partial" (functions returning hardcoded defaults post- gutting — e.g., lookupContextTokens returns constant 200000, resolveThinkingDefault returns undefined) - No current "stub" or "deprecated" entries (nothing currently broken) Gate invariants: 1. Every runtime export has an attestation entry (missing fails CI) 2. Every entry corresponds to a current export (stale fails CI) 3. "live" attestation on a throwing-stub-shape function fails 4. "stub" attestation on a function with non-test callers fails Enforced via scripts/check-attestations.mjs (AST-based classifier with 10 self-test fixtures covering all 4 invariants, expression-body arrow enumeration, category validation, and non-function exclusion). Polish iterations (3 total): 1. Extracted ~330 LOC of duplicated AST classification into new scripts/lib/throwing-stub-shape.mjs shared by check-attestations, generate-attestations, and check-throwing-stub-callers. Single site for the four calibration signals; net -373 LOC across 3 scripts, +210 LOC shared lib 2. Added --self-test mode with 10 fixtures + wired into CI (symmetric with throwing-stub-callers-gate convention). Regressions in the classifier itself now caught before the main gate runs 3. Aligned test-file filter across both attestation scripts via isTestLikeTypeScriptFile; removed 2 dead MODULE_ATTESTATIONS blocks from test-harness files that slipped past the naive filter Validation (fresh-context subprocess, session 2df6a80c) initially found one blocking issue (expression-body arrows silently excluded by isBlock filter) + 3 non-blocking. All addressed; re-validated CLEAN. Polish (session 9a3fc434): CLEAN after 3 iterations. Dry-run verification: - Probe 1 (delete attestation): FAIL "has no MODULE_ATTESTATIONS entry" - Probe 2 (add stale attestation): FAIL "stale attestation" - Probe 3 (live on throwing-stub): FAIL "attested 'live' but matches throwing-stub pattern" - Probe 4 (stub with live callers): FAIL "has 9 non-test caller(s)" AC 8 (PR #2360 dry-run): time-traveling to PR #2360's state is impractical; verified the equivalent case — a "live" attestation on a throwing-stub-shape function fails, and an unattested new export fails. These are the precise failure modes PR #2360 exhibited. HQ ADR 0005 H9 description updated in parallel (hq commit pending) to reflect the as-shipped scope and 6-month sunset review. scripts/generate-attestations.mjs is a one-shot bootstrap tool that remains as a maintenance utility for extending the attestation scope to new directories (idempotent; skips modules with existing blocks).
This was referenced Apr 21, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements H9 of ADR 0005 — semantic-stub detection that H7 (throwing-stub AST gate) and H8 (test-side mock baseline) cannot see. Every runtime export in
src/agents/depth-1 now carries an attestation declaring its implementation status (live/stub/partial/deprecated). Structural consistency enforced byscripts/check-attestations.mjs; semantic correctness enforced by CODEOWNERS review.Scope
src/agents/*depth-1"partial"— functions that were gutted to return hardcoded defaults (e.g.,lookupContextTokensreturns200000,resolveThinkingDefaultreturnsundefined). They work in the narrow case of "return the default"; callers tolerate that."stub"or"deprecated"entries — nothing's currently broken insrc/agents/"live"(real implementations)Design decisions (per user "proceed as issue describes")
"partial"— real fork code has functions that work partially post-gutting; "partial" prevents the false binary/src/agents/ @alexey-pelykh(solo maintainer)as conston plain object, never imported by production — zero bundle costEnforced invariants
"live"attestation on a throwing-stub-shape function fails"stub"attestation on a function with non-test callers failsRuntime exports counted:
export function,export const = () => ...,export const = function...,export class,export default(if function). Types, interfaces, enums, non-function data constants, and re-exports are not counted.Changes
scripts/check-attestations.mjs(new, 526 LOC): the gate. Includes--self-testmode with 10 fixtures covering all 4 invariants, expression-body arrow enumeration, category validation, non-function-export exclusion. Fail messages guide the author to the right fix.scripts/generate-attestations.mjs(new, 261 LOC): one-shot bootstrap tool that walks attested modules, enumerates exports via AST, auto-classifies using H7 calibration signals, writesMODULE_ATTESTATIONSblocks. Idempotent; remains as a maintenance utility for extending scope to new directories later.scripts/lib/throwing-stub-shape.mjs(new, 210 LOC): shared AST classification helpers (looksLikeThrowingStub,classifyThrowingStubShape, and the four calibration-signal primitives). Previously duplicated across 3 scripts; now single source of truth. Net -373 LOC across callers, +210 LOC in lib.scripts/check-throwing-stub-callers.mjs: refactored to use shared lib (its 10 self-tests still pass unchanged).github/workflows/ci.yml: newattestation-gatejob (self-test before main check, mirroringthrowing-stub-callers-gateconvention).github/CODEOWNERS(new):/src/agents/→@alexey-pelykhCONTRIBUTING.md: new § Module attestations with category table, 5-point "when this fires", 4-step "how to update"src/agents/*.ts(83 files):MODULE_ATTESTATIONSblock added after importsVerification
node scripts/check-attestations.mjsnode scripts/check-attestations.mjs --self-testnode scripts/check-throwing-stub-callers.mjsnode scripts/check-throwing-stub-callers.mjs --self-testnode scripts/check-stub-debt.mjspnpm checkFresh-context validation (session 2df6a80c)
Initial pass found 1 blocking issue + 3 non-blocking observations:
ts.isBlock(init.body)filter silently excludedexport const foo = () => exprfrom enumeration. 13 runtime exports uncovered, including 5 semantic stubs with active production callers. This was the exact failure mode H9 was designed to catch per the script's own docstring. Fix applied: dropped the filter; both scripts now treat expression-body arrows identically to block-body arrows. All 13 gaps closed with appropriate classifications..mocks.shared.tssuffix missing (→ added).Re-validated: CLEAN.
Polish iterations (session 9a3fc434, 3 iterations)
throwing-stub-shape.mjslib; ~-373/+210 LOC net; single source of truth for calibration signals--self-testwith 10 fixtures; wired into CI before main gateDry-run probes (AC 8)
PR #2360's regression was equivalent to probe #3. The gate would have caught it at PR time.
Cascade impact
H9 delivered. Unblocks Phase 3 (#2441 composite gate) — H7/H8/H9 all landed.
Follow-up candidates (out of scope, deferred)
src/middleware/andsrc/gateway/(tracked via ADR 0005 H9 description)Test plan
pnpm checkcleanCloses #2437.