Skip to content

test: a harness that is the real host - #110

Open
viztor wants to merge 17 commits into
claude/vigilant-mendel-bctz9n-p-t1afrom
claude/vigilant-mendel-bctz9n-p-t1b
Open

viztor wants to merge 17 commits into
claude/vigilant-mendel-bctz9n-p-t1afrom
claude/vigilant-mendel-bctz9n-p-t1b

Conversation

@viztor

@viztor viztor commented Oct 24, 2026 •

Copy link
Copy Markdown
Owner

Phase P-T1b of docs/improvement-plan.md, stacked on #109.

An in-process harness that runs the plugin inside the real host, so the routing phases that follow (P-H, P-R1, P-R2) are measured against today's behaviour rather than against fakes. Additive only: no src/ change.

The sections from "What changed" to "Verification" describe the original scope. Where they disagree with Restacked onto main 1.8.0 below (the pinned and patched e2e-host cell, the patches/ line, the single S0_TODAY table), the restack section is current.

What changed

Item Files What it does
Harness, tier A test/support/host.ts A bare cordis Context with LlmRuntime and dsh-llm-pi-ai mounted with { providers }, for the internal/config waterfall and pi-ai's credential paths.
Harness, tier B test/support/host.ts dsh-app-boot's boot() with a temporary HOME, a test bundle (llm, llm-pi-ai, editor: ConfigEditor, settings: Settings, the plugin), a fake credentials service and a launch-environment snapshot. Rows carry package names through a stub module loader, because the plugin finds pi-ai by options.name. The apply order is fixed (plugin-first, as the binary does it, or pi-ai-first), because the loader starts rows in parallel. It also rebuilds hasProviderApiKey as providerWithApiKey.
Contract tests test/host-waterfall.test.ts, test/host-shapes.test.ts, test/host-credentials.test.ts, test/host-editor-contracts.test.ts Waterfall: the listener fires for another plugin's fiber, prepend puts it outermost, raw === _config holds for _reload/update/_commitVolatile but not for the editor candidate (F14), and a deep-frozen input is never mutated while the fiber keeps the return value (F12). Shapes: the profile shape, the Config defaults snapshot, recordKeyFor, no secret-role nodes, the loader's interpolation and pi's public exports. Credentials. Editor: configEditor.edit writes raw beside the YAML, _commitVolatile re-resolves through a prepended listener, and settings.describe and hasProviderApiKey get baselines.
Tier A smoke test/host-harness.test.ts listProviders() equals pi-ai's keys (F11), and each builder option is exercised once.
Characterization test/host-characterization.test.ts Today's behaviour on pi 1.1.0, with each row tagged KNOWN_DEFECT or INTENDED_CHANGE where P-R1 is expected to flip it. S0_TODAY is shared with the binary e2e.
Keyless matrix test/support/keyless-matrix.ts, test/keyless-matrix.test.ts, test/e2e/keyless-matrix.e2e.ts The 401-vs-404 cell table and a pure classifier, its unit test, and a gated live run.
Binary e2e test/e2e/host-binary.e2e.ts, test/e2e/host/ Runs the probe bundle in the installed host, gated on DSH_HOST_E2E=1 and reading DSH_HOST_PREFIX.
CI .github/workflows/ci.yml, package.json The e2e-host job. Cell a: pi 1.1.0, pinned and patched, on PRs that touch the host seams, cordis.patch.yml or vite.config.ts. Cell b: whatever npm installs, nightly and on dispatch. Adds the test:e2e:host script.
Docs AGENTS.md, CONTRIBUTING.md, docs/improvement-plan.md, test/support/src.ts, vite.config.ts Repo map, e2e section and commands, the plan's P-T1b entry and status (in review), the test door, and the e2e config base.

Behaviour changes

  • Plugin: none. This is a pinning phase, and no file under src/ changes.
  • Test and CI only:
    • The e2e-host job also runs on pull requests that touch vite.config.ts. That file holds the pack config for lib/index.mjs and the test settings that the e2e config inherits.
    • When the binary e2e fails, its message now gives the real cause. It says "timed out" only when the test's own deadline killed the host, "killed by <signal>" for a crash, and gives the probe's fatal message whenever there is one. The dsh install helper reports spawn errors and signals instead of "exited null".

Review

Three lenses (correctness, tests, repo rules), three rounds. No reviewer was missing in any round.

Round Found Upheld Fixed
1 25 25 25
2 6 6 6
3 4 4 4

Each round's upheld findings were fixed before the next round ran. Round 3's four findings are fixed in this commit:

  • The endpoint: legacy wording is narrowed. Go's Google traffic stays on the modern cell under every family.
  • whyRunFailed separates timeouts, signal deaths and fatal probe results.
  • vite.config.ts is added to the e2e-host scope.
  • The plan now says the harness itself rebuilds hasProviderApiKey.

Verification

Node Step Result
26.12.1 pnpm run check 0 errors, 21 warnings (limit 21)
26.12.1 vp test run 87 files, 1360 tests passed
26.12.1 vp test run --config vitest.mock.config.ts 3 files, 51 tests passed
26.12.1 pnpm run build exit 0, ESM 2 files, 340.57 kB
26.12.1 scripts/check.ts check passed (no ETARGET)
26.12.1 shuffle, seeds 1 / 42 / 1234 87 files, 1360 tests passed each
26.12.1 vp test run --coverage 96.47 / 92.55 / 96.52 / 96.47 against floors of 95.9 / 91.3 / 95.9 / 95.9
24.22.1 shuffle seed 7, mock suite 1360 tests and 51 tests passed
— local-path and credential scan of the diff and new files No local paths found. The only sk- hit is the fixture sk-ambient-go-not-a-key. A canary file gave the expected hits, so the scan did read its input.

The first five rows were run again right before the commit. The rest come from the implementation run on the same tree.

Note: the catalog freshness check fails on every branch until the vendor-catalog refresh lands on main. That failure is unrelated to this PR.

Restacked onto main 1.8.0

The branch now carries main 1.8.0 through its parent, P-T1a (#109), merged in at fb6a686. Head: ec38185.

New scope

A harness that is the real host, on both harness channels.

  • Tiers A and B (test/support/host.ts), the contract tests and the tagged characterization run on whichever channel install is selected. On every PR they run on alpha and rc newest (pi 1.5.0), through P-T1a's CI matrix. Each channel's floor (pi 1.3.0 on alpha, 1.1.0 on rc, unpatched) runs nightly.
  • Where hosts differ, a row carries one expectation per host cell (S0_TODAY_BY_CELL, forHost, forChannel). The rows that differ: pi's catalog bases, the ids pi can place, F10 (pi wires Go's Google protocol natively from 1.3), and pi-ai's default window and max tokens (these follow the bridge, so they are keyed by channel).
  • The keyless matrix splits its dispatch sets. TODAY_DISPATCH is the rc floor's: legacy /zen(/go)/v1 completions plus the modern Responses, Messages and Google routes. NEXT_DISPATCH is what npm installs already reach: modern /inference(/go)/openai/v1 completions.
  • The e2e-host job boots each channel's published binary the way npm installs it. The npm cell runs on PRs that touch the host seam. The floor cell runs nightly and on dispatch, pinned to the recorded cordis family. No cell applies a pi patch.
  • The cordis family (cordis, loader, schemastery, include, group, cosmokit) is pinned exactly in package.json, and the channel switch moves the pins. A relock therefore keeps each lockfile at the record's floors. A new harness-channel case requires every family member the lockfile resolves to be a direct pin.
  • A host defect the plugin cannot fix is recorded as a [HOST_LIMITATION] row. The row is detected from the host's answer, never from a version. Today there is one: on alpha 0.2.2-alpha.2, npm resolves cordis 4.0.6-alpha.2, and under it no config-editor save succeeds. The two save rows skip on both alpha cells.

Dropped because main or the parent now covers it

  • The pinned e2e-host cell (pi forced to 1.1.0, harness patch applied with patch -p1, cordis and loader overrides, cache key on patches/*.patch) and the floating cell. Under D14'' they are replaced by the per-channel npm and floor cells, both with unpatched pi.
  • The patches/ line in the AGENTS.md repo map and the patch -p1 step in the CONTRIBUTING local-run snippet. There is no pi patch (D14'').
  • The alpha 0.2.2-alpha.3 bump and the cordis waterfall-shape rewrite of the tier listeners. They came from an earlier, unpushed attempt. The records stay at alpha.2, as P-T1a has them, and the bump is a follow-up (see below).

Decisions applied

  • D14'': both channels, as each one ships, and no pi patch. This is why the per-channel cells, the floor/newest split and the dropped patches/ line exist.
  • D22'': two channel records, named once in test/support/host-versions.ts. The rows read their cell from the record, and the plan text was returned to P-T1a's version wherever the earlier attempt had moved it to alpha.3.
  • D26: host gaps are the host's job. That is why the alpha save failure is a HOST_LIMITATION row, and why the row is detected from the host's answer rather than from a version.
  • D24 (debug gate) and D25 (tool-fallback plane) concern src/, which this phase does not touch, so neither applies here.

Live re-measures CI must confirm

  • e2e job (keyless matrix, every PR): no path-gone verdict on TODAY_DISPATCH or on NEXT_DISPATCH.
  • e2e-host nightly or dispatch: both floor cells (rc pi 1.1.0, alpha pi 1.3.0) and both npm cells on the CI runner. The alpha cells must still record the HOST_LIMITATION, or stop recording it once the host is fixed. npm must still resolve cordis 4.0.6-alpha.2 for dsh 0.2.2-alpha.2.
  • Nightly test matrix: unit and mock (all tier A/B and contract files) on the alpha and rc floor installs. Measured green locally on 2026-11-03.
  • host-drift job: it should now report dsh alpha 0.2.2-alpha.3 (and cordis, loader and schemastery alpha.2) against the alpha record.

Generated by Claude Code

Add an in-process harness that runs the plugin inside the real host,
so the routing work that follows can be measured against today's
behaviour rather than against fakes. Additive only: no src/ change.

test/support/host.ts gives two tiers. Tier A is a bare cordis Context
with LlmRuntime and llm-pi-ai mounted with { providers }, for the
config waterfall and pi-ai's credential paths. Tier B is dsh-app-boot's
boot() with a temporary HOME, a test bundle, a fake credentials service
and a launch-environment snapshot, for the config editor,
settings.describe and the volatile commit. Tier B's rows carry package
names through a stub module loader, and it fixes the apply order,
because the loader starts rows in parallel.

On top of it:

- contract tests for the waterfall, the profile and Config shapes,
  credentials, and the config editor (host-waterfall, host-shapes,
  host-credentials, host-editor-contracts), plus a tier A smoke test;
- a characterization of today's behaviour on pi 1.1.0, each row tagged
  where P-R1 is expected to flip it, with S0_TODAY shared by the
  binary e2e;
- the keyless 401-vs-404 matrix: a pure classifier, its unit test and
  a gated live run;
- a binary e2e gated on DSH_HOST_E2E=1 with its probe bundle, the
  e2e-host CI job (a pinned, patched cell on PRs that touch the host
  seams or vite.config.ts, and a floating cell nightly and on
  dispatch), and the test:e2e:host script.

The binary e2e now reports why a run failed: a timeout only when its
own deadline killed the host, the signal for a crash, and the probe's
fatal message whenever there is one.

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

viztor commented Oct 24, 2026

Copy link
Copy Markdown
Owner Author

catalog freshness is red because src/catalog-data.ts is stale against the live vendor catalog: the vendor added a Go model (kimi-k3.1-pro) after this stack was branched. The failure doesn't come from this PR, which doesn't touch the catalog or its generator. The same check fails on every branch of the stack (#108, #109). No fix is ported here: the shim is generated, never edited by hand, and regenerating it needs models.opencode.ai.

The fix is the nightly scheduled run on main (it ran at about 09:30 UTC the last few days). It regenerates the shim and opens a chore/generated-refresh pull request. Once that is merged into main, I'll merge main up the stack, which turns this check green. A re-run before then would fail the same way, so I haven't spent one.


Generated by Claude Code

The review ran three rounds through the correctness, rules and matrix
lenses. What it found, and what changed:

- The binary e2e's beforeAll budget was smaller than the blocking
  subprocess deadlines it serializes. Each plugin install now has its
  own deadline, the hook's budget is derived from the installs and the
  boot, and afterAll stops a host a failed hook left running.
- providerWithApiKey claimed to be a line-for-line restatement but
  skipped upstream's credentialRef(ref) check. It now throws the same
  TypeError for a ref outside the grammar (a host-editor-contracts
  case pins it), and its comment names the deliberate differences.
- The pinned e2e-host cell let cordis and the loader float at patch
  level. The overrides now force both, the cache key includes them,
  and the job asserts them against HOST_VERSIONS.
- The pi-ai-first characterization asserted every facet under one
  KNOWN_DEFECT title. Each apply order now generates one test per row
  and facet, titled with that order's own tags.
- CONTRIBUTING said the contract tests pin F11-F20, and the plan said
  P-T1 pins every fact. Both now give the same accounting: which facts
  are pinned by number, which P-R1 exercises first, and why F9 and F17
  are not pinned.
- CONTRIBUTING put the e2e's dummy keys in the profile's credentials
  file; they are in the temporary home's credentials document.
- F5 had no real-host pin: host-shapes now pins that a route-level api
  and baseURL collapse pi's protocols onto one. F6 is recorded as first
  exercised by P-R1.
- The credential-mapping row pinned only the api-key branch of
  toPiCredential. host-credentials now covers all three branches, and
  the env branch is asserted through pi's Models.getAuth, so the case
  fails without it.
- The plan's reason for restating hasProviderApiKey was inaccurate; it
  now says no installed copy reaches the function.
- The new credential cases cited toPiCredential at the wrong lines;
  they now cite auth.ts:74-84.
- F4's listing and dispatch halves were pinned only by KNOWN_DEFECT
  rows P-R1 flips. A plugin-less tier-A case in host-shapes now pins
  that an id pi cannot place is not listed and that a turn on it is
  INVALID_CONFIG with no request; the save and deferred-read halves
  are tagged F4 too.
- The one facet that depends on the apply order lost its tag when the
  pi-ai-first block was split. The fixture case now checks only
  structure (the facets whose value moves are the facets whose tag
  moves), and the exact pin is its own KNOWN_DEFECT case that boots no
  host. CONTRIBUTING and the plan say P-R1 drops todayRowsFor's
  override and turns that case into a BASELINE check in the same diff.

Nothing under src/ changed.

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

viztor commented Oct 26, 2026

Copy link
Copy Markdown
Owner Author

This phase's first reviews ran on the general reviewer because the dedicated reviewer was unavailable. It has now had the dedicated review.

Rounds (by lens: correctness, rules, matrix)

round found upheld fixed
1 15 11 (correctness 4, rules 3, matrix 4) 11 (two pairs were the same issue from two lenses)
2 5 4 (correctness 2, rules 1, matrix 1) 4 (one pair was the same issue)
3 3 3 (correctness 1, matrix 2) 3

All upheld findings were low severity.

Fixed

  • test/e2e/host-binary.e2e.ts: the hook's budget now comes from its own deadlines (two installs plus the boot), each install has its own deadline, and afterAll stops a host that a failed hook left running.
  • test/support/host.ts: providerWithApiKey now runs upstream's credentialRef grammar check and throws the same TypeError, and its comment lists the deliberate differences. The pi-ai-first table now carries its own tags.
  • .github/workflows/ci.yml: the pinned cell now forces cordis and the loader along with pi, uses both in its cache key and asserts both against HOST_VERSIONS.
  • test/host-characterization.test.ts: there is now one test per row and facet in each apply order, titled with that order's tags. The fixture check that the two orders differ is now structural. The single facet that depends on the apply order now has its own [KNOWN_DEFECT] case, which boots no host.
  • CONTRIBUTING.md: it now gives the same F-fact accounting as the plan. It also gives the right place for the dummy keys (the temporary home's credentials document) and says what P-R1 must do to the apply-order case in the same diff.
  • docs/improvement-plan.md: it has the same F-fact accounting. It now gives the correct reason hasProviderApiKey is restated, its credential-mapping row names all three toPiCredential branches, and its Go Gemini bullet carries the P-R1 note.
  • test/host-shapes.test.ts: new F5 pin (a route-level api and baseURL collapse pi's protocols onto one). New plugin-less F4 pin: an id pi cannot place is not listed, and a turn on it returns INVALID_CONFIG without sending a request.
  • test/host-credentials.test.ts: covers toPiCredential's env and non-api-key branches. The env branch is checked through pi's Models.getAuth (when that branch was removed, the case failed). The citation is corrected to auth.ts:74-84.
  • test/host-editor-contracts.test.ts: there is a case for the credentialRef grammar, and the F4 save case is now tagged with its fact number.
  • test/host-waterfall.test.ts: the pi-ai save-check case is now tagged F8/F4.

Declined

No upheld finding was declined. The other findings (4 in round 1, 1 in round 2) did not survive verification, so they were left alone.

Nothing under src/ changed. All gate steps passed: check, unit, mock, build and the bundle gate.

Commit: 409b5e1


Generated by Claude Code

The vendor renamed the Go plane's Gemini model from
gemini-4-argon-contributor to gemini-4-argon. The tier-B fixtures
(S0_PROFILE, S0_TODAY, CHARACTERIZED_PROFILE through S0, and
todayRowsFor's pi-ai-first override) declared the old id as the Go gap
id: one the plugin's catalog describes and pi 1.1.0 cannot place. After
the refresh the catalog no longer described it. They now name the
renamed id, which still plays that role because pi 1.1.0's opencode-go
table has no gemini-4-argon either. The host-shapes and editor-contract
cases follow the same fixture. The pi 1.3.0 note in mount-protocols
names that pi's own row, so it stays as it is.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
claude added 12 commits October 27, 2026 12:32
…nt-mendel-bctz9n-p-t1b

# Conflicts:
#	CONTRIBUTING.md
…t1a' into claude/vigilant-mendel-bctz9n-p-t1b

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
… floor

The rows were measured on pi 1.1.0 with the harness patch, a host no npm user runs. Each tier file now runs on whichever host cell is installed (either channel's newest pi, or a channel's floor), and a row carries one expectation per cell where the hosts differ: pi's catalog bases, the ids pi can place, F10 and pi-ai's own defaults. Facets pi 1.5.0 already serves the way P-R1 keeps are BASELINE on that cell.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
…he floor

The e2e-host job installed one host with pi forced to the harness pin and patched. It now runs per channel with pi unpatched: the npm cell on pull requests touching the host seam, the floor cell nightly and on dispatch, each asserting its own cell's rows. A pi newer than the channel record skips only the pi-dependent rows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
CONTRIBUTING, the repo map and the plan still described one pinned, patched pi and a floating cell.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
Review outcomes of the two-channel restack, without a channel bump:
TODAY_DISPATCH is the rc floor's (the desktop app's pi 1.1.0) and
NEXT_DISPATCH is where both channels' npm install already sends
completions; the decoration case asserts per cell and route whether the
wire went to the repaired base instead of an always-true comparison; the
characterization header, the plan and CONTRIBUTING name the per-cell
tables and the HOST_LIMITATION tag, which no P-T1b row carries; the probe
artifact keeps a seven-day retention.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
The alpha channel's npm install of 0.2.2-alpha.2 now resolves cordis
4.0.6-alpha.2, whose new internal/update call shape breaks the host's own
dsh-app-boot listener: every config-editor save throws before any plugin
runs, so both alpha cells of the binary e2e failed their save rows. The
plugin cannot fix that (D26). The probe now names the error class and the
package that threw it, and the e2e records a HOST_LIMITATION row and skips
the save rows when the host's own code throws, detected from the answer
and never from a version, so a fixed host runs them again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
…ost-limitation check

The review of the P-T1b restack upheld fifteen findings; each outcome:

- both-kept-1-F1 (fixed): the floor cell is now the tree the desktop app
  ships. The channel records name the whole cordis family (cordis, the
  loader, the include/group/timer plugins, cosmokit, schemastery), and
  `floorOverrides` forces it with pi at the range floor through npm
  `overrides`. The report step and the e2e assert every member on the floor
  cell; the npm cell stays fully npm-resolved. harness-channel holds each
  lockfile to the record's family (timer is the one member no lockfile
  resolves; the floor cell asserts it). Measured: with the pinned family the
  alpha floor saves, so the limitation is npm-only.
- resolutions-1-T1B-R3 (fixed, with F1): the floor cache key is the channel,
  its dsh and a hash of the overrides, so a fill never freezes cordis.
- both-kept-1-F2 (fixed): the detector matches only a TypeError thrown by
  dsh-app-boot, and HOST_LIMITATION needs a control to fail the same way:
  the probe now also edits its own entry, which no plugin listener reads. A
  mutant whose control saves while the plane edits fail turns both save rows
  red on the alpha npm cell.
- resolutions-1-T1B-R2 (fixed): the row is titled as the limitation (channel,
  dsh, cell), skips where the host saves, and a BASELINE row asserts the
  control is accepted there.
- both-kept-1-F3, resolutions-1-T1B-R1, rules-docs-1-PT1B-DOCS-1 (fixed in
  one edit): release step 3, D22'' and P-T3's two rows say a bump is data
  only while tiers A/B and the binary e2e stay green; one that turns them red
  re-measures the newest tables or adapts the tier listeners in its own
  reviewed pull request. The cordis alpha.1 to alpha.2 example is replaced,
  and the alpha.3 bump is named as the first such case.
- both-kept-1-F4, rules-docs-1-PT1B-DOCS-3 (fixed): plan step 5 says no
  in-process row carries the tag and the binary e2e records one host-code
  defect; RowTag in host.ts holds the one definition, and the plan's tags
  bullet, CONTRIBUTING and host-characterization point to it.
- both-kept-1-F5, rules-docs-1-PT1B-DOCS-2 (fixed): the two e2e-host
  bullets are rewritten, with no duplicate and no "always run"; the local
  floor snippet writes the record's overrides.
- resolutions-1-T1B-R4 (fixed): the P-T1b restack row describes what
  landed: per-cell rows, pi-ai's defaults per channel, INVALID_CONFIG for
  the unknown id on every cell.
- rules-docs-1-PT1B-DOCS-4 (fixed): the F10 row and the test list say per
  host cell.
- rules-docs-1-PT1B-DOCS-5 (fixed): CONTRIBUTING and WHOLE_CATALOG's doc
  state the measured net change.
- rules-docs-1-PT1B-DOCS-6 (fixed): the restack's comments name the ids by
  role or constant.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
The record's cordis family meant two things: what the cluster's `~` ranges
resolve on npm (the field docs, the drift report, release step 3) and the
tree the desktop app ships (the e2e-host floor cell's overrides). They
already disagree for alpha. The fields now have one meaning, the floor of
the range the published cluster declares, which is what the harness vendors
at the tag, what package.json pins and the lockfile holds, and what the
floor cell forces. The family moves only with dsh.

- fixed: both-kept-2-R2-F1, resolutions-2-T1B-R2-1, rules-docs-2-R2-RD-1.
  scripts/host-drift.ts compares every family member with the floor of the
  range its published declarer declares (FAMILY_DECLARERS: the bridge for
  cordis, the loader and schemastery; dsh for include and timer;
  dsh-app-boot for group; cordis at the cordis floor for cosmokit), not the
  newest patch inside it. host-drift.test.ts has a known answer for today's
  registry (alpha.2 patches inside alpha.2's ranges: no line), the next cut
  (eight lines, one per moved field) and the timer case. The test failed
  before the change. Docs follow in host-versions.ts, ci.yml, CONTRIBUTING
  (release step 3: a family patch under an unchanged dsh is not a bump),
  D22'' and AGENTS.md.
- fixed: both-kept-2-R2-F2, resolutions-2-T1B-R2-2. The record is no longer
  its own witness. The binary e2e, in both cells, holds each family value to
  the floor of the range the installed published package declares (a
  mutated timer fails it). harness-channel.test.ts holds the five members
  the cluster peers on to the lockfile's declared peer ranges, and the drift
  report checks the timer plugin nightly. The comments now say what each
  check asserts.
- fixed: both-kept-2-R2-F3, resolutions-2-T1B-R2-3. CONTRIBUTING and the plan
  make ci.yml's narrower cache claim: a cache filled before the record or
  its overrides moved is never reused, and the rest of the tree is what npm
  resolved at the fill. There is no time component in the key. floorOverrides
  also pins @earendil-works/pi-telemetry at piFloor, so the rc floor cell
  runs the desktop's pi pair (1.1.0/1.1.0) instead of 1.1.0 with telemetry
  1.5.0.
- fixed: rules-docs-2-R2-RD-2. Release step 3 and D22'' say a bump that moves
  piFloor or a family field is green only after a workflow_dispatch run on
  its branch, which adds the floor cells. The re-measure list names the
  floor tables (S0_RC_FLOOR/S0_ALPHA_FLOOR and the floor columns of
  WHOLE_CATALOG and PI_GAPS_BY_CELL), and P-T3's bump-PR row dispatches the
  floors. The PR matrix stays as decision (3) sets it.
- fixed: rules-docs-2-R2-RD-3. RowTag, CONTRIBUTING's Tags paragraph and the
  plan's tags bullet scope HOST_LIMITATION by channel and install: a host
  cell for an in-process row, an e2e-host cell (npm or floor) for the
  binary e2e.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD
A relock re-resolves include, group and cosmokit, which arrive only
transitively, at the newest patch their `~` ranges admit; once the
harness publishes one, the lockfile family case fails on the next
routine dependency change. Measured: a fresh resolve of the alpha
lockfile with the release-age window lifted takes the alpha.2 patches.

- fixed: rules-docs-3-RD3-2 - package.json pins include, group and
  cosmokit like cordis, the loader and schemastery, and pinFor moves each
  with the channel; pnpm resolves those peers from the root pins and
  dedupes cosmokit onto its pin, so a fresh resolve now holds the floors
  (overrides were tried and rejected: pnpm rewrites the lockfile's peer
  ranges with them, which would make the peer-floor witness compare the
  record with itself). A new harness-channel case requires every resolved
  member to be a direct pin (failed on both lockfiles before), and
  use-channel.test.ts holds the new rules. Both lockfiles relocked; only
  importer entries changed. CONTRIBUTING (relock rule, release step 3),
  AGENTS.md and D22'' say a relock keeps the family at the floors.
- fixed: rules-docs-3-RD3-5 - the host-versions.ts and host-drift.ts
  headers say package.json pins every member the install resolves (all
  but the timer plugin), so each lockfile holds the floors by construction.
- fixed: both-kept-3-R3-1 - the harness-channel timer comment names the
  binary e2e and the drift report, not "the next case"; the cosmokit rule
  (checked only where the installed cordis is the record's, otherwise only
  by the drift report; today not on alpha's npm cell) is stated in
  CONTRIBUTING, plan step 1 and the e2e header.
- fixed: resolutions-3-T1B-R3-4, rules-docs-3-RD3-4 - same edit; "each
  record value" narrowed to "each cordis-family field".
- fixed: both-kept-3-R3-2, resolutions-3-T1B-R3-2, rules-docs-3-RD3-3 -
  scripts/host-drift.ts added to the e2e-host scope regex, with its reason
  in the comment, CONTRIBUTING's Triggers and the plan's "When it runs".
- fixed: resolutions-3-T1B-R3-1, rules-docs-3-RD3-1 - the docs/testing.md
  row states the floor rule for all seven members and the known answers.
- fixed: resolutions-3-T1B-R3-3 - the FAMILY_DECLARERS doc says the drift
  report reads the dist-tagged cluster and the e2e the record's.

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

viztor commented Nov 4, 2026

Copy link
Copy Markdown
Owner Author

Restacked onto main 1.8.0. This branch now carries main 1.8.0 through its parent, P-T1a (#109). Pushed head: ec38185d750412b6e520f94b176be8b3e076f1d2. The PR body has a new section, "Restacked onto main 1.8.0", with the new scope.

Conflicts and how they were resolved

Docs

  • AGENTS.md: kept P-T1a's repo-map lines (host-versions with two channel records, report-host-drift, use-channel, and the config line with opencode-store-contract.ts) and added P-T1b's host.ts, keyless-matrix.ts and test/e2e/host/ lines. P-T1b's patches/ line was dropped, because under D14'' this repo carries no pi patch. The Commands block is the union of both sides.
  • CONTRIBUTING.md: kept P-T1a's per-job e2e list with main's newer bullets and added P-T1b's keyless-matrix and host-binary bullets. The real-host harness and e2e-host sections were rewritten for both channels: newest and floor pi, unpatched, npm and floor cells, and per-cell tables. Release step 3 is P-T1a's text.
  • docs/improvement-plan.md: the status table and step 4 are P-T1a's. Step 5 is P-T1b's, rewritten for the per-cell tables. F14, D22'', the waterfall-shape bullet and the P-R1 row went back to the parent's text, because their alpha.3 claims were only true in an unpushed earlier attempt.

Code (the merge had no textual conflict but was wrong)

  • Tier files: on alpha's pi 1.5.0, 26 rows failed. pi's catalog bases had moved, the ids pi can place had changed, F10 is native from 1.3, and pi-ai's defaults follow the bridge. These were re-measured into one expectation per host cell (rc floor 1.1.0, alpha floor 1.3.0, newest 1.5.0), plus forChannel for the bridge's defaults.
  • e2e-host job: rebuilt from pinned+patched/floating into per-channel npm and floor cells with unpatched pi. The binary e2e now reads the table for the cell it installed.

Dropped

  • The pinned cell (pi forced to 1.1.0, the harness patch, cordis and loader overrides, a cache key on patches/*.patch) and the floating cell.
  • The patches/ repo-map line and the patch -p1 step in the local-run snippet.
  • The alpha 0.2.2-alpha.3 bump and the cordis waterfall-shape rewrite from the earlier unpushed attempt. Both are out of scope here and listed below as a follow-up.

Review rounds

Round Found Upheld Fixed
1 15 15 15
2 9 9 9
3 11 11 11

Round 3's main fixes:

  • package.json now pins include, group and cosmokit exactly, alongside cordis, the loader and schemastery, so a fresh relock keeps the whole family at the record's floors.
  • A new harness-channel case requires every family member the lockfile resolves to be a direct pin.
  • scripts/host-drift.ts is added to the e2e-host PR scope.
  • The report-host-drift row in docs/testing.md is rewritten.
  • The cosmokit-check wording was corrected wherever it appeared.

Live re-measures still owed

  • e2e keyless matrix (every PR): no path-gone verdict on TODAY_DISPATCH or on NEXT_DISPATCH.
  • e2e-host nightly or dispatch: both floor cells and both npm cells on the CI runner. The alpha cells must still record the HOST_LIMITATION, and npm must still resolve cordis 4.0.6-alpha.2 for dsh 0.2.2-alpha.2.
  • Nightly test matrix: unit and mock on the alpha and rc floor installs. Green locally on 2026-11-03, not yet on CI.
  • host-drift: it should report dsh alpha 0.2.2-alpha.3 (cordis, loader and schemastery alpha.2) against the alpha record.

Follow-ups

  • Channel-bump PR: alpha moved to 0.2.2-alpha.3. Its cordis changes the internal/config waterfall shape, so the bump has to rewrite the tier listeners. It should land as its own PR, not inside this one.
  • Upstream report: an npm install of dsh 0.2.2-alpha.2 resolves cordis 4.0.6-alpha.2, which breaks dsh-app-boot's own internal/update listener. Every config-editor save fails with "next is not a function". This should be reported to the harness.
  • P-R1: its route claim must accept both waterfall shapes by feature detection.
  • Retargeting: origin/main has moved again (fix: harden the test suite, fix plane/mount/credential defects, and add the improvement plan #105), so the bottom of the stack needs a retarget or a main merge.

The dedicated reviewer was unavailable, so all twelve review and verify passes ran on the general reviewer: review:P-T1b:both-kept#1, review:P-T1b:resolutions#1, review:P-T1b:rules-docs#1, verify:P-T1b#1.1, review:P-T1b:both-kept#2, review:P-T1b:resolutions#2, review:P-T1b:rules-docs#2, verify:P-T1b#2.1, review:P-T1b:resolutions#3, review:P-T1b:both-kept#3, review:P-T1b:rules-docs#3, verify:P-T1b#3.1.


Generated by Claude Code

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