---
name: the-forkening-plan
description: "THE-FORKENING milestone (v0.32.0 counter 59) — private fork to BigscreenVR, gh-CLI distribution, local docs server :5474, update-UX simplification; grilled + ruled 2026-07-14, not yet dispatched"
metadata: 
  node_type: memory
  type: project
  originSessionId: 5b71855b-82d2-483b-908f-4b2c3f57db84
---

THE-FORKENING — operator-grilled 2026-07-14 (grill-with-docs), all rulings locked. Target: **v0.32.0, counter 59, first release published ONLY to BigscreenVR/spt-bs-releases**. todlando builds, doyle gates, **deployah publishes — OPERATOR UPDATE 2026-07-14: deployah BACK ONLINE, normal role split restored; the earlier doyle-drives-release cross-role exception is RETIRED** (todlando's daemon restart also cured their pump stall; `spt daemon refresh` verb still lands in W4 as planned).

## W0 STATUS (2026-07-14, doyle-executed legs DONE)
- ✅ `BigscreenVR/spt-bs-core` + `BigscreenVR/spt-bs-releases` created PRIVATE; full branches+tags mirror-pushed from SaberMage originals (refs/heads/* + refs/tags/* — refs/pull skipped deliberately). **gh release ASSETS not migrated** — counter 58 baseline stays readable on SaberMage/spt-releases; 59+ publish to bs-releases.
- ✅ Origin flipped on the shared checkout (origin=bs-core, mirror=SaberMage/spt-core) — landed BEFORE todlando's first W1 push (their branch `build/forkening-w1-gh-transport` already existed locally at flip time, unpushed).
- ✅ Actions OFF on SaberMage/spt-core + SaberMage/spt-releases (repo-level `actions/permissions enabled=false`).
- ✅ Psyche project-context copy+rename: git-native — `.seed.git` branch `p-github-com-bigscreenvr-spt-bs-core` from `p-github-com-sabermage-spt-core` tip (5478dfe) + worktree `tracked/projects/github-com-bigscreenvr-spt-bs-core`; covers ALL 4 agents (chert/deployah/doyle/todlando); old dir left intact.
- ✅ Memory + CLAUDE.md sweep (CLAUDE.md files had zero SaberMage refs; counter-source memory updated). Deploy-box note: kitsubito deploy checkout origin = local runner workspace (unaffected); any future re-clone fetches BigscreenVR/spt-bs-core; gravity host retired.
- ✅ RUNNERS REGISTERED (doyle 2026-07-15, operator-GO'd): both boxes swapped IN PLACE to bs-core (same dirs, same _work caches, identical labels; kitsubito = full autonomous via passwordless sudo, new systemd unit actions.runner.BigscreenVR-spt-bs-core.kitsubito; HFENDULEAM = elevated script w/ operator UAC click — Windows SERVICE KEPT under its old name actions.runner.SaberMage-spt-core.hfenduleam to preserve stored .\decid credentials, registration under it points at bs-core; rename = optional operator task needing the account password). Stale queued bs-core runs cancelled pre-registration. RECIPE: mint remove-token (old repo) + registration-token (new repo) via gh api; linux = svc.sh stop/uninstall → config.sh remove → config.sh new-url → svc.sh install/start; windows = hide .service marker so config.cmd remove leaves the SCM service intact, re-register, restore marker, restart service.
- ✅ RELEASES_TOKEN SET (operator 2026-07-15 11:39Z, secret confirmed on bs-core via gh secret list; smoke-tested against bs-releases): fine-grained PAT, resource owner=BigscreenVR, Contents R/W on spt-bs-releases only. v0.32.0 assemble/draft step UNBLOCKED. claude-spt-bs fork = perri-direct, untouched.
- ⏳ OPERATOR-ONLY remaining: BIGNET re-pair — flynn-box = HFENDULEAM ([[hfenduleam-hosts-flynn]]), locally executable, parked awaiting operator go + re-pair shape.

## W3 CLOSED (doyle 2026-07-15): PASS @053e008 → MERGED @cff7c1f (bs-core PR #3) + mirror-pushed
- REQ-DOCS-LOCAL-SERVER full (docshost.rs: hyper current-thread, loopback-by-construction, decode-then-sanitize + canonicalize-prefix, GET/HEAD, docs-less loud + stays bound; e2e drives production start() over real HTTP). Riders ratified: REL-1 → HISTORICAL doc-only (xtask site() deleted), license link re-homed to bs-releases README, about-help URL, book.toml site-url "/".
- FIRST REAL bs-core CI run this gate. Two runner lessons: (1) kitsubito `config.sh` re-registration regenerates `~/actions-runner/.path` WITHOUT ~/.cargo/bin → instant exit-127 "cargo: command not found" on every job; fix = prepend to .path + systemctl restart runner unit (patched 2026-07-15, .path.bak kept). Check .path FIRST on instant-127 reds. (2) Attempt-2 residual: two brain-bringup e2es (multi_subnet_bringup, run_no_dup_session) 30s-timeout at Phase-A parallel-burst start with EMPTY brain.stderr.log — wedge upstream of broker bind (docshost logs DOCS_SERVER_* post-bind; none present = W3 exonerated by ordering). Attempt 3 all green = cold-burst flake class on first-run box. RCA-by-log-ordering pattern worth reusing.
- Standing rider for W4/cutover sweep: docs-site/book.toml git-repository-url still SaberMage/spt-releases (dead link once privated at cutover).
- **W4 CLOSED (doyle 2026-07-15): PASS → MERGED @e0a8bb0 (PR #4) + mirror-pushed; branch deleted.** All FOUR REQs (ADAPTERS-VERB alias+comma-list+fail-fast+isolation+summary; DEFAULT-COMPOSITE bare update core-first w/ -c, core-fail aborts/adapters-fail isolated; RESTART-SAFE-SWAP lethal-leg-LAST, seed #12 retired; DAEMON-REFRESH refresh_brain = brain-cycle minus swap). Ints: composite_e2e (hermetic fake-gh channel via gh_fixture [[bin]] on prepended PATH — REUSABLE for any gh-transport test) + daemon_refresh_e2e. Ratified in-gate: skip-exit-0 behavior change; already-current --restart = NO_UPDATE no-op; heavy-at-birth classing for new daemon-tree e2es (doyle seeds as CI-lint candidate). CI rider commit @5199464 = FLAKE-LEDGER #15: 4 daemon-tree e2es + daemon_refresh_e2e added to all THREE HEAVY strings (ci.yml A-exclude/B-include + nextest.toml override, byte-identical mandate); rider run all green FIRST attempt both platforms — reclassification proven live. LESSONS: (1) UAC-740 "update" exe-name class hits TEST binaries too (nextest --list itself 740s) — name e2e files sans "update". (2) Real-daemon e2e (~10s bringup) in Phase-A pool = probabilistic 30s-readiness blowout under 16-way storm; classify heavy AT BIRTH. LAST BUILD WAVE — milestone handed to deployah (doyle briefing for v0.32.0 counter-59 dispatch: bump+CHANGELOG+RUNBOOK:16 PAT-line ride in release PR; CHANNEL-PRIVATE int = the ceremony). Operator-only still open: BIGNET re-pair (flynn-box).

## W2 GATE (doyle 2026-07-15): scoped REWORK @8981d81 (bs-core PR #2) — one trivial blocker
- BLOCKER: clippy too_many_arguments (8/7) build_signed_update_set (xtask main.rs:672, docs param tipped it) — CI -D warnings = red-in-waiting; both platforms. todlando preflight claimed clean → their clippy likely lacks -D warnings (LESSON: gate clippy must mirror CI flags; plain `cargo clippy` warnings still count since CI denies).
- PASS-grade otherwise: Win 1788/1788 + kitsu 1774/1774 + REAL bundle assembly verified both (102 entries, 4 contract files at tar root, node-local llms-full header). Read-gate clean: apply isolation binding (land-after-binary-success, re-verify vs signed entry, docs.new→swap+rollback, UPDATE_DOCS_SKIPPED everywhere), additive docs field w/ skip_serializing_if (docs-less sets byte-identical), tar traversal reasoned-accept (signed-set trust + GNU/bsdtar refuse `..` default, no -P), pre-ruling asserted verbatim in docs_bundle_e2e.
- RATIFIED: CHANNEL-PRIVATE impl-only flip (int = v0.32.0 ceremony, disclosed); schema $id → localhost:5474 WITH bundle (W3 must precede cut — it does); llms-full header pre-claimed from W3; spt-shell-notify stays SaberMage (public, unforked); REQ-INSTALL-1/5 retitled. Disclosures accepted: xtask site() retained = W3 cleanup candidate; adapter.md license link = W3/cutover item.
- Re-gate scope RULED: clippy + fix-only diff, NO full re-sweep. Gate worktree gate-8981d81 kept up. Kitsubito gotcha: mdbook lives at ~/.cargo/bin (not on PATH) — probe both.

## W1 CLOSED (doyle 2026-07-15): PASS @a841f5a → MERGED @832b982 (bs-core PR #1) + mirror-pushed
- Rework fix-only (notif test asserts const). Two-platform manual full green substituted for queued CI: Win (bigscreen) 1785/1785 + clippy + traceable; Linux (kitsubito, full-bundle transfer — deploy checkout origin STALE now that Actions are off; raw-sha bundles refuse, use ref names; 7MB full bundle fine) 1771/1771 + clippy. Merged on gate authority; FIRST merge-time mirror push done (`git push mirror refs/remotes/origin/main:refs/heads/main --follow-tags`).
- inject_control_wedge red on todlando's box = ENVIRONMENT-ANCHORED (green Win+Linux at same sha here; also red on main THERE) — rides the HFENDULEAM incident-cluster RCA (115MB log), not the branch.
- Gate-rig gotchas this cycle: bigscreen disk-full LNK1180 (shared target/debug/incremental was 40GB — deleted; deps 91GB flagged for sweep); nextest leaked 6+6 spt.exe (killed scoped); orphan gate dirs (a841f5a + old w4/w5/w6) handle-pinned at crates/spt-daemon by external scanner — deletion deferred, retry later.
- W2 DISPATCHED to todlando (2026-07-15): DOCS-RELEASE-ASSET + RELEASE-CHANNEL-PRIVATE + riders folded (REQ-INSTALL-1/5 retitle, docs-site SaberMage/Pages sweep incl install-on-demand + quickstarts, ci.yml spt-shell-notify checkout, manifest schema $id flip-or-defer disclosed at build).

## W1 GATE (doyle 2026-07-14): REWORK @2552ee6 — verdict on bs-core PR #1 (historical)
- ONE blocking red: `spt-daemon notif::tests::consent_decision_produces_notif_only_when_gated` — notif.rs:968 asserts old `spt-releases/releases` substring vs new bs URL. Root: todlando ran units `-p spt` only — **workspace-preflight lesson applies to TESTS, not just clippy** (predicted by grep BEFORE the suite red confirmed it). Full workspace nextest fail-fasted 757/1785 (clippy clean, traceable green) — full green still unproven.
- RULINGS RATIFIED: (1) installer scripts stay as hermetic oneliner_e2e fixture + retired headers (REQ-INSTALL-1/3/5/10 evidence stands; W2 retitles public-surface REQ prose); (2) bare `spt install` stands (UAC-740 = exe-NAME class; todlando's test binary `install_verb_e2e` tripped UAC-740 live → renamed `bootstrap_verb_e2e` — class is CURRENT).
- New riders assigned: cli.rs:50 about-help Pages docs URL → W3; manifest.rs:914/2118 schema $id Pages URL → W2/W3 (schema is in the W2 bundle); docs-site install-on-demand + quickstart Pages one-liner cites → W2 docs sweep + perri comms.
- PASS additionally requires Linux leg: bs-core CI green on reworked sha (runners pending) OR doyle kitsubito manual leg.
- Awaiting todlando fix commit → re-gate (NEW worktree of new sha, fresh target; leaked-spt kill BEFORE remove reconfirmed — 6 leaked this gate).

**DISPATCHED 2026-07-14: triage on main @3cb54b4** — ADR-0036 (supersedes ADR-0014) + docs/THE-FORKENING-TRIAGE.md + CONTEXT.md amendments (release channel / docs bundle / docs server / update composite / daemon refresh glossary entries) + 9 REQs minted registry-first (all required_stages=[], flip per-wave in build commits): UPDATE-GH-TRANSPORT, INSTALL-BOOTSTRAP-VERB (W1, todlando dispatched SENT), DOCS-RELEASE-ASSET, RELEASE-CHANNEL-PRIVATE (W2), DOCS-LOCAL-SERVER (W3), UPDATE-ADAPTERS-VERB, UPDATE-DEFAULT-COMPOSITE, UPDATE-RESTART-SAFE-SWAP, DAEMON-REFRESH (W4). W4 late adds ruled: `spt daemon refresh` (brain cycle, no swap, broker untouched); --restart ordering = lethal-leg-LAST (fetch → adapters → finish).

## Repo topology (ruled)
- Fork `SaberMage/spt-core` → **`BigscreenVR/spt-bs-core`** (private) = dev home. `SaberMage/spt-core` = **full passive mirror** (receives everything until a hypothetical second contributor appears; repos MAY diverge later — no pin-file, operator rejected A′).
- **Origin flip FIRST, then build** (flip-first ruled): local checkout origin → bs-core; `mirror` remote → SaberMage. project_id changes to `github-com-bigscreenvr-spt-bs-core` — **copy+rename psyche project-context dirs for ALL involved agents** (operator correction: ALL agents have project-context now, seed #13 "only doyle" is OUTDATED). No lockstep risk: no other machine has agents working spt-core.
- Mirror push = **merge-time, by the merging agent** (`git push mirror main --follow-tags`), folded into merge discipline. **Actions OFF (repo settings)** on SaberMage/spt-core + SaberMage/spt-releases (else mirror pushes double-run CI on self-hosted runners).
- `SaberMage/claude-spt` → private + forked `BigscreenVR/claude-spt-bs`; `adapter add --gh` claimed to already cover private fetch (VERIFY at build); details perri-direct, out of scope here.

## Cutover tooling (doyle 2026-07-15, operator-asked)
Migration scripts published on **bs-releases branch `migration/v0.32.0` @91b1de9**: `migrate-v0320.ps1` + `migrate-v0320.sh` (gh-download via `gh api -H "Accept: application/vnd.github.raw" "/repos/BigscreenVR/spt-bs-releases/contents/<file>?ref=migration/v0.32.0"`, then run). Sequence: auth check → daemon stop → download platform binary → install → daemon start → `spt update fetch --apply` (cache→59 + docs bundle lands — hand-install alone does NOT land docs) → version-asserted verify. Linux auto-selects musl below glibc 2.39. Smoke-tested from this box.

## Cutover (ruled: HARD, no transition release)
- Operator personally hand-updates every node (gh installed + authed via **org membership** per box), then privates SaberMage/spt-releases + spt-core. No anti-brick sequencing. Counter/signing key/update-set format continue unchanged (58→59, same anchor).

## Waves
- **W0 (operator+doyle, no code):** repos created; origin flip + mirror remote; psyche dir copy+rename; runner registration on bs-core; release-publish secret w/ org access; Actions off on SaberMage repos; memory/CLAUDE.md reference sweep (release-counter-from-published → bs-releases metadata; Gravity/kitsubito deploy clone URLs).
- **W1 — gh transport:** discovery `gh api .../releases/latest` + assets `gh release download`, deadline-wrapped subprocess (run_git pattern in gitrun.rs); private-repo gotcha: browser_download_url 404s even with token — gh handles asset-id dance. `SPT_INSTALL_REPO` default → BigscreenVR/spt-bs-releases (seam exists cli.rs:5363; xtask REPO const main.rs:729). Loud `GhCliRequired`/`GhAuthRequired` w/ OS-specific install hints (winget/apt/brew). **Self-install verb** (bootstrap b: `gh release download` binary → one spt verb self-installs; exe keeps `spt-*` name — UAC-740). release_verify_e2e rework to gh. notif.rs consent-changelog URL flip rider.
- **W2 — docs pipeline:** platform-independent `spt-docs.tar.gz` (BUILT mdbook output: html + llms.txt + llms-full.txt + raw .md + manifest.schema.json; ~3.5MB) assembled in release.yml, **entry in SIGNED update-set w/ sha256**; apply lands `SPT_HOME/docs/` (single current copy, replace-on-apply = version-matched docs); docs failure NON-fatal to binary update (`UPDATE_DOCS_SKIPPED` loud). docs-publish.yml retired; book build stays CI drift-gated (CLAUDE.md mandate).
- **W3 — docs server:** **hyper** static server in broker (hyper/tokio/tower/reqwest ALREADY in Cargo.lock via iroh/reqwest — zero new deps; operator ruled battle-tested crate over hand-rolled), **127.0.0.1:5474** default (547 rejected: privileged <1024 on Linux + IANA dhcpv6-server) + config/env override, loopback ONLY (never 0.0.0.0), strict path-sanitize under SPT_HOME/docs, GET-only. `spt docs url` prints; bare `spt docs` opens system browser (cfg(windows) no-console flag). Preserve published URL surface verbatim (llms.txt contract: /llms-full.txt, append-.md, /manifest.schema.json). **ADR-0014 (permanent Pages URL) SUPERSEDED** — no public docs at all (operator ruled b; Pages killed).
- **W4 — update UX:** (1) `spt update adapters [a][,b]...` = thin ALIAS over existing `spt adapter update` (cli.rs:748, gh_release avenue; keep old verb — published surface) + comma-list on both; fail-fast name validation BEFORE any update; per-adapter failure isolation + summary + nonzero exit if any failed; local-path adapters skip loud. (2) plain `spt update` = fetch --apply + update adapters (core→adapters order); if core current → adapters only; `--core-only`/`-c` excludes adapters. **KEY CODE FACT (doyle was wrong, operator corrected, code-confirmed):** `fetch --apply`/`apply` NEVER restart the broker — `apply_staged` (applyhost.rs:303) swaps binary + cycles BRAIN only, broker + all PTYs keep running the previous image; "restart-required" is a printed NOTICE (F-025, cli.rs:4615), not behavior. So the plain composite's invoker can never die — adapters leg always completes in the old exe; NO re-run hint, NO hosted-session detection needed. Broker restarts ONLY under `apply --finish` (apply_staged_daemonless) / new `--restart`. (3) `spt update --restart` — **retires backlog seed #12 REQ-UPDATE-ONE-STEP-SAFE-SWAP**; RULED ordering (i) lethal-leg-LAST: fetch → adapters → apply --finish, so everything completes from any invoking context (hosted invoker dies only at the final step, after all work done); cost accepted: finish-failure leaves new adapters on old-activated core briefly — loud + operator-attended. BUILD-CHECK: adapters leg in plain composite runs while broker is up (no comeback window in the common path); `adapter update` broker retarget (cli.rs:1828) only needs tolerance in --restart's post-finish… N/A — adapters run BEFORE finish under (i).
- 3 W4 REQs: UPDATE-ADAPTERS-VERB, UPDATE-DEFAULT-COMPOSITE, UPDATE-RESTART-SAFE-SWAP. All REQs registry-first at dispatch.

## Post-cutover comms
- perri + flynn: docs moved — local daemon http://localhost:5474 (+ `spt docs url`); their repos otherwise unaffected.
- CI legs fetching public release URLs go red at flip if missed — W1 covers release_verify_e2e.

Kin: [[v0310-published]] (predecessor release), [[spt-core-findings-backlog]] (seed #12 retired by W4; seed #13 outdated re project-context coverage), [[release-counter-from-published]] (counter source moves to bs-releases metadata).
