K17 (4.1): mode matrix lives ONCE in toolexec modegate.go (CHAT/TASK/ PLAN profiles, typed refusals via errors.As, RunGated proves ops never execute on refusal, unknown modes fail closed, RUNE_MODE env keeps parity batteries byte-green). Serve surface: /v1/mode hot-state (PLAN needs consent), /v1/tools/call always gated (typed tool_unreachable_ in_mode), task rows carry lane_activity research styling, sleep/night background hooks never widen the gate. Live CLI: CHAT shell exit 3 no side effect, TASK runs. K1 (0.1): authority map reconciled — deployed v0.128.0 is an ancestor of master (pure lag, 1522 commits behind, zero divergence); nothing deployed-only; qualification chain CI->stamps->ancestry-fenced symlink swap verified. Live attestation: launcher->current->identity->runtime self-report->master ancestry, fail-closed (16/16 frozen red-first; 71 neighborhood green). RUNE_HOME finding: dev checkout IS the live system's data home.
8.7 KiB
Authority Map — checkout vs deployed generation (Spec 0.1)
Task 0.1 of docs/openspec/changes/add-native-rune-tui/tasks.md (0A. Truth
first — authority and runtime audit). Written 2026-10-17T06:46Z against dev
checkout master@ed245b2a. This map reconciles the THREE code generations
that exist on this machine and names the authority for every link between
them. Its enforcement artifact is src/rune/runtime_attestation.py +
tests/test_runtime_attestation.py (live attestation; RED when the runtime
is not the qualified artifact).
1. The generations
| Generation | Location | Identity | Role |
|---|---|---|---|
| Dev checkout | /mnt/workdrive/rune (master@ed245b2a) |
__version__ = 0.310.0, no _build_identity.json → build_info().source == "dev" |
Factory floor; all waves build here; never launched by the launcher |
| Deployed (live runtime) | /mnt/workdrive/rune-code/current → 81099a11f7a8 |
_build_identity.json: commit 81099a11f7a845bea629324e45a2aeef1d00e2a2, version 0.128.0, deployed_at 2026-10-07T20:03:04Z |
The ONLY generation the launcher runs |
| Last-good (rollback) | /mnt/workdrive/rune-code/last-good → 3c13be1d766b |
commit 3c13be1d766bf2bb9d25f032ca0cfdee089a55b0, version 0.127.0, deployed_at 2026-10-07T20:00:09Z |
Previous current; rotated automatically by every promotion |
Facts that matter:
81099a11is an ancestor ofmaster@ed245b2a— the deployed generation is a genuinely CI-qualified master revision. The relationship is pure staleness (lag), not divergence: there is no commit in the deployed tree that the checkout lacks.- The lag is 1522 commits / 182 minor versions (0.128.0 → 0.310.0) and ~10 days (no promotion since 2026-10-07T20:03Z; the factory's whole 0C/0D/I/J-era output — tui/, the rune-entry serve surface, the internal/ library conversion — is undeployed).
/mnt/workdrive/rune-codeholds 300+ staged generations plus 12 orphaned.staging-*dirs; ownershipgitea-desktop-runner. The stale.convergence-intent.jsonthere (version 0.66.57, recorded_at "0") is a leftover record, not an authority.
2. Launcher authority chain (what actually runs)
~/.local/bin/rune (hand-installed shell script, mtime 2026-09-11) is the
single entry point. Resolved chain:
~/.local/bin/rune
└─ wezterm start -- bash -c
cd /mnt/workdrive/rune-code/current/src ← runtime code (generation pinned only by `current`)
RUNE_HOME=/mnt/workdrive/rune ← data home (state/memory of the LIVE system)
RUNE_MEMORY_DIR=/home/nick/.config/opencode/memory
MIMO_PROBE_ENABLED=1 ← ADAPT-LIVE bounded probe policy (2026-09-10)
~/.venvs/memory/bin/python3 -m rune ← interpreter: the memory venv, NOT repo .venv
Authority rows (current vs intended vs dormant):
| Surface | Current authority | Intended (per openspec) | State |
|---|---|---|---|
| Launcher script | owner (hand-installed; not owned by any repo module) | unchanged for the Python face | current |
| Runtime code | rune-code/current generation (deploy pipeline output) |
same mechanism, newer revisions | current, stale |
| Runtime identity | rune/__init__.build_info() + _build_identity.json stamped by deploy_stage.py |
same (already landed 2026-09-10 handoff) | current |
| Data home | RUNE_HOME=/mnt/workdrive/rune (the dev checkout doubles as the live data dir: state/, store/, memory/) |
pin stays; code deploys never move user data | current |
| Memory dir | RUNE_MEMORY_DIR=~/.config/opencode/memory (promotion ledger + memory store live here) |
same | current |
| Promotion decision | scripts/deploy_promotion.py — monotonic ancestry law, flock'd critical section, atomic symlink swap, last-good rotation |
same | current |
| Deploy qualification | scripts/deploy_qualify.py + CI required-checks (fail-closed after the 0.66.28/29 incidents) + scripts/tui_startup_canary.py pre-promotion canary |
same | current |
| Receipts / tamper evidence | src/rune/audit_ledger.py — HMAC-chained ledger under RUNE_MEMORY_DIR (key lineage repair is Task 0.2, out of scope here) |
same | current |
Go face (tui/cmd/rune-tui, src/go/rune-entry front door :8377/:8376) |
exists ONLY in the checkout; nothing deployed runs it | launcher target once 0C/0D converge | dormant |
Paired-build attestation (src/rune/build_attestation.py, task 0.14) |
checkout-only (Go↔Rust build pairing; a different attestation from this one) | gates future paired artifacts | dormant until next deploy |
Surprise worth naming: the dev checkout is also the live system's data
home. RUNE_HOME=/mnt/workdrive/rune means the deployed runtime reads and
writes state inside the factory worktree (state/, store/scaffold,
memory/journal) — the same files the test suites mutate. That is why test
runs dirty the live store and why background workers must restore journal
churn after every run.
3. Module drift — deployed 81099a11 vs checkout ed245b2a
| Tree | Deployed | Checkout | Delta | Deployed-only modules |
|---|---|---|---|---|
src/rune (Python) |
184 | 284 | +100 | none |
src/go |
42 | 94 | +52 | none |
src/rust |
80 | 104 | +24 | none |
tui/ |
absent | 36 packages | +36 | — |
Zero deployed-only modules in every tree: the deployed generation is a
strict prefix of the checkout. Headline checkout-only surfaces (all
undeployed): the entire tui/ face; the J1 internal-library conversions
(src/go/{rune-entry,event-bus,model-routing,tool-executor,work-manager} →
internal/ + thin shells); src/rune/{build_attestation, construction_admission}; the rune-entry serve surface
(/v1/{conversation,tasks,events,health}); boundary codegen (0.12);
versioning port H1–H3. Consequence: any qualification, canary, or attestation
written only in the checkout (including this map's test) does not constrain
the live runtime until the next promotion carries it — that is the intended
0.14/0.15 landing path, not a gap in this task.
4. Reconciliation verdict
- No divergence. Deployed
81099a11is an ancestor ofmaster; the checkout is a superset. Nothing was forked, patched, or hot-fixed inside a staged generation (identity commit == directory name == runtime self-report; verified below by the live test). - Pure lag. 1522 commits / 0.128.0 → 0.310.0 / 10 days without a
promotion. The launcher's comment ("runs the DEPLOYED revision
(CI-qualified, build-identity stamped)") is TRUE of
81099a11at its promotion time and STALE as a description of the system: everything the owner has watched land since Oct 7 (tui, serve, libraries, gates) runs only from the checkout when invoked manually — never viarune. - Rollback target is coherent.
last-good → 3c13be1d(0.127.0) is the immediately preceding generation; promotion rotated it correctly. - The one launch path is the Python face. No second launcher, alias, or
systemd unit runs Rune code (Go binaries under
src/go/are parity harnesses, not installed). The Go face is checkout-dormant by design until 0C/0D converge.
5. Attestation contract (the enforcement half of 0.1)
src/rune/runtime_attestation.py — fail-closed attestation of the chain
launcher → current → generation → identity → qualification:
- launcher exists and its
cdtarget is<deploy_root>/current/src; currentis a symlink resolving to an existing directory inside the deploy root;- the generation carries a well-formed
_build_identity.json(commit + version + deployed_at); - identity commit == generation directory name (a staged tree cannot impersonate another SHA);
- the RUNTIME SELF-REPORTS: importing
runefrom the generation'ssrcyieldsbuild_info().commit== identity commit andsource == "deployed"— a dev/unstamped tree answers"dev"and fails; - the identity commit is an ANCESTOR of the canonical release branch
(
refs/heads/master) in the checkout — an unqualified artifact can never attest; - identity version == the generation package's
__version__(coherent stamp, not a stale one).
Every path is injectable; the live defaults bind ~/.local/bin/rune,
/mnt/workdrive/rune-code, and the repo root. CLI:
python -m rune.runtime_attestation prints the JSON evidence, exit 1 on any
failure. tests/test_runtime_attestation.py freezes hermetic negative
fixtures for each link (launcher missing/repointed, symlink missing/outside
root, identity missing/malformed/mismatched, non-ancestor commit, runtime
self-report mismatch, version incoherence) plus a LIVE test that attests the
real machine chain and goes RED the moment any of it breaks — runtime ≠
qualified artifact.