Skip to content

fix(review): declare each runtime's own identity in the negotiated route - #2244

Closed
aparragithub wants to merge 4 commits into
Gentleman-Programming:mainfrom
aparragithub:fix/review-runtime-identity-route
Closed

fix(review): declare each runtime's own identity in the negotiated route#2244
aparragithub wants to merge 4 commits into
Gentleman-Programming:mainfrom
aparragithub:fix/review-runtime-identity-route

Conversation

@aparragithub

@aparragithub aparragithub commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

🔗 Linked Issue

Closes #2242

⚠️ #2242 does not yet carry status:approved. The Check Issue Has status:approved job will fail until a maintainer applies it. This PR is opened at the contributor's explicit request so the implementation is available for review; it is not a claim that the approval gate was satisfied.


🏷️ PR Type

  • type:bug — Bug fix (non-breaking change that fixes an issue)
  • type:feature — New feature (non-breaking change that adds functionality)
  • type:docs — Documentation only
  • type:refactor — Code refactoring (no functional changes)
  • type:chore — Build, CI, or tooling changes
  • type:breaking-change — Breaking change (fix or feature that changes existing behavior)

📝 Summary

  • The shared review-ledger contract hardcoded --agent claude-code in the negotiated STATUS route. That text is spliced into every adapter's generated orchestrator and sdd-apply assets, so a non-Claude runtime was instructed to declare Claude Code's runtime identity — and would pass the preflight transport gate it must fail closed against. Each runtime's generated route now declares its own identity.
  • A route carrying zero or more than one --agent token was reported as immutable_review_transport_unsupported, naming a capability the facade never evaluated and leaving the caller a terminal stop with nothing to run. That is the envelope reported in fix(opencode): negotiated review status misclassifies supported runtime transport #2242, produced by installed assets predating the gating. It is now a distinct runtime_identity_unresolved outcome with a runnable exit.
  • No runtime gains or loses transport here. Claude Code remains the only supported immutable receipt-review transport; OpenCode and Codex stay transport-disabled pending fix(opencode): provider-bound review inspection is denied on Windows #2076 and feat(codex): add immutable artifact-bound receipt-review transport #2208.

📂 Changes

File / Area What Changed
internal/assets/skills/_shared/review-ledger-contract.md Negotiated route uses the existing {{GENTLE_AI_RUNTIME_AGENT_ID}} placeholder instead of a literal claude-code, in both the Route section and the authority-first procedure
internal/components/sdd/boundedreview.go renderBoundedReviewAsset takes the target agent and resolves the runtime placeholder for every generated asset, not only the orchestrator; substitution runs after the contract sections are spliced in, because those sections carry the placeholder
internal/components/sdd/inject.go Command and embedded-subagent renders pass adapter.Agent()
internal/cli/review_transport_capability.go New reviewRuntimeIdentityUnresolvedReason (runtime_identity_unresolved, next_action: correct_request)
internal/cli/review_facade.go Negotiated STATUS and START classify an absent/duplicated --agent with the new reason; the cause names gentle-ai sync as the recovery
docs/review-integration.md Documents per-runtime route identity and the new typed outcome
testdata/golden/* (12 files) Regenerated: each adapter's route now names that adapter. The Claude goldens are unchanged
Tests Per-agent route coverage across all 16 catalog adapters; new CLI coverage for absent and duplicated identity; two existing tests updated that were pinning the defect

Test baselines that moved

Baseline Why
TestKilocodeReviewSettingsMatchCurrentMainBaseline SHA Settings embed the orchestrator prompt, which now carries Kilocode's own identity
TestOpenCodeRenderedReviewProtocolCost pins (+38 chars each tier) The unrendered contract now holds the 30-char placeholder twice instead of claude-code. Both tiers keep their >15% headroom below the ceilings

🧪 Test Plan

Unit Tests — ✅ pass, 63 packages, 0 failures

go test ./...

Go Format — ✅ pass

go run ./internal/gofmtcheck

E2E Tests⚠️ not run (Docker not available in the authoring environment). Left to CI.

cd e2e && ./docker-test.sh

Benchmark Validation⚠️ not run. This change touches the review lifecycle, so benchmark validation does apply and should not be waived. Flagging it explicitly rather than claiming coverage that was not produced.

  • Unit tests pass (go test ./...)
  • Go format passes (go run ./internal/gofmtcheck)
  • E2E tests pass (cd e2e && ./docker-test.sh)
  • Manually tested locally

Manual verification: built the binary and confirmed the generated OpenCode assets now emit --agent opencode, and that negotiated STATUS without an --agent token returns runtime_identity_unresolved with retry_safe: true and a cause naming gentle-ai sync.


✅ Contributor Checklist

  • PR is linked to an issue with status:approvedfix(opencode): negotiated review status misclassifies supported runtime transport #2242 is not yet approved; see the note above
  • PR stays within 400 changed lines (243: 167 insertions + 76 deletions)
  • I have added the appropriate type:* label to this PR
  • Unit tests pass (go test ./...)
  • Go format passes (go run ./internal/gofmtcheck)
  • E2E tests pass (cd e2e && ./docker-test.sh) — not run locally
  • Benchmark validation completed — not run; applicable to this change
  • I have updated documentation if necessary
  • My commits follow Conventional Commits format
  • My commits do not include Co-Authored-By trailers

💬 Notes for Reviewers

The security-relevant direction is the inverse of what #2242's title suggests. #2242 reads as "supported OpenCode is misclassified as unsupported". It is not: OpenCode's transport is deliberately disabled (ee31bc2e, pending #2076). The real defect is that the product handed unsupported runtimes Claude Code's identity, which would let them through the gate #2207 introduced. This PR closes that, and deliberately does not re-enable any transport.

A second surface is still open and is tracked separately in #2243: gentle-ai review capabilities advertises bootstrap.command with a compile-time --agent claude-code for every caller, and capabilities is exempt from the negotiated-contract argument requirement. It is left out here because bootstrap.command is pinned as a JSON const in the capabilities-v2.1 and v2.2 schemas with byte-pinned fixtures, so resolving it is a contract decision rather than a string edit. It is a prerequisite for #2076 and #2208.

Guard population: this change adds no security/integrity/admission/repair/governance guard and does not alter any guard's legitimate input population; .guard-population-baseline.txt is unchanged. Two refusal:by-design world-action markers were removed from the two reclassified sites, because those refusals now name a runnable exit — the refusal-resolution ratchet flags the combination as contradictory, and it is right to.

Summary by CodeRabbit

  • New Features

    • Added runtime-specific review routing and generated review assets for supported integrations.
    • Added validation for missing, empty, whitespace-only, or duplicate runtime identities before review work begins.
    • Added clear recovery guidance to regenerate routes with gentle-ai sync.
  • Bug Fixes

    • Unsupported runtimes and unresolved runtime identities are now reported separately.
    • Corrective routing requests can be safely retried without starting invalid review work.
  • Documentation

    • Clarified v2.1 transport eligibility and runtime routing requirements.

Test added 2 commits August 2, 2026 02:04
The shared review-ledger contract hardcoded `--agent claude-code` in the
negotiated STATUS route. That contract text is spliced into every adapter's
generated orchestrator and sdd-apply assets, so a non-Claude runtime was
instructed to declare Claude Code's runtime identity and would pass the
preflight transport gate it must fail closed against.

Render the existing {{GENTLE_AI_RUNTIME_AGENT_ID}} placeholder for every
generated asset rather than only the orchestrator: commands and embedded
subagents now render with their adapter's agent. Substitution runs after the
contract sections are spliced in, because those sections carry the
placeholder themselves.

Refs Gentleman-Programming#2242
A negotiated route carrying zero or more than one `--agent` token was
reported as `immutable_review_transport_unsupported`, which named a
capability the facade never evaluated and left the caller a terminal stop
with nothing to run. An absent or duplicated token is a malformed or stale
route, not a claim about any runtime's transport.

Return `runtime_identity_unresolved` with `next_action: correct_request`
instead. The refusal stays retry-safe and its additive `cause` names
`gentle-ai sync` as the way to regenerate the route.

Refs Gentleman-Programming#2242
@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: d52b23de-31a4-4038-9a1f-693c29b2e68b

📥 Commits

Reviewing files that changed from the base of the PR and between 3fa9a42 and 3574a35.

📒 Files selected for processing (1)
  • internal/cli/review_transport_capability_test.go

📝 Walkthrough

Walkthrough

The change replaces hard-coded Claude Code identities with runtime-specific agent IDs in bounded-review assets. Negotiated STATUS and START now distinguish unresolved route identities from unsupported transport and provide gentle-ai sync recovery guidance.

Changes

Runtime identity handling

Layer / File(s) Summary
Runtime-specific review asset rendering
internal/assets/skills/_shared/review-ledger-contract.md, internal/components/sdd/...
Review assets use a runtime agent placeholder and substitute each adapter’s identity during rendering. Tests validate supported runtime assets and updated rendered baselines.
Negotiated route identity preflight
internal/cli/review_transport_capability.go, internal/cli/review_facade.go, internal/cli/*_test.go, docs/review-integration.md
Routes without exactly one adapter-specific --agent token return runtime_identity_unresolved, use correct_request, and identify gentle-ai sync for regeneration. OpenCode routing tests now require opencode.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related issues

Possibly related PRs

Suggested labels: type:bug, size:exception

Suggested reviewers: alan-thegentleman

Sequence Diagram(s)

sequenceDiagram
  participant ReviewStatusOrStart
  participant RoutePreflight
  participant gentleAiSync
  ReviewStatusOrStart->>RoutePreflight: validate generated --agent identity
  RoutePreflight-->>ReviewStatusOrStart: return runtime_identity_unresolved
  ReviewStatusOrStart->>gentleAiSync: regenerate route
  gentleAiSync-->>ReviewStatusOrStart: return adapter-specific route
Loading
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR fixes unresolved-identity classification and recovery, but it does not meet #2242's requirement for OpenCode to use managed immutable transport. Enable OpenCode's managed immutable receipt-review transport, while retaining unresolved-identity handling for missing or ambiguous routes.
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the primary change: declaring each runtime's identity in negotiated routes.
Out of Scope Changes check ✅ Passed The documentation, rendering, CLI, and test changes all support runtime identity handling and negotiated review transport requirements.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/cli/review_facade.go`:
- Around line 763-766: Classify empty or whitespace-only --agent values as
unresolved runtime identities before transport evaluation. In
internal/cli/review_facade.go lines 763-766 and 1480-1482, validate the trimmed
runtimeAgent and return reviewPreflightRefusal with
reviewRuntimeIdentityUnresolvedReason when it is empty; in
internal/cli/review_transport_capability_test.go lines 114-160, add STATUS and
START coverage for both --agent "" and --agent= inputs.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 12d44f26-e6a1-49bf-ac33-7a9c3a640cdc

📥 Commits

Reviewing files that changed from the base of the PR and between 545485d and 344ed0f.

⛔ Files ignored due to path filters (12)
  • testdata/golden/combined-windsurf-global-rules.golden is excluded by !testdata/**
  • testdata/golden/sdd-antigravity-rulesmd.golden is excluded by !testdata/**
  • testdata/golden/sdd-codex-agentsmd-lowcost.golden is excluded by !testdata/**
  • testdata/golden/sdd-codex-agentsmd-powerful.golden is excluded by !testdata/**
  • testdata/golden/sdd-codex-agentsmd.golden is excluded by !testdata/**
  • testdata/golden/sdd-cursor-rules.golden is excluded by !testdata/**
  • testdata/golden/sdd-gemini-geminimd.golden is excluded by !testdata/**
  • testdata/golden/sdd-kiro-instructions.golden is excluded by !testdata/**
  • testdata/golden/sdd-opencode-cmd-sdd-apply.golden is excluded by !testdata/**
  • testdata/golden/sdd-opencode-multi-settings.golden is excluded by !testdata/**
  • testdata/golden/sdd-vscode-instructions.golden is excluded by !testdata/**
  • testdata/golden/sdd-windsurf-global-rules.golden is excluded by !testdata/**
📒 Files selected for processing (13)
  • docs/review-integration.md
  • internal/assets/skills/_shared/review-ledger-contract.md
  • internal/cli/review_facade.go
  • internal/cli/review_transport_capability.go
  • internal/cli/review_transport_capability_test.go
  • internal/cli/sync_test.go
  • internal/components/sdd/bounded_review_contract_test.go
  • internal/components/sdd/boundedreview.go
  • internal/components/sdd/inject.go
  • internal/components/sdd/inject_test.go
  • internal/components/sdd/prompts_test.go
  • internal/components/sdd/review_ledger_contract_test.go
  • internal/components/sdd/reviewer_envelope_guard_test.go

Comment thread internal/cli/review_facade.go Outdated
`--agent ""` and `--agent=` satisfy the cardinality check with a single
token but declare no identity. Both flows fell through to the transport
lookup and were reported as `immutable_review_transport_unsupported`, which
asserts something about a runtime that was never named.

Reject an empty trimmed identity alongside the cardinality check in
negotiated STATUS and START, so the caller gets `runtime_identity_unresolved`
and its runnable exit. Well-formed tokens naming an unknown runtime keep the
unsupported-transport classification.

Refs Gentleman-Programming#2242
@aparragithub

Copy link
Copy Markdown
Contributor Author

Thanks — applied in 3fa9a426.

--agent "" and --agent= do satisfy the cardinality check with a single token while declaring no identity, so they fell through to the transport lookup and were reported as immutable_review_transport_unsupported. That asserts something about a runtime that was never named, which is the same category error this PR exists to fix.

Both negotiated STATUS and START now reject an empty trimmed identity alongside the cardinality check, and coverage was added for --agent "" and --agent= on each. I also included a whitespace-only case, since TrimSpace puts it in the same category.

Verified the new cases fail without the change and pass with it; the three pre-existing cases were unaffected.

Deliberately unchanged: well-formed tokens naming an unknown runtime (open-code, OpenCode) keep immutable_review_transport_unsupported. Those declare an identity that genuinely has no transport, so the transport classification is the honest one there.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/cli/review_transport_capability_test.go`:
- Around line 141-162: Add table-driven START cases for duplicate runtime
identities and whitespace-only runtime identities in the review transport
capability tests, alongside the existing status cases. Route them through
runReviewFacadeStart and assert the established unresolved-identity failure
envelope, covering both duplicate and whitespace-only validation paths without
changing status coverage.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 53ff9ebc-bc1c-4961-9f33-10766b389b9a

📥 Commits

Reviewing files that changed from the base of the PR and between 344ed0f and 3fa9a42.

📒 Files selected for processing (2)
  • internal/cli/review_facade.go
  • internal/cli/review_transport_capability_test.go

Comment thread internal/cli/review_transport_capability_test.go
START resolves the runtime identity in its own preflight branch, but the
duplicate and whitespace-only shapes were exercised only through STATUS.

Refs Gentleman-Programming#2242
@aparragithub

Copy link
Copy Markdown
Contributor Author

Closing this in favour of a root-level fix.

This PR is correct as far as it goes: each runtime's generated route now declares its own identity instead of borrowing claude-code, and an unresolved identity is classified separately from an unsupported transport. But it only makes the refusal honest — it does not let any additional runtime complete a review.

The underlying problem is that immutable receipt-review transport exists for exactly one runtime. Per #2076 / #2221 the resolution for OpenCode was to fail closed, because OpenCode 1.18.10 cannot bind candidate-specific shell permissions to a child session. That left OpenCode's lens agents with no shell — which is the hard requirement already satisfied — but they were never given the prompt-carried evidence path Claude Code has.

Since the inspect-candidate commands are run by the parent orchestrator and never by the lens, the runtime requirement is only 'can launch a shell-less subagent with a large prompt'. The prompt-carried transport is Claude-specific by construction, not by necessity. That is where the fix belongs.

Nothing here is lost: the branch remains at fix/review-runtime-identity-route and the analysis is recorded in #2242.

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.

fix(opencode): negotiated review status misclassifies supported runtime transport

1 participant