Skip to content

fix(router): preserve policy authorization across fallback redirects - #6380

Closed
luvs01 wants to merge 9 commits into
devfrom
fix/luvs01-674-policy-fallback-scope-20261001
Closed

luvs01 wants to merge 9 commits into
devfrom
fix/luvs01-674-policy-fallback-scope-20261001

Conversation

@luvs01

@luvs01 luvs01 commented Oct 1, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Policy fallback could authorize a redirect from a bounded diagnostic trace or reselect a public alias, allowing a retry to escape the original eligible provider/model set. Preserve the first policy evaluation's complete membership as request-owned state, evaluate retries as concrete candidates, and check the final destination before dispatch. Subagent selection, recovery, alias collisions, virtual wire models, and redirects retain that original authorization boundary.

Skip already-attempted physical destinations without losing the last actual upstream failure, route identity, usage, active attempt, or spend tracker. The accounting regression reproduces lost usage before the fix. Affinity fixtures now declare both permitted candidates in the actual policy instead of forging trace eligibility; their original identity-isolation assertions remain intact.

Source history is preserved through commit 2c34217881b072ba618595d1ca57a16e56f814c5, including bot commit 8176e729921290f8544b8a6044bf0ad8e5129dbd. The focused validation used the integration with dev at 0328373fb88fe0d019b29ae278e153d7fed4bcc7. The final bot integration retained the tested runtime and added one separately tested provider-fixture line.

Verification

Current follow-up

Follow-up verification for 05bc47d728dd791ffe796c2356d74d266e752bae:

Fix two deterministic source-oracle regressions: register policy-request-scope.ts in the exact Responses owner inventory; anchor shadow combo option inspection at the actual dispatcher call and assert valid ordered slice boundaries. Existing graph equality, size/cycle constraints and isolation marker assertions remain intact. No runtime, policy membership, attempt budget or role behavior changed.

Both exact CI assertions failed before the test-only corrections. The two complete fixture files and affected source-inventory consumers then passed 53 tests with 511 assertions. Runtime, policy eligibility and attempt budgets are unchanged.

Executed focused commands:

  • bun test ./tests/responses/responses-core-modules.test.ts ./tests/responses/responses-shadow-intercept.test.ts — passed.
  • bun test ./tests/lab/lab-passive-production-evidence.test.ts ./tests/lib/reasoning-replay-scope-source.test.ts ./tests/oauth/generic-oauth-failover.test.ts ./tests/server/passive-route-linker.test.ts -t 'production request path only links|reasoning replay scope propagation|sidecar on429 wiring|Responses owners do not import' — passed.

Required typecheck, structure, privacy and file-size checks passed. Full local suite and unfiltered test:changed were not run; the documented focused/resource exception and remaining coverage limitations remain in effect. No blocked broad Kiro/SOCKS transport test or real-provider validation is claimed.

Cross-platform CI succeeded for this exact HEAD. Checkout ea3280ca8b909d365e87bde6e9a833b93330edbf and the PR HEAD share tree 9b30ee9971a91cd796bf53f1a0b428dfad103d17. Skipped jobs remain skipped.

Independent maintainer approval, explicit security review and any required sponsorship remain pending before merge.

Earlier integration evidence

Current upstream integration: a6114b62ed1b65dede802359ccd373d913979b24; published HEAD 2acbf20e48d6ab6356639bcb03dd7faeb290afae. The source history through 2c34217881b072ba618595d1ca57a16e56f814c5 is retained without rewriting authors or commits. The PR-specific change was checked again after this integration; typecheck, structure, privacy and file-size gates passed. CI was pending when this earlier integration checkpoint was published; the current follow-up is verified above.

Windows, Bun 1.4.0, isolated test temporary directory:

  • bun test ./tests/routing/routing-policy-dispatch-scope.test.ts ./tests/routing/routing-policy-fallback.test.ts ./tests/routing/policy-execution.test.ts ./tests/routing/router-blocked-cross-provider.test.ts ./tests/responses/responses-compaction-recovery-policy.test.ts: 83 passed, 0 failed, 363 assertions. The accounting regression failed before the fix and passed afterward.
  • bun test ./tests/claude-integration/claude-native-affinity.test.ts ./tests/server/spend-instrumentation-log.test.ts ./tests/responses/responses-spend-ledger-wiring.test.ts: 26 passed, 0 failed, 168 assertions. The previous fixture failed with an undeclared candidate; the corrected real policy preserves the original isolation assertions.
  • bun test ./tests/providers/opencode-go-session-header.test.ts -t "affinity across the policy fallback retry": 3 passed, 0 failed, 12 assertions for the additional bot fixture change.
  • bun node_modules/typescript/bin/tsc --noEmit: passed, including after bot integration.
  • bun scripts/structure-ssot.ts: passed; bot integration changed no structure source or documentation.
  • bun scripts/privacy-scan.ts: passed, including after bot integration.
  • bun scripts/file-size-ratchet.ts: passed; the bot integration adds only one fixture line to the previously checked tree.
  • git diff --cached --check 0328373fb88fe0d019b29ae278e153d7fed4bcc7 and the final staged diff check: passed.

The full local suite and test:changed were not run under the focused-validation exception because concurrent isolated worktrees made the full suite impractical. These tests use synthetic dispatch and do not verify a real provider connection. Documentation-site build verification remains incomplete: the available local build and its baseline comparison both fail while loading Astro with require is not defined in the dependency/module loader. This is not a successful documentation build, and no separate successful build is claimed for this change.

Required upstream CI on the final published HEAD is pending; results from another HEAD are not its verification. Applicable documentation CI and independent authorization/accounting review remain required before merge.

Checklist

  • Scope stays focused on request-owned policy authorization, fallback accounting, and matching regressions.
  • Routing contracts and user-facing policy documentation are updated; build limitations are recorded.
  • Security-sensitive changes have independent maintainer review; sponsorship is required before merge where the sponsored-surface gate applies.
  • Author validation is documented for 05bc47d728dd791ffe796c2356d74d266e752bae, known correct findings are addressed, and exact-HEAD CI is complete; author review readiness is confirmed.

Independent maintainer approval, explicit security review, and any required maintainer-sponsored decision remain pending before merge. These are separate from author review readiness; no approval or sponsorship is claimed.

luvs01 and others added 8 commits September 29, 2026 00:29
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
… traces truncate

An eligibility probe that throws (e.g. a blocked-model redirect cycle) now skips that fallback candidate instead of selecting it and dead-ending the retry. Redirect membership uses the full policy evaluation result carried on the request context, so an eligible destination truncated out of the bounded trace can still receive a hop. Eligibility probes run through previewRouteModel so they never write combo selection state.
…d scope

The dev merge made policy fallback authorization request-owned: the retry's
resolved route must sit inside the eligibility captured from the real first
route, and the candidate probe resolves each trace row concretely. Synthetic
traces can no longer authorize candidates the real evaluation never admitted,
so the fixtures now declare them for real: the second candidate joins the
native-hop profile, and opencode-go-2 joins the provider map.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@coderabbitai

coderabbitai Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 20 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 10 included reviews currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Repository: lidge-jun/opencodex/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: 37e11363-b936-4bd8-a585-65a9da99a1c9

📥 Commits

Reviewing files that changed from the base of the PR and between a6114b6 and 05bc47d.

📒 Files selected for processing (25)
  • docs-site/src/content/docs/reference/configuration/routing.md
  • scripts/test-layout/layout.json
  • src/router.ts
  • src/server/request-log.ts
  • src/server/responses/compact.ts
  • src/server/responses/core-normalize.ts
  • src/server/responses/core-options.ts
  • src/server/responses/policy-fallback.ts
  • src/server/responses/policy-request-scope.ts
  • src/server/responses/request-prepare.ts
  • structure/INDEX.md
  • structure/manifest.json
  • structure/runtime.md
  • structure/subagents.md
  • structure/transports/policy-fallback.md
  • structure/transports/responses-failover.md
  • structure/transports/responses.md
  • tests/claude-integration/claude-native-affinity.test.ts
  • tests/fixtures/test-layout-expected.json
  • tests/helpers/responses-core-source.ts
  • tests/providers/opencode-go-session-header.test.ts
  • tests/responses/responses-shadow-intercept.test.ts
  • tests/routing/router-blocked-cross-provider.test.ts
  • tests/routing/routing-policy-dispatch-scope.test.ts
  • tests/routing/routing-policy-fallback.test.ts
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Autopilot is currently an internal CodeRabbit preview.


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.

@github-actions

github-actions Bot commented Oct 1, 2026

Copy link
Copy Markdown
Contributor

✅ Deterministic PR hygiene checks passed.

@github-actions github-actions Bot added the bug Something isn't working label Oct 1, 2026
@luvs01

luvs01 commented Oct 1, 2026

Copy link
Copy Markdown
Collaborator Author

Follow-up verification for 05bc47d728dd791ffe796c2356d74d266e752bae:

Fix two deterministic source-oracle regressions: register policy-request-scope.ts in the exact Responses owner inventory; anchor shadow combo option inspection at the actual dispatcher call and assert valid ordered slice boundaries. Existing graph equality, size/cycle constraints and isolation marker assertions remain intact. No runtime, policy membership, attempt budget or role behavior changed.

Both exact CI assertions failed before the test-only corrections. The two complete fixture files and affected source-inventory consumers then passed 53 tests with 511 assertions. Runtime, policy eligibility and attempt budgets are unchanged.

Executed focused commands:

  • bun test ./tests/responses/responses-core-modules.test.ts ./tests/responses/responses-shadow-intercept.test.ts — passed.
  • bun test ./tests/lab/lab-passive-production-evidence.test.ts ./tests/lib/reasoning-replay-scope-source.test.ts ./tests/oauth/generic-oauth-failover.test.ts ./tests/server/passive-route-linker.test.ts -t 'production request path only links|reasoning replay scope propagation|sidecar on429 wiring|Responses owners do not import' — passed.

Required typecheck, structure, privacy and file-size checks passed. Full local suite and unfiltered test:changed were not run; the documented focused/resource exception and remaining coverage limitations remain in effect. No blocked broad Kiro/SOCKS transport test or real-provider validation is claimed.

Cross-platform CI succeeded for this exact HEAD. Checkout ea3280ca8b909d365e87bde6e9a833b93330edbf and the PR HEAD share tree 9b30ee9971a91cd796bf53f1a0b428dfad103d17. Skipped jobs remain skipped.

Independent maintainer approval, explicit security review and any required sponsorship remain pending before merge.

@lidge-jun

Copy link
Copy Markdown
Owner

Carried to #6396 so it can land in the next release. Your commits are kept as they are and the squash will carry Co-authored-by.

An independent security review of 05bc47d728 found one P2, which #6396 fixes in 5cb070123c: the shadow-call intercept resolved its target through the request's policy capture before deciding to intercept, so a declined policy-profile target scoped the request's own route (a 409 refusal, or a policy relabel that enabled fallback to unselected providers). The probe now skips the capture, and the accepted target is captured where it becomes the route, with a regression case in tests/routing/routing-policy-dispatch-scope.test.ts. Thank you for the change.

lidge-jun added a commit that referenced this pull request Oct 1, 2026
…(carry #6380) (#6396)

Policy fallback could authorize a redirect from a bounded diagnostic trace or reselect a public alias, letting a retry escape the original eligible provider/model set. Keep the first policy evaluation's complete membership as request-owned state, evaluate retries as concrete candidates, and check the final destination before dispatch. Subagent selection, recovery, alias collisions and virtual wire models stay inside that membership.

The shadow-intercept target is probed without capturing that scope and is captured only when interception is accepted, so a declined policy target never scopes the request's own route.

Carried from #6380.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
@lidge-jun

Copy link
Copy Markdown
Owner

Landed on dev through the maintainer carry #6396 (58a26f0), which keeps your authorship with a Co-authored-by trailer. Thank you!

@lidge-jun lidge-jun closed this Oct 1, 2026
@lidge-jun
lidge-jun deleted the fix/luvs01-674-policy-fallback-scope-20261001 branch October 3, 2026 00:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants