Skip to content

fix: show the host's purge refusal and say auto is modern - #106

Merged
viztor merged 1 commit into
mainfrom
claude/vigilant-mendel-bctz9n-p1a
Nov 4, 2026
Merged

viztor merged 1 commit into
mainfrom
claude/vigilant-mendel-bctz9n-p1a

Conversation

@viztor

@viztor viztor commented Oct 23, 2026 •

Copy link
Copy Markdown
Owner

Phase P1a of docs/improvement-plan.md. It is stacked on #105 and targets that branch; once #105 merges, its base moves to main.

The scope below was cut from 1.4.1 and has since shrunk. Most of it is now on main. What this PR still carries is listed under "Restacked onto main 1.8.0" at the end. The table and the two behaviour notes are kept as the original record.

It makes eight small fixes to defects that shipped in 1.4.1. Each one opened with a test that was red on the base.

# Defect Fix Test
1 The deprecated @viztor/dsh-opencode wrapper re-exported a default that the barrel doesn't have. That is an ESM link error on every load: SyntaxError: … does not provide an export named 'default'. The wrapper is now export * only, written by one shared helper (scripts/wrapper-forwarder.ts). test/wrapper-forwarder.test.ts links the generated entry against the built barrel in a real Node process. vite-node would turn the missing export into undefined and stay green.
2 isZenProvider("opencode-google") answered false, because the "go" inside "google" read as the Go plane. Uses the plane rule catalogPlaneForRoute already encodes: Go is opencode-go or opencode-go-*. request-shape.test.ts, plus a usage-service behaviour case
3 enrichModelsResponse answered a 401, 403, 429 or 5xx with a 200 catalog. Every non-2xx response except 404 passes through untouched. A 404 is still filled from the catalog, because the Go plane's inference base has no /models. catalog.test.ts
4 The warning colour named --dsw-alias-label-warning, which the host doesn't define, so warnings rendered as caption text. Now --dsw-alias-state-warn-label, the token the primitives' own modules use. host-tokens.test.ts checks every token the card files name against the primitives' token set. It was checked by planting a bogus token.
5 The settings spinner animated only while the meter was mounted, because its keyframes lived in the meter's stylesheet. The settings summary carries its own dsh-oc-spin keyframes. settings-usage.test.tsx
6 The stream hook wrote debugFile with debug off. debug is the switch and debugFile is only where it writes. The fetch patch already used this gate. stream-hook.test.ts, lifecycle.test.ts
7 The purge row reported the host's own { ok: false } failure as "not a purge result", and cast the answer. It shows the host's message, and parses the answer through the contract's whitelisting parsePurgeResult. settings-purge.test.ts, settings-card-purge.test.tsx
8 The endpoint copy described modern as /inference/v1, which the plugin never sends. The copy names the per-protocol inference family, and auto as its alias. This is what the code already did; behaviour is unchanged. endpoint-copy.test.ts, pi-provider.test.ts

Behaviour changes worth knowing

  • Gateway errors from a /models listing now reach the host as errors. A 401, 403 or 5xx used to show up as a full catalog. The host now gets a failed listing it can report.
  • debugFile without debug: true no longer writes anything. The README examples that paired debug: false with a debugFile were updated.

Both notes are superseded by the restack: the passthrough is on main (#133), and the debug rule is main's (D24), so this PR changes no runtime behaviour around either.

Review

The change was reviewed in three lenses: correctness and host contracts, tests, and repository rules. Two independent skeptics checked each finding. Over three rounds the reviewers raised 23 findings; 22 survived as low severity and were fixed, and one was refuted.

Verification

All run locally:

Node Step Result
26 pnpm run check 0 errors; 23 warnings, unchanged from the base
26 unit suite 1207 tests pass, up from 1186
26 shuffled, seeds 1 / 42 / 1234 pass
26 test:mock 51 pass
26 build and scripts/check.ts pass
26 coverage 96.4% lines, 92.2% branches, above the ratchet
24 shuffled (seed 7) and test:mock pass

The diff contains no local paths.

Restacked onto main 1.8.0

The branch merged its parent (P0, #105), which carries main 1.8.0 and the harness's alpha.2 cluster. Most of what shipped broken in 1.4.1 was fixed on main (#133, #135), so the PR is now scoped to:

  • Purge refusal. settings-purge shows the message of a refusal whose error is the remote protocol's serialized RemoteError. main reads only a string message or error, so that refusal was reported without its reason. Tested in settings-purge.test.ts and settings-card-purge.test.tsx.
  • The endpoint copy (D19). The schema description, the config-values doc, the card's hint and Automatic label, both READMEs and docs/redirect-planes.md name the per-protocol inference family for modern, with auto as its alias. test/endpoint-copy.test.ts pins this. The pi-provider and google-bridge docs and tests say the same, and a test asserts that auto resolves exactly as modern does.
  • isZenProvider("opencode-google") regression tests. They cover the predicate, its agreement with catalogPlaneForRoute, and the usage service's Zen fallback on that route. The fix itself is on main.
  • Warning colour. Both the purge row and the store-inspect row use the bare var(--dsw-alias-state-warn-label). There is no token fallback, because the fallback is what hid the original bug. Rendering tests assert the exact string. host-tokens.test.ts also checks that every token the five card files name is in the host's primitives vocabulary.
  • Catalog refusal tests. This adds three cases main lacks: the Zen-plane 404 fill, the non-JSON 200 answer, and the retry-after passthrough. The passthrough itself is on main (fix: the plane decides the price, the flag and the refusal #133).
  • Debug rule (D24). The stream hook's debug test asserts main's rule. Naming debugFile writes the file, and debug governs the console only.

Dropped, because main now does it:

Decisions applied: D19, which this PR's copy settles over main's "follows the catalog". D24 for the debug gate. D22': the branch runs on main's alpha.2 @deepseek-ai cluster through its parent, and P1a changes no pins. D14' (the pi pin) and D25 (the tool fallback) belong to P-T1a and P1b, and do not touch this diff.

Still open: a comment in src/models-discovery.ts still describes auto as following the catalog. P-R1/P-R2 rewrite that code, so the comment is left for them to avoid another conflict higher up the stack.

Live re-measures CI must confirm: none. This phase changes copy, a client-side message read and tests, and nothing on the live request path. CI must confirm the unit suite (including shuffled), test:mock, vp check, the bundle gate and the coverage ratchet on the restacked tree.


Generated by Claude Code

viztor commented Nov 3, 2026

Copy link
Copy Markdown
Owner Author

Restacked onto main 1.8.0. The branch merged its parent (claude/vigilant-mendel-bctz9n, P0), which carries main 1.8.0. The pushed head is 252d0f8989aaf8dd1b58a44af6ff9e15d54d0845. The PR body and title now describe the shrunk scope.

Conflicts and how they were resolved

Purge row

  • src/settings-purge.ts: kept main's structure (unwrap value, then { ok: false } reads message, then a string error, then parsePurgeResult). Added P1a's one new branch: when error is a RemoteError record, its message is shown. Rewritten as a destructuring for lint.
  • test/settings-purge.test.ts (no conflict): kept only P1a's two RemoteError cases. The rest duplicated main's coverage. Mutation-checked: removing the branch turns the first case red.

Endpoint copy (D19)

  • src/config.ts: kept P1a's endpoint description (auto is an alias of modern). The debugFile description is main's (D24).
  • src/config-values.ts: kept P1a's ENDPOINT_FAMILIES doc.
  • src/settings-copy.ts: endpointModern is main's. P1a's endpointAuto and endpointHint stay.
  • README.md and README.zh-CN.md: kept P1a's endpoint row and paragraph. The debug row and the example comment are main's (D24). The zh-CN file keeps main's stale-row removal and its credentialOrg row. The language pair stays in step.

Warning colour

  • src/settings-card.tsx and src/settings-store-inspect.tsx: both use the bare var(--dsw-alias-state-warn-label) with no token fallback.
  • test/host-tokens.test.ts: main's file, plus P1a's check that every token the card names is in the host's vocabulary.

Taken from main

Debug rule (D24)

  • test/stream-hook.test.ts: kept both describes. P1a's debug describe now asserts D24: debugFile is written with debug off and nothing is logged; debug alone logs only. Mutation-checked: restoring P1a's gate turns the first case red.
  • cordis.patch.yml and test/lifecycle.test.ts merged without conflict but were wrong afterwards. Both were reverted to main's D24 wording and config.

Plan and catalog tests

  • docs/improvement-plan.md: took P0's restacked table. P1a's row and its build-order item were rewritten to the shrunk scope.
  • test/catalog.test.ts: dropped P1a's duplicate passthrough describe. The review restored the three cases main lacks: the Zen-plane 404 fill, the non-JSON 200 answer and the retry-after passthrough.

Dropped, because main now does it

Review rounds

Round Found Upheld Fixed
1 8 7 7
2 3 2 2
3 0 0 0

Round 1 brought the in-tree auto copy (docs/redirect-planes.md) into line with D19, restored the three catalog cases, and corrected the plan's defect table, its P1a scope and the host-tokens header. Round 2 corrected the host-tokens header's reason for leaving the meter out of the card scan, and named the three catalog cases in the plan.

One stale comment in src/models-discovery.ts still says auto follows the catalog. It is left for P-R1/P-R2, which rewrite that code.

Live re-measures still owed

None for this phase: nothing on the live request path changed. CI must confirm the unit suite (including shuffled), test:mock, vp check, the bundle gate and the coverage ratchet on the restacked tree.

Every review ran on the dedicated reviewer; none fell back to the general model.


Generated by Claude Code

viztor commented Nov 3, 2026

Copy link
Copy Markdown
Owner Author

catalog freshness is red on 252d0f8 for the same reason as #105. The vendor added a Zen model, pulse-alpha-free (80 → 81), after main's 2026-10-31 regeneration, and this pull request's diff touches the check's inputs, so the drift gates it.

Nothing in this change is at fault: the branch carries main's generated src/catalog-data.ts exactly. The regenerated file cannot be produced from the machine doing this restack, because the vendor registry is unreachable from there. It will come from the nightly refresh on main, and will be ported into #105 and merged up the stack, this branch included, with the counts that restate it re-derived.


Generated by Claude Code

@viztor
viztor changed the base branch from claude/vigilant-mendel-bctz9n to main November 3, 2026 22:39

viztor commented Nov 4, 2026

Copy link
Copy Markdown
Owner Author

catalog freshness is red again on 894fa6e (now based on main), for a new vendor change: the Zen model crouton-alpha-free (81 → 82), added after the 2026-11-03 refresh this branch carries. The diff touches an import of the catalog generator, so the drift gates it. The other three checks are green.

The regenerated file can only come from the scheduled refresh on main, because the vendor catalog is unreachable from the machine doing this work. When it lands, it will be ported into this branch with the counts re-derived, and the branch merged once every check passes.


Generated by Claude Code

Phase **P1a** of `docs/improvement-plan.md`, restacked onto 1.8.1. Most of what
shipped broken in 1.4.1 is on `main` now (#133, #135), so this is what is left:

- **Purge refusal.** The purge row shows the `message` of a refusal whose
  `error` is the remote protocol's serialized `RemoteError`. `main` reads only a
  string `message` or `error`, so that refusal was reported without its reason.
- **The endpoint copy (D19).** The schema description, the `config-values` doc,
  the card's hint and Automatic label, both READMEs and `docs/redirect-planes.md`
  name the per-protocol inference family for `modern`, with `auto` as its alias.
  A test asserts that `auto` resolves exactly as `modern` does.
- **`isZenProvider("opencode-google")` regression tests.** The predicate, its
  agreement with `catalogPlaneForRoute`, and the usage service's Zen fallback on
  that route. The fix itself is on `main`.
- **Warning colour.** Both rows use the bare
  `var(--dsw-alias-state-warn-label)` — no token fallback, because the fallback
  is what hid the original bug — and `host-tokens.test.ts` checks every token the
  card files name against the host's primitives vocabulary.
- **Catalog refusal tests.** Three cases `main` lacks: the Zen-plane 404 fill, the
  non-JSON 200 answer, and the `retry-after` passthrough.
- **Debug rule (D24).** Naming `debugFile` writes the file; `debug` governs the
  console only.

Dropped because `main` now does it: the wrapper fix (#135), the `isZenProvider`
code change, the `enrichModelsResponse` passthrough, the spinner keyframes, the
`parsePurgeResult` switch, P1a's `endpointModern` label, and P1a's debug gate.

Restacked by rebasing the branch's net change onto 1.8.1 rather than merging
`main` into it: the branch's own history is two merges of `main`, and replaying
them would have carried the pre-refresh catalog back over #151.
@viztor
viztor force-pushed the claude/vigilant-mendel-bctz9n-p1a branch from 894fa6e to e7ad3df Compare November 4, 2026 19:37
@viztor
viztor merged commit 07af3a1 into main Nov 4, 2026
4 checks passed
@viztor
viztor deleted the claude/vigilant-mendel-bctz9n-p1a branch November 4, 2026 19:38
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.

1 participant