Skip to content

chore: remove dead code and tighten the repository's gates - #107

Closed
viztor wants to merge 57 commits into
claude/vigilant-mendel-bctz9n-p1afrom
claude/vigilant-mendel-bctz9n-p1b
Closed

viztor wants to merge 57 commits into
claude/vigilant-mendel-bctz9n-p1afrom
claude/vigilant-mendel-bctz9n-p1b

Conversation

@viztor

@viztor viztor commented Oct 23, 2026 •

Copy link
Copy Markdown
Owner

Phase P1b of docs/improvement-plan.md. It is stacked on #106 (P1a), which is stacked on #105.

Hygiene only. It removes dead code and adds gates. There are no user-facing behaviour changes.

# Change How it's pinned
1 adapter-replacement.ts and its test are deleted. Nothing imported them. docs/engineering-notes.md gains a section on two points. First, deleting another plugin's registry entry is not a host API: registerAdapter is all-or-nothing, and only the owner's handle.replace moves routes. Second, the plugin keeps pi-ai from claiming the planes through the config waterfall instead (D13). A new gate in architecture.test.ts fails the build if anything in src/'s import graph writes the llm registry map (adapters.set/delete/clear, including optional chaining).
2 The stream hook's dead prepared handling is gone. In the host's llm/src/index.ts, stream(options) passes the prepared dispatch as a separate argument, which only prepareCall's one-shot stream supplies. options.prepared is never read. A green pin on the Go-Google redirect: it forwards the caller's request unchanged apart from the provider and the Google-shape history.
3 .freebuff/ is untracked and ignored. It held a per-machine agent workspace id. none
4 The settings partition test walks Config.dict. It used Config({}), which drops keys with no default, and that is how debugFile went missing from it. debugFile is now registered as config-only, and described by the gate main chose (D24): naming it writes both halves whether or not debug is on, and debug governs the console. A new manifest test checks cordis.patch.yml against the schema and the field registry. That surfaced the phantom showUsagePrice, the wrong freeModelMarker: '' text and the incomplete field lists, all now fixed. Red on the base, green now.
5 utils/retry.ts takes its timer and logger as parameters. The utils purity gate now also rejects console and global timers: called or passed as values, bare or through globalThis./window./global./self.. It walks utils/ recursively. Verified by planting violations and watching the gate fail.
6 tool-fallback's unreachable Anthropic schemas are deleted. The plane rule is main's (D25): the request URL decides the plane, with a plane-blind lookup as the fallback. The existing fallback cases, plus a case on the shipped shim whose premise is asserted: a model free on Zen and absent from the Go catalogue is still admitted on Go by the plane-blind fallback.
7 test/support/src.ts is the one door tests use into src/, so later module moves touch one file. This phase converts the files it touches, P2 converts the rest, and CONTRIBUTING.md states the rule (with the setup file as a named exception). The synthetic catalogue rows and the plane-divergent seed are one fixture, test/support/catalogs.ts, behind the door. A gate requires each name in the door to be declared in its target module, not re-exported from elsewhere. Known answers are included.

Restacked onto main 1.8.0

The branch now carries main 1.8.0 through its parent (P1a), which is an ancestor of this head.

Scope after the restack. Deletes src/adapter-replacement.ts and its test (with an engineering note and a registry-write gate), the stream hook's dead prepared handling, and the tracked .freebuff/. The settings partition test walks Config.dict, and a manifest test holds cordis.patch.yml to the schema and the field registry, with debugFile described by D24. utils/retry.ts takes its timer and logger as parameters, and the utils purity gate also rejects console and global timers, walking recursively. tool-fallback loses its unreachable Anthropic schemas. test/support/src.ts is the one door into src.

Dropped because main now does it.

  • The route-mapped tool-fallback plane (a route option on maybeInjectCoreTools, and a plane lookup by route with no plane-blind fallback). main's feat(test): a fixture harness for the worlds the vendor has not produced #138 rule supersedes it (D25).
  • The earlier "Behaviour change" section, which said a model free only on Zen is no longer treated as free on Go. Under D25 the plane-blind fallback admits it, so that change and its test are gone.
  • The fetch-patch case "the turn's route decides off a gateway URL". It is rewritten as "the plane comes from the URL's path, never the turn's route".
  • The standalone test/support/catalog-fixture.ts, folded into test/support/catalogs.ts together with main's test/fixtures/catalogs.ts.

Decisions applied.

  • D25: the tool fallback's plane is the request URL's, with the plane-blind fallback. P1b keeps only the deletion of the dead Anthropic branch.
  • D24: debugFile is described by the gate main chose, in src/settings-fields.ts and cordis.patch.yml.
  • D14'/D22': unchanged here. The question of verifying both host channels (rc and alpha) is recorded for P-T1a in docs/improvement-plan.md, for the owner to decide before P-T1a starts. The committed install and lockfile stay as they are.

Live re-measures CI must confirm. None are new: no change on this branch touches the wire, the routes or the credentials. CI's unit, shuffled and mock suites and the bundle gate cover the head. The scheduled live probe suites only need to stay green on it.

Review

The change went through three review lenses (correctness and host contracts, tests, repository rules). Two independent skeptics checked each finding. Over three rounds before the restack:

  • 30 findings survived: 3 medium, 27 low.
  • All of them were fixed. The registry-write gate was kept as item 1's executable form.

The restack had three more rounds of review. Their counts are in the restack comment on this pull request.

Verification

From the restacked head's gate:

Step Result
pnpm run check 0 errors; 21 warnings
unit suite 85 files, 1346 tests pass
test:mock 3 files, 52 tests pass

The diff contains no local paths.


Generated by Claude Code

claude added 13 commits October 22, 2026 22:24
- 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 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
claude added 11 commits October 26, 2026 13:15
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
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 vendor retired `deepseek-v4-flash` from the Zen plane (it stays on
Go). This pull request changes the catalog generator's own code, so
under the freshness scoping it carries the refresh itself. This takes
`src/catalog-data.ts` exactly as the nightly refresh produced it (#111),
with no hand edits; `src/go-limits-data.ts` did not change. It then
updates the counts that still hard-code the catalog's size:

- the Zen shim count in catalog.test.ts (82 -> 81);
- redirect-planes.md: Zen served 82 -> 81, the no-SDK Zen cell 25 -> 24,
  and "0 of 82" -> "0 of 81" in the prose;
- protocol-routing-and-merge.md: the per-protocol shares now read "of 81",
  with completions at 24;
- both READMEs: the no-SDK row is 24 and the active total is 81. The
  Chinese table had read 27 before this change, and now matches the
  English one.

"127 listed" is unchanged, because the vendor retires a model by marking
it `status: "deprecated"`, which keeps it listed. This could not be
confirmed against models.dev, which cannot be reached from here.

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 walk's fixture held the text `await import("../src/lazy.ts")`. The
test tree's own architecture gate, which starts on the next branch of
this stack, reads a dynamic `src` import anywhere in a test file's text,
including inside a string. It counted that fixture line as a test
bypassing `test/support/src.ts`, so every branch above this one failed
the gate once this pull request was merged into it.

The case is about the dynamic form, not about `src`, so the import now
names `./lazy.ts` beside the script. The walk resolves it from the
importing file's own directory, which is the same rule, and the expected
inputs follow it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
claude added 22 commits November 2, 2026 19:30
The copy scan's file filter lived in the top-level script, where nothing could exercise it. It now sits in scripts/vendor-version.ts beside the other rules, with cases of its own, and a test keeps its list equal to freshness-scope's. Because the script imports that module, it is now an input of the cli:version check, and the strict input list says so.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
The live suite's local modelGone rule gave way to main's verdict module in the merge. Its one shape main lacked, a 400 whose body says the upstream withdrew the model, now lives in retiredAtTheGateway with a unit case, so the free-tier walk and the subject pickers skip it instead of failing on it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
Main's test-system page predates the offline guard, the per-test reset and the engine floor: it placed the store fixture in the shared helpers and called the plane-lookup world per file. It now says where the store fixture lives and why, that a live-catalog world is installed per test, and what the CLI-version rules cover.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
Taking main's usableAsSubject rule in the merge dropped the picker's accept argument, so the free-tier case could pick an unmetered model and assert the gate on a 200. The case's own narrowing now applies after the shared rule.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
Main moved to 1.8.0 and onto the harness's alpha track while the stack was open, and landed several things the plan had scheduled. The plan of record now says so: D14' and D22' replace the pi 1.1.0 and rc.2 pins, D17 restates pi-ai's new defaults, D23 records the freshness scoping, D24 and D25 adopt main's debug gate and tool-fallback plane, and D9, D16 and D19 stand with notes. F10 is gone on pi 1.3. A new phase P-R3 (honest refusals) follows P-T3, each phase has its restack adjustment, the status table shows the restack, and the two community plugins' lessons are a ranked table with what not to adopt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
Main and this branch each raised the tripwire from 128 to 132 KB, each measured without the other's surface. Merged, the client is 135604 bytes, about 0.4 KB over; the owner's standing rule for growth like this is to raise the ceiling, not cut content.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
Close the restack review's findings on #105. Every change is prose, a
comment or a log line; no behaviour moves, so no test is added.

- ci.yml: the pnpm/action-setup comment no longer quotes a pnpm version;
  it names the `packageManager` field, which main's bump had made stale.
  release.yml carries the same stale sentence on main and is left to a
  main-side follow-up.
- scripts/freshness-scope.ts: the GENERATED_OUTPUTS and dataInputs docs
  name scripts/vendor-version.ts (GENERATED_TABLES, PINNED_VERSION), where
  the copy and the regular expression now live.
- test/e2e/protocol-routing.e2e.ts: the free-tier walk's report names the
  causes that can reach it (gated, withdrawn, refused for the account,
  never answered); a throttled walk skips, so "throttled" is gone.
- README pair: the Chinese file now says what the English says about
  403 FreeTierError (the headers are not its cause and the patch does
  not open the free tier), carries the Auto Review route clause and the
  two paragraphs on the API-key-only build and the host restart; the
  English yaml fence drops the nonexistent hiddenModels key.
- README pair: the compatibility section restates the typert peer range
  package.json declares and what its two clauses admit.
- docs/improvement-plan.md: F2, G1 and G2 carry the pi 1.1.0 restack
  note; the sources line names both harness tags; the P1a-P2 test matrix
  says the wrapper is retired; P0's status row counts ten defect fixes.
- docs/protocol-routing-and-merge.md, docs/redirect-planes.md: the count
  tables are dated 2026-10-31 (the shipped shim), apart from the
  documents' measurement stamps; both READMEs name
  `catalog:shim -- --write` as the regeneration command.
- AGENTS.md: the What-moved table names src/utils/retry.ts; the coverage
  line points at vite.config.ts instead of quoting stale thresholds.
- CONTRIBUTING.md: the restart check names CARD_FIELDS rather than a
  field count.
- docs/testing.md: rule 1 counts an upstream's 400 "Model is unavailable"
  as a retirement, and rule 2 says the body, not the status, makes it one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
Close the second review round's findings on the restacked P0. Docs only;
no generated file is touched.

- both-kept-2-R2-1: docs/deep-dive.md no longer names the retired ids
  the shim was said to suppress (main's regenerated shim serves one of
  them on Zen). It states the rule instead: a retired model is a row the
  registry marks deprecated, the generator drops it per plane, and ids
  are not restated; the enrichment item says "registry-deprecated rows".
- rules-docs-2-R2-1: the PR body is replaced at push time from the
  updated draft, with the verification rows re-measured on this head
  and a restack section (what merged from main, what this PR dropped,
  the main-side follow-ups). Nothing is pushed here.
- rules-docs-2-R2-2: the plan's defects table is retitled to where each
  defect now stands; the four rows main fixed are struck with the fix
  named, the purge row keeps only what is still open (a RemoteError
  object shows the generic message, P1a), and D19 records that the
  README's hiddenModels was removed in P0.
- rules-docs-2-R2-3: README.zh-CN.md's merge rule follows the English
  and the code: a row is dropped only when the registry marks it
  deprecated, not when a per-provider list names it. One sentence, so
  the pairing gate's counts are unchanged.
- rules-docs-2-R2-4: CONTRIBUTING.md no longer contradicts the
  repository: warnings are reported and gate in P12 (as its own command
  list says); a manual release creates the GitHub Release and never
  touches CHANGELOG.md; the release step points at the "Verified on
  DeepSeek Harness" line in both READMEs; the e2e section lists all
  five files.
- rules-docs-2-R2-5: both READMEs drop the test total nothing pinned;
  engineering-notes.md's "every count" paragraph records it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
The third review round of the P0 restack. Each outcome:

- The meter mock-ups in both READMEs and both quota-meter guides paired
  one model with another model's monthly allowance. They now name the
  model whose row the figures are, and the panel mock-up's rate line
  prints that model's catalog rates in the format the panel uses. A new
  catalog test reads every "<id> Go $a · Plus $b" figure in the four
  documents back against the generated allowance table; it failed on
  the old mock-ups and holds a known minimum of matches, so a regex that
  stops matching cannot pass as clean.
- engineering-notes: the "deeper half" measurement is scoped to the Go
  plane it was taken on. Both ids are Zen rows and neither has a row in
  the Go catalog, which is what the plane-aware lookup misses; the
  sentence no longer claims they are absent from both shims.
- deep-dive: the two "up to" figures for context window and max output
  are dropped, per the same file's rule that counts which move with the
  vendor are not restated.
- docs/README.md indexes every document in the directory: the test
  system guide, upstream findings, the CLI API note, the parity plan,
  and the plugin page pair, whose two languages the opening sentence
  now names.

No generated file moves.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
…nto claude/vigilant-mendel-bctz9n-p1a

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
The merge resolution read the RemoteError's message by property access,
which the lint gate's prefer-destructuring rule rejects as an error, and
left the merged host-tokens test unformatted. Same behaviour, now through
the gate.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
Outcomes of the merge review:

- both-kept-1-F1, resolutions-1-P1A-2, rules-docs-1-P1A-DOCS-1:
  docs/redirect-planes.md now states D19 (`auto`, the default, is an alias
  of `modern`; `legacy` pins the zen family) instead of "follows the
  catalog". The models-discovery repair comment is left for P-R1, which
  deletes that block, and is named in the PR's follow-ups.
- resolutions-1-P1A-1: the catalog's refusal describe gains the Zen-plane
  404 fill, the non-JSON 200 answer, and a retry-after header that must
  survive the passthrough (mutation-checked).
- resolutions-1-P1A-3: the plan's defect row for the RemoteError purge
  message is struck as fixed by P1a.
- rules-docs-1-P1A-DOCS-2: the plan's status and restack rows name the
  warning token's dropped fallback, matching the build-order item.
- rules-docs-1-P1A-DOCS-4: the host-tokens header names usage-pill among
  the meter files the card scan leaves out.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
- fixed: rules-docs-2-P1A-1 — the host-tokens header drops the template
  clause (no meter file builds a token name from a template) and names the
  measured reasons: usage-pill.tsx would pass the scan; usage-ui.ts and
  usage-panel.tsx each spell the `--dsw-alias-state-*` wildcard in prose, and
  usage-ui.ts names `--dsw-radius-full` behind a literal 999px fallback.
  CARD_FILES is unchanged.
- fixed: rules-docs-2-P1A-2 — the plan's status row, struck defect row,
  build-order item and restack row name the three refusal-passthrough test
  cases P1a adds (the Zen-plane 404 fill, the non-JSON 200 answer, the
  retry-after passthrough); the passthrough itself is on main (#133).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
…a' into claude/vigilant-mendel-bctz9n-p1b

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
P1b's divergent-catalog seed and main's synthetic rows (#138) built the
same thing twice, and main's copy imported src directly. They are now
one module, test/support/catalogs.ts, which reaches src through
test/support/src.ts: the seed is built from main's payload builder, and
the plane-lookup and plane-divergence tests take their src names from
the door too (coreToolDecision is added to it).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
The settings registry and the manifest still said the file is written
only while debug is on. Under main's rule, which this stack adopted as
D24, naming debugFile writes both halves of the log and debug governs
the console alone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
ultracite 8.1.0, which main brought in, reports a then() callback that
returns nothing as an error. The backoff case awaits the sleep in an
async callback instead; what it asserts is unchanged.

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

viztor commented Nov 3, 2026

Copy link
Copy Markdown
Owner Author

Restacked onto main 1.8.0. The branch now carries main 1.8.0 through its parent (P1a, #106), which is an ancestor of this head. Pushed head: 239d6352b4a04214e6b71e5693e434981cdc73f4.

The description was written before the restack and has now been rewritten. It no longer claims a behaviour change, item 6 follows D25, and the verification table holds this head's gate numbers.

Conflicts and how they were resolved

Tool fallback (D25)

  • src/tool-fallback.ts: took main's structure via P1a (coreToolDecision, and isCoreToolModel with a plane taken from the URL and a plane-blind fallback). Ported only the deletion of the unreachable Anthropic schemas.
  • src/fetch-patch.ts (merged cleanly, but wrong): removed P1b's route option on maybeInjectCoreTools. The file is now identical to P1a's.
  • test/tool-fallback.test.ts (merged cleanly, but wrong): retargeted to main's signature, with the plane-blind fallback and the URL-path plane asserted.
  • test/fetch-patch.test.ts (merged cleanly, but wrong): kept "classifies a free model by the plane the request is on". The route case is rewritten as "the plane comes from the URL's path, never the turn's route", covering relay paths and gateway URLs.

Tests and fixtures

  • test/stream-hook.test.ts: kept P1b's door form of hookWith without the unused overrides parameter. main's new cases now go through ./support/src.ts. P1a's D24 cases are unchanged.
  • test/fixtures/catalogs.ts and test/support/catalog-fixture.ts: merged into one fixture, test/support/catalogs.ts, behind the door. coreToolDecision was added to the door, and docs/testing.md was updated.
  • test/retry.test.ts: changed to satisfy main's new promise(always-return) lint. The assertions are unchanged, and it is committed separately as style:.

Docs

  • docs/improvement-plan.md: took P1a's restack status table. P1b's row now reads "merged P1a", and a restack note is added under P1b.
  • src/settings-fields.ts and cordis.patch.yml (merged cleanly, but wrong under D24): debugFile is reworded to match main's gate.

Dropped

  • P1b's route-mapped plane for the tool fallback, superseded by feat(test): a fixture harness for the worlds the vendor has not produced #138 (D25).
  • P1b's "a Zen-only free model is no longer free on Go" change and its test. The plane-blind fallback admits that model.
  • The fetch-patch case "the turn's route decides off a gateway URL", rewritten as described above.
  • The standalone test/support/catalog-fixture.ts.
  • The unused overrides parameter in test/stream-hook.test.ts.

Review rounds

  • Round 1: 6 found, 6 upheld, 6 fixed. These covered stale D25 comments, an unasserted fixture premise, plan and AGENTS.md rows, and the setup-file wording.
  • Round 2: 6 found, 3 upheld, 3 fixed. All three were about the door rule's exception list and the entry-point count.
  • Round 3: 5 found, 5 upheld.
    • Three are about verifying both host channels. They are recorded for P-T1a as an owner decision, with no change to D14'/D22' on this branch.
    • Two are about this description. They are fixed by the rewrite above.

Live re-measures still owed

None from this branch. No change here touches the wire, the routes or the credentials. The scheduled live probe suites only need to stay green on this head.

All reviews ran on the dedicated reviewer. None fell back to the general model.


Generated by Claude Code

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
@viztor
viztor force-pushed the claude/vigilant-mendel-bctz9n-p1a branch from 894fa6e to e7ad3df Compare November 4, 2026 19:37
@viztor
viztor deleted the branch claude/vigilant-mendel-bctz9n-p1a November 4, 2026 19:38
@viztor viztor closed this Nov 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants