Repository navigation
Conversation
- Stop the run on a Node below engines.node, before collecting a file. Below the floor, failures came from the engine (node:sqlite, Intl.DurationFormat, ICU strings) and looked like code regressions. .node-version names the Node CI uses. - Add a CI job that runs the unit and mock suites on Node 24, the floor engines.node promises but no job ran. - The zh fallback duration unit is now 分钟, the platform's own narrow output, so the meter row reads the same with or without Intl.DurationFormat. The DurationFormat tests restore the engine as they found it, rather than leaving a stand-in installed or asserting the engine ships the constructor. - Move the node:sqlite store fixture out of the helpers that the jsdom tests share, into test/support/opencode-store-fixture.ts. - Add an architecture test that walks the client bundle's runtime import graph from settings-page.tsx. It forbids node built-ins, the cordis runtime, pi, and process.env. Checked by planting a violation. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
…n discovery - A rejected internal-route mount ran from a `void` IIFE with no catch, so a Google bridge failure became an unhandled rejection, which Node's default mode answers by exiting the process. mountInternalRoutes now owns the mount and its withdrawal, and reports a rejection. - Three early exits in registerResponsesProvider (internalRoutes off, every route declared, no llm-pi-ai) answered `undefined` after the Gemini bridges had already registered. That left them with no disposer, and the next reload failed DUPLICATE_ADAPTER. They now hand back the bridges' disposer. - A mount that failed to start, or that captured nothing, kept its fiber and every route it had registered. Both paths now release the routes and dispose the fiber. - Model discovery was registered on every activation, and the host's duplicate refusal was swallowed, so the first activation's settings answered for the life of the process. It is now registered once per root and answers from the latest activation's settings. Each namespace registers on its own, so one refusal no longer skips the rest. - Move three doc blocks back above the functions they describe. Each fix has a regression test. The two mount tests fail without the fix. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
…e the suite Request path and meter: - Price a turn on its route's plane. Go-first lookups priced every Zen turn on deepseek-v4-pro at 0.66/1.98 instead of 1.74/3.48. - The listing and model-info patches now act only on the routes this plugin claims. Before, a direct anthropic or openai route lost rows the OpenCode routing called "unservable", and a refused foreign id was answered with OpenCode's catalog. - A relay's Go /models is answered with the Go catalog. The enrichment re-checked the URL against the default gateway markers and fell back to Zen. - The free-model check reads a Request-carried body. That is how DSH sends a turn, and every keyless free turn was reported as a missing credential. The body is now read once for both uses. - The meter's session fallback is the session that most recently ran a turn, not the most recently created one. - A captured key's tier comes from the observed URL, then the route, and never the key's prefix. OpenCode issues oc_sk_ keys for Go, so a working Go key was filed under Zen. An OpenAI sk- key on a claimed relay was filed under Go. Suite isolation: - The unit and mock suites refuse non-loopback requests. Each unit run sent 54 requests to models.opencode.ai through the catalog's background revalidation, so on a networked runner a result could depend on the vendor's live catalog. - Captured keys, session spend and the live catalog are reset after every test (resetCatalogState is new). Shuffled runs failed catalog cases on seeds 42 and 1234. test:shuffle runs the suite in random order, and the Node 24 CI job uses it. Each behaviour change has a test that fails without it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
…egration - The card's store-inspection row called remote.opencodeStore.inspect, but no client contribution carried that namespace's descriptor. The row reported "unavailable" on a host that had the service. storeRemote now carries it, with a whitelist codec, and the client mounts it. - The host/client parity test missed this because it matched only a string literal in super(ctx, "name"), and the store passes a constant. It now resolves constants, and checks every declared Remote method against a client descriptor, not just every namespace. - inspectStore parses through the whitelist instead of a cast, so a field the host did not mean to send (a token) is dropped. An ok:false envelope reports the remote's own message. - The credential reader's legacy-row fallback was uncorrelated: one flagged opencode-go row hid every legacy opencode row, and the Zen key disappeared. The fallback is now per integration. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
… keeps - AGENTS.md's repo map described nine modules this build does not have (the Console login, token store, org cache and sign-in row). They are replaced with one line saying sign-in is v2 work. The go-limits duplication note is gone, because attachAllowance calls allowanceFor. adapter-replacement.ts is marked as not wired. The client-bundle line names the boundary test. - CONTRIBUTING.md documents the engine floor, test:shuffle and test:mock, the offline guard, the per-test state reset, where host-only fixtures live, and that a regression test must fail without its fix. - The no-credential warning no longer tells the reader to "sign in through the settings card", which this build does not have. It points at readOpencodeStore instead, and a test asserts the advice. - CLIENT_BUDGET is raised from 128 to 132 KB for the store descriptor and its parser (about 1.2 KB of source, not a dependency), following the gate's own instruction. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
docs/improvement-plan.md groups the review's findings by cause and orders the fixes in nine phases after this one. Each phase lists its problems, its steps, the test that has to fail first, its acceptance criteria and any decision the owner needs to make. Findings are marked "measured" (reproduced) or "traced" (read in the code). Among the measured ones: the picker and dispatch derive reasoning levels differently for 9 of 95 catalog models. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
Replace docs/improvement-plan.md with the plan of record. It now holds: - the owner's decisions (D1-D11); - what the DeepSeek Harness host supports, with references into packages/llm, llm-pi-ai, session-controller, gateway and ui-settings-models; - the defects this audit found that are not yet fixed; - the target architecture and the phases, one PR each, with a status table that each PR updates. The decisions that change the code: - Settings offers the whole catalog, and the composer offers only the declared models. - The plugin never writes the user's profile and follows the user's configuration at dispatch. - The adapter patch exists to merge provider modes and nothing else. It is generalized to every mode, and its catalog fill is removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
Investigation of the host's source and of the pi catalog it pins (1.1.0) changed the routing design. - llm-pi-ai resolves `api` and `baseUrl` per model, and pi's installed `opencode` catalog already spans Anthropic, Google, Completions and Responses with per-protocol endpoints. One route serves every mode for every model pi knows. - The plugin fills only three gaps: models newer than pi's catalog (including all Gemini on Go), endpoint drift, and profile-level `api`/`baseURL` collapsing the modes. - The new design is one unregistered catalog adapter per plane, keyed by the user's route id, and the adapter patch (merge-modes) delegates only gap models to it. That deletes the hidden routes, the listing hide, the stream redirect, the child mount and the Gemini bridge registration. - A real-host test harness (P-T1) comes before any of it. - One upstream change (per-entry `api`/`baseURL` in llm-pi-ai, U1) would remove the routing layer entirely. It would also let Settings save a model pi doesn't know, which pi-ai's strict write validation rejects today. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
pi-ai registers exactly the providers in its resolved config, and the fiber keeps whatever the internal/config waterfall returns, while the config editor writes the raw value. A prepended listener that resolves pi-ai's config without opencode/opencode-go therefore keeps pi-ai from claiming them, without touching the user's file, and the plugin registers its own PiAiAdapter under the same ids through the public API. Measured on the real host with pi 1.1.0 and the harness's patch: both routes held by the plugin, pi-ai's other routes unchanged, every protocol on both planes (Gemini on Go included) sent to its own endpoint, a catalog-unknown model id saved, listed and dispatched, and both routes handed back to pi-ai on release. Replaces the upstream asks (no upstream changes) and the save-gate design, which is kept only as the fallback. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
A nine-lens review of the routing design, with two independent skeptics per finding (78 of 82 upheld), changed five things before any code moves: - Settings reads pi-ai's resolved config, so a read-only wrapper on settings.describe puts the plane entries back into the displayed value; writes were never affected, the Models page edits by path. - The route claim gets an explicit lifecycle: commits are told from validations by identity, reconcile runs on commit, mount and teardown are ordered, and pi-ai restarts at most once per transition. - The plugin's adapter is built from public pieces only, with pi-ai's credential rule and no captured keys on the adapter path. - The protocol comes from the catalog map, never from a guess at the model's name; metadata and levels are catalog first. - Releases stay on 1.x, phases land as stacked pull requests, and a real host harness plus a binary e2e job pin the behaviour first. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
- The deprecated @viztor/dsh-opencode wrapper re-exported a `default` the
barrel does not have, an ESM link error on every host load. It now
forwards `export *` only, written by one shared helper that a test links
against the built barrel in a real Node process.
- isZenProvider("opencode-google") answered false: "go" inside "google"
read as the Go plane. It now uses the plane rule the catalog already has.
- enrichModelsResponse answered a 401, 403, 429 or 5xx with a 200 catalog.
Those statuses now pass through; a 404 is still filled from the catalog,
because the Go plane's inference base has no /models of its own.
- The warning colour named a token the host does not define, so warnings
rendered as caption text. They now use --dsw-alias-state-warn-label.
- The settings spinner only animated while the meter was mounted; the
settings surface now carries its own keyframes.
- The stream hook wrote debugFile with debug off. debug is the switch and
debugFile only where it writes, the same gate the fetch patch uses.
- The purge row reported the host's own { ok: false } failure as "not a
purge result" and cast the answer; it now shows the host's message and
parses through the contract's whitelisting parser.
- The endpoint copy described modern as /inference/v1, which the plugin
never sends. It now names the per-protocol inference family, and auto as
its alias, which is what the code already did.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
- Delete adapter-replacement.ts and its test. Nothing imported it, and deleting another plugin's registry entry is not a host API; the engineering notes record why, and what the plugin does instead. A gate fails the build if src/ writes the llm registry map directly. - Delete the stream hook's `prepared` handling: the host passes the prepared dispatch as its own argument and never reads options.prepared. - Untrack .freebuff/ and ignore it. - The settings partition test walks Config.dict, which is how debugFile went missing from it; a manifest test checks cordis.patch.yml against the schema and the field registry, and the manifest's phantom showUsagePrice, wrong marker text and incomplete lists are fixed. - utils/retry.ts takes its timer and logger as parameters, and the utils purity gate now also rejects console and global timers, walking the folder recursively. - tool-fallback reads free-tier ids from the request's own plane (Go iff opencode-go or opencode-go-*) and loses its unreachable Anthropic branch. A Zen-only free model is no longer treated as free on Go. - test/support/src.ts is the one door tests use into src/, so later module moves touch one file; CONTRIBUTING.md states the rule. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
The barrel is the host's contract and nothing more: apply, Config, inject, name and the config types. Everything else is internal, and test/public-api.test.ts pins the list, so widening it is a reviewed change. The 1.x line keeps its version scheme: nobody consumes the removed exports (D6). - Every test reaches src through test/support/src.ts, importing each name from the module that defines it; a gate rejects a static src import anywhere else outside its named exemptions. - package.json no longer exports ./src/*, and check.ts fails when an exports target is outside the published files. - resolveRoutedKey is deleted: it was exported and never called. - The internalRoutes setting is deleted; the per-protocol routes always mount until the plugin owns the plane routes. A row that still carries it validates and the key is ignored. - @viztor/dsh-opencode is no longer published. The deprecation message already on npm stays as its final word, and check.ts asserts that the release workflow verifies exactly what publish-scoped.ts publishes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
The test install now runs the host users run. - pi is pinned to 1.1.0, the version the harness's own lockfile pins, with the harness's patch applied verbatim (patches/, hash recorded by pnpm). A pnpm override holds every copy in the tree to it, not just the direct devDependency. - The @deepseek-ai packages move from 0.2.1-alpha.5 to 0.2.1-rc.2, the version a registry install of the published dsh resolves (cordis 4.0.5, loader 1.0.6, schemastery 3.18.5). The boot-tier packages the real-host harness needs next (dsh-llm, dsh-app-boot, dsh-config-editor, dsh-settings, cordis-plugin-loader) are added as devDependencies. - test/support/host-versions.ts names those versions once. test/host-versions.test.ts checks that the pi the plugin loads at runtime is 1.1.0 and the same copy the tests import, that the patch is applied, and that the installed cluster matches. - mount-protocols now checks that every catalog SDK maps to a protocol pi's exported api modules implement, and records as a characterization row that pi 1.1.0's opencode-go provider has no Google API. No src/ behaviour changes: the rc.2 builds of llm-pi-ai, cordis and schemastery are code-identical to alpha.5. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
|
No fix exists yet. The shim needs Generated by Claude Code |
The vendor added kimi-k3.1-pro to the Go plane, so `catalog freshness` went red on every branch of this stack. This takes the two generated files exactly as the nightly refresh produced them (#111), with no hand edits, and updates the counts that hard-code the catalog's size: the Go shim test (28 -> 29), the plane table in redirect-planes.md (Go served 28 -> 29, the no-SDK Go cell 17 -> 18), and the Go completions list in both READMEs. The listed half of "29 served / 33 listed" is models.dev's count, inferred from the one added entry, because models.dev cannot be reached from here. It no-ops once main carries #111. P-T2 turns these counts into invariants so a refresh stops needing this. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
The vendor renamed the Go plane's one Gemini model (dropping its contributor suffix, halving its price and publishing an allowance for it where the limits table had none) and added a free model with no SDK, so `catalog freshness` went red on every branch of this stack. This takes the two generated files exactly as the nightly refresh produced them (#111), with no hand edits, and follows them: - the Go Gemini fixtures in six test files (attachment-services, catalog, go-google, go-google-prepare, models-discovery, responses-routes) now name the renamed id, since each means "the Go Gemini model the catalog serves"; - the usage panel test built its unknown allowance from the table's one unpriced row, which the vendor has now priced, so it builds the `Number.NaN` allowance the generator emits itself; - the Go shim count in catalog.test.ts (29 -> 30); - redirect-planes.md: Go 29 -> 30 served, the no-SDK Go cell 18 -> 19, and "0 of 29" -> "0 of 30" in the prose; - both READMEs: the renamed Gemini id, and the new model in the Go completions list, since it declares no SDK. The listed half of "30 served / 34 listed" is models.dev's count, inferred from one rename (no change) and one addition (+1), because models.dev cannot be reached from here. The dated S0 measurement row in improvement-plan.md keeps the id it was measured with. It no-ops once main carries #111. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
The live routing suite picks its free-tier subjects from the catalog by asking the gateway, but it counted "400 Upstream request failed: Model is unavailable" as an observable answer. The upstream withdrew nemotron-3-ultra-free while the catalog still lists it, so the picker chose it and two cases asserted on a model the gateway no longer serves; the reachability case also failed on a 429 throttle. A withdrawn model (that 400, or a 410) is now skipped like a throttled one. The free-tier routing case only accepts a candidate whose answer is the free-tier gate it asserts, so an unmetered model cannot become its subject, and the reachability walk moves past gated, withdrawn and throttled candidates before it reports. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
The vendor moves its model catalog, its Go limits page and its CLI version almost daily. Each move turned every open pull request red, although none of them caused it: vendor drift is not a regression of the change under test. A pull request now fails a freshness check only when its diff changes that check's generator code: the script, every local module it loads, transitively, and the pinned version file for the CLI check. scripts/freshness-scope.ts derives those inputs from the sources and makes the call, so a new import moves them without a list to edit. Any other pull request reports drift as a warning, as a push to main already did. The offline check that every copy of the CLI version agrees with the pin still gates every pull request, since only the repository can break it. The gates fail closed: a lost scope answer gates rather than skips. The nightly run still regenerates the two tables and proposes the refresh as its own pull request, and warns on the CLI version. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
The status table and the P1b section say what the merge of P1a kept: main's tool-fallback plane rule (D25) with only the Anthropic schemas deleted, and one catalogue fixture behind the door. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
The id is the test's data; the comment describes the rule it shows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
Closes the review of the restacked P1b head. - free-tier-contract: the comment states D25 (the injector reads its plane from the URL, with the plane-blind row as fallback), not the dropped route rule. No assertion changes. - tool-fallback: the shipped-shim fallback case asserts its premise (the id is free on Zen and absent from the Go catalog), so a regeneration that lists it on Go fails loudly instead of leaving the case vacuous. Checked by seeding the id onto Go: the premise assertion fails. - improvement-plan: the six defect rows P1b resolves are struck and marked "Fixed by P1b", with the pre-fix locations kept. - AGENTS.md: the retry.ts row is in the past tense; it no longer says P1b has yet to move the timer and console out. - testing.md and the catalogs fixture: "like every other support module" becomes "like the other fixtures"; the setup file names the defining modules directly because it also loads in the jsdom files. CONTRIBUTING's exception list is left to P2, which names the setup file in its gate. - The #107 body (item 6, the behaviour-change section, the model id and the verification table) is rewritten after step 11 with the other bodies, as the restack plan schedules; nothing in the tree. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
…try points - fixed: both-kept-2-P1B-R3-2 and rules-docs-2-P1B-R3-DOC-2 (applied once): CONTRIBUTING.md's door-rule exception list gains P2's clause verbatim, "and the setup file `test/support/reset-process-state.ts`, which runs before the jsdom tests too", so it agrees with test/support/catalogs.ts and docs/testing.md. The plan's P2 restack row records that the merge conflict on that line resolves to P2's line. - fixed: rules-docs-2-P1B-R3-DOC-1: docs/testing.md's lead-in says "Three entry points", matching the three bullets the fixture exports. Wording only; no code or test changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
Outcomes of the P1b restack review: - both-kept-3-P1B-R4-2, resolutions-3-P1B-R3-CH-1, rules-docs-3-P1B-R3b-1 (one item): no code or decision change on P1b. D14' and D22' stay as P0 wrote them; the P-T1a restack row now records the open question (one verified channel against a both-channel goal), that the owner decides it as D14''/D22'', the cheapest coverage (a per-channel HOST_VERSIONS and an rc row in the e2e-host matrix, floating first, pinned only once the latest rc tag's pi is confirmed), and that the 1.1.0 patch is kept until then. - both-kept-3-P1B-R4-1, rules-docs-3-P1B-R3b-2 (one item): no tree change. The pull request body predates the restack; at push, one PR comment line says so, and the body is rewritten (no behaviour change, the plane rule is main's D25, the shim case named by its premise, test/support/catalogs.ts, the restacked gate's numbers). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
…b' into claude/vigilant-mendel-bctz9n-p2 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
Three files arrived from main without a conflict and import src paths directly (the Go-limits HTML reader, the Google thinking-level test and the gateway contract mock), which the door gate refuses. The door gains LEGACY_PLANE_API, and the gate's own walk check names P1b's merged fixture module (support/catalogs.ts) instead of the file it replaced. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
main's testing guide named scripts/wrapper-forwarder.ts and its link test, both of which P2 deletes when it re-retires the alias (D9). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
The paragraph under "Every count in the documentation, checked against the data" stated an earlier shim's counts in the present tense and said every live count in the docs agreed with them, which stopped being true when the shim was regenerated. It now records the sweep as done against the shim of that day, restates no number (a number there is one no test reads), and points to redirect-planes.md sections 1 and 2, the dated tables test/catalog.test.ts reads back against the shipped shim. Outcomes: - fixed: rules-docs-1-P2-DOC-1. The line is main's and every branch below P2 still carries it; landing it here carries it to every branch above through the cascade, and the bottom-of-stack fix is recorded as a follow-up for #105's docs sweep. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
The vendor added a free Zen model, `pulse-alpha-free`, after main's 2026-10-31 regeneration, and `catalog freshness` gates this pull request because it changes the generator's code. `src/catalog-data.ts` is taken exactly as the nightly refresh produced it (0f22c3e on chore/generated-refresh), with no hand edits; `src/go-limits-data.ts` did not move. The counts that restate the catalog follow it: - Zen 80 -> 81 served, no SDK 23 -> 24, free 8 -> 9 (catalog.test.ts, redirect-planes.md, protocol-routing-and-merge.md, both READMEs); - the registry's listed total 130 -> 131, since an added model is listed as well as served; - the count dates move to 2026-11-03. It no-ops once main carries the same refresh. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
…del-bctz9n-p1a Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
…-mendel-bctz9n-p1b Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
Merge origin/claude/vigilant-mendel-bctz9n-p1b (835c793) into P2, so #108 is one merge from its parent's green tip again. No conflicts; P2's own commits touch none of the count-bearing hunks. - fixed resolutions-3-P2-R3-1: the parent's 798ba2e arrives unchanged. src/catalog-data.ts is the nightly blob (0f22c3e) with the newly listed free Zen model, byte-identical to the parent tip, never hand-edited; src/go-limits-data.ts did not move. The restated counts (Zen 81 served / 131 listed, no-SDK 24, free 9, dated 2026-11-03) come from the parent's side in both READMEs, docs/redirect-planes.md, docs/protocol-routing-and-merge.md and test/catalog.test.ts. Correction 2 ("take main's blobs") is superseded for the generated files by the parents' decision to carry the nightly refresh, so every branch above P2 inherits the same blob through its parent merge. - deferred resolutions-3-P2-R3-2: no worktree file is wrong (docs/improvement-plan.md states D9 correctly); the PR body's D9 line is rewritten in the post-step-11 body pass, per the plan. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
…' into claude/vigilant-mendel-bctz9n-p-t1a Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
scripts/use-channel.ts <rc|alpha> [--floor | --relock] installs a channel's committed lockfile (pi unpatched at the newest version the bridge's range admits, what an npm user runs), or the same cluster with pi at the range's floor, and restores every tracked file it rewrote, so a switch leaves no diff. It leaves a marker the suite reads to know which record to check. pnpm now only warns before a run when the install looks stale, since an automatic reinstall would silently put the default channel back under a run meant to test the other one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
The harness's own pi patch, which only the desktop app ships, removes the per-delta re-parse of streamed tool-call arguments and round-trips thought signatures. npm installs run pi unpatched. The plugin supports both because no src module reads either; this tripwire keeps it so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
A matrix over [alpha, rc] on every pull request, each on the channel's npm install, and on each channel's floor pi nightly and on dispatch. DSH_CHANNEL and DSH_PI make the host-versions test fail by name if the switch did not happen, and the job checks the switch left no diff. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
The plan's D14 and D22 rows become D14'' and D22'': the plugin supports the latest release of both harness channels as each ships, with the measurement that npm installs run pi unpatched and why this repository carries no pi patch. The README pair states the support policy. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
A pipe inside a code span split the row once the formatter ran, and the patch's thought-signature hunk is described without naming a model. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
Closes the audit's findings on the both-channel, no-patch restack. Docs and
comments only; no behaviour changes, so no new failing-first test.
- both-kept-1-F1, rules-docs-1-R2: the plan of record gains D26 ("host
gaps are the host's job", owner 2026-11-03): the Google level wrapper
goes, pi-ai's defaults are not restated, no base or protocol is read
from pi's catalog entries, host gaps are HOST_LIMITATION rows skipped by
feature detection. D16's order and last clause, D17's defaults sentence,
the P-R1 design-table rows and the P-R1 status and adjustment rows now
say so; P-R1 implements it.
- both-kept-1-F2: the status, P3, L13 and gate rows use D14'''s
vocabulary (both channels, newest and floor); L13 moves off P-T3,
since each channel's default install already is the newest pi.
- resolutions-1-L1: kept the rc repin (one coherent cluster per lockfile)
and said so in the rc lockfile test, the CI comment and pinFor: the rc
cell runs the host's schemastery, not the published pin. Widening the
plugin's own pin is left to the owner.
- rules-docs-1-R1: CONTRIBUTING's release step names the "Supported" line
and the Support policy paragraph, and says their versions come from the
channel records and move with the lockfile.
- rules-docs-1-R3: the two per-shape count headers carry the shim's
2026-11-03 date, matching every other stamp (counts re-derived from the
shim: Zen 81 = 24/31/17/8/1, Go 30 = 19/5/5/1).
- rules-docs-1-R5: both READMEs name both test installs (alpha default,
rc) instead of one.
- rules-docs-1-R4: the PR body is rewritten after the push, not here.
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
… P-T1a - fixed (resolutions-3-t1a-rr3-1, rules-docs-3-rr3-docs-1, both-kept-3-rr3-L2): the nightly drift report D22'' asks for now exists. scripts/host-drift.ts is its pure half (hostDrift: dsh at each record's dist-tag; cordis, the loader, schemastery and pi at the newest version the bridge's declared ranges admit; the pi range and its floor; "read nothing" is a line, never "current"), scripts/report-host-drift.ts the CLI (one ::warning:: per drift, exit 0 always), and CI's host-drift job runs it on schedule and dispatch only. test/host-drift.test.ts holds the rules with known answers, runs the CLI against a loopback registry and evaluates the job's condition. D22'' now says P-T1a reports and P-T3 proposes the bump pull request; P-T3's status row, item 11 and restack row carry that half. - fixed (resolutions-3-t1a-rr3-2): the other-channel prerelease check reads each other channel's tag with semver.prerelease and skips a stable channel, so rc going stable no longer fails the alpha cell; a known-answer case (alpha, rc, a synthetic stable record) fails with the old reader. - fixed (both-kept-3-rr3-L1, resolutions-3-t1a-rr3-3): D22'' states a bump is version data only and cites CONTRIBUTING's release step 3, now the one list (rc: record + channels/rc lockfile via --relock; alpha: record, package.json's exact pins, root lockfile; both: the README pair's "today" sentences and minimumReleaseAgeExclude lines for a cut under a day old). test/harness-channel.test.ts now holds both READMEs' support-policy versions to the records. - fixed (resolutions-3-t1a-rr3-4): D26's split and P-R1's restack row give P-R1 the HOST_LIMITATION row, the feature-detected skips, the "Host limitations" list and the upstream report; P-T1b keeps only the per-channel tagging of rows that already differ. - fixed (rules-docs-3-rr3-docs-2, rules-docs-3-rr3-docs-3): the restack intro names both channels' hosts, and names P0's nightly vendor refresh (798ba2e) as the one exception to "generated files take main's blobs", in the intro and in P0's status and restack rows. 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 Conflicts and how they were resolvedDependencies and install
Docs
Tests
Dropped
Review rounds
Round 3's fixes:
Live re-measures still owed
Follow-ups, not done in this restack
Four reviews ran on the general model because the dedicated reviewer was unavailable: review:P-T1a:rules-docs#3, review:P-T1a:both-kept#3, review:P-T1a:resolutions#3 and verify:P-T1a#3.1. Generated by Claude Code |
…s of P-T1a Completes the restack of P-T1a: the review's upheld findings, one outcome each. - both-kept-3-t1a-rr3b-1 (fixed): Dependabot's npm entry ignores `@deepseek-ai/*` and pi for every update type, and its comment states D22'' (a host or pi move is a channel bump: record, lockfile and alpha's exact pins together; the nightly host-drift job reports it, P-T3 proposes it). The wrong google-bridge claim is gone. A new harness-channel case reads .github/dependabot.yml and requires both ignores (red before the config change). - resolutions-3-resolutions-4-t1a-1 (fixed): a per-lockfile case holds each importer section's specifiers to channelManifest(package.json, record), and the lockfile's lockfileVersion, settings, catalogs, overrides and package-manager record to the root lockfile's; its message names `scripts/use-channel.ts rc --relock`. Mutation-checked: a vitest specifier change turns both lockfile cells red, an edited rc override only the rc cell. CONTRIBUTING, AGENTS.md and dependabot.yml say any change to package.json's dependencies or the workspace's catalog or overrides relocks rc in the same commit. - resolutions-3-resolutions-4-t1a-2 (fixed): F10 is keyed by pi line (>=1.1.0 <1.3.0 none, >=1.3.0 <2.0.0 native), with known answers, so a pi bump inside a line stays version data and a pi outside every line or contradicting its row still fails. Release step 3 and D22'' name the pi-moving commands (`pnpm update @earendil-works/pi-ai --no-save`, then `rc --relock`). - rules-docs-3-rr3-docs-E (fixed): step 3's "whole set" is scoped to cuts inside the admitted prerelease tuples; a cut opening a new tuple is a reviewed range change (peer clause, README peer-range line). Mirrored in D22'' and P-T3's item and row. - both-kept-3-t1a-rr3b-4 (fixed): the patched-pi tripwire also matches a `.partial` property read (dotted, optional-chained, bracketed), not a `.partial()` call or `Partial<>`; planted cases go red on the old pattern. - both-kept-3-t1a-rr3b-2 and rules-docs-3-rr3-docs-A (fixed, one change): D17 keys the default window and max tokens on the bridge, i.e. the channel, whichever pi runs; the P-T1b restack row keys the unknown-id context row by channel. - both-kept-3-t1a-rr3b-3 and rules-docs-3-rr3-docs-B (fixed, one change): F2 carries one version-exact note (1.3/1.4 bases, 1.5.0's per-protocol roots, routing reads neither); G1 and G2 point to it. - rules-docs-3-rr3-docs-C (fixed): F10's note is in D14''/D26 terms (holds on rc's floor, per pi line, routing not a gap-fill). - rules-docs-3-rr3-docs-D (fixed): P-T1a's item 4 and test list name the host-drift job, the Dependabot ignore and the lockfile-sync case. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
|
Restacked onto main 1.8.0. The branch now carries The scope follows the owner's 2026-11-03 decision: the plugin supports the latest release of both harness channels, with no pi patch (D14'', D22''). The PR body has the full new scope. Conflicts and resolutionsDependencies and install:
Code and tests:
Docs:
Dropped
Review rounds
The round 3 fixes:
Live re-measures still owed
Locally, all four installs passed 1393 unit and 52 mock tests: alpha on pi 1.5.0 and 1.3.0, and rc on pi 1.5.0 and 1.1.0. Four reviews ran on the general model because the dedicated reviewer was unavailable: round 3's resolutions, both-kept and rules-docs reviews, and the verification pass after round 3. Generated by Claude Code |
5e7a442 to
3654e35
Compare
Phase P-T1a of
docs/improvement-plan.md. It is stacked on #108 (P2), which sits on #107, #106 and #105.After this PR, the test install runs the host users run (D14'', D22''). It is a pinning phase, so no
src/behaviour changes.Restacked onto main 1.8.0
The branch now carries
main1.8.0 through its parent (P2).mainhad followed the harness onto its alpha track, and the owner decided on 2026-11-03 that the plugin supports the latest release of both harness channels, with no pi patch. That decision replaces the scope described in the sections below this one; they are kept as the record of the original phase.New scope
Two channel records in
test/support/host-versions.ts(D22''):rc=dsh@latest0.2.1-rc.5, pi^1.1.0(floor 1.1.0)alpha=dsh@alpha0.2.2-alpha.2, pi^1.3.0(floor 1.3.0)Each record gives the cluster, cordis, the loader, schemastery, the bridge's pi range, the newest pi it resolves (1.5.0 today) and its floor (the harness pin).
No pi patch (D14''). Each channel's committed lockfile pins unpatched pi at the newest version its bridge range admits: the root lockfile for alpha (the committed default, as on
main), andchannels/rc/pnpm-lock.yamlfor rc. The pi devDependency is the union range^1.1.0.scripts/use-channel.ts <rc|alpha> [--floor|--relock]switches the dev install and leaves no diff. Its pure half (scripts/channel-manifest.ts) is unit-tested.pnpm-workspace.yamlsetsverifyDepsBeforeRun: warn, sopnpm runcannot silently reinstall the default channel under an rc run.Tests:
host-versions.test.tschecks the installed tree against the selected record.harness-channel.test.tskeepsmain's both-channel peer rule and holds each lockfile to its record. It also checks that each lockfile's importer specifiers and settings/catalogs/overrides matchpackage.jsonand the root lockfile (so a dependency change that forgetsrc --relockfails offline), that Dependabot ignores the harness cluster and pi, and that the README pair's support-policy paragraph names each channel's versions.mount-protocols.test.tsF10 is now per pi line: no Go Google on>=1.1.0 <1.3.0, native on>=1.3.0 <2.0.0. A pi outside every line fails and says to measure it.srcreads streamed tool-call deltas, partial arguments (including through pi'spartialmessage) or thought signatures.CI:
[alpha, rc]on every PR, and on each channel's floor pi nightly and on dispatch.host-driftjob (schedule and dispatch only) runsscripts/report-host-drift.ts. It reports when a channel's dsh, cordis, loader, schemastery or pi has moved past its record. It warns and always exits 0.@deepseek-ai/*and@earendil-works/pi-ai: a host bump moves the record, the lockfiles and the pins together, and P-T3 proposes it.Docs: the plan's D14''/D17/D22''/D26 rows, the F2/F10/G1/G2 facts, the status rows and restack rows, and the README compatibility section (both languages) state the policy. CONTRIBUTING's release step 3 lists everything a channel bump moves, and says when a bump opens a new prerelease tuple and so becomes a reviewed peer-range change.
Dropped, because main or the owner's decision now covers it
patches/@earendil-works__pi-ai@1.1.0.patch, the pioverridesentry,patchedDependencies, and the patch-hash and patch-hunk tests.main's exact pi 1.4.0 devDependency, which matched neither channel's host. It is replaced by^1.1.0.minimumReleaseAgeExclude: this branch takesmain's list.Decisions applied
srcor test logic. P-T1a reports drift nightly, and P-T3 proposes the bump PR.HOST_LIMITATIONrow for Gemini 4 thinking levels on rc floor pi 1.1.0, the feature-detected skips, the "Host limitations" list and the upstream report belong to P-R1.main's fix: send Gemini 4 thinking levels on older host runtimes #130 Gemini-level code stays until P-R1 deletes it, and it passes on all four installs.Live re-measures CI must confirm
srcbehaviour, so no live result can change its code. The PR'stest · alphaandtest · rcjobs must pass.pi floorcells must pass: rc on pi 1.1.0 and alpha on pi 1.3.0. Thehost-driftjob must run on dispatch.dsh@alphaanddsh@latestfrom the registryWhat is pinned
Original scope. The section above supersedes it.
@earendil-works/pi-aioverridesentry holds every copy in the tree to it, including the onedsh-llm-pi-ai's^1.1.0would otherwise float. The patch is copied verbatim intopatches/, and its hash matches the one the harness lockfile records.@deepseek-ai/*dshresolves. The rc.2 builds of llm-pi-ai, cordis and schemastery have the same code as alpha.5; only theirpackage.jsonranges differ.dsh-llm,dsh-app-boot,dsh-config-editor,dsh-settings,cordis-plugin-loaderminimumReleaseAgeExcludeis now empty. Every pinned version is older than pnpm's 24-hour release-age window, so nothing needs that window lifted.Tests
Original scope. The section above supersedes it.
test/support/host-versions.tsnames the pinned versions once.test/host-versions.test.tschecks four things:loadHostPi) is 1.1.0, and it is the same module instance the tests import.dist, and the lines the patch removes are absent.@deepseek-aicluster matches the pinned versions, within the plugin's own declared ranges.test/mount-protocols.test.tsis rewritten. It now checks that every catalog SDK maps to a protocol that pi's exportedapi/*modules implement. It keeps a characterization row: pi 1.1.0'sopencode-goprovider has no Google API (F10). That gap is what the plugin's provider fills in P-R1.test/harness-channel.test.tsreads the channel fromHOST_VERSIONSinstead of an alpha-channel regex.test/no-local-paths.test.tsnow also scanspatches/andpnpm-workspace.yaml.Review
The change went through three review lenses (correctness and host contracts, tests, repository rules), and two independent skeptics checked each finding. Over three rounds, every upheld finding was fixed: 3 medium and 21 low.
The restack had three more review rounds. They found 26 findings, upheld 24 and fixed all of them.
Verification
All run locally:
pnpm install --frozen-lockfilepnpm run checktest:mockscripts/check.tstest:mockThese figures are from the original scope. After the restack, the unit suite has 1393 tests and the mock suite has 52, and both pass on all four installs.
The diff and the patch file contain no local paths.
Note on CI: the
catalog freshnesscheck will fail here for the reason described on #108. The vendor added a Go model (kimi-k3.1-pro), and this PR doesn't touch the catalog. The nightly refresh fixes it.Generated by Claude Code