Repository navigation
Conversation
The plugin now serves the opencode and opencode-go routes itself, through supported host paths only, and the hidden-route workaround is gone. A prepended internal/config listener hands pi-ai a copy of its config without the two plane entries, so pi-ai keeps every other route. On a commit the plugin reconciles: it builds one plane adapter, a subclass of the host's PiAiAdapter, over pure profiles (utils/plane-profile, plane-model, model-metadata and protocols) and registers only the planes that are declared. A Settings candidate has the plane entries it changes validated strictly. A read-only settings.describe graft puts the committed plane entries back, so the host still sees them. Deleted: responses-provider, responses-routes, google-bridge, pi-provider and utils/google-replay; the listing hide and the discovery decoration; the stream redirect; the D19 settings; and the hidden ids in DEFAULT_PROVIDERS and cordis.patch.yml. What users see: any saved id is accepted and served, and an id no catalog knows dispatches as completions. The protocol comes from the catalog and model info follows the user's own row first. A model whose reasoning is only on or off offers Off/On. The default endpoint is the per-protocol inference family. Keys resolve by pi-ai's own rule, and a plane lists its declared ids even when no key resolves. When several pi-ai rows declare planes, the row the plugin serves stays the same while it is live and still declares one, so no row is left stripped with nobody serving it. If the host's pi-ai module cannot be read, the plugin steps aside even before any plane is declared, so a later Settings save goes to pi-ai's own check. The characterization rows this changes are flipped to new baselines; every other row stays green unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
# Conflicts: # README.md # README.zh-CN.md # docs/redirect-planes.md
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
|
The fix already exists. Generated by Claude Code |
|
Generated by Claude Code |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
The refreshed Go catalog serves its Gemini model as gemini-4-argon, so the plane-dispatch mock, the plane-model cases and the binary e2e's probe expectations name the new id; the Go Google base they assert is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
The review ran three rounds (found 20, 5 and 8; upheld 19, 4 and 8). What it found and what changed: - A completions model whose effort list names none lost its Off. utils/model-metadata.ts now offers Off with none as its wire value on completions, as pi 1.1.0's own entries do; Responses unchanged. Pinned in model-metadata, plane-model and a new mock-gateway case. - A Go entry with no apiKeyEnv authenticates with OPENCODE_API_KEY (pi's lookup, D20), and nothing said so. README "Changed in 1.x" and step 3 now name it; host-planes.test.ts pins both cases. - A Settings save of a plane was refused as "cannot be validated yet" while the host modules were unloaded. host/route-claim.ts now judges it with the last modules that loaded; route-claim.test.ts pins it. - Fiber.update(config) with noSave false would persist the stripped config and drop both planes. Recorded as a constraint in route-claim.ts and the plan; no caller does it today. - Stale text: cordis-context.ts comments (stream redirect, isolate, root inject), deep-dive.md (pi's Go lookup, who answers Fetch), CONTRIBUTING (field count, the host-modules floor), and historical banners on opencode-parity-plan.md and upstream-findings.md. - The mock body-shape row asserted only body.model. It now checks each protocol's required fields and that the gateway answered 200, or the vendor's 404 for the unknown id. - Route-set rows: removing the last plane now pins replace([]) on the live handle, and "booting with none" waits for the plugin's row to be active instead of sleeping 50 ms. - The live protocol-routing suite now sends paid models through the plane adapter on a tier-A host, not only raw probes. - README's credential-isolation claim was false: the Go meter can send the Zen key. README.md, README.zh-CN.md, deep-dive.md, credentials.md and redirect-planes.md now give the real order and the 403 remedies; readme-parity.test.ts keeps both READMEs in step. - The keySource hint described Automatic backwards. settings-copy.ts (en and zh) now gives literal key, captured key, then reference. - The live adapter blocks dropped a protocol whose model was withdrawn. They now walk up to three candidates per protocol (support/live-walk.ts), pass a "model is unavailable" turn only when a raw probe confirms it (support/live-probe.ts), and skip naming a protocol no candidate reached. - A mock comment claimed a body passed shape checks the mock lacks. Declined: a toggle beside an effort list still offers no Off, which moves baseline facets and needs the owner's decision; the Models store's join stays a documented restatement rather than importing a client UI package; the PR description is edited outside the tree. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
Second review of P-R1This phase's first reviews ran without the dedicated reviewer, which was unavailable at the time. It has now had that review: three rounds, through the correctness, rules and test-matrix lenses.
In total 31 findings were upheld and 23 fixed. Round 3's two lenses found the same two problems: the Chinese README was not ported, and the live walk dropped a protocol. Fixed
Declined
Commit: 0cceb81. Gate before the commit: check, 1387 unit tests, 63 mock tests, build and bundle gate, all passing. Generated by Claude Code |
…levels The live suite caught the Go plane's Gemini model refusing a thinking budget: the gateway answered that the model takes a thinking level and not a budget. Pi chooses a thinking level over a thinking budget only by matching the model id against its own pattern, so a model the pattern does not name was sent a budget it cannot accept. The plugin now makes that decision from the catalog, as D16 asks: a model whose catalog entry offers discrete effort levels on the Google protocol gets a thinking level. It builds that request through pi's public exports, on both the enabled and the disabled path, and hands every other model back to pi's own path unchanged. Tests pin it: the pure rule over the catalog, a differential check that the wrapper builds the same request as pi's own streamSimple for an id pi already recognises, the lazy loading of the pi pieces, and a mock-gateway case that the turn completes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
|
Fix pushed: Google's thinking level for Gemini models the catalog describes by level (4dbd22e) The live failure. The live suite caught a turn on the Go plane's Gemini model failing. The gateway refused a token thinking budget with 400
Cause. pi 1.1.0 picks Google's discrete Fix. The decision now comes from the catalog, as D16 requires. A model whose catalog entry offers discrete effort levels on the Google protocol ( Tests that pin it.
The full gate passed before the push: check, unit suite, mock suite, build and the bundle gate. The fix reaches the stacked PRs above through the sync. These reviews ran on the general model because the dedicated reviewer was unavailable: review:tests#1, review:correctness#1, verify#1.1, review:tests#2, review:correctness#2, verify#2.1, review:tests#3, review:correctness#3, verify#3.1. Generated by Claude Code |
…h' into claude/vigilant-mendel-bctz9n-p-r1 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
Three documentation defects the synced base carries into P-R1. None was caused by the merge (each is identical on the merge-base and on both parents), and each wants the same change on the lowest branch (#105) and, for the README date, on P-R2's cherry-pick of d13cbe2. - PRE-1, docs/redirect-planes.md: "The Go plane serves 12 models on shapes other than completions" restores the count its own table gives (5 openai + 5 anthropic + 1 google = 11, the Go shim's 30 less its 19 no-SDK models). The 12 was right when written (6 + 6) and a later refresh moved the cells but not the sentence. test/catalog.test.ts now holds the sentence to the table's non-completions Go sum, so the next refresh cannot strand it again. - PRE-2, README.md and README.zh-CN.md: the 81-model count is dated 2026-10-27, the refresh that produced it (d13cbe2); on 2026-10-23 the count was 82, so the date no longer matched the number. - PRE-3, README.md and README.zh-CN.md: both install snippets name "^1.4.1" (package.json's version), where they had drifted to ^0.14.0 and ^0.12.0, neither of which can resolve to a 1.x release. test/readme-parity.test.ts pins the two snippets to one range on package.json's major. Both new assertions were checked against the stale values: each fails on them and passes on the corrected text. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
…-mendel-bctz9n-p-r1 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
Each finding the third audit round left open, re-verified on this head: - README.zh-CN.md still says Zen keys never query the Go quota endpoint: already fixed (0cceb81, dec00c8). The feature bullet, step 3, the EntitlementError row and the credential bullet match README.md. - The withdrawn-model fix drops a protocol instead of trying its next model: already fixed (0cceb81). walkPerProtocol walks up to three candidates per protocol and names an unreached protocol in a skip; test/live-walk.test.ts pins both. - N1's claim stands in docs/deep-dive.md and the keySource hint describes auto backwards: already fixed (0cceb81) in deep-dive.md and both hint strings. The same claim survived in a source comment, KEY_SOURCE_ORDER's "tier safety" note in src/go-discovery.ts; this commit corrects it: a key is filed by the plane its request went to, so a Go entry without apiKeyEnv files the Zen key as a Go key. - PR #113 lists counts, not the flipped rows and the four records: fixed in the PR body. - The R2 fix passes the live rows without performing a protocol, the skip decided by message text: already fixed (0cceb81). A "gone" verdict needs a raw probe of the same id to confirm it, and a protocol no candidate reached skips by name. - README.zh-CN.md lacks the N1 fix, the Go apiKeyEnv step and the "Changed in 1.x" bullet: already fixed (0cceb81). - PR #113 omits the D20 Go behaviour change: fixed in the PR body. - docs/deep-dive.md says resolveGoApiKey excludes Zen keys and a Zen-only setup hides the ring: already fixed (0cceb81). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
The vendor retired `nemotron-3-ultra-free` from the Zen plane, so `catalog freshness` gated this pull request (it changes the generator's inputs). `src/catalog-data.ts` is taken exactly as main regenerated it (#132), which today's registry still matches apart from that one row, with no hand edits. What restates the catalog follows it: - Zen 81 -> 80 served, no-SDK 24 -> 23, free 9 -> 8: catalog.test.ts, redirect-planes.md, protocol-routing-and-merge.md and both READMEs ("127 listed" stays; a retired model stays listed as deprecated); - the README model lists, in both languages, now name ids the catalog ships: the Zen and Go lists had kept seven ids the vendor has since retired. The lists are main's; this branch's own prose around them (how the Go Google base is served) is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
The live gateway job failed on `gemini-3-flash`: the registry still lists it, and the gateway now answers it with an error of type `ModelDeprecated`. The adapter walk moves past a withdrawn model only when both its pre-filter (`isModelGoneMessage`) and the raw probe that confirms it (`modelGone`) recognise the answer, and neither knew this shape, so a vendor retirement read as the plugin's refusal. Both now recognise `ModelDeprecated` (by type, at any status, as main's `retiredAtTheGateway` does). `test/live-probe.test.ts` is new and holds `modelGone` to each shape; `keyless-matrix.test.ts` gains the message row. Removing either rule fails its test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
The vendor published `opencode/1.19.5`, and `cli:version` gates this pull request because its diff touches that check's inputs. Main made the same bump in #132 after comparing every cited vendor source between the two tags: the one that moved (`session/llm/request.ts`) only dropped an unused type import, so no header the plugin emulates changed. This takes the same bump in the 17 files that carry a copy here; `cli:version --copies` reports all 58 copies and mentions at 1.19.5. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
…pure half Outcomes of the review round on P-T1a: - both-kept-2-rr2-L1 / resolutions-2-rr2-T1 (one finding): fixed. test/use-channel.test.ts feeds withoutHostPackages a two-document lockfile in pnpm's shape (the package-manager record, then the project document with quoted host keys in the importer's three dependency sections, packages and snapshots, one peer-suffixed snapshot key, a pi entry and a non-host package naming a host peer in its sub-map). It asserts every host key is gone from all five sections, the input held one in each (so a strip that read nothing fails), pi and the non-host entries survive with their sub-maps, the first document is unchanged, and the strip is idempotent. Planted four mutations (a section dropped from the list, the importer's optional section dropped, the key match broken, deletion at the wrong path): each turns it red. harness-channel.test.ts also reads every @deepseek-ai version in each committed lockfile and fails on one from the other channel's prerelease line, which the record fields (dsh, cordis, loader, schemastery) did not cover; planting an alpha cordis-plugin-include entry in the rc lockfile turns it red. - both-kept-2-rr2-L2 / rules-docs-2-rules-docs-2-R1 (one finding): fixed. docs/testing.md's pure-halves table gains the use-channel.ts -> scripts/channel-manifest.ts row, and AGENTS.md's use-channel line names the pure half, its four rules and test/use-channel.test.ts. - both-kept-2-rr2-L3: no tree change, by the finding's preferred route. The README policy sentence stays as written in both languages; the plan of record's D16 row already says main's #130 Gemini level rewrite leaves with the module P-R1 (#113) deletes, and the #109 pull request body carries the same sentence, so P-R1 does not have to undo a README clause. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
…h' into claude/vigilant-mendel-bctz9n-p-r1 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
The Google level wrapper re-implemented pi 1.3's own rule for which Google models take a thinking level, for older pi. That is the host's job (D26): the plugin now hands every Google turn to pi's own protocol and sends what pi builds. pi 1.3 and later name the Go plane's level-only model, so every npm install of either channel is unaffected. The rc desktop app's pi (1.1.0) does not, and sends a budget the gateway refuses. That is recorded as a HOST_LIMITATION row in the in-process characterization and the binary e2e, both detected from pi's own exported usesGoogleThinkingLevel, never a version; the mock and live cases that need the level skip by the same predicate. The READMEs list it under "Host limitations", beside the alpha save defect. The catalog's level rule moves to test/support/thinking-levels.ts, where the cases that pick a subject by it live. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
A model's protocol was the catalog SDK, then pi's installed entry; its legacy base took pi's own /zen base when pi filed the model there. pi's catalog is the host's to reshape, and 1.5.0 did (per-protocol roots, and refiled models), so a pi bump could move a turn the plugin routes. The protocol is now the catalog SDK, then the plane entry's route-level api, then completions (D16), and the base comes from the endpoint family table alone (D26). pi's entry still fills metadata the user's row and the catalog leave unstated (D17). A new case builds every catalog model on both planes and families twice, with pi's entry and with that entry reshaped, and holds both the protocol and the base still. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
The plane profile restated pi-ai's default context window and output tokens (262_144 / 32_768) as the fallback for an entry pi-ai's Config had not filled. The alpha bridge has since raised both (1_000_000 / 128_000): a copy that goes stale silently, and would understate a window wherever it was reached, the overflow trap D17 exists to avoid. pi-ai's own Config fills both into the entry the plugin reads back, with the channel's values, so the plugin now restates neither (D17, D26). Where no Config ran nothing fills them, and a model no source sizes is an error in pi-ai's words rather than an invented window. The characterization's catalog-unknown rows take each channel's value from one record (PI_AI_DEFAULTS), which host-shapes pins against the installed pi-ai, and the unit and e2e fixtures that fed the copy back in now pass stand-in values. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
…laim The route claim's note on F12 cited cordis's Fiber.update at the rc lines only; alpha.2 moved it (764-782). Every other host line the src cites was checked at both tags (rc.5 and alpha.2) and still holds. docs/redirect-planes.md said the plane provider puts all the gateway headers on every protocol. It adds only pi's own session header per call; the client, project and session-id headers come from the global fetch patch, which P10a moves into the call. The plan's P-R1 section records the restack: one row table for every host cell, and the three compensations for the host's pi removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
The case built a plane profile with no normalize, so its undeclared model was sized by the plugin's copy of pi-ai's defaults. With that copy gone the model is an error, as the profile case pins; the case now hands the entry to pi-ai's own Config, as the route claim does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
Deleting the Google level wrapper removed a module held at 100%, and the global function floor (97.4%) fell to 97.37% with nothing newly uncovered. Rather than lower the ratchet, this covers the five wire codecs' create() doors, which no test reached: a runtime that builds a codec per call takes that door, so a codec whose two doors parse differently decodes one way in tests and another on the host. A mutated create() fails the case. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
Run on the rc floor (pi 1.1.0), the mock suite's per-model dispatch cases sent the Go plane's level-only model the budget pi builds there, and the mock gateway refused it, so the nightly floor cell would fail on a host limitation rather than record it. Those cases now expect the gateway's budget refusal where pi's own usesGoogleThinkingLevel does not name the model, and keep asserting the path, the model and the key. Measured on both floors and both channels' newest installs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
Run on the published binaries, both rc cells and the alpha floor serve the planes through the route claim. On alpha's npm cell, npm resolves cordis 4.0.6-alpha.2, whose internal/config waterfall hands listeners the fiber and reads the config from next(), and the claim speaks the earlier contract, so pi-ai serves both planes there; the binary e2e failed on that cell. The probe now records which contract the host dispatched, and the e2e asserts the measured state as a KNOWN_DEFECT row and skips the rows that need the claim, by name. dsh 0.2.2-alpha.3 requires that cordis, so the alpha bump must adopt the contract (feature-detected) and flip the row; the READMEs, CONTRIBUTING and the plan say so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
Close the review of the restacked P-R1 head. One test change, the rest documentation and comments; no src behaviour moves. - both-kept-1-F1 / resolutions-1-F1 / rules-docs-1-F1: the "Your row wins" bullet in both READMEs now gives the protocol as the catalog's SDK, then the plane entry's route-level `api` (only for ids the catalog does not classify), then Chat Completions; the plan's P-R1 item says the route `api` covers ids the catalog does not classify (D26). - both-kept-1-F2 / resolutions-1-F2 / rules-docs-1-F2: CONTRIBUTING's release step 3 and the D22'' row name the tables that exist: a pi move re-measures the cell's column of WHOLE_CATALOG and PI_GAPS_BY_CELL, a cluster whose bridge defaults moved updates PI_AI_DEFAULTS (feeding s0PluginFor's catalog-unknown rows), no S0 row follows pi; the three deleted S0_* names are gone. - rules-docs-1-F5: AGENTS.md and CONTRIBUTING say each cell takes its channel's s0PluginFor table, differing only in PI_AI_DEFAULTS, with forHost/forChannel for expectations outside the table. - both-kept-1-F4 / resolutions-1-F5 / rules-docs-1-F3: redirect-planes, CONTRIBUTING's cells bullet and the plan's e2e-host section say the claim-dependent binary-e2e rows run where the route claim engages; on a host whose internal/config hands listeners the fiber a [KNOWN_DEFECT] row asserts pi-ai serves the planes and those rows skip by name, until the 0.2.2-alpha.3 bump flips it. - resolutions-1-F4: the D26 walk now reshapes pi's entry to the served protocol on a /zen root of its own, and walks uncatalogued ids filed by pi under every non-completions protocol. Checked against 7ed93a7's parent: the full old module fails on the legacy base, and the old protocol order alone fails on the uncatalogued walk. - both-kept-1-F3 / resolutions-1-F7: the mock gateway's level-only note, the dispatch assertion message and the binary e2e's pi-root comment no longer describe the deleted wrapper or the retired floating cell. - resolutions-1-F6: hostSendsBudgetTo and claimCannotEngage/CLAIM_SKIP sit above the doc blocks of expectAnswered and hostCannotSave, so each doc is on its own function again. - resolutions-1-F3: the stream hook's price comment no longer points at a dispatch P-R1 deleted. - rules-docs-1-F7: the protocols and model-metadata comments name no model and justify the @ai-sdk/mistral row by the gateway's path; the two other "follows pi" sentences are recorded in the plan's P7 row. - rules-docs-1-F4: the English quota-ring row carries the same apiKeyEnv advice as the Chinese one. - rules-docs-1-F6: engineering-notes' base-URL section is past tense and marked superseded by P-R1 (D13, D26): baseUrlFor over the generated family table is the only base source. - rules-docs-1-F8: the plan's Models-store restatement cites the lines modelsPageRows cites, at each channel record's tag, not rc.2. - rules-docs-1-F9: both READMEs give the gatewayUrls default as both families and list both in the example. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
… restack sweep Closes the second review round of the P-R1 restack. - both-kept-2-R2-1: README pair, "Changed in 1.x": one paired bullet says the Google thinking control is now the host pi's own, that the level rewrite for older runtimes released in 1.4.3 (#130) is removed, and that on a pi 1.1.0 host (the rc desktop app) the affected model's thinking turns are refused by the gateway on either plane until the host bumps pi; it links to the Host limitations list. - both-kept-2-R2-2: ci.yml's e2e-host npm-cell comment and the binary e2e's header now say the rows are asserted where the route claim engages, name the [KNOWN_DEFECT] claim row and its CLAIM_SKIP skips, and that the save rows skip where the host cannot save. - both-kept-2-R2-3 / rules-docs-2-F1: protocols.ts no longer states an unmeasured gateway path; it grounds the Mistral SDK row in the generated family table (the vendor's OpenAI root), says the dialect is unmeasured, and points at the plan's P7 row. The P7 row now lists all six places that justify the row by pi's data (the README pair's SDK table rows and protocol-routing-and-merge's table row added). - both-kept-2-R2-4 / rules-docs-2-F3: the characterization header says every S0 facet and named case is [BASELINE] except the one [HOST_LIMITATION] row, and todayRowsFor "answers the cell's rows for either order" (header and CONTRIBUTING). - both-kept-2-R2-5: the README pair's support policy and ci.yml's test-job comment say the in-process suites run each channel's cluster with pi as npm resolves it and the cordis family at the versions the harness vendors (a second exception beside schemastery), and that the e2e-host npm cell is the run that lets cordis float. - resolutions-2-F1: both D15 save rows in the binary e2e also skip with CLAIM_SKIP where the route claim cannot engage; CONTRIBUTING and the plan's skipped-row list say so. Test-only: the change is the skip in the e2e itself, which no offline host can drive red. - resolutions-2-F2: the Host limitations bullet (both languages), redirect-planes, CONTRIBUTING's host cells, the plan's P-R1 record and the mock's predicate doc scope the pi 1.1.0 Google thinking-level limitation to the model on either plane: measured live on Go, expected on Zen under the same pi rule and not yet measured there. The in-process row stays Go-only (S0 declares it there); declaring it on Zen would move S0 rows and is left out. - resolutions-2-F3: patch-method's rewrapOnAdaptersUpdated doc keeps the two caveats and drops the deleted bridge, hidden-route and KNOWN_DEFECT references; host-shapes' F10 doc says the plane adapter routes Go's Google models; reload.test's reconfigured doc drops the deleted listing, keyless filter and reinstall-case sentences; an architecture tripwire comment puts the deleted decoration in the past tense. - rules-docs-2-F2: the plan's defect table strikes the mode-merging row as fixed by P-R1 (one plane adapter answers picker and dispatch in D17's order; toggle models offer Off / On, D1), cited at utils/model-metadata.ts and utils/plane-model.ts, and re-cites the P3 row by function name. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
- both-kept-3-R3-1: CONTRIBUTING's release step 3 and D22'' now say a moved host event is adopted by the route claim's own listener and the tier listeners, detected from the dispatch, with every shape a supported channel dispatches accepted while the channels' cordis differ; the contract facts are re-measured per channel, and dsh@alpha is already 0.2.2-alpha.3. - resolutions-3-r3-F1: the README pair and redirect-planes say every turn of the level-only Gemini 4 model carries a budget on pi 1.1.0, thinkingBudget 0 when no effort is chosen, not only a turn with thinking. - resolutions-3-r3-F2, both-kept-3-R3-2: the "Changed in 1.x" bullet no longer states the gateway's refusal on both planes; it points to Host limitations, which scopes it (measured on Go, expected on Zen). - resolutions-3-r3-F3, both-kept-3-R3-3: comments no longer describe the deleted Google bridge, and the mock's level predicate is scoped to either plane. - rules-docs-3-F1: the support policy and Host limitations, in both languages, say the current dsh@alpha (0.2.2-alpha.3) installed with npm runs both planes on pi-ai's routing until the plugin adopts its cordis's configuration-hook contract. - rules-docs-3-F2: "Changed in 1.x" names the catalog's one @ai-sdk/mistral model as now offered, sent as Chat Completions on the vendor's OpenAI root, its dialect unmeasured. - rules-docs-3-F3: the P7 row lists the two test places that justify the Mistral row by pi's data and drops its count; the mock note cites P7. - rules-docs-3-F4: the manifest case is retitled to what it holds. - rules-docs-3-F5: the plan's host-support bullets and lesson L1 record what P1b and P-R1 already did. - rules-docs-3-F6: credentials.md's login-reader paragraphs move under a v2-record heading, without the bridge. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
|
Restacked onto main 1.8.0. This branch now carries main 1.8.0 through its parent P-H ( Conflicts and how they were resolvedSource
CI and config
Host harness and characterization
Live suites
Other tests
Docs
Dropped because main or the host now does it (D26)
Review rounds
The declined finding sets P0's plan row to merged. It belongs at the bottom of the stack (P1a) and will reach this branch through the P-H parent merge. Editing it here first would only create a conflict for that merge. Live re-measures still owed (CI)
Known defect, high priority. On cordis All rounds' reviews ( Generated by Claude Code |
|
No fix exists yet. The machine doing the restack cannot reach the vendor catalog, so the regenerated file can only come from the scheduled refresh on Generated by Claude Code |
Phase P-R1 of docs/improvement-plan.md, stacked on #112.
The plugin now serves the
opencodeandopencode-goroutes itself (the D13 design), using only supported host paths. The hidden-route workaround is gone.Restacked onto main 1.8.0
This branch now carries main 1.8.0 through its parent (P-H) and the two-channel host: rc
0.2.1-rc.5and alpha0.2.2-alpha.2, with pi unpatched. Some sections below describe the branch before the restack; where they disagree, this section wins.Scope now. The plugin owns the
opencodeandopencode-goroutes: the route claim,PlaneAdapter, the describe graft and the host modules. One characterization table serves every host cell (S0_TODAY_BY_CELL, built per channel bys0PluginFor). Rows differ only where the host decides.Dropped because main or the host now does it (D26).
src/host/google-levels.ts) is deleted, with its wiring inplane-provider,plane-profile,host-modulesandcordis-context, its tests, its 100% coverage floor and its doc lines. The thinking control is pi's own. The catalog level rule now lives only intest/support/thinking-levels.ts, where it picks test subjects. The "Behaviour changes" bullet aboutthinkingLevelabove no longer holds.src/utils/plane-model.ts, including thelegacybranch that took pi's own/zenbase (D16). The protocol order is catalog SDK, then the route's api, then completions. Bases come only from the endpoint table.plane-profileno longer restates pi-ai's default window and output tokens (D17).test/google-thinking.test.tsimported the deleted bridge. Its intents moved to the mock suite and to theHOST_LIMITATIONrows.decoratePlaneAdapterscase and its stream-hook "cannot be served" case are both obsolete after this PR.withMoved, the keyless/keyed listings,saveRejectedUnknown,SAVE_BLOCKED_BY_ANY_UNDESCRIBED, the pi-ai-first override andNEXT_DISPATCH. Every host cell now reachesTODAY_DISPATCH.Decisions applied.
D14': the route claim and the plane adapter are built from the host's own pi on each channel, and nothing is bundled or patched.
D22': a channel bump re-measures F8/F12/F14/F20 per channel against that channel's own expectation, and the route claim adopts a moved
internal/configcontract by detecting the shape the host dispatches, never its version.D24:
debug/debugFilefollow main's wording incordis.patch.yml, and the lifecycle test usesapply(ctx, { debugFile }).D25: host limitations are recorded and not fixed:
0.2.2-alpha.2installed by npm cannot save.Both are detected from the host's own answers, and both READMEs list them.
Known defect. On cordis
4.0.6-alpha.2(alpha's npm cell) the route claim does not engage, so pi-ai serves the planes. This is a[KNOWN_DEFECT]row, and the claim-dependent and save rows skip on that cell. The currentdsh@alpha(0.2.2-alpha.3) requires that cordis, so its bump must adopt the new contract first.Live re-measures CI must confirm.
protocol-routing.e2e: the Google level case on Go with a key, on the newest pi. It must skip asHOST_LIMITATIONon the rc floor.thinkingBudgetfor the Go level-only model. TheHOST_LIMITATIONrows rest on this, and Zen is expected to refuse too but is not yet measured.keyless-matrix.e2e:TODAY_DISPATCH, all four protocols on the modern family on both planes.protocol-routing.e2e: the keyed adapter walks throughPlaneAdapteron tier A for both planes.e2e-hostfor both channels' npm and floor cells. It recordsconfigHookper cell and confirms the alpha npm[KNOWN_DEFECT]row and the rc floorHOST_LIMITATIONrows.x-opencode-request,x-opencode-projectandRetry-Afterrows, and the combined Google User-Agent.What changed
inject: [].src/host/route-claim.ts(new)internal/configlistener gives pi-ai's fiber a fresh copy of its config withproviders.opencodeandproviders["opencode-go"]removed. It runs the nested waterfall on that copy behind a re-entrancy guard. On a commit it schedulesreconcile. On a Settings candidate it strictly validates only the plane entries that changed. The served pi-ai row is sticky: it stays the same while it is live and still declares a plane.src/host/plane-provider.ts(new)reconcilebuilds onePlaneAdapter, a subclass of the host'sPiAiAdapter, and registers only the declared planes throughregisterAdapter/handle.replace. pi-ai keeps every other route.src/utils/plane-profile.ts,plane-model.ts,model-metadata.ts,protocols.ts(new)utils/purity gate covers them.src/host/describe-graft.ts(new)settings.describewrapper, built onpatchMethod, that grafts the committed plane entries back (D18).src/host/host-modules.ts(new)cordis-context.ts. pi-ai's module comes from pi-ai's own loader entry during its commit run, so nothing waits on a timer.responses-provider.ts,responses-routes.ts,google-bridge.ts,pi-provider.ts,utils/google-replay.ts(removed after a mock-gateway replay test showed a single provider label); frommodels-discovery.ts: the listing hide,decoratePlaneAdaptersanddecorateModelInfo; the stream redirect; the D19 settings; the hidden ids inDEFAULT_PROVIDERSandcordis.patch.yml.host-planes), contract (describe-graft,catalog-change) and mock (plane-dispatch) suites. Characterization rows flipped to new[BASELINE]values: 14S0_TODAYfacets, 14 namedhost-characterizationcases and 5 binary-e2e rows, each named under "Characterization rows this PR flips" below. Every other row stays green unchanged.Some details refine the plan text on purpose, and the plan's P-R1 entry records each one:
legacyuses pi's own base only when pi files the model under the same protocol and that base is a/zenroot.infothe way D17 does, so theINFO_NOT_FROM_CATALOGBASELINE guard stays intact.Behaviour changes
After this phase:
/inference/go/google/v1beta.apiKeyEnvnow sends the Zen key. pi's own lookup readsOPENCODE_API_KEYon both planes, so such an entry authenticates every Go protocol with it. Before, Go's Responses, Messages and Google turns defaulted toOPENCODE_GO_API_KEY(completions already took pi's rule). The meter follows: it prefers the key a Go turn carried, so after the first such turn it sends the Zen key to the Go usage endpoint, is refused, and falls back to the Zen pill or "subscription required". The fix for a user isapiKeyEnv: OPENCODE_GO_API_KEYon the Go entry; README step 3 and "Changed in 1.x" (both languages) say so, andtest/host-planes.test.tspins both cases.thinkingLevel, never athinkingBudget(src/host/google-levels.ts); Gogemini-4-argonrefused the budget live.Two changes from the last review round:
Characterization rows this PR flips
Every row below was
[KNOWN_DEFECT]or[INTENDED_CHANGE]on the base and is[BASELINE]here. No[BASELINE]row on the base moved.S0_TODAYfacets (test/support/host.ts; facet order info / callConfig / wire), 14:opencode/deepseek-v4-pro[INTENDED_CHANGE]/zen/v1/chat/completions/inference/openai/v1/chat/completionsopencode/gpt-5.3-codex-spark[KNOWN_DEFECT]user row ignored (128000),INVALID_CONFIGokopencode/not-in-any-catalog[KNOWN_DEFECT]INVALID_CONFIG, nothing sentok, sent as completions on/inference/openai/v1(D15, D16)opencode-go/deepseek-v4-pro[INTENDED_CHANGE]/zen/go/v1/chat/completions/inference/go/openai/v1/chat/completionsopencode-go/minimax-m3[KNOWN_DEFECT]toggle-only model offered Minimal…Maxopencode-go/gemini-4-argon[KNOWN_DEFECT]INVALID_CONFIGokopencode-go/minimax-m3.1-flash[KNOWN_DEFECT]INVALID_CONFIG, nothing sentok, sent on/inference/go/openai/v1opencode-go/not-in-any-catalog[KNOWN_DEFECT]INVALID_CONFIG, nothing sentok, sent on/inference/go/openai/v1The listing rows
keylessListing/keyedListingare replaced bylistingBeforeTurn/listingAfterTurn(every declared id, D21), andsaveRejectedUnknownis gone (D15).Named
host-characterizationcases, 14 (base title → head title):[INTENDED_CHANGE]registry: both planes are pi-ai's, six hidden routes →[BASELINE]registry: both planes are the plugin's adapter, no hidden route (D13)[INTENDED_CHANGE]keyless listing hides every paid model →[BASELINE]listing before any turn: every declared id (D21)[KNOWN_DEFECT]keyed listing: only pi-resolved ids →[BASELINE]listing after a turn: gap ids and the unknown id included (G1)[KNOWN_DEFECT]toggle-only model offered Minimal/Xhigh/Max →[BASELINE]offered Off / On, an untaken level refused (D1)[INTENDED_CHANGE]completions dispatch to pi 1.1.0's legacy bases →[BASELINE]completions dispatch to the modern family on both planes[KNOWN_DEFECT]the adapter decoration never runs in this order →[BASELINE]the plugin patches nothing on its ownPlaneAdapter[KNOWN_DEFECT]Zen gpt-5.3-codex-spark: user row ignored,resolveCallConfigrefuses →[BASELINE]user row reaches model info, sent on Responses (D17)[KNOWN_DEFECT]Go minimax-m3.1-flashINVALID_CONFIG→[BASELINE]validates, sent once as completions on Go's modern base (G1)[KNOWN_DEFECT]Go gemini-4-argon refused while served through the bridge →[BASELINE]validates, sent on Go's Google base with the Go key (F10)[KNOWN_DEFECT]a stored gap id blocks every save of its plane →[BASELINE]a stored gap id blocks no save; the unknown id is listed, validates and is sent (D15)[KNOWN_DEFECT]the probe's save sequence needs the gap ids dropped first →[BASELINE]the first append of the unknown id is accepted[INTENDED_CHANGE]the adapter decoration runs in pi-ai-first order →[BASELINE]pi-ai held the planes first, so the claim restarted it exactly once[KNOWN_DEFECT]the apply order decides one facet (Go gemini-4-argon) →[BASELINE]no facet depends on the apply order (todayRowsFor's override dropped)[KNOWN_DEFECT]the unknown id is what the save check names →[BASELINE]the save check accepts it and the file holds it (D15)Binary-e2e rows (
test/e2e/host-binary.e2e.ts), 5:[INTENDED_CHANGE]registry: the planes are pi-ai's, hidden routes registered →[BASELINE]both planes are the plugin'sPlaneAdapter, no hidden route (D13)[INTENDED_CHANGE]keyless listing hides every paid model →[BASELINE]listing before any turn: every declared id (D21)[KNOWN_DEFECT]keyed listing: the gap ids are missing →[BASELINE]listing after a turn on each plane: every declared id (G1)[KNOWN_DEFECT]a stored gap id blocks saving any new id →[BASELINE]a stored gap id blocks no save (D15)[KNOWN_DEFECT]a catalog-unknown id cannot be saved →[BASELINE]it saves, is listed, validates and is sent as completions on the modern base (D15, D16)The binary e2e also gained rows with no base counterpart: the plane provider is built from the host's own pi, the Go Gemini level model is sent a thinking level and no
thinkingBudget, and the Settings graft (below).Records the plan asks for
docs/improvement-plan.md(Test plan, P-R1) asks this PR body to record four things.auto=modern) dispatch: Zenhttps://opencode.ai/inference/{openai/v1, anthropic/v1, google/v1beta}, Gohttps://opencode.ai/inference/go/{openai/v1, anthropic/v1}andhttps://opencode.ai/inference/go/google/v1beta(the catalog's family map, elseMODERN_FALLBACKinsrc/utils/protocols.ts).legacy:/zen/v1and/zen/go/v1(/zen,/zen/gofor Messages), with Go's Google staying on/inference/go/google/v1betaunder every family. The keyless matrix (every PR in CI) asserts that no cell the default endpoint dispatches to answers404; the binary e2e records the URL each characterized model was sent to through the shipped bundle (the wire facets above), including Gogemini-4-argonon/inference/go/google/v1betawith a thinking level.describegraft.src/host/describe-graft.tsgrafts the committed plane entries back into pi-ai'ssettings.describevalue (D18). Held by the binary-e2e row "the Settings graft shows each plane's own entry, and the Models page reads both planes configured under their apiKeyEnv", by the[BASELINE]hasProviderApiKeyrow in both apply orders, and bytest/describe-graft.test.ts.PiAiAdapterowns them again), and pi-ai's own save check is back in force; dispose then apply hands them to the plugin again (test/host-planes.test.ts, tiers B and A). When the host's modules cannot be read the plugin stands down and says so; a failing handback restart is reported, not thrown (test/route-claim.test.ts).Review
In rounds 2 and 3, reviewers reported some of the same defects (the catalog-listener unsubscribe; the store-opt-in case reading the shell's
OPENCODE_API_KEY; the modules-unreadable refusal). Round 3's fixes:Three new route-claim cases fail under the old behaviour and pass with the fix.
The audit round's eight findings repeat four defects. The README.zh-CN.md credential wording, the live adapter walk (a withdrawn model now moves to the protocol's next candidate, a withdrawal is confirmed by a raw probe, and a protocol no candidate reached skips by name) and
docs/deep-dive.md's key-isolation claim were already fixed on this branch; a source comment insrc/go-discovery.tsstill claimed the isolation and is corrected; the description findings are this body's flipped-row and record sections and the D20 Go entry above.Verification
pnpm run checkvp test runvitest.mock.config.ts)vp test run --coveragepnpm run buildlib/index.mjs322.89 kB, build completescripts/check.ts(bundle gate)check passed, exit 0DSH_HOST_E2E=1)Before each commit, the full diff and the new files were checked for absolute local paths and anything shaped like a credential. Nothing was found, and the pattern was confirmed to match a known positive.
Note: the
catalog freshnesscheck now gates a pull request only on its own generator changes (D23, from the base), and it passes on this branch.Generated by Claude Code