Skip to content

fix(pipelines): ops-pr-respond audit children scan whole repo despite pr-context injection #1453

@nextlevelshit

Description

@nextlevelshit

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

  1. The instruction sits below 200+ lines of audit-axis-specific prompt content. The LLM treats it as advisory, not constraining.
  2. 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.
  3. 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

  • An ops-pr-respond run 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.
  • No audit-* finding's file is outside pr_context.changed_files at runtime. Verifiable via jq on merged-findings.json.
  • Audit child token usage drops to < 30 k each (currently 60–100 k).

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

Metadata

Metadata

Assignees

No one assigned

    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