Phase 13: multi-backend strength-routing (the Trust Ledger goes live)#57
Merged
Conversation
…Selector) Closes the Trust Ledger feedback loop — makes the shipped ledger LIVE — additively and default-off byte-identical. When an operator configures >1 coding backend, the historically-strongest is tried FIRST and a verify-fail races the DISTINCT backends with the verifier as judge; the per-candidate race_outcome events then carry different backends, which is the signal the ledger learns from. - agent.Selector seam: Select(ctx, Task, names) []string — orders WHICH backend to run; the verifier still decides "done" and the race winner (I2). The ledger only biases. - Orchestrator gains Backends []string, NewEnvFor func(dir,name) Env (resolves a NAMED backend FRESH per worktree — fixes the stale-instance problem), Selector. multiBackend() = len(Backends)>1 && NewEnvFor!=nil. executeSingle picks the best name (orderBackends) + builds it + emits a metadata-only `backend_select`; raceEscalate races one candidate per distinct ordered backend. Both gate on multiBackend(): UNSET => the existing NewEnv/Router/RaceN single path is byte-identical (existing tests are git-diff-empty + a default-off test proves it). - trust.Selector implements the seam structurally (Order by smoothed rank; nil/empty ledger => names unchanged), no agent import (leaf rule, deps_test holds). make verify green; -race green; golangci-lint 0; stdlib only; nothing wires the new fields yet (the cmd -backends flag is the next commit) so the default binary is behavior-identical. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ackends) Activates the Trust Ledger's routing — the deferred follow-on now lands. ADDITIVE, default-off byte-identical. - `-backends native,codex,claude-code` (registerCommon): empty ⇒ the single `-backend` path (byte-identical); one name ⇒ same as `-backend`; two+ ⇒ multi-backend routing. Unknown name is FATAL. `-backends` wins over `-backend`. N× race cost capped by the meter. - parseBackends (validate/dedup/order), multiEnvFactory (the NewEnvFor analogue: reuses the per-worktree env machinery — selectSandbox + the behavioral verifier — and swaps the backend by name via buildBackend; each name resolves its OWN provider/advisor and creds through the SecretStore seam, never to the model — I3), wireMultiBackend (the gate: <=1 ⇒ leaves the new fields unset = byte-identical; >=2 ⇒ sets Backends/NewEnvFor/Selector from trust.Replay(logPath); a broken-chain Replay logs + emits trust_replay_error + falls back to configured order, never aborts; empty/missing log ⇒ configured order until evidence). - Wired into runMain + buildRunOrchestrator. serve is out of scope (it builds no Orchestrator). The verifier still governs every race + the final gate (I2 — the core enforces it). Tests: default-off proof (all three fields nil without -backends), activation, per-name backend swap, unknown-fatal. make verify green; -race green; golangci-lint 0; stdlib only. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…es[0]) Review MEDIUM: a Selector is documented as ordering AND filtering, so a conforming one could return zero names; executeSingle indexed names[0] unguarded. orderBackends now falls back to the configured set (non-empty by multiBackend's len>1 precondition) when a Selector drops everything — one guard defending both callers (raceEscalate already guarded). + a regression test (empty Selector => runs the first configured backend, no panic). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The 'locked into one model vendor' row + the nilcore trust line now note that with -backends configured the Trust Ledger drives live verifier-judged backend routing. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
RNT56
pushed a commit
that referenced
this pull request
Jun 21, 2026
… routing Refresh the four in-scope docs to match merged Phase-13 work: - HORIZON.md: add a "Shipped since" banner; mark A1 (Trust Ledger, PR #55/#57), A7 (trace explorer, PR #55) and live multi-backend strength-routing (PR #57) as SHIPPED; note A1's "honest boundary" (multi-backend not wired) is now CLOSED; update the ranked summary + the "next move" footer (A1 done → A2/A5 next). Remaining horizon ideas left intact. - MULTI-AGENT.md: rewrite the stale §0 line-18 paragraph (one task / executePlanned not wired / dead-code budget Ledger / unhardened worktree.git) to today: single-task path + wired supervised project loop (ShouldSupervise → project.Loop), super.Supervisor bounded fan-out (caps), multi-backend routing (-backends + trust.Selector), swarm, charged budget meter, hardened git; add the wired-defaults caps. - ARCHITECTURE.md: add the multi-backend strength-routing seam (agent.Selector + Orchestrator.{Backends,NewEnvFor} + trust.Selector + -backends, I2 preserved) to the routing row and the I-section seams; add internal/{trust,trace} to the layer map. - CHANGELOG.md: close the trust+trace "Honest boundary" with a forward reference to the now-merged multi-backend routing-wiring entry. make verify green (exit 0); doc-only, no code or invariant change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes the Trust Ledger feedback loop — the deferred follow-on the trust PR flagged now lands. Configure multiple coding backends and NilCore tries the historically-strongest first, then on a verify-fail races the distinct backends with the verifier picking the winner; the per-backend
race_outcomeevents feed the ledger so it learns which backend wins on your codebase. Additive, default-off byte-identical. Adversarially reviewed — CLEAN on I2 / default-off / I3 / race-correctness / leaf-rule / contract; the one MEDIUM (an unguardednames[0]) is fixed.Core (
internal/agent,internal/trust)agent.Selectorseam (Select(ctx, Task, names) []string) — orders/filters which backend to run; the verifier still decides "done" and the race winner (I2).internal/trust.Selectorimplements it structurally (orders by the ledger's smoothed rank; nil/empty ledger ⇒ configured order), noagentimport.Orchestrator.{Backends, NewEnvFor, Selector}—multiBackend() = len(Backends)>1 && NewEnvFor!=nil.executeSingleruns the trust-strongest first (NewEnvForresolves the named backend fresh per worktree — no stale instance);raceEscalateraces one candidate per distinct backend. Both gate onmultiBackend(): unset ⇒ the existingNewEnv/Router/RaceNsingle path is byte-identical (existing testsgit-diff-empty + a default-off test).orderBackendsnever returns empty (falls back to the configured set).Wiring (
cmd/nilcore)-backends native,codex,claude-codeonnilcore run(+buildRunOrchestrator): empty ⇒ single-backendpath (byte-identical); two+ ⇒ routing. Unknown name FATAL.multiEnvFactoryreuses the per-worktree env machinery + swaps the backend by name viabuildBackend; each backend resolves its own creds via the SecretStore seam, never to the model (I3).Selector = trust.NewSelector(trust.Replay(log)); a broken-chain replay falls back to configured order (never aborts). N× race cost capped by the budget meter.Gate
make verifygreen ·go test -race ./internal/{agent,trust}/... ./cmd/nilcore/...green ·golangci-lint run ./...0 issues ·internal/backendcontract +go.mod/go.sumunchanged (I1/I6) · default binary behavior byte-identical without-backends.🤖 Generated with Claude Code