Relationships
#3145 Record the commands affected by a change in the verification attestation
Opened by zack · 10/7/2026· Shipped 10/7/2026
Problem
The verification attestation records which checks ran against a commit, but nothing about which CLI commands that commit can affect. Since swamp-club#3143 (PR swamp-club/swamp#2902) the import graph from deno info --json is precise enough to answer that: a file under src/libswamp/ used to be in the closure of a median 195 of 198 command files and is now in a median of 6. Nothing computes or records the answer yet, so UAT test selection still has no input to work from and a reviewer cannot see a change's blast radius.
Proposed solution
Generate the list of commands affected by a change during the attestation step of the issue lifecycle, and carry it in the attestation.
- Compute it. For the verified commit, take the files changed against the merge base with
origin/main(the same three-dot diff the review guards use). For each command entry point undersrc/cli/commands/, take its module closure fromdeno info --json. A command is affected when its closure contains a changed file. - Record it.
scripts/build_attestation.tsadds the result to the attestation, as a new optional field inAttestationSchema(extensions/models/_lib/schemas.ts), for exampleaffectedCommandswith the command list, the total number of commands, and how the list was derived (diff base, edge kinds counted). Optional so existing attestations and CI validation keep working. - Show it. The verification checklist the agent presents before the PR opens includes the affected commands, and
post_attestationcarries the field to swamp-club with the rest of the document.
Things to decide
- Command identity. The graph gives command files (
src/cli/commands/vault_create.ts); UAT selection and people want command names (vault create). Group files such asvault.tscontain every subcommand, so they are always affected when a subcommand is. Decide whether to report files, names, or leaf commands only. - Type-only edges.
deno infolists modules reached only throughimport type(median closure 268 with them, 233 on runtime edges). Including them is conservative; excluding them is tighter. The JSON distinguishescodefromtypeper dependency. - Changes outside any closure. Docs, skills, workflows,
deno.json,deno.lock, the Deno version pin and build scripts are in no command's closure but can affect every command. These need an explicit rule (probably: treat as all commands) rather than silently reporting none. - What the graph cannot see. Runtime wiring — extension loading, registries, bundled skills and assets, non-literal dynamic imports — is invisible to static analysis. The field should say it is derived from static imports so nobody reads an empty list as proof of no effect.
- Always-affected commands.
extension,extension_sourceandextension_source_addhave a closure of about 1,216 modules because of the import cycle throughsrc/cli/mod.ts, so every change selects them. Breaking that cycle is separate work but limits how useful the list is until then. - Cost. One
deno info --jsonper command file is about 200 invocations. A singledeno info --json main.tsgives the whole graph; per-command closures can be computed from it in-process. - Trust.
scripts/build_attestation.tsis a trust-root file hashed inconfigIntegrity, and CI'svalidate-attestationreads the document. Decide whether CI only carries the field or also recomputes and compares it.
Alternatives considered
- Compute the list in CI at PR time instead of in the attestation: simpler trust story, but the agent and the human do not see it before the PR opens, and the lifecycle record on the issue does not carry it.
- A standalone script with no attestation field: usable for test selection, but leaves no durable record of what a shipped change was believed to affect.
Out of scope
Mapping affected commands to UAT tests and actually selecting tests in swamp-uat. This issue produces the input for that.
Shipped
Click a lifecycle step above to view its details.
Sign in to post a ripple.