Skip to content

feat(review): operator OpenCode config overlay + file-based base (ADR-0099) - #464

Merged
stephane-segning merged 1 commit into
mainfrom
claude/magical-bardeen-3d20b6
Jul 17, 2026
Merged

feat(review): operator OpenCode config overlay + file-based base (ADR-0099)#464
stephane-segning merged 1 commit into
mainfrom
claude/magical-bardeen-3d20b6

Conversation

@stephane-segning

Copy link
Copy Markdown
Contributor

1. Summary

This PR changes:

  • Moves the review OpenCode config off the Rust json! blob in render_review_config onto a checked-in, human-readable base at integrations/opencode/config/review.jsonc (mirrors the open-mode precedent). It carries the invariants + defaults with a documented injection/override header.
  • Adds a trusted operator overlay (review.opencode in ai-helm-values, surfaced as ReviewFile.opencodeReviewConfig.opencode_overlay), deep-merged last over base+injection with full override (objects merge recursively; arrays/scalars from the overlay replace ours).
  • Adds a render-time floor-diff WARNING (not a lock): each relaxation (a built-in re-enabled, a permission opened, the lightbridge MCP or a required plugin dropped/replaced) is tracing::warn!'d and noted on the review's coverage disclosure. The overlay is captured (redacted) in the run-config audit trail.

It solves:

Note: the ADR merged as ADR-0099, not 0098 as the task referenced — 0098 was taken by the A2A per-finding streaming work.


2. Intent

The intent of this PR is:

Let a SysAdmin pass their own OpenCode config for review — merged with ours, full override — and make the base config OpenCode-native and readable, documenting exactly what the runtime injects/overrides so the operator sees what their overlay is overriding. Awareness over prevention (owner's choice, ADR-0099 §4): relaxing a review invariant is warned + disclosed, never blocked. The trusted operator config surface is orthogonal to — and does not reopen — the untrusted-checkout isolation of ADR-0097 #6 (HOME/XDG stay empty, cwd neutral; the overlay is the only external config source, host-side merged).


3. Scope

In Scope

  • integrations/opencode/config/review.jsonc (new base) + Rust loader (jsonc comment strip, include_str!), deep-merge helper, floor-diff.
  • The opencode overlay field on the file/resolved config with tier→flat fallback, and its redaction in the audit trail.
  • The per-task prompt is now written to a file and referenced via {file:*} (was inlined), per ADR-0099.

Out of Scope

  • ai-helm chart companion (surface config.review.opencode in the values schema) — a separate PR in the ai-helm repo; the runner already accepts the field.
  • Removal of the dead run_native_agent path (separate in-flight task; still present in main).

4. Verification

I verified this change by:

  • Running automated tests
  • Running manual tests
  • Checking logs
  • Checking metrics
  • Testing error cases
  • Testing permissions/security behavior
  • Testing rollback or failure behavior, if relevant

Commands run:

cargo build --workspace
cargo clippy --workspace --all-targets -- -D warnings
cargo test -p lci-review-agent -p agent-runner
# real opencode 1.18.3 on PATH — the two gated e2e proofs:
cargo test -p agent-runner --lib review::opencode::e2e::drives_a_real_opencode_review_to_finished -- --nocapture
cargo test -p agent-runner --lib review::opencode::e2e::rendered_config_with_overlay_is_accepted_by_real_opencode -- --nocapture

Results:

cargo build --workspace           -> Finished (clean)
cargo clippy --all-targets -Dwarn -> Finished (0 warnings)
lci-review-agent lib tests        -> ok. 131 passed; 0 failed  (incl. 13 new opencode::config tests)
agent-runner lib+integration      -> ok. 48 passed; 0 failed   (incl. redact overlay-secret + tier-fallback tests)
e2e drives_a_real_opencode_review_to_finished                 -> ok. 1 passed (base tools block => built-ins not advertised; agent=build)
e2e rendered_config_with_overlay_is_accepted_by_real_opencode -> ok. 1 passed
    (opencode debug config ACCEPTS the merged base+injection+overlay;
     overlay sub-agent present; permission.bash=allow honoured;
     untouched floor read=false intact; {file:*} prompt resolved; {env:*} secrets resolved;
     render.floor_breaches flagged the bash relaxation)

Key new tests: overlay adds a sub-agent → present in the merged config, no breach; overlay flips permission.bash to allow → merged config reflects it AND the floor warning fires; empty/absent overlay → byte-identical to base+injection (no behaviour change); jsonc comment-strip preserves // inside strings ($schema URL); deep-merge recurses objects and replaces arrays/scalars; an inlined credential in the overlay is redacted in the audit trail.


5. Screenshots / Evidence

  • Ground-truth (real opencode 1.18.3): opencode debug config resolves {env:*} and {file:./review-prompt.md} in agent.review.prompt at config load (config-dir-relative), and rejects unknown keys — so the base must be real .jsonc (verified), and inline→{file:*} for the prompt is behaviour-neutral (opencode works from the already-substituted config either way).
  • The existing ACP e2e confirms opencode-over-ACP runs its build agent, which is why the built-in disables are top-level (load-bearing) and hold under the base.

6. Risk Assessment

Risk level:

  • Low
  • Medium
  • High

Potential risks:

  • Full override lets a trusted operator relax the coverage/read-only floor (by design). A malformed overlay fails the whole review (opencode's strict schema) — loud, not silent.
  • The prompt delivery changed from inline to {file:*} in agent.review.prompt.

Mitigation:

  • Floor relaxations are WARNed + noted on the coverage disclosure so findings under a custom config aren't read as default. Absent/empty overlay is proven byte-identical to base+injection.
  • {file:*} prompt resolution proven equivalent to inline against real opencode; the prompt file is co-located with the config so the relative reference always resolves. The base is include_str!'d (compile-time), so no new runtime file dependency and no Dockerfile change.

7. AI Usage Declaration

AI was used for:

  • Understanding existing code
  • Generating code
  • Refactoring
  • Generating tests
  • Drafting documentation
  • Reviewing the diff
  • Not used

Human verification:

  • I understand every meaningful change in this PR
  • I checked generated code manually
  • I checked generated tests manually
  • I removed unsupported AI assumptions
  • I accept responsibility for this PR

8. Reviewer Focus

Please focus your review on:

  • The deep-merge + floor-diff logic in services/review-agent/src/opencode/config.rs (full-override semantics; the floor is derived from the base so it can't drift).
  • The overlay resolution/fallback in services/agent-runner/src/bootstrap/config/review.rs (review.opencode reaches both tiers; a per-tier block overrides).
  • That ADR-0097 [Ticket]: Kubernetes manifests + Helm/Kustomize (deploy/) #6 (checkout isolation) is untouched — the overlay is the only external config source and it is trusted.

@changeset-bot

changeset-bot Bot commented Jul 17, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 6bb571d

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@github-actions

Copy link
Copy Markdown
Contributor

✅ AI Governance check passed

This PR declares AI usage, references a source of truth, and provides verification evidence. Thank you.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements ADR-0099, introducing support for operator-supplied OpenCode config overlays (review.opencode) in review runs. It adds a base review.jsonc configuration file, updates the agent runner configuration to parse, fallback, and redact overlays (scrubbing inline credentials), and enhances the review agent to deep-merge overlays with base and runtime configurations. It also adds floor breach detection to warn when an overlay relaxes read-only or mediated coverage invariants, along with comprehensive unit and integration tests. There are no review comments to address, and no additional feedback is provided.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

…-0099)

Move the review OpenCode config off the Rust `json!` blob onto a checked-in,
human-readable `integrations/opencode/config/review.jsonc` base (mirroring
`open` mode), and add a trusted operator overlay merged host-side with full
override.

Three layers, last-writer-wins, merged in Rust so the untrusted checkout is
never a config source (ADR-0097 #6 reaffirmed):
1. base — review.jsonc (invariants + {env:*}/{file:*} placeholders), baked in
   via include_str!; opencode resolves the placeholders at load.
2. runtime injection — attribution headers (#89, dynamic keys), the tier
   reasoning flag (ADR-0069), temperature; the per-task system prompt is
   written to review-prompt.md beside the config and referenced {file:*}.
3. operator overlay — `review.opencode` from ai-helm-values (trusted),
   deep-merged LAST with full override (objects recurse; arrays/scalars replace).

Full override is intentional; the system makes relaxations visible, not
impossible: render diffs the merged config against the base floor and WARNs
each relaxation (built-in re-enabled, permission opened, lightbridge MCP or a
plugin dropped/replaced), and notes it on the review's coverage disclosure.

The overlay is captured (redacted) in the run-config audit trail.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@stephane-segning
stephane-segning force-pushed the claude/magical-bardeen-3d20b6 branch from d1a7ec5 to 6bb571d Compare July 17, 2026 10:46
@stephane-segning
stephane-segning merged commit ba2e05a into main Jul 17, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant