Symptom
When ops-pr-respond.parallel-review invokes its six audit-* sub-pipelines with config.inject: [\"pr-context\"], every audit scans the entire repository instead of restricting itself to pr_context.changed_files. Empirical baseline runs show:
- audit-architecture surfaces 17 critical findings on
internal/pipeline/executor.go and other files NOT in the PR diff (file internal/pipeline/executor.go:16 is not in PR 1441's changed files).
- audit-tests, audit-duplicates, audit-doc-scan all do the same — findings on unrelated
cmd/wave/, internal/state/, etc.
- Token cost: each child takes 60–100 k tokens. Whole-repo scan is the dominant driver.
- Time cost: each audit step burns 7–13 minutes.
PR #1436 (issue #1411) added a conditional preamble to each audit-* prompt: "if .agents/artifacts/pr-context exists, restrict scan to changed_files". But the LLM consistently ignores or weakens this instruction at runtime. Findings on out-of-scope files reach merge-findings, which then relies on the deterministic filter-scope step to drop them.
Why the prompt-level guard is insufficient
- The instruction sits below 200+ lines of audit-axis-specific prompt content. The LLM treats it as advisory, not constraining.
- Audit prompts use Read / Grep / Glob with no path restrictions. Even if the LLM "intends" to scope itself, its tools see the full mount and the model picks up findings opportunistically.
- There is no tool-level guard that REJECTS a finding emitted against a file outside
changed_files at the source.
Proposal
Layer 1 — workspace mount narrowed to changed_files (preferred)
Instead of mounting the entire project at /project readonly, the orchestrator should construct a subset workspace containing only the files in pr_context.changed_files. Each audit child sees exactly the diff scope. Tools physically cannot escape it.
Implementation sketch:
- ops-pr-respond's
parallel-review step computes a sparse mount config from pr_context.changed_files before launching children, OR
- Wave gains a
workspace.mount.subset_from_artifact directive: "mount only files listed in <artifact>.changed_files".
Layer 2 — tool allowlist constraint (defense in depth)
audit-* personas already use Read / Grep / Glob. Add a persona-level path-prefix allowlist that rejects access outside changed_files. This catches model drift even if the workspace contains more.
Layer 3 — finding-emission contract (defense in depth)
Audit output schema (shared-findings.schema.json) gains a JSON-Schema pattern constraint on the file field that requires the value match a regex computed from changed_files. Findings on out-of-scope files fail contract validation.
Acceptance
Source
Operator note 2026-04-28 during ops-pr-respond validation cascade. Run ops-pr-respond-20260428-000751-c161 on PR #1441: all 6 audits completed but scope was full-repo despite the conditional prompt preamble.
Related
Symptom
When
ops-pr-respond.parallel-reviewinvokes its six audit-* sub-pipelines withconfig.inject: [\"pr-context\"], every audit scans the entire repository instead of restricting itself topr_context.changed_files. Empirical baseline runs show:internal/pipeline/executor.goand other files NOT in the PR diff (fileinternal/pipeline/executor.go:16is not in PR 1441's changed files).cmd/wave/,internal/state/, etc.PR #1436 (issue #1411) added a conditional preamble to each audit-* prompt: "if
.agents/artifacts/pr-contextexists, restrict scan tochanged_files". But the LLM consistently ignores or weakens this instruction at runtime. Findings on out-of-scope files reach merge-findings, which then relies on the deterministicfilter-scopestep to drop them.Why the prompt-level guard is insufficient
changed_filesat the source.Proposal
Layer 1 — workspace mount narrowed to changed_files (preferred)
Instead of mounting the entire project at
/projectreadonly, the orchestrator should construct a subset workspace containing only the files inpr_context.changed_files. Each audit child sees exactly the diff scope. Tools physically cannot escape it.Implementation sketch:
parallel-reviewstep computes a sparse mount config frompr_context.changed_filesbefore launching children, ORworkspace.mount.subset_from_artifactdirective: "mount only files listed in<artifact>.changed_files".Layer 2 — tool allowlist constraint (defense in depth)
audit-* personas already use Read / Grep / Glob. Add a persona-level path-prefix allowlist that rejects access outside
changed_files. This catches model drift even if the workspace contains more.Layer 3 — finding-emission contract (defense in depth)
Audit output schema (
shared-findings.schema.json) gains a JSON-Schemapatternconstraint on thefilefield that requires the value match a regex computed fromchanged_files. Findings on out-of-scope files fail contract validation.Acceptance
ops-pr-respondrun on a 10-file PR produces ≤ 30 raw findings (down from ~127 baseline today). PR feat(pipelines): scope audits to PR diff and improve ops-pr-respond signal-to-noise #1411 acceptance criteria already track this number, but the criteria were not enforced because the LLM-only guard didn't move it.fileis outsidepr_context.changed_filesat runtime. Verifiable viajqonmerged-findings.json.Source
Operator note 2026-04-28 during ops-pr-respond validation cascade. Run
ops-pr-respond-20260428-000751-c161on PR #1441: all 6 audits completed but scope was full-repo despite the conditional prompt preamble.Related