Skip to content

feat: a smaller public API - #108

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

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

Conversation

@viztor

@viztor viztor commented Oct 23, 2026 •

Copy link
Copy Markdown
Owner

Phase P2 of docs/improvement-plan.md. It is stacked on #107 (P1b). Below that come #106 (P1a) and #105.

This is a 1.x minor (D6). Nobody consumes the removed exports, so there is no ! and no BREAKING footer.

The barrel

src/index.ts is the host's contract and nothing more:

export { inject, name } from "./identity.ts";
export { apply } from "./lifecycle.ts";
export { Config, type ModelOverrideConfig, type ModelRouteConfig, type PluginConfig, type ResolvedPluginConfig } from "./config.ts";
export { type EndpointFamily, type KeySourcePolicy } from "./config-values.ts";

test/public-api.test.ts pins this list, so widening it is a reviewed change. It opened as a green pin of the old barrel, then shrank in this PR.

  • Added: ModelRouteConfig. PluginConfig.modelRoutes already referenced it, but it could not be named from the barrel.
  • Removed (no longer re-exported):
    • Identity: LEGACY_NAME, LEGACY_PKG, OPENCODE_CLI_VERSION, OPENCODE_PATCH_USER_AGENT, OPENCODE_USER_AGENT.
    • Config: CONFIG_DEFAULTS, the ten DEFAULT_* constants, ENDPOINT_FAMILIES, KEY_SOURCE_POLICIES, resolveConfig, ALL_MODELS_MARKER, readBoolean, readString, readStringList, unwrapNode.
    • Session: fallbackSessionId, isOpenCodeMessageId, isOpenCodeSessionId, headerValueFor, newOpenCodeMessageId, openCodeSessionIdFor, OPENCODE_UA, pinnedSessionId, sessionIdForRequest and the four session header constants; also withStore and the ActiveTurnState type.
    • Request path: DUMMY_BASH_TOOL, DUMMY_READ_TOOL, isCoreToolModel, maybeInjectCoreTools, RESPONSES_PATH, hasSessionHeader, isOpenCodeRequest, patchFetch and the CordisContext type.
    • Credentials: clearCapturedApiKeys, extractApiKeyFromHeaders, getCapturedApiKey, isPlaceholderApiKey, recordCapturedApiKey, tierForRequest, discoverGoConfig, effectiveGoKeyRef, resolveGoApiKey, resolveGoBaseURL, resolveOpencodeStoreKey, resolveZenCreditInfo, toGoBaseURL.
    • Usage and cost: GoUsageService, parseGoUsage, parseUsageQuery and the GoUsage, UsageQuery and UsageWindow types; calculateTurnCost, clearSessionUsageStore, describeModel, formatModelRate, formatUsd, getSessionUsage, recordTurnUsage and the ModelCostRate and SessionUsageSnapshot types.
    • Catalog: every models-catalog constant and function, plus the CatalogModelSpec, CatalogProvider and ParsedCatalogs types.
    • Discovery: the models-discovery decorators and helpers.
    • Routes: every responses-routes constant and function, and the responses-provider helpers.
  • Deleted outright: resolveRoutedKey and the RoutedKeyDetails type (D4: exported and never called).

scripts/check.ts' consumer probe reads only apply and Config, so it still passes.

Also in this PR

  • One door for tests. All 62 test files that imported src now go through test/support/src.ts. It re-exports each name from the module that defines it. A gate in architecture.test.ts rejects a static src import anywhere else. Its exemptions are named: vi.mock targets, re-imports after vi.resetModules(), the architecture and public-API tests, the jsdom client tests, and test/support/. The source-reading gates share a comment blanker that has its own known-answer tests.
  • exports ⊆ files. ./src/* is gone from exports. check.ts now fails when an exports target is outside the published files, using the pure helpers in scripts/package-checks.ts, which are tested against fixtures.
  • internalRoutes is deleted (D2). The per-protocol routes always mount until P-R1 makes the plugin own the plane routes. A row that still carries internalRoutes validates and the key is ignored; a test feeds such a row and pins that. The bridge-disposer test now targets the "every internal route is already declared" exit.
  • @viztor/dsh-opencode is no longer published (D9). The deprecation message already on npm stays as its final word.
    • SCOPED_TARGETS lives in a side-effect-free scripts/scoped-targets.ts.
    • release.yml verifies exactly that list, and check.ts asserts the two agree.
    • main's fix(publish): the retired alias must LINK, not fail on every load #135 forwarder (scripts/wrapper-forwarder.ts) and its real-Node link test (test/wrapper-forwarder.test.ts) are deleted again. The last published alias, 1.8.0, stays a working one.
  • Docs. AGENTS.md (barrel scope, the test door), CONTRIBUTING.md, the README's "Changed in 1.x", and three prose mentions of resolveRoutedKey.

Restacked onto main 1.8.0

The branch now carries main 1.8.0 through its parent: #107 merged #106, which merged #105, the one phase that merges main. 0563db6 re-merges the parent after its catalog refresh, so this branch is one merge from #107's tip.

Scope after the restack

  • The barrel is cut to the host's contract: apply, Config, inject, name and the config types. test/public-api.test.ts pins that list.
  • The ./src/* export is gone, every exports target is inside files, and resolveRoutedKey and internalRoutes are deleted.
  • Every test reaches src through test/support/src.ts, including the tests main added (go-limits-html, google-thinking, the gateway-contract mock, catalog, usage-contract, settings-remote). parseAccountRef, callUsageRead, GO_MODEL_LIMITS and LEGACY_PLANE_API are reached through the door, not the barrel.
  • The @viztor/dsh-opencode alias that main revived in fix(publish): the retired alias must LINK, not fail on every load #135 is retired again (D9). scripts/wrapper-forwarder.ts and its test are deleted, and publish-scoped/release.yml publish only dsh-opencode-patch and @viztor/dsh-opencode-patch.

Dropped because of main or the parent

  • main's alias publishing in scripts/publish-scoped.ts: the forwarder, its forwarding cordis patch and the redirect README for @viztor/dsh-opencode. D9 supersedes it.
  • main's scripts/wrapper-forwarder.ts and test/wrapper-forwarder.test.ts, under D9.
  • The parent's wide src/index.ts export list, which this PR's barrel replaces.
  • The internalRoutes lines in cordis.patch.yml, because this PR deletes the setting.

Decisions applied

  • D9: the alias is not published.
  • D24: cordis.patch.yml takes the parent's wording: debug governs the console, and naming debugFile writes the file.
  • D25: inherited from the parent unchanged. The request URL decides the tool fallback's plane, with a plane-blind lookup as the fallback.
  • D14' and D22' do not touch this phase. They land in P-T1a (build: pin the host the plugin runs on #109).

Restack commits:

  • bab4fc8 merges the parent.
  • 521b98f routes main's new tests through the one door. The door gains LEGACY_PLANE_API.
  • 737a49d drops the forwarder from docs/testing.md.
  • c15aca0 stops the count-sweep record asserting a superseded catalog.
  • 0563db6 re-merges the parent.

Catalog: src/catalog-data.ts is the nightly generated blob, carried unchanged from #105 through the parent and never hand-edited. Zen serves 81 of its 131 listed models, as of 2026-11-03.

Live re-measures CI must confirm: the restack adds none of its own. CI on 0563db6 must pass two checks:

  • the catalog freshness gate on the 81-row blob;
  • the publish-list check, which requires release.yml and SCOPED_TARGETS to agree on the two packages.

The scheduled live suites are owed exactly as on the parent. The Verification table below predates the restack, so CI on 0563db6 is the verification of record.

Review

Three lenses reviewed the change (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 18 low.

The restack had its own three review rounds. They found 4 findings, all 4 were upheld, and all 4 are now fixed: 2 in the worktree and 2 in this body.

Verification

All run locally:

Node Step Result
26 pnpm run check 0 errors; 21 warnings, unchanged from the base
26 unit suite 1234 tests pass, up from 1222
26 shuffled, seeds 1 / 42 / 1234 pass
26 test:mock 51 pass
26 build and scripts/check.ts pass; this includes the new exports ⊆ files and publish-list checks
26 coverage 96.4% lines, 92.3% branches
24 shuffled (seed 7) and test:mock pass

The diff contains no local paths.


Generated by Claude Code

viztor commented Oct 23, 2026

Copy link
Copy Markdown
Owner Author

catalog freshness is red, and the cause is not this PR's diff. The job compares src/catalog-data.ts with the live catalog at models.opencode.ai. Between this branch's base and this run, the vendor added one Go model:

opencode-go: 28 -> 29
  + 1: kimi-k3.1-pro
opencode  : 82 -> 82
shim is STALE — re-run with --write

This PR doesn't touch the catalog or its generator. Any branch that runs the check now fails it the same way, including the base of this stack (#105).

There is no fix yet. The shim has to be regenerated with pnpm run catalog:shim -- --write, which needs network access to models.opencode.ai. The session that built this stack can't reach that host. The generated file must not be hand-edited.

The repository's nightly run (37 4 * * *) regenerates it and opens chore: refresh the generated catalog and limits tables against main. Once that merges, I'll merge main up through this stack. I'm re-running the failed job once to confirm it reproduces identically.


Generated by Claude Code

viztor pushed a commit that referenced this pull request Nov 3, 2026
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

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 (#107 → #106 → #105). The pushed head is 0563db66e8490e75ff3a5bf8229a75828921a72b.

Conflicts and how they were resolved

Barrel and test door

  • src/index.ts: kept P2's barrel (apply, Config, inject, name, the config types, EndpointFamily/KeySourcePolicy) and dropped the parent's wide export list. The names main's tests need come through test/support/src.ts instead.
  • test/catalog.test.ts: dropped the direct imports from src/catalog-data.ts and src/go-limits-data.ts. GO_MODEL_LIMITS was added to the existing door import.
  • test/settings-remote.test.ts: the import now goes through the door, which gains callUsageRead.
  • test/usage-contract.test.ts: the import now goes through the door instead of src/index.ts. The door gains parseAccountRef, which stays out of the barrel.
  • test/e2e/protocol-routing.e2e.ts: kept the door import and added main's ./verdict.ts import.

Wrapper alias (D9)

  • scripts/wrapper-forwarder.ts (modify/delete): deleted. P2 retires again the wrapper main revived in fix(publish): the retired alias must LINK, not fail on every load #135.
  • test/wrapper-forwarder.test.ts (modify/delete): deleted along with the forwarder.
  • scripts/publish-scoped.ts: took P2's side. SCOPED_TARGETS comes from scripts/scoped-targets.ts, and there is no alias branch.

Config and docs

  • cordis.patch.yml: took the parent's D24 wording for debug/debugFile, and dropped the internalRoutes lines.
  • AGENTS.md: kept P2's barrel and one-door bullets. Took the parent's client-safe module list, which names a file that exists.
  • CONTRIBUTING.md: kept P2's full list of door exceptions, and dropped the parent's line that said "still to come in P2".
  • docs/improvement-plan.md: took the parent's restack status table and marked the P2 row as merged.

Follow-ups after the merge

  • 521b98f routes three of main's conflict-free files through the door (go-limits-html, google-thinking, the gateway-contract mock). Without it, the door gate fails on 7 imports. The door gains LEGACY_PLANE_API.
  • 737a49d drops the forwarder's row and its link-test bullet from docs/testing.md.
  • c15aca0 stops the count-sweep record asserting a superseded catalog.
  • 0563db6 re-merges the parent at 835c793, which carries its nightly catalog refresh. The merge had no conflicts and hand-edits nothing.

Dropped

  • main fix(publish): the retired alias must LINK, not fail on every load #135's alias publishing in scripts/publish-scoped.ts: the forwarder, its forwarding cordis patch and the redirect README. D9 supersedes it.
  • main's scripts/wrapper-forwarder.ts and test/wrapper-forwarder.test.ts, under D9.
  • The parent's wide src/index.ts export list.
  • The internalRoutes lines in cordis.patch.yml, because P2 deletes the setting.

Review rounds

  • Round 1: 1 found, 1 upheld, 1 fixed. engineering-notes still asserted the old catalog counts.
  • Round 2: 1 found, 1 upheld. The PR body attributed the deleted forwarder to P1a; that is fixed in the body now.
  • Round 3: 2 found, 2 upheld, 2 fixed. The first was that P2's head was behind its parent (below). The second was the same P1a attribution, deferred to the body pass and now fixed.

Live re-measures still owed

The restack adds no live re-measures of its own. CI on 0563db6 must pass the catalog freshness gate on the 81-row blob, and the publish-list check that holds release.yml and SCOPED_TARGETS to the two packages. The scheduled live suites are owed exactly as on the parent.

Unresolved high findings

  • "P2's HEAD is behind its parent: p1b moved after the merge (pulse-alpha-free catalog refresh), so feat: a smaller public API #108 ships the 80-row shim CI's catalog gate will judge stale". This was raised in round 3. 0563db6 addresses it by merging the parent tip 835c793, which is now an ancestor of the pushed head. As a result the branch carries the parent's 81-row nightly blob byte-for-byte. It stays listed until CI's catalog gate confirms the fix on 0563db6.

Generated by Claude Code

@viztor
viztor force-pushed the claude/vigilant-mendel-bctz9n-p1b branch from 835c793 to a503b98 Compare November 4, 2026 19:41
@viztor
viztor force-pushed the claude/vigilant-mendel-bctz9n-p2 branch from 0563db6 to d0fbb2c Compare November 4, 2026 19:48
@viztor
viztor changed the base branch from claude/vigilant-mendel-bctz9n-p1b to main November 4, 2026 19:49
@viztor
viztor force-pushed the claude/vigilant-mendel-bctz9n-p2 branch from d0fbb2c to 5e7a442 Compare November 4, 2026 19:51
Phase **P2** of `docs/improvement-plan.md`, restacked onto 1.8.1.

The barrel is the host's contract and nothing more — `apply`, `Config`,
`inject`, `name` and the config types — and `test/public-api.test.ts` pins the
list, so widening it is a reviewed change rather than an accident of an export
statement. Everything else is internal.

- **`test/support/src.ts` is the one door tests use into `src`.** Each name is
  re-exported from the module that DEFINES it, never through the barrel, so a
  module move edits one file. `test/architecture.test.ts` enforces both halves:
  every name is declared in its target, and no test outside the named exemptions
  imports a `src` path.
- **The retired alias is retired again (D9).** `@viztor/dsh-opencode` stops
  publishing: `scripts/wrapper-forwarder.ts`, its test, and the wrapper branch of
  `publish-scoped.ts` are gone, and the deprecation message already published
  stays as the final one. `main` had revived the alias to fix its forwarder
  (#135); this is the other half of that decision, now that the forwarder works.
- **The scoped targets move to `scripts/scoped-targets.ts`**, so the release
  workflow and the publish script read one list.
- **`scripts/package-checks.ts`** holds the manifest assertions the publish path
  and the bundle gate share.

Restacked by rebasing the branch's net change onto 1.8.1, then removing the two
files the patch deletes rather than empties.

Restacked onto main after P1b merged; the branch was pushed while the pull
request still targeted the stacked base, so this commit is re-pushed to trigger
the workflow against `main`.
@viztor
viztor force-pushed the claude/vigilant-mendel-bctz9n-p2 branch from 5e7a442 to 3654e35 Compare November 4, 2026 19:57
@viztor
viztor merged commit 5905caa into main Nov 4, 2026
4 checks passed
@viztor viztor mentioned this pull request 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.

1 participant