Skip to content

Slice 2: boot build-parity assertion + smoke-gated hub swaps - #298

Draft
aarontrowbridge wants to merge 3 commits into
local/amicodefrom
slice2-binary-currency
Draft

Slice 2: boot build-parity assertion + smoke-gated hub swaps#298
aarontrowbridge wants to merge 3 commits into
local/amicodefrom
slice2-binary-currency

Conversation

@aarontrowbridge

Copy link
Copy Markdown
Member

Closes #295 (D3 of spec-20260905-045114 — session & device lifecycle). Sibling of #296 (slice 1); no file collisions.

What landed

Boot build-parity assertion (base, hub + clients)

  • packages/opencode/src/installation/parity.tsParity.assert compares the running build (channel + version + sha) against the release channel's npm dist-tags and records exactly one of parity-ok | parity-drift | channel-unreachable in opencode.log. Fail-open: unreachable channel, error status, malformed JSON, hung channel (bounded at 5s), and local builds (no release channel) all record channel-unreachablenever parity-ok. The assertion never fails boot.
  • Boot hooks: hub (serve, asserted before listen so even a crashed boot carries its record), client (run), client (attach).
  • Build sha baked at build time (OPENCODE_SHA define from git rev-parse HEAD in script/build.ts; unknown outside release builds). Comparison is tag-based — dist-tags carry versions.

Smoke gate (base ops tooling, in-tree)

  • packages/opencode/script/hub-smoke-gate.sh — a passing ops/hub-upgrade-smoke.sh run (which lives in the ops surface, outside this repo) records <staged>.smoke.json (outcome=pass + sha256 of the smoked binary); the gate is the reader every swap goes through. check/swap modes; any missing, non-pass, or sha-mismatched record is refused and the refusal names the missing gate (hub-upgrade-smoke). On pass, swap is rename-only (mv + sha sidecar refresh) — no process stop, so a running hub is never left down.

Green (with the tests that pin them)

  • AC1 — every boot records exactly one outcome in its log: 10 unit tests on the record (one structured entry per assert, all three outcomes exercised) + subprocess tests that spawn the REAL CLI (serve and run) and assert the log file under the isolated XDG dir carries exactly one record. ✅
  • AC2 — channel unreachable fails open, recorded as channel-unreachable, never parity-ok: unit tests for connection failure, HTTP error status, malformed body, missing dist-tag, hung channel (bounded), and local builds (no probe at all). ✅
  • AC3 — a swap without a passing smoke run is refused, refusal names the missing gate: 4 gate tests (no record / non-pass outcome / sha mismatch / check-mode). ✅
  • AC4 — a swap with a passing smoke run proceeds rename-only, hub never left down: rename assertions (staged gone, live replaced, sidecar matches) + a real long-running process executing the live binary that survives the swap untouched. ✅

All green locally: 22 installation tests, 7 smoke-gate tests, 2 subprocess boot tests, serve suite, run suite (200 pass), tsgo --noEmit clean in opencode + core, oxlint adds zero findings.

Not green / out of repo (deliberate)

  • Ops-side adoption — the swap machinery (ops/hub-restart.sh) and the smoke harness (ops/hub-upgrade-smoke.sh) live OUTSIDE this repo. In-tree this slice ships the gate + the record contract; adopting it is a one-line call in hub-restart.sh's swap mode and a record-write in the harness's PASS path. AC3/AC4 are enforced and tested in-tree at the gate; the live ops scripts are not edited from here.
  • Fleet surfacing of drift (posture view, alerting) is slice 4 per the spec.
  • Clients whose boot is not this repo's process (desktop shell, web UI bundle — the web app build IS the hub build since it's embedded) — noted, not wired.

Verification matrix note

H2-family per the spec: the release channel is exercised up / drifted / down via service-injected HTTP (no globalThis mocks) and via real subprocess boots; the gate is exercised against the real script with real files and processes.

…ail-open (amicode#295 AC1 unit + AC2)

D3 (spec-20260905-045114): every client and the hub assert their build
(channel + version + sha) against the release channel's dist-tags at boot
and record exactly one of parity-ok | parity-drift | channel-unreachable
in the log. An unreachable / erroring / hung / malformed channel fails
OPEN but is recorded as its own outcome — never as parity-ok. A local
build has no release channel and records channel-unreachable without
probing. The boot sha is baked at build time (OPENCODE_SHA define).
…icode#295 AC1)

serve (hub), run (client), and attach (client) each assert the build at
boot via Parity.assertBoot — bounded (5s hub, 2s clients), fail-open, one
record per boot in opencode.log. Subprocess tests spawn the real CLI and
assert the log file carries exactly one record; a local channel reads
channel-unreachable, never parity-ok.
…ename-only proceed (amicode#295 AC3+AC4)

The DB-snapshot boot smoke is the only road to a hub swap: a passing
ops/hub-upgrade-smoke.sh run records <staged>.smoke.json
(outcome=pass + sha256 of the smoked binary), and the gate refuses any
swap without a passing, sha-matching record — the refusal NAMES the
missing gate (hub-upgrade-smoke). On pass, swap is rename-only (mv) with
a sha sidecar refresh; no process stop, so a running hub is never left
down. Tested against the real script with real files and a real
long-running process holding the live binary open across the rename.

The swap/restart driver itself lives in the ops surface (outside this
repo); adopting the gate there is a one-line call in hub-restart.sh's
swap mode.
@coderabbitai

coderabbitai Bot commented Sep 5, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@aarontrowbridge

Copy link
Copy Markdown
Member Author

HELD — do not merge. Same fork-retirement disposition as #296: parity assertion + smoke gate are harness-side boot behavior; re-homes as a Harness Contract field + upstream reference PR. Reference implementation preserved here.

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.

Slice 2: boot-time build parity assertion + smoke-gated hub swaps

1 participant