Files
rune/docs/authority-map.md
Nick 993fb21cfa feat(runtime): K17 hard modes 4.1 + K1 authority map 0.1
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.
2026-10-17 10:58:07 +01:00

8.7 KiB
Raw Permalink Blame History

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:

  • 81099a11 is an ancestor of master@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-code holds 300+ staged generations plus 12 orphaned .staging-* dirs; ownership gitea-desktop-runner. The stale .convergence-intent.json there (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

  1. No divergence. Deployed 81099a11 is an ancestor of master; 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).
  2. 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 81099a11 at 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 via rune.
  3. Rollback target is coherent. last-good → 3c13be1d (0.127.0) is the immediately preceding generation; promotion rotated it correctly.
  4. 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:

  1. launcher exists and its cd target is <deploy_root>/current/src;
  2. current is a symlink resolving to an existing directory inside the deploy root;
  3. the generation carries a well-formed _build_identity.json (commit + version + deployed_at);
  4. identity commit == generation directory name (a staged tree cannot impersonate another SHA);
  5. the RUNTIME SELF-REPORTS: importing rune from the generation's src yields build_info().commit == identity commit and source == "deployed" — a dev/unstamped tree answers "dev" and fails;
  6. the identity commit is an ANCESTOR of the canonical release branch (refs/heads/master) in the checkout — an unqualified artifact can never attest;
  7. 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.