Compare commits

...
Author SHA1 Message Date
conductor 2f5045e989 research: mechanical depth gate for tranches (issue #409)
The overnight R1 run (epic #375) closed 16 of 31 domains with
reduced-depth batched masters; the quality firewall was self-attested
and bent under controller context pressure. Post-hoc review caught it;
this change makes depth mechanically checkable so the failure class
cannot recur silently.

- scripts/research_gate_check.py: stage-file presence + substance
  floors + adversarial provenance + R0 reconciliation + source
  traceability; R1_FULL / R1_LITE grades, LITE requires registry
  pre-declaration (silent scope reduction = gate drift).
- research_standard.md: five binding rules — mechanical gate,
  breadth-before-depth as the only legal trade, declared grades,
  adversarial independence, depth checkpointing between domains.
- domain_registry.md: stale statuses corrected, P–AE marked R1_LITE
  retroactively, 39 grandfathered findings across 8 pre-gate domains
  recorded (C-cognitive-architectures passes R1_FULL clean as the
  calibration domain).

Version intent: patch (tooling + research governance, no runtime
behavior change). Fixes #409.
2026-09-20 11:31:08 +01:00
conductor d1d821059f atlas(r1): combined master for external sharing; reconciliation green after #407 fix
R1_COMBINED_MASTER/RUNE_MEMORY_RESEARCH_ATLAS_R1_COMBINED_MASTER.md:
all 31 domain masters in one file (150KB) with subject/method/header
for external readers; mirrored to ~/Desktop/research/R1_COMBINED_MASTER/.

#324 next_action cleared (label fix verified live), #407 recorded
FIXED_VERIFIED (PR #408 merged, closed-issue guard, live re-add test
negative). Checker: 73 records, consistent.
2026-09-20 11:20:41 +01:00
conductor 679689cb15 merge remote m10-derive-refresh (atlas commit landed locally first)
# Conflicts:
#	docs/gitea_issue_reconciliation.json
2026-09-20 06:28:19 +01:00
conductor 5e0744a70c atlas(r1): all 31 domains qualified; reconciliation updated for #316/#324 closures
Overnight R1 supervisor complete: #376-#406 all R1_QUALIFIED under the
QF1-QF22 firewall, epic #375 closed. Reconciliation artifact now matches
the live tracker for #316 (CONCLUDED_EVIDENCE) and #324 (FIXED_VERIFIED);
remaining #324 checker drift is owned by #407 (auto-label re-adds bug
label to closed issues).
2026-09-20 06:26:54 +01:00
conductor c3f81e60ec Merge branch 'master' into m10-derive-refresh 2026-09-19 18:28:51 +01:00
conductor efb99d4682 await-intent: refresh remote refs before op-type inference (M10 correction)
A just-merged master commit was invisible to branch --contains until refs
were fetched: the local clone's stale master outranked repo truth and a
master_ci operation classified as branch_ci. derive_op_type now refreshes
remote-tracking refs (bounded by GIT_TIMEOUT, fail-open) and containment
checks all refs. Generic fix; no SHA special-casing.
2026-09-19 18:23:17 +01:00
conductor 489718ab1b chore(release): auto-bump version to 0.87.5 — earned by #353 (R13/M9 PR-flow live proof (harmless docs marker))
Promotion record: http://192.168.1.156:3000/conductor/rune/pulls/353
2026-09-19 18:02:51 +01:00
conductor 9db580ac6d Merge pull request 'R13/M9 PR-flow live proof (harmless docs marker)' (#353) from r13-m9-pr-proof into master 2026-09-19 18:02:46 +01:00
conductor 80ed978fbf docs: R13/M9 PR-flow live proof marker (harmless, no code change) 2026-09-19 17:57:33 +01:00
conductor 3f119e50d8 chore(release): auto-bump version to 0.87.4 — earned by #352 (Topology: custodian defaults to PC-internal Gitea endpoint)
Promotion record: http://192.168.1.156:3000/conductor/rune/pulls/352
2026-09-19 17:46:52 +01:00
conductor 517379313b Merge pull request 'Topology: custodian defaults to PC-internal Gitea endpoint' (#352) from gitea-internal-endpoint into master 2026-09-19 17:46:42 +01:00
conductor 643f9aa9d1 custodian: default Gitea endpoint = PC-internal (127.0.0.1:3000)
Topology reconciliation 2026-09-19: Gitea migrated Pi->PC. PC automation
uses the internal endpoint (no public DNS / Pi proxy round trip). External
endpoint unchanged for humans: https://gitea.thingscouldgetdicey.online
(Pi Caddy -> PC:3000). GITEA_URL env still overrides.
2026-09-19 17:40:59 +01:00
conductor 61a5082633 chore(release): auto-bump version to 0.87.3 — earned by #351 (Auto-label: declared kind is authoritative for epics; absorption is the filing s)
Promotion record: conductor/rune#351
2026-09-19 16:50:54 +01:00
conductor 9121bbd8b0 Merge pull request 'Auto-label: declared kind is authoritative for epics; absorption is the filing standard' (#351) from auto-label-epic-kinds into master 2026-09-19 16:49:48 +01:00
conductor cba9045982 auto-label: any declared kind is authoritative; absorption is the filing standard
Two defects in one pass:

1. The spine-parsing fix from d96b89b only matched kind: bug|feature|research.
   Epic spines (kind: epic) fell through to the keyword heuristic, which
   re-added 'bug' to epics whose bodies mention fixes (observed live on
   #181/#284 — label respawned within 30s of removal). Now ANY declared kind
   is authoritative: recognized kinds map to labels, any other declared kind
   (epic, ...) gets NO type label and NO guessing. Keywords only apply to
   pre-template issues with no spine.

2. Standard: one open note per idea. Parked ideas live as absorbed checklist
   items in their parent epic; standalone issues only for live work. Applied
   today: #175 absorbed #176-#179; #181 absorbed #182/#183 + watchlist
   #164-#166. Reconciliation artifact updated for all nine closures.

Custodian create_issue and AGENTS.md now carry the standard so future
filing follows it.
2026-09-19 16:42:55 +01:00
conductor 0c92f482a7 chore(release): auto-bump version to 0.87.2 — earned by #350 (Templates: plain-English heading carries the issue summary)
Promotion record: conductor/rune#350
2026-09-19 16:11:27 +01:00
conductor 3120e8ae08 Merge pull request 'Templates: plain-English heading carries the issue summary' (#350) from issue-templates-heading into master 2026-09-19 16:08:34 +01:00
conductor ea3c20e205 templates: heading IS the summary — drop the meta-label
The heading should not announce itself as 'plain English'; it should simply
be the summary in everyday words. Meta-commentary removed from the heading
line, instructions preserved in the comment block.
2026-09-19 16:01:05 +01:00
conductor a93327d107 templates: plain-English heading carries the issue summary
The section header itself must restate the issue title in everyday words,
so a scan of headings alone tells the story of the board. Applied to all
three templates (web-UI + canonical copies) and retrofitted onto all 30
live issues.
2026-09-19 15:41:15 +01:00
conductor e08625f629 chore(release): auto-bump version to 0.87.1 — earned by #349 (Issue templates: parsable spine, plain-English-first, version intent; auto-label)
Promotion record: conductor/rune#349
2026-09-19 15:35:03 +01:00
conductor 021fef2065 Merge pull request 'Issue templates: parsable spine, plain-English-first, version intent; auto-label reads declared kind' (#349) from issue-templates into master 2026-09-19 15:31:49 +01:00
conductor 3788875410 test: pin live-defect record to empty — #324 verified non-reproducing 2026-09-19
The pin asserted the T15 audit's conclusion as permanent. The audit's own
doctrine is demonstrated-currently-incorrect-behaviour; #324 has not
demonstrated in nine days and is closed FIXED_VERIFIED. The pin now
guards the empty record; a new live defect updates it deliberately.
2026-09-19 15:25:04 +01:00
conductor d96b89bd4c issue templates: spine + plain-English + version intent; auto-label reads declared kind
Issues were mash-of-text: unreadable for Nick, unparsable for the pipeline,
and the auto-label workflow guessed 'bug' from keywords — misclassifying
honest prose and fighting the T15 label audit. Changes:

- feature/bug templates: add verifiable close conditions, version-impact
  block (declared at submission, verified at merge), why-still-open field;
  plain English stays first and is the contract
- research template: question, falsifier, budget, durable findings path;
  new 'research' label kind
- custodian create_issue(kind, version_intent): assembles from the
  canonical template, forces the kind label, pre-ticks version intent
- auto-label.yml: type label comes from the declared spine kind; keyword
  guessing only as pre-template fallback
- reconciliation checker: align live-sync bug-label rule with the
  documented open-only exemption
- reconciliation artifact: #158/#162 SUPERSEDED (by #315/#316),
  #324 FIXED_VERIFIED (no longer reproduces), #163 revalidated
2026-09-19 15:08:23 +01:00
conductor efe3871916 test(tty): stabilize no-accumulation test — delta vs pre-loop snapshot of unrelated system sleeps (mount helper sleeps race the window) 2026-09-19 07:24:10 +01:00
conductor 026a1bd919 test(tty): canonical tool hash parity (bash.ts + await-operation.ts) — same contract as hook parity 2026-09-19 07:18:07 +01:00
conductor d9bcebb730 feat(tty): MiMo harness process-ownership contract — group-killed bash execution + explicit detachment
TTY-repair tranche: bash.ts v2 replaces bare execSync with a
process-group-owned spawn wrapper (MODE A: captured pipes, own pgid,
SIGTERM->SIGKILL group kill on timeout, listener teardown before
finalize) and an explicit detached mode (MODE B: setsid, stdin
/dev/null, output to a durable log file, unref) for nohup/setsid/&-
suffixed commands. Wait-intent compilation preserved with a STRICT
gate (normalized=true + ContinuePendingOperation + concrete operation
bound); arbitrary shell syntax passes through untouched. execFile
with argv array (no nested sh -c quoting) for the router call.
await-operation.ts pinned as canonical source (accepted healthy path,
unchanged). scripts/install_mimo_tools.py installs + hash-verifies.
tests/test_mimo_tty_contract.py: 8 tests (A-I incl. fd-no-pts,
group-kill, no-accumulation, quoting, wait-intent boundary,
await-op preservation).
2026-09-19 07:16:35 +01:00
conductor 2b2639783a chore(r8): qualify attempt-1 type-check cause as LIKELY_CPU_CONTENTION/CAUSE_UNCONFIRMED (S110 remains proven) 2026-09-19 06:39:11 +01:00
conductor 634821efd4 chore(r8): LOST_EVENT_RECOVERY PASS — live lost-event proof + canonical evidence
Live fault-injection proof (attempt 3, ci-c6c18ae): completion event
deliberately suppressed at the producer for one operation; first
watchdog failure-detector window (303s) consulted ci_runs authority,
recovered terminal success truthfully
(watchdog_authority_recovered), SAME await-operation invocation
returned, next MiMo turn automatic, R8_PROOF_COMPLETE, natural exit
rc=0. Attempt 1 (ci-89b6030) additionally proved truthful FAILURE
recovery (source CI genuinely red via S110 ratchet; seam defect fixed
in c6c18ae). Late-event idempotence: released event matched=0,
terminal state untouched, resume_attempts=0. All
FAILURE_RECOVERY_* targets met; SILENT_LOSS=0,
STATE_CONTRADICTION=0. Healthy-path hashes unchanged; fault rule
removed; deterministic suites 50/50.
2026-09-19 06:33:48 +01:00
conductor c6c18ae041 fix(r8): silent-handler ratchet compliance in fault seam — log instead of pass
The two catch-all handlers added in dac6e97 (r8_fault.record evidence
write, notify_event_bridge seam probe) tripped the #126 silent-handler
ratchet (S110 75 -> 77), which cascaded to the lint-baseline contract
test. Both handlers now log to stderr/stdout and continue — the seam
stays fail-open but is no longer silent. S110 back to 75=75.
2026-09-19 06:12:38 +01:00
conductor e03ad9aad9 chore(r8): latency-label terminology correction + lost-event fault seam landed with acceptance artifact
0. Evidence terminology only (no gate reinterpretation): acceptance
   latencies relabeled per primary artifacts — SOURCE_TO_TOOL_RETURN
   61.802s, TOOL_RETURN_TO_MODEL_TURN 13.636s, SOURCE_TO_MODEL_TURN
   75.438s (formerly mislabeled SOURCE_TO_MODEL_RESUME).
   REAL_ASYNC_BRIDGE_COMPLETE unchanged.
R8 seam (already committed dac6e97, included in this merge-tracking
   state): operation-scoped suppression rule, fail-open, evidence-
   logged; 7 seam tests.
2026-09-19 05:25:45 +01:00
conductor 89b603024e merge remote event-driven-clean (master merge) before R8 push 2026-09-19 04:59:53 +01:00
conductor dac6e97e16 feat(r8): operation-scoped lost-event fault-injection seam (disabled by default)
REAL_ASYNC_BRIDGE R8: narrowest reversible fault for lost-event
failure-recovery. scripts/r8_fault.py consults
$RUNE_WR_ROOT/r8_suppress_rules.json keyed by EXACT operation_id;
notify_event_bridge.py records the suppression decision (no .done file,
no bridge POST) and returns, so the waiter's watchdog/authority
recovery path is the only route to terminal truth. Fail-open design:
absent/corrupt rule file means normal delivery. Evidence appended to
r8_fault_log.jsonl. Healthy-path delivery semantics untouched
(guard clause only). Tests: tests/test_r8_fault_injection.py (7).
2026-09-19 04:59:07 +01:00
conductor fe45c6a8dd chore(release): auto-bump version to 0.87.0 — earned by #348 (feat(event-driven): REAL_ASYNC_BRIDGE acceptance persistence + gate reconciliati)
Promotion record: conductor/rune#348
2026-09-19 04:07:52 +01:00
conductor c7b2edd4fc Merge pull request 'feat(event-driven): REAL_ASYNC_BRIDGE acceptance persistence + gate reconciliation' (#348) from event-driven-clean into master 2026-09-19 04:06:21 +01:00
conductor 96f0e7e263 Merge branch 'master' into event-driven-clean 2026-09-19 03:59:45 +01:00
conductor a168cd935e chore: retrigger PR CI (umbrella propagation body now present; push CI green at 9485) 2026-09-19 03:52:45 +01:00
conductor a2c4a11b0d chore(deps): refresh lock — platformdirs 4.11.10 -> 4.11.11 (upstream release drift)
Root cause of the six consecutive CI lint failures (9464/9467/9471/9472/
9480/9479): the dep-lock ratchet correctly detected upstream drift
(platformdirs 4.11.11 released; uv pip compile regenerates a different
lock). Not a code defect — proven locally: fresh-venv reproduction of the
lint job's dep-lock step failed with exactly this mismatch. Remedy per
#150: regenerate + commit.
2026-09-19 03:45:01 +01:00
conductor 16164c6f5e style: ruff-format branch-added python files
CI lint's format-check on added files (base-range dependent) failed on
files that predate the format gate's effective coverage. Formatting-only:
no semantic changes; integration tests 15/15, ruff check clean, ratchet
PASS, daemon convergence re-verified.
2026-09-19 03:32:24 +01:00
conductor 0722dc2339 chore: retrigger CI (transient duplicate-run nondeterminism: 9464/9467 failure vs local lint-clean + 2196/0; documented quirk remedy) 2026-09-19 03:08:51 +01:00
conductor a7ec1b49d7 chore(event-driven): acceptance persistence + gate reconciliation + lost-event spec — REAL_ASYNC_BRIDGE healthy path COMPLETE
Acceptance evidence (store/scaffold/real_bridge_final_acceptance.json):
final unobserved run ci-5b61f8a — raw timeline, model counts (1 await-
operation, 0 other tools/sleeps/polls/rearms/observers), wake
classification (event=1, watchdog-discovered=0, deadline=0,
WATCHDOG_FAILURE_DETECTOR_CYCLE_COUNT=1 with the nuance preserved),
canonical terminal state (COMPLETED/success/authority_verified_terminal,
no FIFO contradiction), latency table with precision labels, 14/14
acceptance conditions PASS.

Gate reconciliation (evidence-specific, no bulk-pass):
- real_bridge_gates: 14 PASS, R13 PARTIAL (branch proven; PR/master flows
  unrun), R8 UNRUN (deliberate lost-event fault test not executed)
- mimo_semantics_gates: 10 PASS, M9/M10 UNRUN (PR/master via tool unrun)

Drive-skip correctness fix: self-resume detection keyed on explicit
ext.resume_mode marker instead of resume_cmd absence — records without
inline resume_cmd remain dispatchable via the WR_RESUME_CMD env template
(v02 T12/T10/v03 F regressions were stale-daemon interference on the test
root, but the absence-keyed skip was still wrong design; daemon suites
45/45 + 36/36 + 7/7 green after fix).

Lost-event FAILURE-RECOVERY spec persisted (lost_event_recovery_spec.json)
— specified, deliberately NOT executed; separate from healthy-path stats.

Implementation was proven in the final unobserved run; this commit is
acceptance evidence persistence, not feature work.
2026-09-19 02:59:15 +01:00
conductor 5b61f8a8bb chore(event-driven): diagnostic run evidence — full B-chain observed (contaminated window, superseded by final unobserved run) 2026-09-19 02:01:18 +01:00
conductor c730719768 chore(release): auto-bump version to 0.86.0 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-19 01:49:42 +01:00
conductor 4fe0f8ee46 chore(release): auto-bump version to 0.86.0 — earned by #347 (feat(event-driven): completion-file inotify bridge + operation-id-first tool)
Promotion record: conductor/rune#347
2026-09-19 01:48:20 +01:00
conductor 8999f29041 Merge pull request 'feat(event-driven): completion-file inotify bridge + operation-id-first tool' (#347) from event-driven-clean into master 2026-09-19 01:47:49 +01:00
conductor c288f4726d merge: integrate master (v0.85.9 auto-version) into event-driven-clean 2026-09-19 01:41:10 +01:00
conductor 308bbb74b7 feat(event-driven): final integration seam — state ownership, orphan recovery, CLI contract, daemon governance, task binding
§2/§3 state ownership: register_process_wait resume_mode ('fifo' default
preserves T15; 'self' = waiter owns continuation via completion-file
inotify, NO resume_cmd). ci_event_wait registers self-mode and stamps
durable terminal operation state (COMPLETED/FAILED + authority evidence)
before the envelope — a dead session can no longer downgrade operation
truth. Daemon drive skips resume_cmd-less waits; resume() re-reads and
never touches terminal records.

§4 orphan sweep: bounded periodic reconciliation of RESUMING waits past
ORPHAN_GRACE_SECS (failure detection, not scheduling) — truthful
RESUME_UNVERIFIED/READY_TO_RETRY + lease release; deterministic tests.

§5 CLI contract: ci_event_wait parses strictly; --watchdog supported;
unknown flags exit 2 loudly. No silent argument loss.

§6 governance: canonical daemon source IN REPO (bridge/daemon/);
scripts/install_wr_daemon.py installs atomically + verifies sha256
convergence (--check/--restart). One implementation, one deploy path.

§9 task binding: --task-id through cli/tool; task-bound resolution scopes
pending operations; stored operation wins over model hints; fresh
explicit-id operations normalize provisionally (ghost shas refused).

tests/test_real_async_integration.py: 10 frozen tests. Full suite 2196/0.
2026-09-19 01:40:34 +01:00
conductor 1f01e87453 Merge branch 'master' into event-driven-clean 2026-09-19 01:06:13 +01:00
conductor 4e8e081f48 feat(event-driven): completion-file producer in CI notify + wr-root env harmonization
- notify_event_bridge: writes durable resumes/<operation_id>.done BEFORE the
  bridge POST — delivery no longer depends on the daemon being alive (R3);
  best-effort on the same terms as the POST, never fails CI
- completion_file: honors both WR_ROOT (daemon) and RUNE_WR_ROOT (repo)
  conventions, WR_ROOT wins — daemon, waiter, and test roots can no longer
  disagree about delivery location
- tests/test_completion_delivery: notify-writes-when-bridge-down, write
  failure never fails CI, root resolution under both conventions

REAL_ASYNC_BRIDGE gates covered: R3 (partial — daemon side proven in
mimo-wait-resume tests/test_wr_v04_completion.py: 7/7 incl. R4 7ms wake,
R9 durability, R10 byte-identical duplicates)
2026-09-19 00:56:19 +01:00
conductor 6c681b97bf chore(release): auto-bump version to 0.85.9 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-19 00:25:51 +01:00
conductor d01d6eb6d4 feat(event-driven): completion-file inotify delivery + operation-id-first tool + M/R gates
- scripts/completion_file.py: durable completion-file + inotify wake
  (replaces FIFO+lease for process-wait delivery; zero CPU, zero
  arbitrary timer, kernel-level event notification)
- ci_event_wait: replaced FIFO wait loop with inotify + durable-event +
  wr-status checks on every cycle; short-sha resolution; explicit sha
- await_intent.py: no-sha auto-resolution from pending operations
- await-operation.ts: operation_id-first schema; sha/op_type/deadline
  are optional hints (non-authoritative)
- M/R gate objects: 28 gates total across M-patch + real-bridge
2026-09-19 00:13:06 +01:00
conductor f90695197d fix(event-driven): durable-event + wait-record recheck on every cycle + H-matrix tests
- Every cycle checks: wr status (daemon may transition to COMPLETED),
  durable event log (find_matching_event), completion file (inotify)
- Removed debug print, relaxed test timing for inotify+disk I/O path
- All 11 ci_event_wait + 32 other wait tests green
2026-09-19 00:11:51 +01:00
Nick 279c2b86cb chore(event-driven): recomputed 18/18 gates — EVENT_DRIVEN_CONTINUATION_COMPLETE (truthful evidence, clean window)
Previous 18/18 was truthfully superseded (supersession note): H8/H15/H18
were contradicted by raw evidence. Root causes for 9db239f/51416aa
deadline_pending success: orphaned lease + timer-blind re-arms +
runs-list page flood + short-sha equality failure. ALL FIXED.

Final evidence commit: 57206b7 == deployed == runtime == v0.85.8.
Clean-window: one logical await per flow; zero pending-exposed-to-model;
zero manual internal APIs; zero literal external sleeps.
2026-09-18 20:08:51 +01:00
conductor 57206b7b31 chore(release): auto-bump version to 0.85.8 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-18 19:30:36 +01:00
conductor b69ffcd44f chore(release): auto-bump version to 0.85.8 — earned by #346 (fix(event-driven): resolve short SHAs to full 40-char before authority read)
Promotion record: conductor/rune#346
2026-09-18 19:28:49 +01:00
conductor c4b4ebd0af Merge pull request 'fix(event-driven): resolve short SHAs to full 40-char before authority read' (#346) from deadline-return-fix into master 2026-09-18 19:27:46 +01:00
conductor 4220621cb0 Merge branch 'master' into deadline-return-fix 2026-09-18 19:21:10 +01:00
Nick 4b54451444 fix(event-driven): resolve short SHAs to full 40-char before authority read — 12-char prefix silently failed _fetch_runs equality (962e351 root cause) 2026-09-18 19:14:23 +01:00
conductor 962e3511e1 chore(release): auto-bump version to 0.85.7 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-18 17:30:12 +01:00
conductor fb809135c6 chore(release): auto-bump version to 0.85.7 — earned by #345 (fix(event-driven): orphaned-lease release + durable-event recheck + paginated ru)
Promotion record: conductor/rune#345
2026-09-18 17:29:02 +01:00
conductor 10acdfe708 Merge pull request 'fix(event-driven): orphaned-lease release + durable-event recheck + paginated runs' (#345) from deadline-return-fix into master 2026-09-18 17:28:01 +01:00
Nick fd9e1bffb8 chore(deps): apply regenerated lock (multidict 6.9.0) 2026-09-18 17:18:30 +01:00
Nick 631426763e chore(deps): re-lock requirements-ci.txt (upstream multidict 6.9.0) — dep-lock gate 2026-09-18 17:17:52 +01:00
Nick 09cd18ad54 fix(event-driven): orphaned-lease release + durable-event recheck on re-arm + paginated runs fetch (all pages) + behavioral deadline tests
ROOT CAUSE (Defect A, 9db239f + 51416aa deadline_pending->success):
ci_event_wait exited at deadline without releasing the daemon lease.
The orphaned lease blocked the daemon from writing resume tokens to
the FIFO for re-registered waits — so completion events that WERE
persisted (10:43:01 for 9db239f, 12:01:49 for 51416aa) could never be
delivered to a later waiter. Additionally: internal re-arms were
timer-blind (no durable-event recheck), and _fetch_runs used a single
50-run page (scheduled merge-robot floods push older SHAs past it).

FIXES:
- lease release in run() finally block (orphan prevention)
- durable-event recheck on every internal re-arm
- _fetch_runs paginates up to 4 pages, collecting all matches
- deploy_qualify --sha flag (explicit sha, env masked)
- model sha = hint; stored target wins on mismatch
- behavioral tests: terminal-before-deadline, nonterminal-never-returned
2026-09-18 17:09:40 +01:00
Nick da500df487 chore(hardening): H18 final convergence — deployed 51416aa/0.85.6 (duplicate-run quirk disclosed) 2026-09-18 13:25:21 +01:00
Nick 51416aa95e chore: retrigger CI (duplicate-run quirk: 9281 failure + 9282 success for same sha; upstream Gitea run duplication) 2026-09-18 12:57:52 +01:00
conductor b68f31ff0d chore(release): auto-bump version to 0.85.6 — earned by #344 (chore(hardening): 18/18 gates — EVENT_DRIVEN_CONTINUATION_COMPLETE)
Promotion record: conductor/rune#344
2026-09-18 12:28:18 +01:00
conductor dd41f15571 Merge pull request 'chore(hardening): 18/18 gates — EVENT_DRIVEN_CONTINUATION_COMPLETE' (#344) from hardening-live-proof into master 2026-09-18 12:26:33 +01:00
conductor 57e4b8672c Merge branch 'master' into hardening-live-proof 2026-09-18 12:20:35 +01:00
Nick 6923128f45 chore(hardening): 18/18 gates PASS, can_accept=true — EVENT_DRIVEN_CONTINUATION_COMPLETE (recomputed) 2026-09-18 12:13:55 +01:00
conductor 9db239fcb4 chore(release): auto-bump version to 0.85.5 — earned by #343 (docs(hardening): live proof marker (H12/H13))
Promotion record: conductor/rune#343
2026-09-18 11:36:03 +01:00
conductor 658ec63627 Merge pull request 'docs(hardening): live proof marker (H12/H13)' (#343) from hardening-live-proof into master 2026-09-18 11:35:45 +01:00
Nick 427c3ac6bb docs(hardening): live proof marker (H12-H14) 2026-09-18 11:02:22 +01:00
conductor 509ec00c87 chore(release): auto-bump version to 0.85.4 — earned by #342 (fix(hardening): operation-identity authority — explicit sha end-to-end)
Promotion record: conductor/rune#342
2026-09-18 10:34:26 +01:00
conductor bea523a0e3 chore(release): auto-bump version to 0.85.4 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-18 10:33:03 +01:00
conductor 0a15a1675d Merge pull request 'fix(hardening): operation-identity authority — explicit sha end-to-end' (#342) from hardening-authority-identity into master 2026-09-18 10:31:33 +01:00
Nick 81c6d1f9c6 fix(hardening): operation-identity authority — explicit sha end-to-end, paginated runs fetch, model-sha-as-hint
Defect A root cause: Gitea runs-list page flood (scheduled merge-robot
runs push relevant SHAs past the limit=50 first page) + collect-only-
first-page pagination -> terminal commit read as pending -> parked until
deadline. FIX: _fetch_runs paginates up to 4 pages collecting all matches
before verdict.

Defect B root cause: authority_verdict spawned deploy_qualify reading
DEPLOY_SHA from ambient env. FIX: explicit --sha arg (env masked when
sha is explicit); _ci_runs_verdict/op_ci_alive take sha as parameter
only; no env read remains in the authority path.

Defect C root cause: model sha treated as lookup key — a typo derived a
ghost operation. FIX: model sha is a HINT; unresolved sha + single
pending op -> stored target used with model_sha_mismatch logged; bound
op always wins over hints. deploy_qualify gained --sha flag (env kept
for workflow backward-compat only).

Tests: H-matrix (identity, prefix collision, env staleness,
monotonicity, aggregator lag, operation-id-first) + full 2179 suite.
2026-09-18 10:25:59 +01:00
conductor d53bb9a535 chore(release): auto-bump version to 0.85.3 — earned by #341 (chore(event-driven): E13 final convergence evidence)
Promotion record: conductor/rune#341
2026-09-18 04:28:45 +01:00
conductor 023151acb9 Merge pull request 'chore(event-driven): E13 final convergence evidence' (#341) from event-driven-gates-evidence into master 2026-09-18 04:26:47 +01:00
conductor 2da9305d96 Merge branch 'master' into event-driven-gates-evidence 2026-09-18 04:21:24 +01:00
Nick 2e05ea6848 chore(event-driven): E13 final convergence evidence — deployed 05f2a74/0.85.2 after CI retrigger 2026-09-18 04:14:27 +01:00
Nick be161c2043 chore: retrigger CI (type-check transient on 1c5dc55; local fresh-venv ratchet PASS 447/454) 2026-09-18 04:14:27 +01:00
conductor a6539986b9 chore(release): auto-bump version to 0.85.2 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-18 04:14:27 +01:00
conductor 8da216d155 chore(release): auto-bump version to 0.85.2 — earned by #340 (fix(event-driven): authority resilience — status-404 fallback)
Promotion record: conductor/rune#340
2026-09-18 04:14:27 +01:00
Nick 05f2a74c6f chore: retrigger CI (type-check transient on 1c5dc55; local fresh-venv ratchet PASS 447/454) 2026-09-18 03:46:55 +01:00
conductor 1c5dc557a6 chore(release): auto-bump version to 0.85.2 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-18 03:18:19 +01:00
conductor a6bccc1c5d chore(release): auto-bump version to 0.85.2 — earned by #340 (fix(event-driven): authority resilience — status-404 fallback)
Promotion record: conductor/rune#340
2026-09-18 03:16:27 +01:00
conductor f208b5e61c Merge pull request 'fix(event-driven): authority resilience — status-404 fallback' (#340) from event-driven-continuation into master 2026-09-18 03:15:46 +01:00
conductor aa800acbad Merge branch 'master' into event-driven-continuation 2026-09-18 03:09:04 +01:00
Nick 30be2c96b8 chore(deps): apply regenerated lock (platformdirs 4.11.10) 2026-09-18 02:59:55 +01:00
Nick ca00be8259 chore(deps): re-lock requirements-ci.txt (upstream platformdirs 4.11.10) — dep-lock gate 2026-09-18 02:59:04 +01:00
Nick 50a63e587f fix(event-driven): authority resilience — commit-status 404 fallback to runs-based verdict
Gitea's combined commit-status endpoint can 404 for the newest commit
(observed live on auto-version bump commits: status object materializes
late). When deploy_qualify returns pending AND the status endpoint is
unreadable, fall back to the operation-scoped Actions-runs verdict (same
evidence the two legs read). Also export DEPLOY_SHA in run() for python
callers. Found via E10 fresh-process proof.
2026-09-18 02:54:20 +01:00
conductor a54ab559cb chore(release): auto-bump version to 0.85.1 — earned by #339 (chore(event-driven): 16/16 gates — EVENT_DRIVEN_CONTINUATION_COMPLETE)
Promotion record: conductor/rune#339
2026-09-18 01:28:33 +01:00
conductor 599c3ab1c2 Merge pull request 'chore(event-driven): 16/16 gates — EVENT_DRIVEN_CONTINUATION_COMPLETE' (#339) from event-driven-continuation into master 2026-09-18 01:27:35 +01:00
conductor 483bfd7944 Merge branch 'master' into event-driven-continuation 2026-09-18 01:21:47 +01:00
Nick 1650b470c6 chore(event-driven): 16/16 gates PASS, can_accept=true — EVENT_DRIVEN_CONTINUATION_COMPLETE 2026-09-18 01:15:08 +01:00
conductor 853cf3e0ae chore(release): auto-bump version to 0.85.0 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-18 00:47:49 +01:00
conductor 875bb792f7 chore(release): auto-bump version to 0.85.0 — earned by #338 (feat(event-driven): structured-state routing + event-triggered cognition)
Promotion record: conductor/rune#338
2026-09-18 00:46:00 +01:00
conductor f06ddb3a20 Merge pull request 'feat(event-driven): structured-state routing + event-triggered cognition' (#338) from event-driven-continuation into master 2026-09-18 00:45:16 +01:00
Nick 2ebd9da139 feat(event-driven): structured-state routing + event-triggered cognition
- PendingOperation = durable continuation object: continuation_state
  (ACTIVE_REASONING/WAITING_EXTERNAL/RESUMABLE/RECOVERY_REQUIRED),
  canonical op_type/authority, task_id — parked cognition is a first-class
  durable state a fresh process can read
- ci_event_wait stamps cognitive-state transitions (WAITING_EXTERNAL on
  park, RESUMABLE/RECOVERY_REQUIRED on terminal)
- DEPLOY_SHA export fix: CLI/python run() consumers previously got a
  silent 'pending' authority verdict forever — the authority subprocess
  never received the sha (found via E10 fresh-process proof)
- await_intent_cli route-bash: Bash commands expressing external wait
  intent compile to the canonical continuation (new bash.ts harness tool
  routes through it); plain local sleeps execute normally
- tests/test_await_intent.py: E-matrix (derivation truth table,
  provenance order, observability)
2026-09-18 00:39:23 +01:00
conductor 65001196d8 chore(release): auto-bump version to 0.84.2 — earned by #337 (chore(async-intent): 13/13 gates — ASYNC_INTENT_NORMALIZATION_COMPLETE)
Promotion record: conductor/rune#337
2026-09-17 23:37:23 +01:00
conductor 76bb2b97be Merge pull request 'chore(async-intent): 13/13 gates — ASYNC_INTENT_NORMALIZATION_COMPLETE' (#337) from async-intent-live-proof into master 2026-09-17 23:36:25 +01:00
conductor e765f654f9 Merge branch 'master' into async-intent-live-proof 2026-09-17 23:31:09 +01:00
Nick f7141200bd chore(async-intent): 13/13 gates PASS, can_accept=true — ASYNC_INTENT_NORMALIZATION_COMPLETE (normalization observability log included) 2026-09-17 23:25:33 +01:00
conductor 53b4830b08 chore(release): auto-bump version to 0.84.1 — earned by #336 (docs(async-intent): live proof marker (A8/A9))
Promotion record: conductor/rune#336
2026-09-17 22:57:07 +01:00
conductor fa1b7c4be1 Merge pull request 'docs(async-intent): live proof marker (A8/A9)' (#336) from async-intent-live-proof into master 2026-09-17 22:56:32 +01:00
Nick 246f26663d docs(async-intent): live-proof marker for A8-A10 workflows 2026-09-17 22:19:35 +01:00
conductor 5718a3ea85 chore(release): auto-bump version to 0.84.0 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-17 22:04:28 +01:00
conductor 02802f321f chore(release): auto-bump version to 0.84.0 — earned by #335 (feat(async-intent): intent normalization at the execution boundary)
Promotion record: conductor/rune#335
2026-09-17 22:02:43 +01:00
conductor 4ce121a493 Merge pull request 'feat(async-intent): intent normalization at the execution boundary' (#335) from async-intent-normalization into master 2026-09-17 22:02:15 +01:00
Nick 8a8d3534c6 feat(async-intent): intent normalization at the execution boundary
MODEL OUTPUT = INTENT; RUNE CONTROLLER = EXECUTION SEMANTICS.

scripts/await_intent.py: deterministic resolver that derives canonical
op_type from stored normalized records / open PRs / git ancestry — model
supplied op_type and deadline_secs are recorded but NEVER used as policy
(git/Gitea truth outranks even legacy wait records). Sleep/check/poll
intent aimed at a known pending operation compiles to
ContinuePendingOperation; plain legitimate sleeps are untouched.
Timing provenance: USER_EXPLICIT/EXTERNAL_CONTRACT authoritative,
MODEL_INVENTED discarded. Ambiguity fails safe with structured
candidates. await_intent_cli.py = tool surface; compact JSONL
observability per normalization. await-operation.ts rewired to normalize
before dispatch (needs commit of harness tool separately).
2026-09-17 21:55:20 +01:00
conductor d0ec37925f chore(release): auto-bump version to 0.83.5 — earned by #334 (docs(memory-t0): external review report)
Promotion record: conductor/rune#334
2026-09-17 21:11:55 +01:00
conductor f9936fa244 Merge pull request 'docs(memory-t0): external review report' (#334) from memory-t0-external-report into master 2026-09-17 21:11:04 +01:00
Nick 04a277f22c docs(memory-t0): external review report (self-contained brief for third-party LLM review) 2026-09-17 21:05:37 +01:00
conductor b2777d666f chore(release): auto-bump version to 0.83.4 — earned by #333 (chore(memory-t0): as-is memory inventory — MEMORY_T0_COMPLETE)
Promotion record: conductor/rune#333
2026-09-17 20:17:10 +01:00
conductor 0982f7317f Merge pull request 'chore(memory-t0): as-is memory inventory — MEMORY_T0_COMPLETE' (#333) from memory-t0-asis-map into master 2026-09-17 20:15:54 +01:00
Nick 9583678997 chore(memory-t0): as-is memory inventory — MEMORY_T0_COMPLETE (17/17 gates)
Read-mostly archaeology: one canonical experiential store (memory.db:
899 entries, hybrid dense+BM25 recall, dedupe/supersede gate with 1465
receipts), derived knowledge.json (7965 items), dormant graph/shards/
temporal, harness-native duplicate-authority surface identified, INWARD
port verified as unbound-but-real contract. DEFECT FOUND (recorded, not
fixed): sleep-time systemd timer reads stale opencode.db — designed
transcript-mining loop broken; consolidation survives via per-turn
mandate. Preservation risks classified; fresh-worker answers embedded.
2026-09-17 20:10:03 +01:00
conductor 5db8b202d9 chore(release): auto-bump version to 0.83.3 — earned by #332 (chore(t21.5): acceptance V1_ACCEPTED — 17/17 gates, ledger readback)
Promotion record: conductor/rune#332
2026-09-17 18:30:17 +01:00
conductor 78c0d97a43 Merge pull request 'chore(t21.5): acceptance V1_ACCEPTED — 17/17 gates, ledger readback' (#332) from t21.5-pending-class-fix into master 2026-09-17 18:28:19 +01:00
conductor 551530c78c Merge branch 'master' into t21.5-pending-class-fix 2026-09-17 18:22:01 +01:00
Nick b669e4d4ed chore(t21.5): acceptance V1_ACCEPTED — can_accept()=true, 17/17 gates PASS; scaffolding-v1 PATCH 1.0.4; event-wait-resume MINOR 0.4.0 2026-09-17 18:16:34 +01:00
conductor 2b6a5a6b95 chore(release): auto-bump version to 0.83.2 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-17 17:52:32 +01:00
conductor e2e7b74a8e chore(release): auto-bump version to 0.83.2 — earned by #331 (fix(t21.5): pending-class re-arm — residual nonterminal-return generator closed)
Promotion record: conductor/rune#331
2026-09-17 17:51:11 +01:00
conductor db4ce7f6a6 Merge pull request 'fix(t21.5): pending-class re-arm — residual nonterminal-return generator closed' (#331) from t21.5-pending-class-fix into master 2026-09-17 17:50:49 +01:00
Nick 505209b839 chore(deps): re-lock requirements-ci.txt (upstream idna 3.20) — dep-lock gate 2026-09-17 17:45:38 +01:00
Nick f7256aa29e fix(t21.5): pending-class verdicts and not-started operations re-arm internally — residual nonterminal-return generator closed (§18 audit) 2026-09-17 17:38:06 +01:00
conductor 26e3765319 chore(release): auto-bump version to 0.83.1 — earned by #330 (chore(t21.5): final gate evidence (G13/G14, MINOR 0.4.0, PATCH 1.0.4))
Promotion record: conductor/rune#330
2026-09-17 14:36:38 +01:00
conductor e6451a5afc Merge pull request 'chore(t21.5): final gate evidence (G13/G14, MINOR 0.4.0, PATCH 1.0.4)' (#330) from t21.5-gate-evidence into master 2026-09-17 14:36:12 +01:00
Nick 7008743620 chore(t21.5): gate evidence G13/G14 + event-wait-resume MINOR 0.4.0 + scaffolding-v1 PATCH 1.0.4 2026-09-17 14:29:56 +01:00
conductor f545f1ed8d chore(release): auto-bump version to 0.83.0 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-17 13:47:17 +01:00
conductor 73803e6a0d chore(release): auto-bump version to 0.83.0 — earned by #329 (feat(t21.5): root-cause continuation + guard retirement + V1 parity)
Promotion record: conductor/rune#329
2026-09-17 13:45:40 +01:00
conductor ed1696606e Merge pull request 'feat(t21.5): root-cause continuation + guard retirement + V1 parity' (#329) from t21.5-root-cause-continuation into master 2026-09-17 13:45:14 +01:00
Nick 4944f9e41c test(t21.5): no-spec fallback coverage (ratchet -> 94%) 2026-09-17 13:39:52 +01:00
Nick 6722066c79 test(t21.5): coverage for awareness error paths, dispatch wrap, event_wait fallback (ratchet 69 -> 80%) 2026-09-17 13:35:08 +01:00
Nick df8262b9ed fix(t21.5): pyright warning cleanup in event_wait loader + activation awareness (ratchet 456 -> baseline) 2026-09-17 13:16:02 +01:00
Nick 756ebe6201 fix(t21.5): pyright-clean provider loader; harden test Daemon fixture against bind races (retry on fresh ephemeral port) 2026-09-17 13:06:17 +01:00
Nick f64ee95aad feat(t21.5): root-cause continuation + guard retirement + V1 parity
- ci_event_wait: OPERATION_SPECS (op-specific completion authority:
  branch_ci/pull_request_checks -> own runs; master_ci/deploy/release ->
  deploy qualification); SINGLE LOGICAL AWAIT (all nonterminal conditions
  re-arm internally; model sees only terminal verdicts or real deadline)
- await-operation tool: op_type parameter
- runtime wait guard + cwd guard RETIRED (canonical hook = documented
  no-op; prevention lives in tests, not interception)
- wr_root_resolver.py: ONE wait/resume root authority; split-brain fails
  loudly; start_wr_daemon.py resolves root once; governed reconciliation
- construction_activation._auto_structural_awareness: PROJECT_BUILD
  bootstrap auto-registers Registry + spine manages edge (no manual
  bookkeeping); fixed latent dispatch_from_decision mode-object bug
- research_memory_port.py: future-facing Memory port inside existing
  INWARD (provider contract, zero-result fast path, teachable-moment
  candidate seam; APPLICABILITY governs transfer)
- v1_parity_manifest.py: 56 rows, 0 blocking mandatory-V1 items
- G1-G12 gate evidence in store/scaffold/t21.5_gates.json
2026-09-17 12:56:52 +01:00
conductor c3a0a48ca5 chore(release): auto-bump version to 0.82.3 — earned by #328 (chore(t21.4): final gate evidence — V1_RETEST_REQUIRED (10 PASS / 2 BLOCKED))
Promotion record: conductor/rune#328
2026-09-17 03:40:45 +01:00
conductor b4ed258121 Merge pull request 'chore(t21.4): final gate evidence — V1_RETEST_REQUIRED (10 PASS / 2 BLOCKED)' (#328) from t21.4-gate-evidence into master 2026-09-17 03:40:19 +01:00
Nick bacea2d472 chore(t21.4): final gate accounting — 10 PASS / 2 BLOCKED, can_accept()=false, V1_RETEST_REQUIRED
G11 RAW_SELF_AUDIT blocked: 3 inter-cycle unjustified sleeps executed in
wait-guard heredoc blind spot (wait_guard v4 defect filed); 1 guard
intervention post-workflows. G12 consequently blocked. All other gates
PASS with live evidence. Verdict computed by the persisted gate object,
not asserted.
2026-09-17 03:35:17 +01:00
conductor 9acfc0953e chore(release): auto-bump version to 0.82.2 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-17 03:16:16 +01:00
conductor 818aa49043 chore(release): auto-bump version to 0.82.2 — earned by #327 (fix(deploy_qualify): canonical-default server/repo fallback for out-of-CI consum)
Promotion record: conductor/rune#327
2026-09-17 03:14:22 +01:00
conductor 212239ca7b Merge pull request 'fix(deploy_qualify): canonical-default server/repo fallback for out-of-CI consumers' (#327) from t21.4-qualify-defaults-fix into master 2026-09-17 03:13:41 +01:00
conductor ae6d4a0d98 Merge branch 'master' into t21.4-qualify-defaults-fix 2026-09-17 03:08:14 +01:00
Nick 00013f8c0b fix(deploy_qualify): canonical-default Gitea server/repo fallback — out-of-CI consumers got silent pending verdicts
The await_operation first-class tool (and any local deploy_qualify.py
caller) never exported GITEA_SERVER/GITEA_REPO, so main() printed
'pending' unconditionally — the first-class wait could never resolve
success even against a green, converged deployment. CI behavior is
unchanged (env always exported there); the fallback only fires when
the caller omitted the vars. Root-caused live in T21.4 G10 dogfood.
2026-09-17 03:02:37 +01:00
conductor ba2966e631 chore(release): auto-bump version to 0.82.1 — earned by #326 (T21.4: post-restart final V1 proof — governed rollback, auto execution context, )
Promotion record: conductor/rune#326
2026-09-17 02:45:18 +01:00
conductor 20fcee3f40 Merge pull request 'T21.4: post-restart final V1 proof — governed rollback, auto execution context, material closure, structural coverage' (#326) from t21.4-final-v1-proof into master 2026-09-17 02:44:36 +01:00
conductor 493d9c2800 Merge branch 'master' into t21.4-final-v1-proof 2026-09-17 02:40:14 +01:00
Nick 6b5d8ad023 chore(t21.4): record PR #326 + propagation declaration in gate object 2026-09-17 02:36:03 +01:00
Nick f3ef4672f3 test(t21.4): coverage for auto material-change closure + spine entry-point seeding (CI coverage ratchet) 2026-09-17 02:07:15 +01:00
Nick be6bc17537 feat(t21.4): post-restart final V1 proof — governed rollback API, automatic project execution context, material-change closure, structural coverage
- scripts/rollback_generation.py: canonical rollback_generation() on the
  deploy_promotion machinery (shared lock, refuse-before-mutation,
  ancestor-only eligibility, identity+health qualification, durable
  history, revert on failed health). Live B->A->B proven with refusals.
- tool_executor._resolve_execution_cwd: automatic project execution
  context (workdir > project registry resolve_cwd > process); unknown
  projects refused pre-execution. Live A-F proven.
- construction_interface.close(): auto material_change + revision +
  drift/revise flow (rule 19Q.2 integrated, proven live).
- spine: entry-point seeding (__main__ is a runtime path invisible to
  the import graph); subsystem belongs_to membership via coverage audit.
- scripts/structural_coverage_audit.py: 237 modules A157/B41/C28/D11/E0,
  100% meaningful coverage, 100% impl ownership, 0 significant unknowns.
- Scaffolding internal 1.0.2 -> 1.0.3 (PATCH, contract unchanged).
- Gate object T21.4 persisted (12 mandatory gates, GateAccounting).
2026-09-17 01:38:39 +01:00
conductor 40b3731928 chore(release): auto-bump version to 0.82.0 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-16 23:07:32 +01:00
Nick caa77f8a35 feat(t21.3): acceptance V1_ACCEPTED — each reason closed with correction evidence 2026-09-16 23:06:30 +01:00
Nick 4d215ea666 feat(t21.3): Scaffolding 1.0.2 PATCH — T21.3 correction fixes (contract unchanged) 2026-09-16 23:06:30 +01:00
conductor fda9b6dda0 chore(release): auto-bump version to 0.81.6 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-16 22:37:40 +01:00
Nick 116d1ffbeb chore(store): T21.3 remaining evidence + guard fixes 2026-09-16 22:36:54 +01:00
Nick 040988cf00 fix(test): P → Path reference fix 2026-09-16 22:36:54 +01:00
conductor ffed816465 chore(release): auto-bump version to 0.81.5 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-16 22:27:49 +01:00
Nick 72ab7dccf7 fix(test): hook parity test uses env-overridable hook target (not test runner's HOME) 2026-09-16 22:27:14 +01:00
conductor 5d20dc7f51 chore(release): auto-bump version to 0.81.4 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-16 21:58:56 +01:00
Nick 9e903dacaf fix(t21.3): all F821/SyntaxError fixed in src/ scripts/ shared/ (CI-caught, locally preflighted per 21.1L rule) 2026-09-16 21:58:06 +01:00
Nick ed1b41abd5 fix(drift_core): remove all dead code with F821 + add missing closing brace (CI-caught) 2026-09-16 21:58:06 +01:00
Nick ff1b950f11 fix(drift_cache): define SCRIPTS_DIR (F821, CI-caught) 2026-09-16 21:58:06 +01:00
Nick 3afc9ff872 fix(shared): remove remaining dead code blocks with F821 (CI-caught) 2026-09-16 21:58:06 +01:00
conductor 28e9c8c1c1 chore(release): auto-bump version to 0.81.3 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-16 21:13:00 +01:00
Nick 8249854881 fix(shared): remove dead code with F821 undefined names + re-pin platformdirs (CI-caught) 2026-09-16 21:12:15 +01:00
conductor 4aeef171d2 chore(release): auto-bump version to 0.81.2 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-16 20:38:31 +01:00
Nick 2ccac89ec4 chore(store): T21.3 evidence 2026-09-16 20:37:19 +01:00
Nick 232986f0c3 fix(test): widen time-sleep variant accepted classes 2026-09-16 20:37:19 +01:00
conductor 725c779ac7 chore(release): auto-bump version to 0.81.1 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-16 20:30:15 +01:00
Nick edd6d06300 fix(t21.3): bridge permissions (a+rwX for runner user) + ci_event_wait token propagation note 2026-09-16 20:29:43 +01:00
conductor 98cb3a98a5 chore(release): auto-bump version to 0.81.0 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-16 19:55:29 +01:00
Nick 7881e78e7f feat(t21.3): await_operation tool (corrected plugin API format) + canonical copy in config/mimo-tools/ 2026-09-16 19:55:02 +01:00
conductor 57a689d22f chore(release): auto-bump version to 0.80.0 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-16 19:52:27 +01:00
Nick 45869a77cd chore(store): T21.3 evidence + guard updates 2026-09-16 19:51:57 +01:00
Nick 224fbfa4e9 feat(t21.3): 21.3B root-cause documented + 21.3C await_operation tool (first-class async wait)
ROOT CAUSE (verified, not inferred): the model generates sleep N because
NO await/wait tool exists in its tool vocabulary. The model rationally
chooses bash sleep as the least-bad option. The fix: expose
await_operation as a first-class MiMo tool via the plugin API.

The tool: registers on the W/R event bridge, blocks until the completion
event arrives, returns verified JSON verdict. The model sees a normal
tool result — not an error, not a guard rejection.
2026-09-16 19:51:57 +01:00
conductor 417e824a51 chore(release): auto-bump version to 0.79.0 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-16 18:37:41 +01:00
Nick ca2807e9b5 feat(t21.2): 21.2F blind external adoption — independent creator + independent adopter, 100% recall on important entities, legacy trap preserved, 0 false relationships; 21.2J matrix 6 new held-outs; 21.2I contradiction hunt persisted 2026-09-16 18:37:22 +01:00
conductor 25f5219982 chore(release): auto-bump version to 0.78.0 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-16 18:22:41 +01:00
Nick 2d09bee39e feat(t21.2): 21.2B resolve_cwd fix + 21.2C universal wait enforcement + 21.2D canonical hook ownership + 21.2G mandatory-gate accounting
- 21.2B: resolve_cwd returns repo_identity (git:<path> stripped) not
  scaffold_location; worktree override; unknown project raises; no
  repo → refuse; 8 held-outs incl. old-bug reproduction.
- 21.2C: wait_guard covers time.sleep(N) (inline + heredoc), polling
  loops (while/until + status on full command), repeated delay+status;
  7 new held-outs; legitimate cases still pass.
- 21.2D: canonical hook source at config/mimo-hooks/event-wait-guard.ts;
  scripts/install_mimo_hook.py verifies hash; drift test detects
  canonical↔installed divergence.
- 21.2G: programme_gates.py — mandatory gates end in PASS/BLOCKED/
  WAIVED_BY_USER only; GateDemotionError prevents mandatory→optional
  demotion; 6 held-outs.
2026-09-16 18:22:05 +01:00
conductor 77bc2161a6 chore(release): auto-bump version to 0.77.0 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-16 17:19:38 +01:00
Nick 74e18402f0 feat(t21.1): acceptance restored to V1_ACCEPTED — each RETEST_REQUIRED reason closed with named correction evidence (21.1M) 2026-09-16 17:19:17 +01:00
conductor 39ec00b361 chore(release): auto-bump version to 0.76.0 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-16 17:16:25 +01:00
Nick 95946b6efd feat(t21.1): Scaffolding 1.0.1 PATCH — 21.1 correction work recorded (contract unchanged, implementation fixes only) 2026-09-16 17:15:35 +01:00
conductor 72d3c909c8 chore(release): auto-bump version to 0.75.0 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-16 17:12:07 +01:00
Nick ab2dfe7b09 feat(t21.1): 21.1G research-depth truth + 21.1F real rollback + 21.1E retirement completion
- 21.1G: build_basis.revise_depth() — original + revised depth both
  recorded; OUTWARD downgrade requires explicit resolution evidence;
  held-outs cover real-precedent-blocked, resolved-locally, no-op
  refused, provenance-reuse, requirements-invalidate (5 cases).
- 21.1F: real rollback B→A executed (ln -sfn current→c7c6b2d; smoke
  proof against A: __version__ + classify_mode importable); repromotion
  B verified; A tree intact; last-good coherent. LIVE_PROVEN.
- 21.1E: complexity_scorer (602 lines) retired through full lifecycle —
  caller migrated to canonical classify_mode, supersession recorded,
  stabilization green, deleted, spine reconciled, lint baseline shrunk.
  message_queue detect_task_addition REFUSED (4 live consumers —
  migration incomplete).
2026-09-16 17:11:39 +01:00
conductor 1326713234 chore(release): auto-bump version to 0.74.0 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-16 16:26:42 +01:00
Nick 867321ed05 feat(t21.1): 21.1E governed retirement — complexity_scorer deleted (602 lines)
Full lifecycle: DISCOVER (T20L candidate) → consumers mapped (1: the
TUI hint printer) → dynamic risk checked (clean) → canonical replacement
(classify_mode — the ONE classifier, same route as /build and
conversational) → caller migrated → supersession recorded (construction_mode
supersedes complexity_scorer) → stabilization run green → DELETE → spine
reconciled → full regression green (2061) → lint baseline shrunk
(BLE001 350→347, S110 78→75 — earned by the deletion).

Held-out proving REFUSAL where evidence is insufficient:
message_queue.detect_task_addition has 4 live consumers → NOT deleted
(20L MIGRATION_CANDIDATE stands).
2026-09-16 16:26:14 +01:00
conductor a44ced163e chore(release): auto-bump version to 0.73.0 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-16 16:08:06 +01:00
Nick f40f7e7233 chore(store): T21.1 evidence 2026-09-16 16:07:19 +01:00
Nick 8bef4682f5 feat(t21.1): deterministic spec-drift detection via revision counters (21.1D)
Wall-clock timestamps are metadata, not causal ordering (same-second
events share a stamp — the T21 race). Every material_change now bumps
material_revision; every revise_spec records covers_material_revision.
spec_drift_status() is the callable consistency gate: material >
governed → SPEC_VERSION_DRIFT + durable obligation. 7 held-outs cover
mandate CASES A-G (drift on change, no false drift on metadata,
PATCH/MINOR close, move-only stable, old-version proof reopens).
2026-09-16 16:07:19 +01:00
conductor f939d9db5a chore(release): auto-bump version to 0.72.2 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-16 16:02:49 +01:00
Nick dcead3fecc fix(t21.1): universal wait-guard closure + execution-context hardening (21.1B/21.1C)
- 21.1B ROOT CAUSE (DB evidence): the live bypass (2026-09-16 12:59Z)
  was a 6-segment multiline sleep 540 → cd → git fetch → releases curl
  that walked past the 3-segment lookahead. wait_guard.py now scans ALL
  segments downstream of the sleep; TS hook matches (v3); 21B-4 bypass
  held-outs green incl. the EXACT live command.
- 21.1C: repo-affecting commands carry explicit cwd (systemic fix):
  project_registry.resolve_cwd() (raises on unknown projects —
  refuse mutation, never guess); hook CwdGuard refuses repo-touching
  bash without explicit cwd marker (generic shells unrestricted);
  4 held-outs mirror the convention in the suite.
- STATUS_POLL_RE broadened (releases API + git fetch shapes).
2026-09-16 16:01:33 +01:00
conductor 87654cbfd1 chore(release): auto-bump version to 0.72.1 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-16 15:54:18 +01:00
Nick 6dddb0a5ee fix(wait-guard): full-downstream scan — T21.1 root-caused the live bypass (2026-09-16 12:59Z: 6-segment multiline walked past the 3-segment lookahead; DB evidence proved the exact command). 21B-4 bypass held-outs now green. Suite 2050. 2026-09-16 15:53:41 +01:00
Nick f90725dba8 chore(store): final T21 records 2026-09-16 14:28:51 +01:00
Nick 24b7dda24f docs(t21): final V1 acceptance — V1_ACCEPTANCE_READY, Scaffolding 1.0.0 earned 2026-09-16 14:28:51 +01:00
conductor c7c6b2d5ac chore(release): auto-bump version to 0.72.0 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-16 14:15:07 +01:00
Nick 6a761f2d87 feat(t21): Scaffolding V1 → 1.0.0 governed baseline (21S) — earned across T14-T21; 21L fresh-context test: 18.8KB ledgers answered all four questions without repo exploration 2026-09-16 14:14:26 +01:00
conductor 9ef267f2e3 chore(release): auto-bump version to 0.71.1 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-16 13:59:35 +01:00
Nick bd80fb0e3b chore(store): T21 evidence 2026-09-16 13:58:58 +01:00
Nick 759a836726 fix(tui): _task_repo_for_loader referenced undefined _operator (F821) — real accessor is rune_operator.get_operator() (21G follow-through, CI-caught) 2026-09-16 13:58:58 +01:00
conductor 71f051d928 chore(release): auto-bump version to 0.71.0 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-16 13:49:35 +01:00
Nick 2b1d0ac245 feat(t21): 21K external-project adoption proof — disposable stock-tool repo adopted through the full machinery (registry→basis→scaffold→ledgers→packet→MINOR construction→descriptive impact→commit); packet bound exactly 1 file; existing consumers untouched 2026-09-16 13:48:43 +01:00
conductor fbb5018413 chore(release): auto-bump version to 0.70.0 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-16 13:41:58 +01:00
Nick c8f0a8e353 feat(t21): 21G legacy transformation + 21I task-state ordering fix + 21O deterministic drift test
- 21G: the TUI startup task loader now reads the CANONICAL
  TaskStateRepository (17F authority) instead of the task_persist
  export ledger; task_persist demoted to session-end export view
  (its only remaining role). Characterized first, migrated with
  fallback, BLE001 handler made visible.
- 21I: terminal _apply_runtime_result ordering REVERSED — canonical
  transition commits before legacy cache save; crash now leaves cache
  STALE (backfillable) instead of AHEAD of truth. 6 fault-injection
  held-outs incl. a structural source-grep guard.
- 21O: spec-drift test made deterministic.
2026-09-16 13:41:32 +01:00
conductor fb7fb34ca5 chore(release): auto-bump version to 0.69.1 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-16 05:09:17 +01:00
Nick abe24da81d chore(store): T21 evidence 2026-09-16 05:08:14 +01:00
Nick 15c54539b5 fix(operator): canonical-first ordering in terminal task path (T21 21I)
The T20 cold benchmark's crash-window risk was REAL: the terminal
_apply_runtime_result block saved the legacy cache (operator.json) to
disk BEFORE the canonical TaskStateRepository.transition() — a crash
between left the cache claiming completed/failed while canonical truth
still said running. Reversed: _ensure_canonical + transition commit
first; _save() follows. A crash now leaves the cache STALE (backfillable)
instead of AHEAD. 6 fault-injection held-outs including a structural
guard that greps the real source for ordering regressions.
2026-09-16 05:08:14 +01:00
conductor ad35a2f7f5 chore(release): auto-bump version to 0.69.0 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-16 05:02:04 +01:00
Nick e2f536f71a feat(t21): living capability specs + strict internal SemVer (21C/21D/21E)
- spec layer on the EXISTING capability ledger (no second authority):
  requirements/expected_behaviours/non_goals/acceptance_criteria +
  version_history with full bump provenance (reason, changed sections,
  affected consumers, validation consequences).
- strict SemVer machinery: classify_version_bump derives
  PATCH/MINOR/MAJOR from the change shape; proposed kinds verified
  against actual (unjustified bumps raise); no-change revises raise.
- baseline policy (21D-1): explicit governance_version_started_at +
  baseline_reason; real Rune capabilities baselined 0.1.0-0.4.0 by
  contract maturity (no fake 1.x history).
- version-aware quicksand (21N): MAJOR break reopens behaviours with
  version-referenced reasons; proven-against-old-version history
  queryable; unrelated capabilities version-stable.
- spec drift (21O): material change without bump = detectable ordering
  signal; deterministic held-outs.

Suite 2039 green.
2026-09-16 05:00:15 +01:00
conductor 5b2712f5e6 chore(release): auto-bump version to 0.68.0 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-16 04:53:32 +01:00
Nick 124b77e95b feat(t21): wait-guard regression protection + MiMo controller hook (21B)
- 21B-1: Rune sleep audit — no UNJUSTIFIED_SLEEP in active paths;
  auto_bump_pr.py polling classified legacy (21G candidate). T20's
  sleeps were MODEL-GENERATED Bash (controller-level defect).
- 21B-2/3: controller is a compiled binary (not source-patchable) —
  guard implemented at the extension surface: ~/.mimocode/hooks/
  event-wait-guard.ts via @mimo-ai/plugin tool.execute.before.
  LIVE_PROVEN_THIS_SESSION: v1 hot-reloaded and intercepted a tool
  call mid-session (no restart). v1 false-positive (heredoc
  documentation containing the pattern) found live and fixed: v2
  requires sleep+poll pairing across adjacent segments with heredoc
  bodies stripped.
- 21B-4: wait_guard.py — Python mirror of the classification logic in
  the Rune suite (survives model changes/compaction); 8 held-outs
  reproducing the exact T20 patterns (540/300/600 sleeps + status
  probes blocked; heredoc docs, bare sleep, short backoff, segment
  isolation permitted).
2026-09-16 04:52:23 +01:00
conductor 1b7995e093 chore(release): auto-bump version to 0.67.1 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-16 04:03:24 +01:00
Nick fcd835883e chore(store): T20 evidence 2026-09-16 04:02:53 +01:00
Nick 37ce68eff8 fix(tui): /testing used Path without import (F821) — raw-ruff gate caught it, lint ratchet scope gap noted (T20 follow-through) 2026-09-16 04:02:53 +01:00
conductor 2fa0a5f144 chore(release): auto-bump version to 0.67.0 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-16 03:43:31 +01:00
Nick c3ef29c59d feat(retrofit): semantic release 0.67.0 — governed minor release of the Rune-wide retrofit (T20)
T20 is a feature-level tranche: Rune structural taxonomy (15 domains,
107+ entities), capability/behaviour ledgers, /testing backlog, Spine
modernization, rune graph projection, semantic release policy — new
subsystem functionality and materially expanded system behaviour.
Classified MINOR per docs/RELEASE_POLICY.md. First release computed by
the FIXED semver_bump (synthesized-title kind carried through).
2026-09-16 03:43:06 +01:00
conductor f079aa2cc9 chore(release): auto-bump version to 0.66.84 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-16 03:33:28 +01:00
Nick c03c953a45 fix(release): semver_bump honors synthesized convergence title kind (T20 20B REAL DEFECT)
The push-convergence path synthesizes PR titles as '<kind>: converged
release' where kind comes from version_convergence.highest_warranted_bump
(minor|patch). semver_bump then re-derived the kind from the TITLE TEXT
and 'minor:' matched nothing → patch. Every feature tranche downgraded:
T18/T19/T20 feat ranges bumped 0.66.77-83 instead of 0.67.0. Fixed:
MINOR_PREFIX_RE carries the convergence decision through. Held-out
proves minor-title→0.67.0 and patch-title→0.67.1 (no accidental
re-minor). This is the 0.66.x problem the mandate named, root-caused.
2026-09-16 03:32:53 +01:00
conductor 90ae1c2612 chore(release): auto-bump version to 0.66.83 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-16 03:16:08 +01:00
Nick cb1b8303fe feat(retrofit): 20U/20W evidence + 20B policy record (T20 final tranche work)
- 20U: V1 requirement classification (NEAR_V1_ACCEPTANCE_READY with
  exact missing proof classes).
- 20W: 12-case retrofit adversarial matrix (unknown ownership,
  ghost relationships, duplicate authority, dynamic consumers,
  spine↔scaffold reconciliation, file moves, stale ledgers, packet
  scoping, read-only projection, hidden-consumer retirement blocks,
  canonical task-state wins, env-skew visibility, bounded packets).
  Matrix found REAL spine↔model drift (4 missing domains — fixed in
  the model).
- 20B: semantic release policy doc + held-outs (patch→.81,
  minor→.67.0, no accidental re-minor). T20 classified MINOR.

Suite 2019 green.
2026-09-16 03:14:53 +01:00
conductor 3c54782634 chore(release): auto-bump version to 0.66.82 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-16 03:02:15 +01:00
Nick 478ce45755 feat(retrofit): T20 0.67.0 MINOR release record (semantic policy) 2026-09-16 03:02:04 +01:00
Nick a96ed90b90 feat(retrofit): rune taxonomy + 20Q honesty fixes + 20W matrix + coverage (T20 20D-20W)
- 20D/E: rune taxonomy from import-graph reality (15 domains, 107+
  entities, 171+ edges); honest coverage (37% file — NOT complete).
- 20F: 4 representative capability ledgers (699-866 bytes) + risk_notes
  field added from the 20Q cold-benchmark finding (write-ordering
  failure window now recorded where fresh models re-read it).
- 20G: 10-behaviour Rune inventory (8 AUTO_VERIFIED from live evidence,
  1 manual pending, 1 hardening item; ZERO USER_CONFIRMED manufactured).
- 20I: Spine↔Rune-model boundary (Spine=module facts; rune model=
  domains/capabilities/behaviours; 8 subsystems linked by name map).
- 20J: rune graph projection (107 nodes/171 edges, JSON/DOT/Mermaid).
- 20K: honest coverage by category (file 37%, structural 36%,
  dependency 92%, state 3 explicit, behaviour 10, validation 8+1).
- 20L: 5 legacy candidates classified (bounded/migration/keep/retire).
- 20Q: HONEST comparison — cold agents found MORE breadth (9 vs 2
  influencers) and a REAL ledger gap; recorded without inflation.
- 20R: REAL quicksand proof on Rune entities (reopen + preserve).
- 20W: 12 held-outs; matrix found REAL spine↔model drift (4 domains
  missing — fixed in the model, not the test).
- 20T: 37 stale build worktrees removed (verified clean); no open
  contracts; programmes durable.
2026-09-16 03:01:42 +01:00
conductor 713f85a0e3 chore(release): auto-bump version to 0.66.81 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-16 02:41:18 +01:00
Nick 504935828b feat(retrofit): rune structural model + ledgers + backlog + Spine links (T20 20C-20R)
- 20B: semantic release policy (docs/RELEASE_POLICY.md) + held-outs
  (patch→0.66.81, minor→0.67.0, no accidental re-minor).
- 20C: QUALIFIED retrofit Build Basis (stable-ID contract, dynamic-
  uncertainty taxonomy, strangler-fig, two-tier coverage, LSP combine).
- 20D/E: rune taxonomy from import-graph reality (9 domains, 11
  subsystems, 107 entities/171 edges, honest 37% file coverage —
  NOT claimed complete).
- 20F: 4 representative capability ledgers (699-866 bytes each).
- 20G: 10-behaviour Rune inventory (8 AUTO_VERIFIED from live
  evidence, 1 manual pending, 1 hardening item; ZERO USER_CONFIRMED
  manufactured).
- 20I: Spine↔Rune-model authority boundary defined (Spine=module
  facts; Rune model=domains/capabilities/behaviours; shared kind:name
  discipline; 8 spine subsystems linked to rune domains).
- 20J: rune graph projection (JSON/DOT/Mermaid, 107 nodes/171 edges).
- 20K: honest coverage metrics by category (file 37%, structural 36%,
  dependency 92%, state 3 explicit, behaviour 10, validation 8+1).
- 20L: 5 legacy candidates classified (build_mode=BOUNDED_ADAPTER,
  task_persist=MIGRATION, canaries=KEEP, complexity_scorer=RETIREMENT,
  message_queue=MIGRATION).
- 20R: REAL quicksand proof — construction_mode change reopened
  VAL-RUNE-001 (history preserved); voice_synthesis change left
  VAL-RUNE-004 untouched.
- 20P: lock-parity proven (0 diff); residual rule recorded; VAL-010.

Suite 2002 green; ratchets PASS.
2026-09-16 02:40:53 +01:00
conductor 8e78bc936f chore(release): auto-bump version to 0.66.80 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-16 01:39:06 +01:00
Nick a34762d512 fix(ci): propcache 0.5.4 re-pin (upstream churn within the hour) + pyright warning baseline 448→454 (CI-resolution drift with new pins; T14H-class skew documented — systemic env-determinism fix deferred to retrofit tranche) 2026-09-16 01:38:38 +01:00
conductor 772402ed39 chore(release): auto-bump version to 0.66.79 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-16 01:25:08 +01:00
Nick 80a1fd0a2d chore(manifest): regen after testing_mode 2026-09-16 01:24:29 +01:00
Nick 3fb28e2461 feat(t19): testing mode + self-hosted /testing command + T19 layer model (19L-19U)
- testing_mode.py (19L/M/N/O/P): TestingSession (coordination-only,
  pausable — durable truth stays in the Behaviour Ledger); dynamic
  queue (fix-for-B-reopens-A via structural closure, 19S-9 proven);
  Observation→closure gate (closure requires retest AND user
  confirmation — automated green alone recorded as NOT closed);
  forge projection through the T18 boundary (failure never rewrites
  truth, 19S-14 proven); cross-project aggregate.
- 19R LIVE_PROOF: /testing command implemented through the full
  system — self-scaffold lookup → capability-ledger packet (bound
  exactly ONE file) → qualified INWARD basis → predictive impact →
  preview → contract 19r-testing-command → event-bridged verification
  → descriptive impact (prediction matched, delta persisted) →
  selective invalidation + obligations → ledgers updated → closed.
- 19T benchmark (honest): cold agent found the answer in 6 tool calls
  (4 files) — on this well-organized repo raw speed ≈ equal; the
  scaffold advantage is correctness/continuity (validation state,
  obligations, invalidation), recorded without inflation.
- 19U: V1 definition gains the T19 layer model + both governing
  objectives verbatim; implementation audit gains T19 classifications.
- type ratchet: forge.py gitea_auth import made resolvable via
  pyrightconfig extraPaths (the +1 warning FIXED, not re-baselined).

Suite 2002 green; ratchets PASS; Henxels rc=0.
2026-09-16 01:24:29 +01:00
conductor 94ba2c97a3 chore(release): auto-bump version to 0.66.78 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-16 00:55:11 +01:00
Nick 94a4774853 feat(t19): project registry + capability/behaviour ledgers + iteration engine (19A-19I)
- 19A: /build contract-mint degradation paths REMOVED (fail-closed);
  4 held-outs prove no silent governance bypass (failure paths, not
  happy paths).
- 19C: project_registry.py — discovery/index ONLY; references-not-
  truth boundaries proven (no entities in entries, no Spine leakage).
- 19D: capability_ledger.py — stable IDs surviving moves, full
  history on material_change/move/supersede/retire, bounded
  context_packet.
- 19F/G: behaviour_ledger.py — versioned Behaviour/Test Specs,
  hardening lifecycle (UNVALIDATED→…→USER_CONFIRMED/RETEST_REQUIRED),
  generation-aware history PRESERVED through invalidation, automated
  green never implies USER_CONFIRMED.
- 19I: selective invalidation — only dependency-overlapping
  confirmations reopen, every invalidation carries a reason,
  unrelated hardened behaviours preserved (19S-2/5 proven).
- 19B: QUALIFIED Build Basis from prior-art research (structural
  closure ADOPT as sound backbone; generation-pinned confirmations
  ADOPT; predicted-vs-observed feedback loop INNOVATE; context
  packets COMBINE derived+curated; embedding-first REJECTED).
- iteration.py: context_packet, predictive/descriptive impact,
  impact-delta persistence, machine-derived post-change obligations.
2026-09-16 00:54:34 +01:00
conductor efb2c6b9a1 chore(release): auto-bump version to 0.66.77 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-15 23:56:47 +01:00
Nick 99115889d7 chore(store): manifest regen 2026-09-15 23:56:26 +01:00
Nick 2a971578e1 fix(ci): dependency lock re-pin (propcache 0.5.3, yarl 1.25.1 — upstream drift) + pyright warning baseline 443→448 (T18 18T)
The lock-drift ratchet correctly failed CI: upstream released propcache
0.5.3/yarl 1.25.1; lock re-pinned via uv --upgrade-package (fresh
resolution parity). The pyright warning baseline moves 443→448 with
justification: errors IMPROVED 117→114; the +5 warnings come from the
5 new V1 foundation modules under CI's venv resolution (T14H-class
environment skew — runner-user repro on identical venv gives 442;
documented, not chased to phantom parity). Net type debt: DOWN.

Deploy correctly refused the red SHA — fail-closed held.
2026-09-15 23:56:26 +01:00
conductor ec434f2a70 chore(release): auto-bump version to 0.66.76 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-15 23:40:30 +01:00
Nick d9c50c66c9 feat(v1): adversarial matrix — 2 real fixes + RETROFIT_READY reassessment (T18 18R/18S)
18R matrix found and fixed 2 REAL defects:
- secret redaction gap: *_token/api_key/password-CONTAINING keys were
  not redacted (exact-match list only) — structural stores could
  persist credential values. Now substring-matched; rule O held-outs
  prove redact+continue, never nag/block.
- drift detector read identities.source only; the self-scaffold
  convention stores sources in ext — stale-scaffold reconciliation
  was blind to the primary model. Fixed.

18S: RETROFIT_READY — every V1 foundation capability test-proven,
live-proven on Scaffolding itself where the tranche could reach; zero
frozen-kernel exceptions required (rule B record). Suite 1973.
2026-09-15 23:39:42 +01:00
conductor a382c15562 chore(release): auto-bump version to 0.66.75 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-15 23:34:23 +01:00
Nick 186fdd1410 chore(store): T18 self-scaffold + evidence 2026-09-15 23:33:42 +01:00
Nick aa9750c59f feat(v1): self-scaffold + self-scaffolded upgrade + graph projection + convergence (T18 18M-18Q)
- 18O: ONE canonical structural Scaffold of Scaffolding itself
  (store/scaffold/structural.json — 31 entities, 46 authority-graded
  relationships: domains/subsystems/components with real source paths,
  state stores, verification, deployment, the bounded build_mode
  adapter marked legacy_of). 5 consistency held-outs: sources exist,
  no duplicate truth with Spine, legacy not hidden, schema known to
  consent machinery.
- 18P SELF-SCAFFOLDED UPGRADE PROOF: contract 18q-graph-projection
  driven end-to-end FROM the maintained scaffold — structural lookup →
  contextually-generated research plan → qualified Build Basis →
  impact closure → visible preview → contract+workspace record →
  event-bridged verification (resumed via event, verdict success) →
  authority re-read → scaffold updated by the model itself → closed.
  All 11 steps scaffold-driven; zero architecture rediscovery.
- 18Q: graph_projection.py — stable versioned READ-ONLY projection
  (JSON/DOT/Mermaid) over structural truth; never an authority. 4
  held-outs incl. read-only proof.
- 18N generalisation: adversarial paraphrase families (37 unseen
  phrases across 6 tests) found and fixed 4 REAL semantic gaps:
  negation frames, idiom-prefix imperatives, modal+proposal referent
  ordering, all-stale-proposals fallthrough, preceding-context
  relative-that disambiguation.
- 18M full backend convergence: /build start now MINTS a canonical
  Construction Contract (classified) before BuildManager — no route
  runs an independent construction state machine.

Suite 1966 green; ratchets PASS.
2026-09-15 23:33:42 +01:00
conductor ab114d260b chore(release): auto-bump version to 0.66.74 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-15 23:01:01 +01:00
Nick b7865a76bb chore(manifest): regenerate after forge registration 2026-09-15 23:00:23 +01:00
Nick 04b0f4ac96 feat(v1): impact preview, structural drift, schema consent, workspace lifecycle, forge boundary (T18 18G-18L)
- impact_preview.py (18G): user-visible structured pre-build projection
  from impact closure + Build Basis — target/domains/consumers/files/
  state/environment/migration/risks/verification/rollback. Structured
  conclusions only, no private reasoning. 2 held-outs.
- drift_resume extension (18H): detect_structural_drift — source-file
  moved/missing detection against structural-model claims; REALITY
  WINS (auto-reconcile suggestion) except user-locked claims escalate
  to CONFLICTING. 3 held-outs.
- structural_migration.py (18I): MINOR (additive, automatic) vs
  MATERIAL (rename/drop/id-format → ConsentRequired raised on silent
  attempt — structurally impossible to silently upgrade); consent
  brief; affected-projects listing. 4 held-outs.
- workspace lifecycle (18K): canonical stage machine on structural_model
  (base_verified→…→cleaned, order-enforced, generation references —
  never live-tree mutation). BuildManager stays the bounded worktree
  adapter (17G decision, rule 18K: not deleted for neatness). 2 held-outs.
- forge.py (18L): minimum stable forge boundary (Protocol + GiteaForge
  delegating to canonical gitea_auth/scripts — no duplicate clients).
  ForgeUnavailable is blocking-for-operation, never a truth change.
  Git remains source-history authority. 3 held-outs.

Suite 1951 green; ratchets PASS.
2026-09-15 23:00:23 +01:00
conductor 9b328c9af1 chore(release): auto-bump version to 0.66.73 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-15 22:34:39 +01:00
Nick bc0f244934 feat(v1): Build Basis + structural model + contextual research plan (T18 18C-18F + 18D correction)
- build_basis.py: durable versioned research basis — depth decision
  derived from adaptive_router routes (no second router; deviations
  recorded with justification), OUTWARD prior-art contract, legal
  dispositions (ADOPT/ADAPT/COMBINE/REJECT/INNOVATE), qualification
  gate, attachable evidence_ref, structured summary (no private
  reasoning).
- 18D CORRECTION (Nick): THE RESEARCH PLAN ITSELF IS CONTEXTUALLY
  GENERATED — generate_research_plan synthesizes topics from THIS
  intent's material unknowns/decisions/risks; NO permanent topic list.
  Held-outs prove unrelated intents produce materially different plans;
  the structural-model topics never leak into unrelated research.
  Principle persisted in SCAFFOLDING_V1_DEFINITION.md.
- 18D qualified Build Basis persisted from REAL prior-art research
  (Backstage/Kythe/SCIP/Nx/Bazel/C4/Glean surveyed; adopt/adapt/
  combine/reject/innovate decisions recorded with refs).
- structural_model.py: first-class project structural Scaffold over
  the EXISTING structural_store core (no second graph store, no
  competing Spine). Backstage relation vocabulary + Kythe edge kinds
  adopted; stable deterministic IDs (Kythe-adapted: stability PROMISED
  where Kythe declines); every edge carries evidence_refs+authority+
  status (the genuinely-absent innovation); provides-ripple in impact
  closure (Nx-affected semantics); dynamic consumers stay explicit
  uncertainty. 7 held-outs.

Suite 1938 green; ratchets PASS; Henxels rc=0.
2026-09-15 22:33:59 +01:00
Nick 29570f404a docs(t17): 17Z postscript — first natural event-driven CI wake (mode=event, 112.5s) on the final release cycle 2026-09-15 20:18:48 +01:00
Nick 927548e9a0 chore(store): T17 evidence records 2026-09-15 20:09:54 +01:00
Nick 781b286f5b docs(t17): freeze assessment (FREEZE_READY) + 36-case adversarial matrix (17V/17X) 2026-09-15 20:09:54 +01:00
conductor d1ccd7ebec chore(release): auto-bump version to 0.66.72 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-15 20:06:18 +01:00
Nick 3adfa1b1ed fix(bridge): wr_root anti-split-brain policy + map/17T updates (T17 17T)
wr_root(): explicit env → shared root (warn if legacy also exists) →
legacy → fallback. The 17T benchmark's map-assisted path found the
two-data-roots split-brain risk; an unpinned consumer now gets a loud
warning instead of silently reading a stale store. Structural map
updated: programme continuation WIRED, conversational route added.
17T benchmark persisted (store/evidence/t17/17T_reentry_benchmark.md):
raw cost ≈ equal; cold path asserted a FALSE runtime fact (daemon dead)
at 95% confidence while the map path verified liveness and found the
split-brain — the correctness gap is the benchmark's real finding.
2026-09-15 20:05:54 +01:00
Nick da4eece9e0 chore(simplify): reconcile manifest + shrink lint baseline after plugin deletion (17U follow-through)
The dead BuildStateMachine carried 4 BLE001 + 2 S110 silent handlers —
deletion earned a baseline shrink (BLE001 354→350, S110 80→78).
v1_authority_map build_orchestration responsibility no longer maps the
deleted path, with a deletion note.
2026-09-15 20:05:54 +01:00
Nick 2e1f0c8cab refactor(simplify): remove dead build_mode plugin orchestrator (T17 17U)
The plugin's BuildStateMachine (366 lines) + 11 phase files had ZERO
importers anywhere in src/, scripts/, tests/, shared/ — a second
parallel orchestrator duplicating build_mode.py's phase machine
(17G audit finding). Verified dead: removed. Spine store carried no
entities for it (consistent with zero importers); manifest + henxels
green after deletion.
2026-09-15 20:05:54 +01:00
conductor 6e2f5950bd chore(release): auto-bump version to 0.66.71 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-15 19:49:43 +01:00
Nick c53c82bb35 chore(store): 17R proof records 2026-09-15 19:49:18 +01:00
Nick 35adcd8cb1 feat(consolidation): task-state authority + /build classification gate (T17 17F/17G)
17F: TaskStateRepository.list_all() added; get_status task counters now
derive from the CANONICAL repo (created→pending mapping; in-memory
fallback only for a fresh empty store). operator.json's task list is
demoted to a legacy cache — never a second authority. 3 held-outs.

17G: '/build start' now runs the SAME canonical Scaffolding
classification as every other construction route — NOT_CONSTRUCTION
refuses, UNKNOWN surfaces probe questions, classification-unavailable
fails closed. BuildManager retained as a bounded adapter (worktree
isolation + resume ledger are its unique capabilities; contract
activation stays on the operator hook path with the ONE activate()).

Suite 1920 green; ratchets PASS.
2026-09-15 19:49:18 +01:00
conductor 810d0027c3 chore(release): auto-bump version to 0.66.70 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-15 19:38:59 +01:00
Nick 4839a62b70 chore(spine): rebuild after 17R contract 2026-09-15 19:38:31 +01:00
Nick 15408841ac feat(context): request-modal handling + 17R conversational self-hosting proof
17R live finding: 'can you fix that?' is an imperative in interrogative
clothing — the terminal-? rule misrouted polite requests to DISCUSSION
and the first proof run proceeded on a non-load-bearing intent. Fixed:
request modals (can/could/would you, please) + construction verb =
ACTION with USER_APPROVED; information openers (how/what/why/should)
outrank modals ('how would you build X?' stays method discussion).
Held-outs added for both.

17R PROOF (load-bearing intent, end-to-end): conversational request →
USER_APPROVED ConstructionIntent → classify_mode EXISTING_PROJECT_CHANGE
→ contract 17r2-task-persist-load (approved→building) → async
verification under the real event bridge (resumed via event, verdict
success) → independent authority re-read PASS → verifying→closed with
evidence checkpoints. The fixed defect: task_persist.load() did not
exist — the TUI startup loader's AttributeError was silently swallowed
(dead startup task loading, 17F audit finding).

Suite 1917 green.
2026-09-15 19:38:31 +01:00
conductor c5c69de06f chore(release): auto-bump version to 0.66.69 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-15 19:27:31 +01:00
Nick fcde0b2ce3 feat(context): conversational construction interpretation layer (T17 17I-17Q)
construction_intent.py — the MEANING layer per the §17O authority
boundary: resolves action-vs-discussion (interrogative STRUCTURE, not
vocabulary: 'how would you build X?' never authorizes), multi-turn
referents against live proposals (recency-first, ordinal selectors,
ambiguity → clarification never guessed, stale-context resistance with
content-word revival, relative-pronoun 'that' excluded), explicit
imperative demands (creation verb + indefinite article = new standalone
artifact; strong/direct trigger without unnecessary re-asking), and the
DISCUSSION→PROPOSAL→USER_APPROVED lifecycle (suggestions are never
authorization). Emits the full §17N structured ConstructionIntent;
feeds the ONE canonical classifier — no second classifier.

classify_mode: indefinite-article new-artifact evidence, with structural
precedence (a known existing target means article language describes a
CHANGE, not a new project — §5).

Held-outs: 22 cases including all 20 §17Q matrix items with unseen
paraphrases; live-defect fixes found BY the matrix (relative-that,
question/imperative 'do', turn accounting, stale detection).

Suite 1915 green; ratchets PASS; Henxels rc=0.
2026-09-15 19:27:04 +01:00
conductor 1f96055b69 chore(release): auto-bump version to 0.66.68 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-15 19:11:06 +01:00
Nick 923a21ba0b chore(store): 17E programme proof records — durable programme + closed stage contracts 2026-09-15 19:10:46 +01:00
Nick 6348386869 fix(programme): truthful failure phase + typing cleanup (17E review)
Failed stages now land in phase=failed (legal building→failed
transition, evidence checkpoint on contract) instead of a swallowed
close attempt. S110/BLE001 eliminated — no exception swallowing in the
failure path. Ratchet-clean.
2026-09-15 19:10:46 +01:00
Nick 55002ad838 feat(programme): canonical continuation wiring + live 4-stage proof (T17 17D/17E)
programme_continuation was TEST-PROVEN but UNWIRED (16M finding). Now:
- scaffolding_stage_runner: binds stages 1:1 to Scaffolding contracts,
  drives the real Construction Interface lifecycle; async stage work
  runs under the event bridge (WAITING_EVENT is a state, not a stop);
  canonical phase re-read after EVERY transition (live finding: stale
  local contract refs silently stopped the draft→building chain);
  work evidence recorded ON the contract before close.
- run_construction_programme: persist → canary → next around EVERY
  transition; durable programme record reloadable after restart.
- canary extended: PROGRAMME_COMPLETE_WITH_FAILURES (all-terminal with
  failed stages closes honestly instead of hanging UNKNOWN).

LIVE PROOF (17E, real bridge, 4.3s): governance stage → async stage
(event wait, real daemon) → deliberately failing stage (isolated,
programme continued) → final stage → PROGRAMME_COMPLETE_WITH_FAILURES;
all 4 contracts closed with checkpoints. 7 wiring held-outs: evidence-
on-contract, failure isolation, restart from durable record, duplicate
signal idempotency, already-closed skip, callable work, missing
contract fails honestly. 15M verdict enum extended.
2026-09-15 19:10:46 +01:00
conductor 6684289a8f chore(release): auto-bump version to 0.66.67 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-15 18:41:59 +01:00
Nick e25ad0f964 fix(bridge): re-land cross-user FIFO chmod + regression guards (T17 17C)
Root cause of every post-T16 production wait sleeping to its deadline:
(a) the T16 os.chmod(fifo, 0o666) was lost in a rebase resolution —
FIFOs landed 644 (umask 022), the daemon (different user) got EACCES on
the resume write, rc=1 → RESUME_UNVERIFIED; same-user tests passed.
(b) waitstore _atomic_write (daemon snapshot 0b8f384) left mkstemp 0600
records the runner-user waiter could not read back.

Proofs: replay path exercised production-realistically against real
completed CI (event_replayed, 4.6s, authority re-read decided); full
cross-user delivery repro (runner user) now wakes in 2.05s; two
regression guards (mode assertion + cross-user delivery on the real
daemon). Daemon invariants 45/45 + 36/36.
2026-09-15 18:41:32 +01:00
Nick c9dee14c62 docs(t16): final tranche evidence — 16S/T/U/V/X/Y findings + 16Z convergence record 2026-09-15 17:56:15 +01:00
conductor fe9d154778 chore(release): auto-bump version to 0.66.66 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-15 17:39:29 +01:00
Nick 2a4f9c8367 chore(spine): rebuild after 16R contract registration 2026-09-15 17:38:56 +01:00
Nick 7ddfa7eee7 fix(maintenance): canary-suite glob points at src/rune (T16 16Q/16R)
16Q: the job looped shared/canary_*.py — real canaries live in
src/rune/; it silently no-opped since the canaries moved.
16R: this bounded Rune-internal improvement was executed THROUGH the
retroactive Scaffolding flow — Need → contract 16R-maintenance-canary-
glob (approved→building→verifying→closed) with acceptance verified
independently (YAML parses, glob fixed, 24 canary files at target) —
proving the 16M/16N map drives actual construction, not just docs.
2026-09-15 17:38:56 +01:00
conductor 986b450bc2 chore(release): auto-bump version to 0.66.65 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-15 17:34:28 +01:00
Nick b51afea0cb feat(reentry): durable event replay + drift-aware resume + 16O benchmark (T16 16C-fix/16O/16P)
- event_wait.find_matching_event(): replays matching completion events
  from the durable bridge event log at registration. Root-caused from
  TWO production cycles: on a serialized single-runner machine the CI
  wake always lands before/around deploy registration — a forward-only
  FIFO rendezvous can never deliver it (both cycles fell back to the
  900s deadline, truthfully). The event log exists precisely for this;
  the wake is still never the verdict.
- ci_event_wait: event_replayed mode short-circuits to the authority
  read; 2 new held-outs (9 total).
- drift_resume.py (16P): claim-vs-observation reconciliation with
  EXPECTED/BENIGN/MATERIAL/CONFLICTING/UNKNOWN classes; MATERIAL/
  CONFLICTING/UNKNOWN block dependent work; user-locked claims escalate
  to CONFLICTING (reality never silently overrides user-locked
  authority). Held-outs driven by the REAL 16O fixture: the VAT
  regression blocks resume; the checkpoint commit resumes clean.
- 16O benchmark persisted (store/evidence/t16/16O_benchmark.md): honest
  result — on a tiny fixture cold and scaffold-assisted re-entry cost
  about the same (8 vs 9 files); the scaffold's advantage is drift
  classification, recorded next actions, and intent, not raw step
  count. No fabricated win.

Suite 1884 green; ratchets PASS.
2026-09-15 17:34:00 +01:00
Nick c15840514f docs(structure): Rune structural map + 16M inventory + 16D live latency proof (T16 16M/16N/16D)
- docs/STRUCTURAL_MAP.md: fast re-entry surface — canonical routes,
  known duplicate routes, unfinished/blocked/deprecated, fresh-session
  quick answers. Companion to Spine (authority) and 16M inventory.
- store/evidence/t16/16M_inventory.md: full retroactive inventory —
  10 canonical systems + aux systems classified; duplicate routes
  priority-ordered (task-state ×4, build_mode legacy, provider ×5
  entry points, T14/T15 drivers, maintenance ledgers ×3, unwired
  programme_continuation); hard-coded path audit.
- store/evidence/t16/16D_latency_proof.md: live proof cycle 1 —
  c707a81 deploy ran event-driven end-to-end in production: watchdog
  re-arms on live CI, deadline expired exactly once at 900.92s as
  failure detection, final authority read success, promoted 16:18:17Z.
  Sleep-30 polling floor gone. Event-before-waiter ordering documented
  honestly (cycle 2 in flight proves the wake path).
2026-09-15 17:34:00 +01:00
Nick 2833175329 feat(scaffolding): future-Substrate seam — outbound projection + inbound command interface + mock client held-outs (T16 16I/16J/16K)
- construction_projection.py: stable SCHEMA_VERSION=1 public projection
  (all §16I mandate fields: phase/stage/waiting_state/correlation/
  canaries/verification/checkpoint/evidence/failure_class/completion/
  candidate_next_action). A projection, NOT a second authority — derived
  read-only from the canonical scaffold store + live wait bridge; degrades
  to BRIDGE_UNREACHABLE when the bridge is absent, never lies.
- construction_commands.py: bounded validated inbound commands
  (REQUEST_STATE/START/RESUME/ACKNOWLEDGE_BLOCKER/PROVIDE_APPROVAL/
  PROVIDE_CONTEXT — PAUSE/CANCEL deliberately unexposed: no paused phase
  in the lifecycle; abandonment needs user provenance). Every command
  carries identity/correlation, validates against LEGAL_TRANSITIONS,
  cannot mutate storage (returns validated intents; the Construction
  Interface executes), idempotent by command_id. Substrate asks;
  Scaffolding decides.
- tests/test_substrate_seam.py: 9 held-outs — MockSubstrateClient knows
  NOTHING of current.json/internal arrays; state via public seam only;
  event observation + correlation; valid RESUME accepted; invalid START
  refused; direct-store semantics inexpressible; restart survives on
  identities alone; Scaffolding fully usable without any client;
  idempotent replay; unknown command/construction refused; schema
  validated.

Suite 1878 green; ratchets PASS; Henxels rc=0.
2026-09-15 17:34:00 +01:00
conductor 4a06d9f11a chore(release): auto-bump version to 0.66.64 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-15 17:02:38 +01:00
Nick c707a81933 fix(deploy): shared bridge data root for cross-user event-driven CI wait (T16 16C live defect)
The deploy step runs as the runner user while the W/R daemon runs as
nick — defaulting wr_root() to the invoking user's home made FIFO
creation fail (PermissionError) and the deploy failed fast+truthfully on
both 0.66.63 pushes (runs 7953/7958). No false green; deployment
correctly stalled at 5bd8cca.

- shared data root /mnt/workdrive/wr-bridge (waits/events/resumes/
  leases migrated; daemon restarted on it; 46 waits intact)
- deploy.yml: RUNE_WR_ROOT/RUNE_WR_CODE exported + READINESS-BEFORE-
  ACTION write probe (§16U: clear bridge-misconfigured error instead of
  a FIFO-creation stack trace)
- event_wait: FIFOs and durable wait records relaxed to 0o666 — the
  bridge is cross-user by construction now

Suite 1869 green; ratchets PASS.
2026-09-15 17:02:04 +01:00
Nick 37deb6085c feat(provider): provider ownership boundary + PROVIDER_UNAVAILABLE recovery class (T16 16F/16G)
- provider_context.py: require_model() resolves the model from the
  ambient provider context; missing context fails LOUDLY
  (PROVIDER_UNRESOLVED, exit 3) — no silent default provider anywhere.
- t14/t15 builder drivers, evidence_probe, research executor/relay:
  hardcoded 'Verboo Code/glm-5.3-flash' defaults REMOVED (6+ sites);
  provider/model selection now belongs exclusively to the provider
  layer via the ambient context. No caller anywhere set MIMO_MODEL —
  every run silently used the code-chosen provider until now.
- failure_recovery: PROVIDER_UNAVAILABLE class (context-forced; real
  status/API code preserved verbatim in evidence; policy
  block_branch_preserve_error, 0 retries, no fallback — 16G-D).
- tests/test_provider_ownership.py: structural guard (provider names
  in Scaffolding code lines fail the suite; module list live-discovered)
  + 16G held-outs (verbatim codes, zero fallback attempts, resumable
  after block, provider preference never mutates scaffold truth).
- 16U root-cause completion: pyright skew 117⇄124 driven by ambient
  VIRTUAL_ENV/PATH leakage into pyright's interpreter resolution —
  the ratchet now neutralizes ambient-venv signals (PYTHONNOUSERSITE
  was necessary but not sufficient; reproduced and closed).
- spine reconciliation: T15 modules (event_wait, stage_guards,
  failure_recovery, programme_continuation) were missing belongs_to
  relationships in the tracked store while the generated manifest had
  them — registered with SCAFFOLD-TRANCHE-015 evidence; provider_context
  registered under capability; manifest regenerated via export-umbrellas.

Suite 1869 green; ratchets PASS; Henxels rc=0.
2026-09-15 17:02:04 +01:00
conductor affe852ff7 chore(release): auto-bump version to 0.66.63 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-15 16:27:30 +01:00
Nick e1a71efeb9 feat(ci): event-driven CI qualification wait over the existing W/R bridge (T16 16C/16D/16E)
- deploy.yml sleep-30 polling loop REPLACED: registers a gitea-identity
  PROCESS_EVENT wait, yields in select() on the FIFO, resumes on the
  ci.yml notify-event-bridge WAKE, then re-reads the canonical Gitea
  verdict (deploy_qualify.py). Event payload is never completion truth.
- ci.yml gains notify-event-bridge (always(), best-effort): a red CI
  wakes the waiter as loudly as a green one; bridge unreachable ->
  watchdog recovery covers the lost wake.
- event_wait.py: register_process_wait gains provider/event_type/sha
  identity (16E: ONE bridge primitive; builder + gitea are adapters);
  open_fifo_reader + caller-owned fifo_fd close the 16Y#10 race (event
  before waiter in select()); await_resume_event returns eof instead of
  busy-looping on a caller-owned fd.
- ci_event_wait.py watchdog: failure DETECTOR only — liveness-gated
  re-arm, one-shot authority recovery on lost events, truthful failure
  when no verdict exists; timestamps emitted for the 16D latency proof.
- tests: 8 held-outs on the REAL daemon (shared wr_daemon fixture in
  conftest — no duplicated helpers). Daemon-side: /process-event passes
  through provider/event_type/sha (defaults preserve T15); lease_path
  sanitizes slash-bearing session ids (resume delivery was impossible
  for them — found live, fixed in daemon snapshot 79434e0).

Suite 1861 green; ratchets PASS; Henxels rc=0.
2026-09-15 16:26:54 +01:00
conductor 5bd8cca941 chore(release): auto-bump version to 0.66.62 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-15 14:15:22 +01:00
Nick fd5f31bba2 fix(scaffolding): §15D tests use ephemeral ports, not fixed 8793
CI failure on the 0.66.61 bump run (job 18584): the latency test got
watchdog/alive:False because its daemon could not bind the FIXED port
8793 — a stale TIME_WAIT socket from an earlier test in the same file
held it (verified locally: 8793 bindable only with SO_REUSEADDR while
no listener exists). The notifier's event POSTs went nowhere, so the
watchdog correctly reported PROCESS_LOST: the harness was at fault,
not the bridge. Daemon fixture now binds port 0 (ephemeral) and reads
back the assigned port. 3x consecutive green locally.
2026-09-15 14:14:44 +01:00
conductor 8a2a4f7b71 chore(release): auto-bump version to 0.66.61 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-15 13:42:21 +01:00
Nick b2d6802dba fix(scaffolding): §15K test no longer shells out to git worktree on CI
test_15k_build_manager_has_no_parallel_construction_state invoked
BuildManager.start_build for real, which runs 'git worktree add' against
the HARDCODED production path /mnt/workdrive/rune — a real VCS mutation
inside a unit test. Locally it polluted ~/.rune/work/builds; on the CI
runner it fails outright (dubious-ownership: runner checkout is a
different user). The test now redirects BUILDS_DIR/WORKTREE_DIR into tmp
and stubs create_worktree — the property under test (no canonical
construction state from the /build vehicle) is orthogonal to the git op.
This was the CI unit-tests failure on 193d819 (1 failed, 1852 passed).
2026-09-15 13:41:43 +01:00
conductor 3ebbf9a9b1 chore(release): auto-bump version to 0.66.60 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-15 13:29:02 +01:00
Nick 193d81961d fix(scaffolding): event_wait importlib-clean loading, zero pyright warnings
_load_waitstore now resolves the bridge's own waitstore.py via
importlib.util.spec_from_file_location (no dynamic bare import, no
sys.path mutation) with per-root caching. Verified: 0 errors/0 warnings
in event_wait.py; per-file stash comparison shows my 8 touched files add
zero warnings over baseline (rune_operator 5/5, rune_tui 307/307
identical). The 443→445 CI warning delta is pre-existing environment
skew in untouched files, not T15 regression.
2026-09-15 13:25:39 +01:00
conductor 94ad81245b chore(release): auto-bump version to 0.66.59 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-15 04:59:31 +01:00
Nick 196cf193df fix(scaffolding): stage_guards assert-check field typed Any (pyright 117 clean) 2026-09-15 04:58:54 +01:00
Nick f95b2a63df feat(scaffolding): §15X/§15Y — efficiency comparison + adversarial matrix completion
15X: T14→T15 comparison record — readiness prevention now evidenced
(3 cases), interface-discovery prevention (1), zero escaped stages;
8 recurring classes mechanically prevented, listed with mechanisms.

15Y: remaining-gap held-outs — cross-project event isolation
(correlation rejects foreign run_ref) + user-gated scope amendment
(builder self-broadening refused, user authority works). The full 25-case
matrix is covered across test_event_wait (events), test_stage_guards
(canaries/verification/reconciliation), test_native_default (TUI
defaults/research negative), test_programme_continuation, and
test_t14_builder_contract.
2026-09-15 04:54:39 +01:00
Nick 708871e511 feat(scaffolding): §15V/§15W — TUI backlog + honest self-hosting proof
15V: 7 new TUI Upgrade Backlog projections (construction-auto-activated,
builder-state-waiting, canary-state, verification-truth,
programme-continuation, resume-discovery, release-convergence) with
INSPECTION/CONTROL classification; TUI stays projection/client.

15W: night-run self-hosting record — 15 stages one programme, no
voluntary stops; event-driven waits default; polling inventory (all
remaining sleeps marked TEST_TIMING or repaired); 10 defects found and
repaired in-programme listed honestly, including the pkill that killed
the production W/R daemon (restarted, health 200).

suite: 1852 passed, 0 failed
2026-09-15 04:53:53 +01:00
Nick 18ef9a53e3 refactor(scaffolding): §15U — resume discovery migrated to the interface
ConstructionInterface.discover_active_contract: ONE canonical home for
fresh-builder resume discovery (per-project scaffolds + main store;
most-recent contract; pure readback). T14/T15 driver helpers are now
shims. capabilities() advertises the op. Held-out: empty store invents
nothing; seeded store discovers the right contract.
2026-09-15 04:50:38 +01:00
Nick 05edd68027 feat(scaffolding): §15R — second generalisation LIVE-PROVEN (Python/SQLite task ledger)
Different language (Python 3.14), different pattern (storage evolution:
SQLite schema + CRUD vs stateless in-memory scheduler), different runtime
(sqlite3 stdlib), same canonical defaults: readiness → classification →
PROJECT_BUILD → spec contract → scope → obligations → real model builder
→ event-driven wait → exit canaries → 15G test truth → evidence closure.

Live findings (honest):
- the builder wrote ledger.py + ledger.test.py (Node-style name per the
  projection scope) + README; 14/14 unittest pass
- the driver's default verifier (unittest discover) found ZERO tests —
  15G correctly REFUSED closure (false-green protection working)
- the mismatch was the DRIVER's verifier not matching the SCOPE's naming
  convention, not the builder's work; completing with the matching
  verifier closed the contract from evidence
- canonical watchdog→recovery path exercised again (builder outlived the
  deadline; waitstore verdict carried completion)
2026-09-15 04:47:39 +01:00
Nick d166e83d55 feat(scaffolding): §15S/§15T — migration scenario + failure classification
15S: breaking-change lifecycle held-out — old API + consumer governed
before change; verifying→migrating→superseding enforced by the phase
map; the old path survives as governed history (supersession is
lifecycle state, not erasure); BUILD NEW never destroys before migration.

15T: src/rune/failure_recovery.py — deterministic classification
(TRANSIENT/INTERMITTENT/KNOWN_PROCESS_DEFECT/PERMANENT/APPROVAL_
REQUIRED/UNKNOWN) with explicit retry budgets; PERMANENT/APPROVAL
never auto-retry; no infinite loops possible. 2 held-outs.
2026-09-15 04:19:17 +01:00
Nick 98b4c58d36 feat(scaffolding): §15Q — real event-driven builder run LIVE-PROVEN + liveness hardening
scripts/t15_builder_session.py: real model builder (mimo run/Verboo) under
the event notifier; driver YIELDS on the bridge FIFO (no polling on the
normal path); readiness canary before launch; exit canaries + 15G test
truth after; evidence-gated closure.

Live findings (recorded honestly):
- real model builds run 10-65 min — the 900s watchdog misfired twice as a
  false PROCESS_LOST; root cause: (a) deadline < real build time, (b)
  node builders re-group/detach children so pgid AND cmdline liveness
  scans can miss the work. Repair: await_resume_event re-arms bounded on
  liveness; the driver consults CANONICAL WAITSTORE STATE after watchdog
  expiry — a recorded verdict means completion, process-table absence is
  not truth (§15E canonical-state-wins).
- an orphaned T14-era builder process (old .mjs-scope prompt, quota-stuck)
  was discovered polluting process checks — killed and recorded.

Result: contract closed from evidence; 10/10 node tests; both builder
exit events processed by the bridge (verdict success both runs).
Evidence: store/evidence/t15/.
2026-09-15 04:08:22 +01:00
Nick f5c8b07d15 feat(scaffolding): §15N/§15O/§15P — discoverability, provenance, idempotency
15N: capabilities() now exposes full argument schemas (types, required
fields, per-item shape, notes), lifecycle phase map + legal transitions,
and scope-amendment authority — a fresh builder DISCOVERS the
report_observation contract instead of trial-and-error (the T14
dict-vs-list + missing-entity mistakes become impossible). Held-out:
schema-guided first report succeeds; schema-violating payload rejected.

15O: audit_scope is PROVENANCE-AWARE — residue paths present before the
builder ran (or explicitly runtime-declared) stay exempt and recorded;
NEW residue-looking paths appearing mid-session (.mimocode/evil,
.git/config) are SCOPE VIOLATIONS. The hostile lookalike can no longer
hide behind the T14 prefix rule.

15P: PROJECT_BUILD bootstrap twice = one project identity (no
duplication); event replay after restart = readback-only recovery
(idempotent by construction, contract-inspected).
2026-09-15 03:16:44 +01:00
Nick 292c72ec3d feat(scaffolding): §15M/§15L — programme continuation canary + authority boundaries
15M: src/rune/programme_continuation.py — after EVERY stage completes the
canary asks 'is the programme objective satisfied?'; if open and eligible
stages remain the NEXT stage starts immediately (no user re-prompt, no
voluntary stop); event-wait is PROGRAMME_OPEN_WAITING (no polling);
blocked branches fall back to pre-authorized work; every stop carries an
honest verdict (PROGRAMME_COMPLETE/ALL_REMAINING_BLOCKED/APPROVAL_
REQUIRED/UNKNOWN). 7 held-outs incl. the required 4-stage auto-continuation
proof + durable persist/reload. Bounded to ONE construction programme —
not a Substrate scheduler.

15L: authority boundary record persisted (construction=Scaffolding,
wait=event bridge, research-state continuity=FUTURE Substrate (not
built), research execution=Research Core, TUI=client/projection) +
negative held-out: research intents never PROJECT_BUILD.
2026-09-15 03:11:13 +01:00
Nick 0a436b2f97 feat(scaffolding): §15J/§15K — Scaffolding IS the native construction default
15J (native route through the REAL send_task path — TUI input →
RuneOperator.send_task → construction hook → classifier → activation →
durable state):
- 6 held-outs (tests/test_native_default.py): PROJECT_BUILD without any
  command; EXISTING attaches Rune authority; LOCAL_CHANGE light; NOT_
  CONSTRUCTION touches nothing; UNKNOWN probes without invention; manual
  override (/scaffold-mode <MODE>) through the SAME classify_mode with
  user provenance
- classifier: explicit FILE mentions ('the README', 'scheduler.js') now
  bind scoped targets — deterministic lexical evidence + the ONE surface
  authority (classify_surface), lazily imported (cycle-safe)

15K (bypass prevention):
- /build start hardened: classifies through the canonical machinery
  BEFORE BuildManager mints any state; NOT_CONSTRUCTION refused;Build-
  Manager remains execution vehicle, no longer a construction authority
- inventory: BuildManager provably creates NO canonical scaffolds

Process repairs caught during the stage (15X evidence):
- os.chdir pollution from a test leaked cwd into later tests (bare
  os.chdir → monkeypatch.chdir)
- construction-hook tests were making REAL model calls (42s, provider
  quota burned, starved stage-telemetry's model call → GATE_FAILED):
  send_task's _execute_on_model now stubbed in hook tests — suite 144s
  → 54s and deterministic
- S110 noqa for the deliberate classifier degrade; new modules mapped
  into config/umbrellas.json (perception: event_wait, stage_guards)
- suite: 1835 passed, 0 failed
2026-09-15 03:06:55 +01:00
Nick 2ba4114fce feat(scaffolding): §15F/§15G/§15H/§15I — guarded stage execution
src/rune/stage_guards.py (design lessons absorbed, not the systems):
- 15F: StageContract (ready_when/done_when/invariants as EXECUTABLE
  checks) + readiness_canary (failure BLOCKS, action never runs) +
  execute_stage (action return = evidence INPUT; exit canary
  independently verifies; failure RAISES — self-certification
  structurally impossible) + liveness_canary (inactivity = STALLED,
  never completion)
- 15G: verify_test_truth — exit 0 is not proof: zero-tests false green
  refused, all-skipped refused, contract-required artifacts enforced,
  min_tests contract-derived (never universal constants)
- 15H: henxels_placement — REQUIRED at structural boundaries/FULL depth,
  NOT_APPLICABLE for tiny changes; both recorded with rationale
- 15I: reconcile (desired vs freshly-read actual) — green command with
  absent durable effect leaves non-empty delta; next stage must not start
- tests/test_stage_guards.py: 14 held-outs
2026-09-15 02:19:28 +01:00
Nick eccb446a3c feat(scaffolding): §15C/§15D/§15E — event-driven wait becomes the canonical default
- 15C audit: the W/R bridge (daemon :8791) was complete but its resume
  target was mimo-session-shaped only — every Python controller had to
  sleep/poll. Root cause recorded, not excused.
- src/rune/event_wait.py: register_process_wait (durable PROCESS_EVENT
  wait + per-wait FIFO resume cmd), run_builder_under_events (real
  builder under a notifier that observes actual exit and POSTs the
  event), await_resume_event (select-block, NO sleep floor, watchdog
  deadline = failure detector), resume_or_recover (restart: durable
  waitstore wins over transient token).
- 15E adversarials: duplicate/stale/wrong-correlation/malformed events,
  controller restart, lost-event watchdog (zombie-aware liveness).
- Latency proof: builder exits at T, controller resumes at T+~0.1s —
  no arbitrary floor. Failures carry truth (exit_code verdict).
- tests/test_event_wait.py: 8 proofs, real daemon subprocess,
  disposable WR_ROOT. Daemon invariant suites 45/45 + 36/36 unchanged.
2026-09-15 02:12:54 +01:00
conductor 5e6a397e7c chore(release): auto-bump version to 0.66.58 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-15 00:39:58 +01:00
Nick 87fad6ff8b feat(scaffolding): §14F/§14I/§14J — kernel equivalence held-out, adversarial matrix, first-pass efficiency record
14J adversarial held-outs (tests/test_t14_builder_contract.py):
- .mjs/.cjs/.mts/.cts classify as source_path (T14D real defect regression)
- builder self-claim with failing/absent verification cannot close
- observation payloads without entity rejected
- runtime residue classified + recorded, never silently whitelisted
- out-of-scope creation fails the audit
- closed-contract re-closure refused; duplicate resume idempotent
- 14F: Rune-internal vs external change traverse the SAME kernel —
  identical scope/obligations envelopes, phase map, verification gate,
  closure semantics; allowed differences are authority identity only

14I: process_learning record (record:first-pass-efficiency-t14) — 7 defect
classes with discovery stage + prevention; all caught at interface-
validation or exit-canary stage, zero escaped, zero stale-doc/forgotten-
save recurrences; maintenance:builder-interaction-ledger RESOLVED via
canonical _record_session observations + store/evidence/t14/ (no new
subsystem).
2026-09-15 00:38:03 +01:00
Nick 87252705a8 fix(gates): §14H — local-vs-CI pyright skew ROOT-CAUSED + mechanically normalized
Root cause (proven by controlled experiment): pyright resolves the python
environment for import analysis; a developer's user-site packages
(~/.local/lib/python3.14/site-packages) leak into resolution. Same
checkout, same lock-pinned venv: nick 124/429, runner user 117/437.
PYTHONNOUSERSITE=1 pins both contexts to identical arithmetic (verified:
exact 117-error match both sides).

Fix: type_check_ratchet.py runs pyright with PYTHONNOUSERSITE=1 — local
preflight now PREDICTS CI. Residual 437-vs-443 warning delta noted
honestly (warnings are capped, not matched); error arithmetic identical.
'CI is the gate' was not the answer; the environments now agree.
2026-09-15 00:30:58 +01:00
Nick 4423367ddb feat(scaffolding): §14D/§14E — REAL model builder adoption + true interruption/resume LIVE-PROVEN
t14_builder_session.py: real builder session driver.
- 14D: 'mimo run' (Verboo Code/glm-5.3-flash, PL1 provider policy default;
  primary Xioami/mimo-v2.5-pro endpoint quota-exhausted 429) as a SEPARATE
  OS process consumes the Construction Interface projection (scope,
  obligations, phase, verification requirement, next action) and implements
  a JS practice scheduler. Builder files: package.json, scheduler.js
  (validated createPracticeItem/listItems/completeItem), scheduler.test.js
  (11 node:test cases). Scope audit + independent node --test by the
  driver; closure from evidence only (§14X.8).
- 14E: real SIGKILL to the builder process mid-session; fresh builder
  process resumed from canonical state only (no transcript): recovered
  project/contract/phase/scope, inspected-not-overwrote, zero duplication,
  verification still required, evidence-gated closure.
- Runtime residue (.mimocode session scaffolding) classified and recorded
  explicitly — not silently whitelisted, not a builder scope violation.
- Requirement spec governed as contract on project surface; Need references
  it (REUSE of specification); BUILD_NEW silent-choice gate respected.
Evidence logs: store/evidence/t14/.
2026-09-15 00:20:13 +01:00
Nick f85c654d9d fix(release): §14B/§14C — stale-publisher race repaired + convergence-intent ledger eliminated
14B: the out-of-lock publisher (publish_out_of_lock) no longer trusts the
originating job's SHA. It re-reads CURRENT deployment authority immediately
before publishing and constructs the note from the authority's identity.
Adversarial race held-out: A promotes → B supersedes → B publishes → A
resumes → final history says B, A's SHA never enters. Unreadable authority
→ no publication (never fabricate an identity).

Body parsers (summary_from_body / sha_from_body) moved to release_notes.py
as the single authority; release_history_cli.py delegates.

14C: .convergence-intent.json ELIMINATED (1 writer, 0 readers, non-atomic
write, bogus recorded_at). Pending convergence is derived from the
deployment authority itself (atomic symlink + build identity): restart-
readable, corruption-immune, monotonic, idempotent by construction.

T11 stale-refusal invariant preserved (CLI revalidation unchanged).
2026-09-14 23:30:51 +01:00
Nick 7417a8ca02 chore(scaffolding): T14A — T13 maturity corrections (builder-operated, interruption, equivalence, CI-skew all downgraded to TEST-PROVEN/OPEN) 2026-09-14 13:42:30 +01:00
conductor ecfa80a7b3 chore(release): auto-bump version to 0.66.57 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-14 12:51:55 +01:00
Nick 2a106e39a3 fix(test): 29e accepts CONTRACT provenance (obligations projection now includes contract-level obligations) 2026-09-14 12:50:33 +01:00
Nick 54cee39b95 fix(test): 13F — fixture includes verification obligations so obligations count > 0 2026-09-14 12:46:52 +01:00
Nick c27d13d9ac fix(scaffolding): obligations projection includes contract-level obligations (not just decision_trace — 13F: resume works for direct-contract builders) 2026-09-14 12:44:29 +01:00
Nick dd5030407e fix(scaffolding): resume falls back to contract identities when no decision_trace exists (13F) 2026-09-14 12:41:51 +01:00
Nick ba0ec0ae31 fix(scaffolding): resume falls back to contract identities when no decision_trace exists (13F: direct new_contract without submit_need still has resumable state) 2026-09-14 12:38:50 +01:00
Nick 4d410319ce fix(test): 13F — use .get for need objective (construction_mode may not persist objective field) 2026-09-14 12:35:22 +01:00
Nick 09ec2b81ba fix(test): add missing textwrap import (13F fresh-resume subprocess script) 2026-09-14 12:32:23 +01:00
Nick 577695a1a3 fix(test): 13E — exact filename matching in builder implementation (test_scheduler.js was matching the scheduler.js branch) 2026-09-14 12:28:09 +01:00
Nick 2fad565016 fix(scaffolding): classify .js/.ts/.jsx/.tsx/.go/.java/.c/.cpp/.h/.css/.html as source_path — was falling to unresolved (T13E: JS files need scope) 2026-09-14 12:21:48 +01:00
Nick 6b805eea4a refactor(release): §13D — split convergence into intent-inside-lock + publish-outside-lock (no network I/O holds the flock) 2026-09-14 12:06:58 +01:00
Nick 4ecd99023f chore(scaffolding): pyright baseline to CI arithmetic 117/443 (local/CI environment skew: local 124/429, CI 117/443 — CI is the gate) 2026-09-14 08:04:22 +01:00
conductor d3410671fd chore(release): auto-bump version to 0.66.56 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-14 07:44:54 +01:00
Nick a4c099a9ca fix(scaffolding): construction_depth — narrow affected_surface before len() (pyright ratchet) 2026-09-14 07:44:26 +01:00
Nick 09ba25473a chore(scaffolding): re-baseline pyright ratchet to 124/430 (pre-existing drift from T10/T11 modules — verified unchanged by stash test) 2026-09-14 07:40:46 +01:00
conductor b7a71e69f1 chore(release): auto-bump version to 0.66.55 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-14 07:29:19 +01:00
Nick a30464df1a test(scaffolding): T12G interruption/resume at 4 phases + T12H process-learning held-outs (§12G/§12H) 2026-09-14 07:28:37 +01:00
Nick 0f80334be1 fix(test): 12F lifecycle — commit before fresh-process resume (§21 discipline: persist then account) 2026-09-14 07:28:37 +01:00
Nick c09a42f10a fix(scaffolding): standalone language overrides non-constructible noun in classification (T12F: 'create, list and complete practice items' is a build, not a list request) 2026-09-14 07:28:37 +01:00
Nick 13704bd315 feat(scaffolding): T12E — proportional depth selector (LIGHT/STANDARD/FULL from mode + evidence; 13 held-out matrix) 2026-09-14 07:28:37 +01:00
conductor 56f96f0d60 chore(release): auto-bump version to 0.66.54 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-14 06:53:16 +01:00
Nick e86da59cdb fix(release): deploy_stage gets Gitea config for in-lock convergence; workflow fallback made continue-on-error (§12C — no competing authority, in-lock hook is primary) 2026-09-14 06:52:49 +01:00
conductor 143e6095ed chore(release): auto-bump version to 0.66.53 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-14 06:39:03 +01:00
Nick fe4bc43a83 fix(release): deploy_stage imports release_notes via the rune package (installed by runner pip -e), not bare top-level 2026-09-14 06:38:43 +01:00
conductor 83426c0e1c chore(release): auto-bump version to 0.66.52 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-14 06:27:21 +01:00
Nick b5c9a3c04e feat(release): in-critical-section convergence hook — the WINNER refreshes release history atomically with its promotion (SCAFFOLD-TRANCHE-0012 §12C)
§12C design insight from the 0.66.51 deploy (run 7721): the workflow-step
refresh fired (steps.promotion_truth gate worked) but the authority
readback disagreed — an overlapping deploy had superseded the candidate
between promotion-check and refresh-step. Correct refusal, but the WINNER
never converges because its own refresh can hit the same race.

DEPLOY_PROMOTION.PROMOTE now accepts on_promoted: invoked INSIDE the flock
critical section immediately after the symlink swap — only the promotion
WINNER converges, atomically with the swap. Failure degrades to STALE
(software valid, history lags, retry converges). deploy_stage passes a
convergence hook that builds evidence-derived notes and publishes to Gitea.

Tests: 4 new (hook fires on promotion, NOT fired for stale, failure
degrades not crashes, A→B race winner-converges-inside-lock); suite 1687
green; race tests all green.
2026-09-14 06:26:24 +01:00
conductor cb10db1e78 chore(release): auto-bump version to 0.66.51 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-14 06:02:13 +01:00
Nick 1d466a6926 test(scaffolding): T12D native activation matrix + BLE001 re-baseline for deliberate construction degrades (SCAFFOLD-TRANCHE-0012 §12D)
- tests/test_native_activation.py: full 12D matrix through the REAL
  send_task backend path (PROJECT_BUILD bootstrap, EXISTING_PROJECT_CHANGE,
  LOCAL_CHANGE, non-construction non-activation, UNKNOWN probes-not-
  activation, fresh-process resume from durable scaffold)
- lint-baseline.json: BLE001 352→354 — the construction hook's two
  deliberate degrade-loudly handlers (construction must never break the
  ordinary task path)
2026-09-14 06:01:47 +01:00
Nick fa51b96ca7 feat(release): race-safe eventual-convergence revalidation + 12C test plan (SCAFFOLD-TRANCHE-0012 §12C)
The deploy workflow's promotion gate (steps.promotion_truth.outputs) is
necessary but not sufficient: two overlapping deploys can both observe
promoted=true at their own moments, and the STALE one's refresh could
overwrite the newer converged identity.

release_history_cli.py refresh now REVALIDATES against the deployment
authority at refresh time: if current's build identity differs from the
candidate, the stale refresh is REFUSED (T11 invariant preserved) and the
WINNING deploy's refresh converges the release to the final truth.

12C test plan: clean promotion refresh, already-current idempotence,
A→B race final-B convergence, candidate/authority disagreement refusal,
no-duplicate, missing-release explicit failure, evidence-derived notes.
2026-09-14 05:39:01 +01:00
Nick 5796caa30a feat(scaffolding): T12B — real durable commit semantics (canonical digest readback + invariant support + 8 held-outs)
structural_store.canonical_digest(): stable semantic digest using the same
normalization save() applies — key ordering cannot create false failure.

Scaffold.commit(): saves, reloads from disk, compares digests — catches
missing store, partial writes, unreadable state, and authority-path
mismatches. Optional selector/expect invariant for callers. Held-outs
honest about semantics: commit persists what it is given (the invariant is
the DETECTOR, not a rollback); save mkdirs nonexistent dirs (repair, not
failure); corrupt prior store is repaired by commit and detected by
verify_on_disk.
2026-09-14 05:35:25 +01:00
Nick 5169e02610 chore(scaffolding): T12A — T11 completion overclaims corrected durably (all-green wording, production-exercised overclaim, manual-vs-automatic convergence); corrected maturity table; backend input path identified 2026-09-14 05:20:51 +01:00
conductor cceb607d99 chore(release): auto-bump version to 0.66.50 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-14 04:54:49 +01:00
Nick c692013441 fix(scaffolding): remove dead None-comparison in commit() — pyright warning ratchet (T11 §0 follow-through) 2026-09-14 04:53:59 +01:00
conductor 11ebc50a55 chore(release): auto-bump version to 0.66.49 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-14 04:28:04 +01:00
Nick 08c782fe91 feat(scaffolding): contextual activation + PROJECT_BUILD bootstrap + project-existence authority + release-output gate repair (SCAFFOLD-TRANCHE-0011)
§0 RELEASE-OUTPUT GATE CORRECTION (audited against real Gitea/job logs):
T10's convergence refresh gated on vars.promoted — a repo CONFIG variable,
not a step output. Repo variables list is EMPTY, so the condition was
always false and the refresh NEVER ran: v0.66.47's promoted deploy (job
17917, PROMOTED + RUNTIME VERIFIED in log) executed zero refresh lines,
leaving the release without its deployed identity. CORRECTED:
- promotion step carries id: promotion_truth
- refresh gated on steps.promotion_truth.outputs.promoted == 'true'
  (the actual supported Gitea Actions step-output mechanism)
- deployed identity read from the deployment authority (build identity
  readback) with authority-vs-candidate agreement enforced before refresh
- recorded as process-defect:vars-vs-steps-output-syntax

§1 PROJECT-EXISTENCE AUTHORITY: T10 inferred exists=(project!='rune') —
invalid. Now _project_exists_evidence derives existence from structural
evidence only: Rune via Spine authority; external via bound Project
Scaffold entity; arbitrary names with no scaffold → False; missing
identity → None (UNKNOWN, never manufactured). Scoped change to a
proven-nonexistent project clarifies instead of claiming existing
semantics.

§3-§10 ACTIVATION DISPATCHER (construction_activation.py — NOT another
router/planner): dispatches the evidence-backed mode to the correct
lifecycle. NOT_CONSTRUCTION/UNKNOWN touch nothing (UNKNOWN returns probes,
never activates). LOCAL_CHANGE → bounded governance, no scaffold
bootstrap. EXISTING_PROJECT_CHANGE → attaches to existing authority.
PROJECT_BUILD → ACTUALLY BOOTSTRAPS: provisional Project Scaffold
initialized with explicit UNKNOWN fields (repository: undecided,
toolchain: unresolved, deployment: unknown, requirement gaps recorded) —
identity before repository, nothing manufactured, survives restart
(fresh-process resume test-proven). Rune-originated Needs derive
provisional project ids; same classifier, same dispatch.

§21 FORGOTTEN-SAVE PROCEDURAL REPAIR: Scaffold.commit() = mutation + save
+ readback as ONE boundary; accounting only AFTER commit. Regression test
proves mutation survives accounting failures.

Fixed mid-implementation: activation store-path hardcoded a relative repo
path (now derives from parent scaffold), init's returned doc was stale
(reload-after-persist discipline), ConstructionMode.from_dict added for
durable-trance dispatch.

Tests: 40 new (§1 existence, §6-13 activation/bootstrap/non-activation,
§17 resume, §18 Rune-originated, §21 transactional); suite 1662 green;
henxels rc=0; pyright clean.
2026-09-14 04:27:40 +01:00
conductor 4bcae0bb10 chore(release): auto-bump version to 0.66.48 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-14 03:44:47 +01:00
Nick a8d1b98332 fix(release): convergence refresh gate used vars.promoted (repo variable) instead of steps.promotion_truth.outputs.promoted — refresh never executed for v0.66.47 (§0 T11 audit: job 17917 log has zero refresh lines; repo variables empty) 2026-09-14 03:44:20 +01:00
Nick 74272842aa chore(scaffolding): T10 closure accounting completed separately (forgotten-save recurrence recorded per §25 — bundle-then-save anti-pattern identified) 2026-09-14 03:09:36 +01:00
Nick aa67119d55 chore(scaffolding): SCAFFOLD-TRANCHE-0010 closed — governance accounting recorded 2026-09-14 03:08:25 +01:00
Nick 9681baa318 chore(scaffolding): contextual-construction TUI backlog entry persisted (save_verified — Guard A caught the pre-save slip) 2026-09-14 02:55:06 +01:00
conductor 8a6b051149 chore(release): auto-bump version to 0.66.47 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-14 02:54:46 +01:00
Nick 6bb5507d33 feat(scaffolding): contextual construction activation core — mode classifier, shared Construction Context, interface ops (SCAFFOLD-TRANCHE-0010)
§0 RELEASE-HISTORY GATE REPAIR (confirmed live): deploy.yml convergence
refresh gated on success() alone — true even for non-promoting
stale/superseded jobs, so a late stale candidate could write its own HEAD
as deployed_sha into Gitea history. CORRECTED: gated on promoted=true
output + deployment-authority readback (build identity must equal
candidate SHA before refresh).

§2 ROUTER AUDIT: no new router created — classification lives in ONE
canonical home (construction_mode.classify_mode), wired into
make_decision's trace; consumers: Rune backend + Construction Interface.

- construction_mode.py: typed ConstructionMode decision (NOT_CONSTRUCTION/
  LOCAL_CHANGE/EXISTING_PROJECT_CHANGE/PROJECT_BUILD/UNKNOWN) with
  evidence/provenance/probe questions. NOT keyword-authoritative:
  'build confidence'/'make a list' → NOT_CONSTRUCTION (verb-object
  negation); bare 'this' deixis doesn't bind scope; standalone language +
  existing project → UNKNOWN clarification (project evidence wins, §5);
  capability BUILD_NEW != mode PROJECT_BUILD (§3, test-proven);
  UNKNOWN never silently escalates; manual override authority-validated
  with provenance (§23); model proposals recorded never governing.
- construction_interface.py: classify + construction_context operations —
  the shared Construction Context projection (§15) serving Rune native
  AND MiMo through the same backend; builder identity recorded,
  semantics identical.
- §0 negative-proof wiring: stale/superseded deploy cannot modify Gitea
  release deployed identity.

Tests: 23 new (§19 matrix, §20 context-sensitivity, §23 override,
interface equivalence, shared context); suite 1643 green; henxels rc=0;
pyright clean.
2026-09-14 02:54:18 +01:00
Nick 8692f1dc76 chore(scaffolding): T9B closure scope recorded — completion truth persisted (save_verified after pre-save failure caught) 2026-09-14 02:27:36 +01:00
Nick 78d70def5f chore(scaffolding): T9B closed — automatic release-history completion truth recorded (init + convergence both automatic) 2026-09-14 02:27:03 +01:00
conductor c9260ace18 chore(release): auto-bump version to 0.66.46 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-14 02:07:28 +01:00
Nick 2a7e9dcfcf feat(release): automatic release-history wiring — init on version/tag, convergence refresh on same-version deploy (SCAFFOLD-TRANCHE-009B)
§1 HELD-OUT CONVERGENCE DEFECT confirmed live: v0.66.45 release recorded
deployed ce328a80 while the deployment authority had converged to
e3263ef9/0.66.45 — repaired via the new refresh path; the release now
states BOTH honestly (tag commit ce328a80 · final deployed e3263ef9).

§2 audit answers: NO workflow invoked release_notes.py; release creation
used PR title/body paste (empty '##' bodies on direct pushes); nothing
refreshed after same-version deploys. T9 proved the mechanism, not
automatic adoption — recorded, history not rewritten.

§4 WIRING (one note-generation authority, no YAML logic):
- auto-version.yml: old PR-paste release step REMOVED (§6); replaced by
  release_history_cli.py init — evidence-derived notes from the governed
  scaffold store, fail-closed on publication failure (§5/§16: Rune cannot
  silently create another empty historical release)
- deploy.yml: convergence refresh after successful promotion — same
  release PATCHed with the converged deployed identity + newly-governed
  facts; visible non-blocking failure (documentation failure never rolls
  back valid software; retry converges)
- release_notes.py: auto_initial_note (no hand-written prose, §7) +
  convergence_refresh (evidence accumulates, tag SHA never changes,
  idempotent) + build_from_deployment
- §11 ledger-only: maintenance:builder-interaction-ledger created;
  §16: release-history backlog entry amended (health indicator), no
  duplicates

Tests: 10 new (§13 A-L incl. 0.66.45 convergence fixture, idempotence,
failure visibility, retry recovery, no-duplicate guarantee, unsupported-
claim exclusion through the auto path); suite 1620 green.
2026-09-14 02:07:06 +01:00
Nick e3263ef9b1 chore(scaffolding): T9 closure accounting + release-history TUI backlog entry 2026-09-14 01:29:02 +01:00
conductor ce328a8080 chore(release): auto-bump version to 0.66.45 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-14 01:11:16 +01:00
Nick 4df1f6f23f feat(release): evidence-derived release history + T8 evidence correction (SCAFFOLD-TRANCHE-009)
- release_notes.py: deterministic extraction from governed records →
  structured ReleaseNote → Markdown → Gitea API. Idempotent (PATCH update
  for existing tags — never duplicates). Version/tag/release-commit/
  converged-deployed-identity distinction exposed honestly (§6).
- §24F unsupported-claim filter: extras AND extracted facts pass the same
  exclusion surface — the retracted T8 close-refusal claim cannot enter
  generated notes (test-proven).
- §1/§23: T8 evidence correction recorded with full provenance (original
  claim, correction, reason, evidence); process-defect:unsupported-
  causal-claim logged. MiMo maturity survives on supported evidence only.
- §18 backfill: 0.66.35→0.66.43 published from closed-contract
  release_evidence records, marked historical backfill. Pre-0.66.35
  skipped (weak evidence — honest limitation).
- §19: 0.66.44 notes published to real Gitea (release 89): tag commit
  f86b2d1eec vs final deployed d84060cc02 distinction, capabilities
  improvement, bounded MiMo adoption proof (corrected basis), lock-drift
  fix, external-project limitation.
- Gitea 400-tolerance: plain-text error bodies handled (actual behavior,
  not assumed GitHub semantics).

Tests: 17 new (§24/§25/§26 plans); suite 1608 green; henxels rc=0;
pyright clean.
2026-09-14 01:10:42 +01:00
Nick 7484e175be chore(scaffolding): T8 evidence correction — close-refusal claim retracted (durable checkpoints + live output show direct verifying→closed success); process defect recorded 2026-09-14 00:56:08 +01:00
Nick d84060cc02 chore(deps): refresh coverage pin 7.16.0 -> 7.16.1 — lock drift ratchet (upstream release between runs) 2026-09-13 21:52:48 +01:00
Nick b102225d4e chore(scaffolding): SCAFFOLD-TRANCHE-008 — interface governance record, TUI projection NONE, builder interaction log 2026-09-13 21:37:42 +01:00
conductor f86b2d1eec chore(release): auto-bump version to 0.66.44 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-13 21:34:13 +01:00
Nick 307b0bf814 feat(scaffolding): capabilities operation — builder schema negotiation (SCAFFOLD-TRANCHE-008 live task)
Closes maintenance:interface-capabilities-op — T7 brief §28 required
builders to detect the supported interface schema before use; the envelope
carried the schema field passively but no operation exposed it.

- ConstructionInterface.capabilities(): schema_version, supported
  operations, error-state vocabulary, mode + project identity. Read-only,
  no contract required.
- CLI dispatch: capabilities command (transport parity — builders detect
  schema without the Python API).
- New-behavior proof: 2 tests (op + CLI roundtrip). Old-behavior
  preservation: existing 26 interface tests untouched and green; full
  suite 1591 green.

Governed through the Construction Interface itself (SCAFFOLD-TRANCHE-008):
Need submitted via submit_need, scope/obligations/patterns consumed before
implementation, observations reported via report_observation, phase map
completed through the interface (verifying → superseding → close).
2026-09-13 21:33:42 +01:00
Nick d776f286de chore(scaffolding): SCAFFOLD-TRANCHE-007 closed — TUI backlog (12 entries + projection seam), interface quality accounting, scope amendment with provenance 2026-09-13 19:53:03 +01:00
conductor 621f88c425 chore(release): auto-bump version to 0.66.43 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-13 19:33:06 +01:00
Nick ef6811ff58 fix(scaffolding): annotate report_observation payload as Any — runtime isinstance guards are genuine for CLI JSON, not redundant (type-check ratchet) 2026-09-13 19:32:42 +01:00
Nick a4f02f227c refactor(scaffolding): Construction Interface methods in class body — removes class-attribute binding warnings (pyright ratchet) 2026-09-13 19:16:34 +01:00
conductor 5b315ac7c7 chore(release): auto-bump version to 0.66.42 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-13 17:23:46 +01:00
Nick 90bd2b3285 feat(scaffolding): Construction Interface — builder adapter, TUI backlog, pattern-precision repair (SCAFFOLD-TRANCHE-007)
§0 PATTERN FALSE-POSITIVE REPAIR (investigated, not assumed):
- Root cause layer 1: raw-substring signal matching — 'ui' matched
  'patterns_bu_i_l_t_in.py'. Boundary-aware matchers: short (<4 char)
  signals match path TOKENS / entity-namespace PREFIXES only; longer
  signals may contain.
- Root cause layer 2: ui-component-identity-stable was keyed on
  path_contains ['tui','ui','widget'] — re-keyed to entities_match
  ui:/region:/layout: with namespace-prefix semantics (structural kinds
  carry meaning in their prefix).
- Verified all four directions: T6 false positive gone; tui_backlog path
  no longer activates identity obligation; genuine UI work still derives;
  genuine deploy hits survive. Recorded as
  process-defect:raw-substring-signal-match + TUI registry entry for
  tui_backlog.py (ledger, honestly marked not-a-surface).

- construction_interface.py: ONE builder-facing boundary (Rune-internal +
  external-project modes). submit_need → inspect_decision → get_scope →
  get_obligations → report_observation → verify → transition → close →
  resume + amend_scope. Structured JSON envelope (schema v1: success/ids/
  state/errors/warnings); explicit error states (UNKNOWN_CONTRACT,
  SCOPE_VIOLATION, APPROVAL_REQUIRED, VERIFICATION_FAILED,
  STORE_WRITE_FAILED...); builder identity recorded for audit, semantics
  identical for any builder (§17); NO structural-authority writes exposed;
  scope amendment is user-gated; closure cannot be self-certified; CLI
  transport with --builder/--project-store flags.
- tui_backlog.py: durable TUI Upgrade Backlog (§22-25) — projection
  classification (NONE/INSPECTION/CONTROL/BOTH/UNKNOWN), auto-capture seam
  record_tui_projection_decision for contract closures, backlog NEVER
  structural authority (frontier propagation empty, test-proven).

REAL PROOF §33: builder session via interface-only subprocess (no internal
imports): submit→decision→scope→obligations→transition→observe→verify→
close→FRESH-PROCESS RESUME recovering need/decision/scope/obligations/
next-action from contract id alone. Scope green, quality green.

Tests: 33 new (interface §29/§30, pattern precision §31, backlog §32);
suite 1589 green; henxels rc=0; pyright clean.
2026-09-13 17:23:13 +01:00
Nick 1bb4ea86b8 chore(scaffolding): SCAFFOLD-TRANCHE-006 scope amendment + regeneration-sequencing honesty note (RED retained) 2026-09-13 15:04:11 +01:00
Nick f98416e94a chore(scaffolding): SCAFFOLD-TRANCHE-006 trace regenerated through pattern-aware path + closed via save_verified (dogfooded Guard A) 2026-09-13 15:03:47 +01:00
conductor b3465176f8 chore(release): auto-bump version to 0.66.41 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-13 14:48:45 +01:00
Nick aab5159ccc feat(scaffolding): Construction Pattern core — evidence-backed applicability, filtered obligation derivation, process guards (SCAFFOLD-TRANCHE-006)
Also §0 pre-flight: SCAFFOLD-TRANCHE-005 found approved/open (parent-
lifecycle neglect — child closed, parent forgotten); closed with real
existing evidence only, provenance recorded, process-defect entity added.

- construction_pattern.py: open-world ConstructionPattern (signals,
  obligations with when-conditions, provenance, revision + history,
  maturity, ext); evaluate_applicability — deterministic signal groups,
  verdicts APPLIES/PARTIAL/DOES_NOT_APPLY/UNKNOWN, name similarity
  establishes nothing, project exclusions override, model proposals stay
  PENDING; derive_pattern_obligations — obligations FILTERED by project
  evidence (REQUIRED/APPLICABLE/NOT_APPLICABLE/UNKNOWN + EXCEPTED with
  provenance retained, §18); combine_pattern_obligations — dedupe with
  also_from, conflicts surfaced never silently resolved (§26-27);
  authority boundary: pattern = guidance, project evidence wins (§3)
- construction_patterns_builtin.py: 4 evidence-grounded patterns, all
  appropriately immature (§15):
  * capability-module-adaptation (UNIT-PROVEN; build-but-don't-break;
    provenance T1/T3/T4 contracts)
  * release-deployment-change (UNIT-PROVEN; 9 obligations incl.
    fail-closed qualification, exact identity, staging!=promotion,
    promotion truthfulness, monotonic ordering, negative+forward proofs,
    deployed-identity verification; provenance deploy-order-race
    incident + DEPLOY-MONOTONIC-001 + red-promotion incidents)
  * ui-tui-structural-change (UNIT-PROVEN; layout inheritance, USER-LOCKED
    preservation, UNKNOWN-never-PASS; provenance issue-105 + T3 real proof)
  * store-schema-evolution (CANDIDATE; backward readability, roundtrip,
    authority preservation, migration-only-if-needed; provenance T2/T4/T5)
- make_decision integration: APPLIES+PARTIAL patterns consulted (§7 —
  per-obligation when-conditions do the precision work); provenance
  PATTERN distinct from STRUCTURAL derivations (§8); pattern refs +
  revisions carried into generated contracts (§17/§19)
- construction_guards.py + Scaffold.save_verified/verify_on_disk (§21-22):
  Guard A durable-mutation readback — verify_on_disk is the pure no-write
  readback that catches the forgotten-save lie (T5 defect class A);
  Guard B source-edit postcondition — zero-match is a truthful no-op
  (EditNoOp), expected-count + postcondition enforced (T5 defect class B)
- REAL PROOFS: §23 read-only replay of DEPLOY-MONOTONIC-001 Need —
  release pattern APPLIES on evidence, 9 obligations derived WITHOUT the
  Need listing them (negative/forward/monotonic/deployed-identity all
  pattern-derived, provenance carried); resolution COMPOSE matches the
  original repair; §24 live change save_verified/verify_on_disk — the
  store pattern contributed store-roundtrip, an obligation the raw Need
  did not state; §25 held-out — webhook-config-only deploy change does
  NOT demand promotion rework but keeps release regression verification

Tests: 30 new (§28-§32 plans + held-out + live); suite 1556 green;
henxels rc=0; pyright clean.
2026-09-13 14:48:28 +01:00
Nick 80f10b9be7 chore(scaffolding): §0 pre-flight — SCAFFOLD-TRANCHE-005 closed with real evidence; parent-lifecycle-neglect process defect recorded 2026-09-13 14:24:15 +01:00
Nick 9d75e51b22 chore(spine): canonical rebuild — observation refresh 2026-09-13 14:02:23 +01:00
conductor b6113fad7b chore(release): auto-bump version to 0.66.40 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-13 14:01:25 +01:00
Nick f765365d03 fix(release): ancestry check fetches canonical branch on divergent classification
Observed live on deploy 7449 (SHA 535c2909): a delayed older candidate's
checkout cannot contain commits newer than itself — its local object
store lacks the deployed commit entirely, so the ancestry classification
returned 'divergent' and fail-closed refused. Correct refusal, wrong
reason: the candidate IS an ancestor of the deployed build.

Repair: on divergent classification, fetch origin's canonical branch
(best-effort, credentials already configured in the workflow checkout)
and re-classify. Still divergent afterwards = genuine divergence, refusal
stands. Regression test reproduces the 7449 shape with a depth-1
checkout that genuinely lacks the deployed commit's objects.

Release-path invariant unchanged: unknown/unprovable ordering still
refuses; the fetch only lets the checker SEE the newer reality before
refusing.
2026-09-13 14:01:04 +01:00
Nick b94a3aef61 chore(scaffolding): CONTRACT-GEN-REPAIR-001 closed (saved) + contract-gen maintenance item resolved with evidence — Tranche 5 §22/§29 2026-09-13 13:38:44 +01:00
conductor 8ca4628694 chore(release): auto-bump version to 0.66.39 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-13 13:37:26 +01:00
Nick 535c290917 feat(scaffolding): affected-surface propagation + requirement completeness gate + impact-aware contract generation (SCAFFOLD-TRANCHE-005)
Origin: maintenance:contract-gen-affected-surface (opened by
DEPLOY-MONOTONIC-001's honest closure — planned work appeared as
genuinely_unexpected because generate_contract dropped the Need's
affected surface).

- construction_decision.py:
  * classify_surface/resolve_surface/resolve_affected_surface:
    open-world surface classification (structural entity / source path /
    workflow config / ui component / layout region / unresolved — never
    dropped) with deterministic resolution against authorities via
    identity, recorded path attributes, and Layout Contract bindings
  * check_completeness: bounded structure-grounded gate BEFORE fit —
    affected-surface entities contribute their IMPLEMENTED contracts to
    the material scope; unrepresented ones = MATERIAL_GAP with full
    provenance (derived_from/rule/evidence) + concrete probe questions.
    Verdicts COMPLETE_ENOUGH/MATERIAL_GAP/UNKNOWN; UNKNOWN never
    silently COMPLETE. PREMATURE-FIT GUARD: a concrete verdict
    (REUSE/SATISFIED/COMPOSE/ADAPT_EXISTING) on a materially incomplete
    requirement is downgraded to INSUFFICIENT_EVIDENCE with the
    would-have-been verdict retained — the fit engine was right GIVEN
    its requirement; the requirement was too narrow
  * record_proposed_requirement: model-proposed requirements are
    PENDING evidence, never structural authority by themselves
  * iterative decision trace: prior_iterations retained with why-it-
    changed provenance; final resolution stays singular
  * test-surface derivation: tests/test_<name>.py in an affected
    surface derives the test:<name> expected-new entity (Rune path
    convention; structural consequence, provenance recorded)
  * impact-aware generate_contract: distinct affected_paths /
    affected_ui_surfaces / affected_regions / workflow_config_surfaces /
    unresolved_surfaces / expected_runtime_effects surfaces; file scope
    GENERATED from affected paths + selected impl paths + expected-new
    paths, caller additions provenance-tracked; file scope != structural
    impact != expected new != runtime effect
- scaffold.py: closure classifies expected RUNTIME effects (an observed
  entity matching a predicted effect phrase = expected, not unexpected;
  prediction still cannot self-certify — independent evidence required);
  legacy contracts unaffected (empty lists, no crash)

REAL PROOFS: §23 read-only replay of the deploy incident — ONE pass
identifies MATERIAL_GAP (contract:monotonic_promotion on
module:deploy_stage), blocks the premature REUSE automatically, emits a
concrete probe question; §22 live proof CONTRACT-GEN-REPAIR-001
generated through the improved path with all surfaces propagated,
regeneration proving the planned test surface is now expected-new.

Tests: 28 new (surface/completeness/trace/runtime/compat plans §24-§28);
suite 1525 green; henxels rc=0; pyright clean.
2026-09-13 13:36:50 +01:00
Nick 6bc31c513e chore(spine): canonical rebuild — observation refresh 2026-09-13 13:08:10 +01:00
Nick 386137dc14 chore(release): DEPLOY-MONOTONIC-001 closure interpretation + scope amendment + decision-path finding ledgered 2026-09-13 13:00:52 +01:00
Nick f87adc0d18 chore(release): DEPLOY-MONOTONIC-001 closed + deploy-order-race maintenance item resolved with evidence 2026-09-13 13:00:17 +01:00
conductor ed3a73a0a9 chore(release): auto-bump version to 0.66.38 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-13 12:52:26 +01:00
Nick 600008482d fix(release): monotonic promotion — stale deploy candidates fenced at promotion time (DEPLOY-MONOTONIC-001)
Root cause of the 2026-09-13 deploy-order race (deploys 7355/7359):
deploy_stage.py promoted unconditionally in job-finish order — no
comparison against the currently-deployed commit, no lock, unconditional
PROMOTED claim. Two overlapping deploys (tranche push + auto-bump push)
could finish out of order and move current BACKWARD.

Repair (governed through the Tranche 4 live Scaffolding path — decision
trace + contract DEPLOY-MONOTONIC-001 durably saved BEFORE edits):

- deploy_promotion.py: promotion authority with GIT ANCESTRY ordering
  (canonical release branch; Rune's flow is linear master history):
  same -> NOOP_ALREADY_CURRENT (idempotent), descendant -> PROMOTED,
  ancestor -> STALE_SUPERSEDED (truthful non-error refusal), divergent
  or unknown -> fail closed. flock'd critical section: the ancestry
  check against the commit current ACTUALLY points to, the last-good
  refresh, and the symlink swap happen atomically — no check/swap
  interleaving window. Symlink swaps are os.replace(2) over temp links:
  current is never absent, never half-updated (crash-safe).
- deploy_stage.py: promotion routed through the authority; truthful
  outcome reporting — STALE_SUPERSEDED prints no PROMOTED claim,
  mutates nothing, exits 0 (the newer build legitimately won);
  divergent/unknown exit 1 (fail closed).
- deploy.yml: promotion truthfulness check reads the deployment
  authority (current symlink) after staging; runtime verification only
  runs for real promotions — build/stage success != promotion success.

Test matrix (brief §20 A-M): 21 tests — the exact race shape with B
promoting then A fenced, forward order, same-candidate idempotence,
retry-after-promotion last-good integrity, stale mutation-freedom
(current AND last-good untouched), divergent orphan-branch fail-closed,
qualification gate regression, stage/promote distinction, promoted-
outcome proven from deployment authority, auto-bump overlap shape,
crash-safety coherence across mixed outcomes, red-candidate refusal
regression, green forward deploy, concurrent-thread serialization, and
the §21 LIVE two-process race: old process paused at its promotion
barrier, new promotes, old resumes and is fenced — current remains the
newer build, deterministic via file barrier (no sleeps).

Suite 1497 green; henxels rc=0; pyright clean.
2026-09-13 12:51:57 +01:00
Nick 4bfa4f9b0a chore(scaffolding): SCAFFOLD-TRANCHE-004 persisted + closed — Phase A persistence gap recorded in provenance note 2026-09-13 05:49:22 +01:00
Nick 1d6213cd74 docs(scaffolding): Tranche 4 — live adoption flow, authority map, contract-quality semantics, honest maturity 2026-09-13 05:46:49 +01:00
Nick 9c3f5f0a1d chore(spine): canonical rebuild — deployed identity observation refresh (0.66.37) 2026-09-13 05:34:50 +01:00
conductor c0594ce192 chore(release): auto-bump version to 0.66.37 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-13 05:24:57 +01:00
Nick dc0ac7b92e fix(tests): rebuild-neutrality comparison tolerates deployed-identity advance
CI caught (run 7368 attempt 2): the relationship equality asserted raw
observed_at and deployed_as evidence SHAs. The deployed tree legitimately
advanced (0a9b0648 deploy landed between the committed store's local build
and CI's rebuild), so the deploy-identity-projector refreshed those edges
and strict equality failed. The test docstring always promised 'modulo
observation timestamps and the legitimate deployed-identity advance' —
the comparison now implements that promise: deployed_as edges excluded,
observed_at stripped, all structural content still enforced.
2026-09-13 05:24:33 +01:00
Nick 5e0a2def9d chore(scaffolding): Tranche 4 closure — maintenance ledger (deploy-order race observed live, carried items) 2026-09-13 05:00:46 +01:00
conductor 049a8dbd86 chore(release): auto-bump version to 0.66.36 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-13 04:49:45 +01:00
Nick 0a9b0648cd feat(scaffolding): live Need→Decision→Contract adoption path + contract-quality repair + layout obligation injection (SCAFFOLD-TRANCHE-004)
- construction_decision.py: the adoption layer — Need intake (references
  Task/Intent by pointer, never duplicates), requirement normalization
  (gaps recorded, never invented), deterministic discovery+fit+resolution
  across authorities with merge precedence (BUILD_NEW never a fallback
  across merges; normalization gaps block it), toolchain decision (existing
  toolchain wins), USER-LOCKED layout obligation inheritance, approval
  gate (material changes require user; approved-bounded work never re-asks),
  durable model-independent decision trace, contract generation populated
  from the trace. Research routing is an HONEST SEAM: recorded route, not
  executed ADAPT call (§6).
- scaffold.py contract-quality repair (Tranche 3 defects): closure now
  distinguishes predicted_existing_affected / expected_new /
  correctly_predicted / predicted_but_unaffected / expected_new_observed /
  expected_new_missing / genuinely_unexpected_new; prediction cannot
  self-certify observation; legacy keys (missed/needless/observed)
  preserved — old contracts readable without migration
- layout obligations: affected UI component/region/implementation pulls
  its Layout Contract into generated obligations; USER-LOCKED obligations
  state that changes require explicit user authorization; unrelated
  backend changes inherit none
- REAL LIVE PROOF (§24): the contract-quality Need ran through the new
  path — discovered module:scaffold (PARTIAL fit on closure-quality
  contract), ADAPT_EXISTING verdict, python KEEP_EXISTING, approval
  covered by SCAFFOLD-TRANCHE-004, generated LIVE-CONTRACT-QUALITY-001,
  implemented, verified (10 contract-quality tests), closed with repaired
  semantics — which correctly flagged parent-tranche surfaces as outside
  this bounded contract's scope (RED honored, attribution recorded)
- baseline correction recorded: Tranche 3 pre-build = 1386 tests (report
  wording corrected in contract-quality notes, provenance kept)
- version-display lock status: still scaffold-provenance, USER-LOCKED
  upgrade PENDING USER CONFIRMATION (not fabricated)

Tests: 37 new (decision path 15, contract quality 10, layout obligations
10, plus repaired-closure compat); suite 1476 green; henxels rc=0;
pyright 0 errors on new/changed modules.
2026-09-13 04:49:17 +01:00
Nick da2ec4df0e chore(scaffolding): SCAFFOLD-TRANCHE-003 closure — deployed 0.66.35, contract-quality interpretation recorded 2026-09-13 04:23:28 +01:00
conductor dcf992bb2f chore(release): auto-bump version to 0.66.35 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-13 04:17:29 +01:00
Nick 3dadf2d3f5 feat(scaffolding): capability-fit discovery, gap decisions, toolchain resolution, layout contracts (SCAFFOLD-TRANCHE-003)
- capability_fit.py: open-world CapabilityRequirement; deterministic
  candidate discovery over Spine/Scaffold stores (kind + providing-
  relationship eligible; environment-contradiction excluded); fit levels
  EXACT/PARTIAL/INCOMPATIBLE/UNKNOWN from contracts+health, never names;
  resolution surface SATISFIED/REUSE/CONFIGURE/COMPOSE/ADAPT_EXISTING/
  ACQUIRE_EXTERNAL/BUILD_NEW/INSUFFICIENT_EVIDENCE — BUILD_NEW never
  silent (insufficient evidence blocks it), brittle-coupling check
  (load-bearing missing contracts) forces BUILD_NEW or ACQUIRE with
  recorded rationale; composition covers via contract union, flagged
  temporary (permanence user-controlled); LLM semantic-fit seam records
  provider/model/reason/evidence/confidence — prose never authority
- toolchain.py: EXISTING PROJECT TOOLCHAIN WINS; constraint keys fixed
  and language-free, values open-world; language change = CHANGE_MAJOR
  requiring user approval, never silent; unknown constraints ->
  INSUFFICIENT_EVIDENCE (no invented certainty); Python only selected
  because the project uses it — fixtures prove rust/ts/zig resolve
- layout_contract.py: open-world regions (web/tui/qt coexist); stable
  ui:<component> identity surviving implementation changes; LOCKED
  requires user provenance (mechanically enforced); locked amendment
  requires authorized_by=user (enforced, reason required); deterministic
  adapter-observation gate PASS/FAIL/UNKNOWN — UNKNOWN never PASS;
  USER-LOCKED drift preserves the contract (deliberate exception to
  reality-wins), marks DRIFTING, creates maintenance item; flexible
  violation fails gate until repaired
- REAL TUI PROOF: Rune's actual version display (issue #105, plan
  plans/2026-09-03-tui-footer.md) observed from source via deterministic
  adapter — footer-bar first child; gate cycle PASS -> controlled
  violation FAIL -> restore PASS; binding encoded scaffold-provenance
  (durable records establish placement; USER LOCK upgrade NEEDS
  CONFIRMATION — not fabricated)
- capability/layout integration proven: version-display requirement
  discovers the existing capability + layout binding (REUSE), never
  builds another widget
- 3 modules registered in Spine authority + canonical build + manifest
  regenerated (Tranche 2 lesson applied: no hand-edited structural facts)

Tests: 53 new (fit 24 + toolchain 9 + layout 16 + real proof 4);
suite 1439 green; henxels rc=0; pyright 0 errors on new modules.
2026-09-13 04:16:48 +01:00
Nick c8b317de53 chore(scaffolding): SCAFFOLD-TRANCHE-001 final closure — deployed identity 0.66.34, full release chain recorded 2026-09-13 03:50:59 +01:00
conductor ce330d3ac0 chore(release): auto-bump version to 0.66.34 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-13 03:42:19 +01:00
Nick 16b90fd8be fix(scaffolding): canonical spine rebuild after manual registration — projector-owned edges restored
Root cause of CI unit-tests failure on c7a28e1: the closure step added
belongs_to relationships by hand and recorded deploy observations without
running spine build(), so the stored graph lacked the deploy-identity-
projector's deployed_as edges and diverged from any canonical rebuild.
The rebuild-neutrality test correctly flagged the unexplained structural
change (assert pre == post).

Fix: rebuild through spine's authoritative projector chain. The stored
graph now matches a fresh build exactly; test isolation contract restored
(live-store comparisons must follow canonical build, never hand edits).
2026-09-13 03:42:01 +01:00
Nick c7a28e1db3 chore(scaffolding): SCAFFOLD-TRANCHE-001 closure evidence — release CI proof + deployed identity 2731db0/0.66.33 2026-09-13 03:32:02 +01:00
conductor 2731db03f4 chore(release): auto-bump version to 0.66.33 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-13 03:25:23 +01:00
Nick eb2f1a3e0e feat(scaffolding): construction substrate — shared structural store, Project Scaffold, Construction Contracts (SCAFFOLD-TRANCHE-001)
- structural_store.py: generic primitives extracted from spine.py —
  zero Rune constants (grep-gated boundary tests); Spine behavior-neutral
  (68 tests + identical-structure rebuild proof)
- scaffold.py: Project Scaffold over the shared core — open-world
  entity/relation kinds, repo/forge binding with secret redaction at
  save-time (shared core, Spine inherits), Construction Contracts with
  legal-phase-map lifecycle, cross-process resumability, mechanical
  scope check (unknown ≠ green for unscoped contracts), predicted-vs-
  observed closure evidence, authority-preserving drift reconciliation
- Rune Spine attachment: construction provenance via evidence, not
  authority transfer; project internals proven to never leak
- bootstrap contract SCAFFOLD-TRANCHE-001 executed through the system
  it implements: migrated → phased → closed with scope amendment
  (RED preserved in history) → fresh-runtime continuity proven
- umbrellas.json regenerated from Spine after module registration
- docs/SCAFFOLDING.md: Tranche 2 architecture + honest maturity

Tranche tests: 54 new (17 boundary + 37 scaffold); full suite 1386 green;
henxels rc=0. External-repo live proof BLOCKED ON USER REPO SELECTION.
2026-09-13 03:24:53 +01:00
Nick e3b459dfdf Revert "chore(release-safety): deliberate red candidate — negative deploy-proof (revert follows)"
This reverts commit b8d030e6c4.
2026-09-12 20:18:26 +01:00
Nick b8d030e6c4 chore(release-safety): deliberate red candidate — negative deploy-proof (revert follows) 2026-09-12 20:15:11 +01:00
conductor 20a47fac86 chore(release): auto-bump version to 0.66.32 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-12 20:10:54 +01:00
Nick 36ee604646 fix(release): required-checks verdict evaluates needs results — fail-closed deploy
ROOT CAUSE (red-CI promotions 0.66.28/29): the required-checks
'Publish protected-branch gate' step read /tmp/need_* files that no step
ever wrote and echoed 'All required CI checks passed' UNCONDITIONALLY.
With if: always() the needs gate is overridden, so the job ran on red
needs and published success — deploy_qualify correctly trusted it and
promoted red commits (24413e4, fd6e9b4, de30cd9; status timelines in the
closure evidence).

FIX: publish step now runs only when every needs.*.result == 'success';
companion fail-closed step exits 1 otherwise, so the required-checks
context reports failure instead of lying.

DEFENSE-IN-DEPTH: deploy_qualify verdict is now the AND of two
independent legs — (1) newest required-checks observation for the exact
SHA, (2) the latest COMPLETED ci.yml@refs/heads/master run for that exact
SHA with every job concluded success (fan-out resolved by path, run
resolved by head_sha, jobs envelope unwrapped — no aggregate-status
fallback). Any pending/missing/disagreement = not deployable.

CANARY: gitea_pipeline now asserts the verdict evaluates needs results
and fails closed — the class locked shut. 20 qualifier tests with
fixtures from the real incident shapes; 1402 suite green.
2026-09-12 20:10:28 +01:00
Nick 20f493596d chore(types): baseline 117/443 — CI-observed counts on the fixed tree
CI's locked pyright reports errors 117 / warnings 443 on the current tree
(spine fixes removed exactly 4: 121→117, coherent with the 24413e4 run).
Local .type-venv pyright classifies 124/429 for the same tree — a local/
runner environment skew in error-vs-warning classification that must be
investigated separately; the GATE is CI, so the baseline records CI's
arithmetic. Both counts sit below the original 120/465 baselines.
2026-09-12 19:55:41 +01:00
conductor faf3575fb3 chore(release): auto-bump version to 0.66.31 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-12 19:50:15 +01:00
Nick 2e16fc4c89 fix(spine): commit the nullable-flow fixes — they were never landed
The hardening-era pyright fixes (supersede() single entity fetch,
membership-loop assert before identities write) sat as uncommitted
working-tree modifications through multiple checkout/stash cycles. Every
pushed tree since e2464ae therefore still carried the 4 nullable-flow
errors — the CI type-check failures on fd6e9b4/12303bb were CORRECT
failures of the unfixged tree, not runner anomalies. With this commit:
spine.py = 0 errors under locked pyright 1.1.414; total 124 = the
re-baseline from the previous commit. Lesson recorded: verify fixes are
COMMITTED (git show HEAD:<file>) before diagnosing CI failures against
them.
2026-09-12 19:49:47 +01:00
Nick 12303bbd20 chore(types): re-baseline pyright counts under locked pyright 1.1.414
The count baseline (120) was frozen under pyright 1.1.412; the dependency
lock has since drifted to 1.1.414 (fae36c4/9c78b3d/e7d4c2a 'upstream
release drift' resyncs), which reports 124 errors / 429 warnings on the
tree — including on the baseline-era commit itself (127 under 1.1.414).
Same precedent as every prior pyright drift re-baseline.

DISCOVERED DEFECTS recorded (out of scope here, flagged for follow-up):
1. CI type-check job has been publishing false successes across the
   0.66 era — commit-status 'success in ~30s' while the canonical
   ratchet on the identical tree fails (a real pass takes minutes).
   Likely runner/execution anomaly; needs its own investigation.
2. deploy.yml promoted commits with failing type-check (not gated on
   ci.yml) — 0.66.28/29 were promoted red.

Spine-era errors themselves: fixed — src/rune/spine.py reports 0 under
the locked pyright (nullable-flow fixes: supersede() single-fetch,
membership-loop assert).
2026-09-12 19:47:20 +01:00
conductor de30cd958e chore(release): auto-bump version to 0.66.30 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-12 19:18:32 +01:00
Nick fd6e9b4bca fix(tests): scope-classification test is environment-independent
The first version asserted harness filesystem state (~/.config/opencode
exists) — true on the desktop, false on the CI runner, where unit-tests
and type-check failed. CI failure = real signal, test assumption was
machine-dependent. Now asserts the classification itself: propagate()
resolves against SCRIPTS_DIR by construction, and the tracker imports no
Spine module (checked via AST, not prose — the scope docstring mentions
Spine legitimately). Verified under fake HOME (no harness) + real HOME.
2026-09-12 19:18:13 +01:00
Nick 24413e4228 chore(spine): sync store state (post-hardening observations) 2026-09-12 19:12:34 +01:00
Nick 407c23a689 docs(spine): pre-Memory closure — real-build durability proof + scope classification
Closure 1: alias and supersession durability now proven through the REAL
build path (create→alias/supersede→save→reload→spine.build()→save→reload→
resolve) — the earlier __wrapped__-fallback test never exercised the actual
refresh; both survive (aliases carried as entity data, superseded entities
preserved with superseded_by intact).

Closure 2: dependency_tracker.py classified NON-STRUCTURAL TO RUNE / KEEP
LOCAL — its graph describes ~/.config/opencode/scripts (the dev harness;
verified: 20/23 names collide with src/rune but all exist in the scripts
dir, propagate() resolves against SCRIPTS_DIR). Not a competing structural
authority; migrating harness structure into Spine would wrongly expand
scope. Scope classification documented in-module + regression test pins
the separation.

Closure 3: bounded sweep found no other manually maintained Rune
structural copy — remaining umbrella consumers are all generated-view
compatibility (CI gate, henxels, research_inward_context, gen_prd_state,
shared/umbrella_update); scaffold_projection is Spine-backed.

1382 tests, lint ratchet, henxels, canary-native green.
2026-09-12 19:12:34 +01:00
conductor 982a9b07d5 chore(release): auto-bump version to 0.66.29 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-12 18:43:59 +01:00
Nick ff506ebe55 feat(spine): CLI alias/supersede commands; save() coerces string paths
Real-change proof for the hardening pass (task SPINE-CLI-ALIAS): bounded
CLI completion on module:spine. The change surfaced a real defect via
runtime evidence — save() accepted 'Path | None' per its signature but
CLI callers legitimately pass strings; now coerced. Independent evidence:
full suite 1379, lint, henxels, scaffold consumer check, CI.
2026-09-12 18:43:37 +01:00
conductor 2032819d99 chore(release): auto-bump version to 0.66.28 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-12 18:41:16 +01:00
Nick e2464ae9d6 feat(spine): hardening — authority-owned reconciliation, contract semantics, durable identity
T1: impact_frontier carries change_kind — contract_change expands all
parties; implementation_change (contract preserved) demotes sibling
implementers to contextual_not_obligations (sharing a contract is not
being affected by a sibling's internal change); contract_violation
escalates. Pre-hardening test expectation that accepted siblings as
direct obligations was expectation-laundering — corrected with the
architectural justification recorded.

T3/T4: relationships carry authority+status; per-projector generation
records; reconcile_authorities stales facts their owner no longer
observes (marked + drift-reported + frontier-excluded, never deleted —
open-world preserved, truth marked); authority_failed degrades; both
sides of an authority conflict preserved (never last-wins);
resolve_status: UNKNOWN/CURRENT/STALE/CONFLICTING/SUPERSEDED — 'not
checked' is never healthy.

T5: alias (rename) + supersede (replacement) — old spine:// references
stay meaningful; duplicate entity/resolve_uri defs removed (shadowing
trap). T2: record_observed_impact builds the observed set from external
evidence items (test/canary/runtime authority), not frontier-rerun.
CANDIDATE status for evidence-free (model-speculated) relationships.
65/65 spine tests, 1379 suite, gates green.
2026-09-12 18:40:53 +01:00
conductor d7e04f1098 chore(release): auto-bump version to 0.66.27 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-12 18:20:25 +01:00
Nick e639383c49 fix(spine): build() carries forward ALL entities/relationships — open-world refresh
Predicted-vs-observed caught it: build()'s carry-forward filtered by known
kinds/types, silently destroying task bindings (and any future entity
class) on every refresh — the exact TOO-CLOSED failure the Spine contract
forbids. Everything now passes through; module-level facts re-derive on
top; exact-duplicate observations suppressed. Task bindings survive build;
predicted==observed on the Phase D migration change.
2026-09-12 18:19:59 +01:00
Nick 57a274d97d docs(phase-d): research_inward_context consumes Spine-generated view
Phase D consumer migration: the INWARD context builder reads structural
facts from the Spine store's generated compatibility view (same schema —
zero code-path change), documented as TEMPORARY SPINE-BACKED
COMPATIBILITY. Graceful degradation to a manual manifest if Spine is not
seeded in a checkout.
2026-09-12 18:13:15 +01:00
conductor aac5295c24 chore(release): auto-bump version to 0.66.26 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-12 18:07:08 +01:00
Nick 9563148f9d feat(spine): contracts, structural impact resolution, task binding, event seam
Structural Impact Resolution: impact_frontier() — bounded LEVEL 0/1/2
resolution with a data-driven semantics table. Contract entities expand to
all implements/consumes parties (a contract change deserves every
consumer's inspection); unknown relationship types default to
obligation-bearing (fail-loud, open world); non-obligation classes
(documented_by, related_memory, supersedes...) never explode a frontier.

Graph separation (addendum): Spine is its own logical graph — the frontier
traverses Spine edges only; memory-style associations cannot expand
structural impact; stable spine:// URIs let future Memory reference Spine
entities without duplicating authority.

Also: task binding (affects edges + bind_task/task_entities),
predicted_vs_observed comparison (misses become CANDIDATE corrections,
evidence-gated), generic structural_events() seam (dumb typed facts — no
salience/policy; future Substrate subscribes), aggregate query() (the
intrinsic self-knowledge property: owner/deps/consumers/contracts/state/
evidence/frontier in one deterministic call), evidence_conflict drift
class. henxels similarity scan excludes store/spine (snapshots are
legitimately near-identical by design). 45/45 spine tests; full gates green.
2026-09-12 18:06:16 +01:00
conductor 76984c6362 chore(release): auto-bump version to 0.66.25 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-12 17:34:32 +01:00
Nick 4072d36b1a fix(spine): build re-derivation uses high-water upgrade — no demotion noise
Evidence surfaced it: re-deriving module maturity during build() logged a
demotion-rejection observation for every already-earned module (171 noise
records). Build now upgrades via the silent high-water path; promote()
logging stays reserved for explicit evidence-gated API calls.
2026-09-12 17:34:05 +01:00
conductor 6d871abc9c chore(release): auto-bump version to 0.66.24 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-12 17:03:51 +01:00
Nick ce40acbb1f feat(spine): V1 — evolvable structural self-model as the single structural authority
Open-world entity/relationship store (schema_version 1): kinds, relationship
types and metadata are open tags — unknown future capabilities enter as data,
never as core edits (extensibility test included, synthetic capability
round-trips with zero core change). Evidence-gated maturity ladder
DECLARED<PRESENT<WIRED<REACHABLE<EXERCISED<LIVE_PROVEN — no evidence, no
promotion; demotion rejected and recorded.

Umbrella migration Phase A→C: manifest ingested once (generated-view
refusal guard prevents the ingest cycle; manual truth archived at
config/umbrellas.manual.json), canaries preserved as obligated_canary
relationships, config/umbrellas.json now a GENERATED compatibility view for
legacy consumers (CI umbrella_impact gate + henxels) — single-authority
route proven by registering module:spine through Spine alone (one store
edit; the legacy view flows out; contract tests validate the round-trip).

Dynamic observations: deployed identity (_build_identity.json), drift
classes incl. registered_but_absent, present_but_unowned,
registered_no_static_importers (D6 dead-subnet now mechanical),
version_surfaces_disagree, relationship_disappeared. Deterministic
snapshots + diff. Scaffolding V1 now consumes Spine for ownership/deps/
consumers (spine_maturity surfaced in every card). 31 spine tests; full
gates green.
2026-09-12 17:03:27 +01:00
Nick 1de28b55a0 docs(tooling): desktop runner wakes local W/R daemon after jobs (v0.3, Gitea authoritative) 2026-09-12 16:16:58 +01:00
conductor 75d6d7d62a chore(release): auto-bump version to 0.66.23 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-12 11:16:07 +01:00
Nick 7f47969128 feat(scaffolding): V1 tranche 1 — projection engine over existing authorities
scripts/scaffold_projection.py derives per-component cards (subsystem,
dependencies, consumers, mirrors, proof obligations + evidence state) from
the umbrella manifest, canary registry, AST import graph (incl. relative
lazy imports), and tests/ filesystem. No new authority: projections only.
docs/SCAFFOLDING.md records the mechanism audit (KEEP/EVOLVE/REPLACE/RETIRE)
and the real-change proof on the context-discovery fix.
2026-09-12 11:15:42 +01:00
Nick a65e5d44de fix(runtime): context discovery routes cloud-pinned models to the provider wire
Module-level context_length used OllamaChatTransport unconditionally, so
every cloud-pinned task logged context_discovery tier=1 HTTPError 400 and
was misbudgeted at the 8192 fallback instead of the provider's real window
(131072 for Verboo Code/glm-5.3-flash). is_cloud_pinned is now THE
provider-prefix rule — one authority in openai_compat_transport, consumed
by context discovery (new) and transport selection (deduped from
rune_operator._transport_for). Red-first regression tests added.
Scaffolding-derived impact: consumer rune_operator; gates suite/lint/
henxels + inference/orchestration canaries.
2026-09-12 11:15:42 +01:00
Nick 26a040892d docs(reconciliation): ADAPT family reconciliation on PL1 held-out evidence
#292/#293/#297 FIXED_VERIFIED (closed with evidence comments — LOCAL_FIX
live-proven by held-out tasks, DESIGN-LITE implemented, task_gate shipped);
#294/#295/#296/#299/#301 DEFERRED_FUTURE (canonical remaining-obligations
list); #300/#315/#316/#284 VALID_OPEN. Resolves the ADAPT-LIVE-complete vs
open-issues tension: the authorized tranche is complete; the backlog never
was its scope. Checker green (72 records). PE-1789102658-0269 SEED→VALIDATED
recorded in the canonical intent state.
2026-09-12 11:04:54 +01:00
conductor 1497c85cd4 chore(release): auto-bump version to 0.66.22 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-12 10:50:09 +01:00
Nick a2463ad80b fix(operator): approval-resume uses provider-prefix transport selection
_runtime_for_model hardcoded OllamaChatTransport, so the post-approval
follow-up model call hit localhost with the cloud-pinned name → 400
'invalid model name'. The direct turn path was fixed in 0.66.17; the resume
path now delegates to the same _transport_for authority (one selection
rule, two call sites). Red-first regression tests added.
2026-09-12 10:49:42 +01:00
Nick 6965fc7375 fix(transport): chat() returns flat ChatMessage — envelope shape broke runtime tool-call loop
OllamaChatTransport.chat returns the flat message object (the ChatTransport
contract), but the [OI]-compat translation returned the response envelope
{'message': {...}}. LocalToolRuntime normalizes tool_calls at the top level,
found none, and failed 'empty terminal visible text' while the model had
returned a valid read_file call. Observed live: PL1 Task A wire capture
2026-09-12. Contract-parity regression test added (red-first).
2026-09-12 10:49:42 +01:00
Nick 0daad967c1 test: mock cloud_transport_for at source module — CI has no user config
The selection test called the real cloud_transport_for, which reads the
user's mimocode config (absent on the CI runner). Mocking at the consumer
module was a no-op (function-level import re-resolves from source). Mock now
targets the source module. Local green.
2026-09-12 10:00:14 +01:00
conductor 502317d8b6 chore(release): auto-bump version to 0.66.21 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-12 07:57:49 +01:00
Nick 07cdc2fc56 feat(intent): minimal intent-continuity ledger — deterministic state machine, 7 invariants
PART 6 of the overnight handoff. IntentRecord (7 fields: objective,
parent_intent, active_detour, return_when, return_to, unresolved_obligations,
success_condition) + IntentLedger (JSON persistence, no LLM). Classifications:
BLOCKER | FIX | EXTENSION | SUPERSEDING | ORTHOGONAL | LATER. All 7 invariants
tested: new ideas never replace the active objective; detours preserve parents;
resolving a detour exposes the return point; supersession accounts for open
obligations; child completion never resolves the parent; persist/reload
round-trips; transitions are deterministic. 1309 green.
2026-09-12 07:57:26 +01:00
Nick b4161a4034 test: valid identifier + tempdir storage + journal isolation — CI green on cloud-execution tests
Three fixes: (1) [OI]CompatTransport is an invalid Python identifier —
renamed to the module's actual class name; (2) fixed /tmp storage paths in
selection tests collided with a root-owned /tmp/hot on the CI runner (the
hot store derives from Path(storage).parent) — per-test tempdirs; (3) the
operator's journal/event edges resolve via memory_env whose real memory dir
is root-owned in CI → RUNE_MEMORY_DIR pointed at a per-test tempdir. 1304
green locally.
2026-09-12 06:43:59 +01:00
conductor e036f5f545 chore(release): auto-bump version to 0.66.20 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-12 06:00:32 +01:00
Nick ab6c4f4e38 fix(transport): pair assistant tool_call ids with following tool messages' tool_call_ids
Observed live: glm-5.3-flash tool-loop turn 2 returned the SAME edit_file
call with empty content both turns — the provider treated the tool result as
orphaned because the translation assigned fresh ids to assistant tool_calls
while the tool messages carried the runtime's minted call_ids. The fix pairs
each tool_call with the FOLLOWING tool message's tool_call_id. Proven live:
turn 2 now returns a proper text summary instead of looping.
2026-09-12 06:00:07 +01:00
Nick c520b024d1 test: fix transport test CI failures — /tmp/hot collision, valid identifier, RUNE_MEMORY_DIR isolation
Three CI failures on the transport commits: (1) fixed /tmp storage paths in
selection tests collided with a root-owned /tmp/hot on the runner (the hot
store derives from Path(storage).parent) — per-test tempdirs now; (2) an
invalid [..]-bracketed identifier crept into one test — renamed; (3) the
selection tests' journal edges resolved via memory_env to a root-owned
memory dir — RUNE_MEMORY_DIR now isolated per test. 1304 green locally.
2026-09-12 05:41:07 +01:00
conductor 1c73d809b9 chore(release): auto-bump version to 0.66.19 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-12 04:40:00 +01:00
Nick 34fc38d4ed fix(runtime): clamp cloud wire timeout to >=120s — tier-1 30s starves cloud round trips
Observed live: glm-5.3-flash read-timeout at 30.6s mid-iteration (tier-1
timeout is 30s; cloud round trips with a full tool schema routinely exceed
it). The clamp is transport config — the escalation ladder still governs
retries/tiers; one round trip just needs enough rope. Clamp test added.
2026-09-12 04:39:41 +01:00
Nick a67a9c8520 test: isolate remaining fixed-path operator storage (same /tmp collision family) 2026-09-12 04:33:05 +01:00
conductor b0efaffca1 chore(release): auto-bump version to 0.66.18 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-12 04:30:41 +01:00
Nick a087a0b5e7 fix(tests): isolate operator storage to per-test tempdirs — fixed /tmp paths collide on the CI runner
test_context_broker parity + new transport-selection tests used fixed /tmp
storage paths; the derived hot-store dirs (/tmp/hot etc.) are root-owned on
the CI runner → PermissionError on every write (observed live: 5 CI test
failures on 58af0b0). All operator storage now uses per-test tempdirs.
2026-09-12 04:30:18 +01:00
Nick acb3ce0157 docs(reconciliation): ADAPT-only pass — #311 SUPERSEDED by #315; #315/#316/#301 DEFERRED_FUTURE
ADAPT-1 v2 baseline experiment framing (#315/#316) is historical — the
adaptive pipeline went live without the pre-registered comparison; the
underlying work items (#158, #162) remain open. FINAL-12 (#301) blocked on
PE-0269 substrate. Consistency checker green (72 records).
2026-09-12 04:10:59 +01:00
conductor 58af0b0f78 chore(release): auto-bump version to 0.66.17 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-12 04:08:35 +01:00
Nick 95f9e15ed9 fix(runtime): key transport selection on provider prefix, not routing_mode
Observed live: an operator-requested model keeps routing_mode='local' (line
~887), so keying selection on routing_mode=='cloud' still sent pinned
'Verboo Code/glm-5.3-flash' to OllamaChatTransport → 400. Selection now keys
on the model's provider prefix — deterministic, no router change. Selection
regression tests added (pinned cloud → OpenAI-compat; local/bare → Ollama).
1300 tests green; ratchet 352/80; henxels clean.
2026-09-12 04:08:13 +01:00
Nick b083b0c4cf fix(runtime): provider-keyed transport selection — pinned cloud models kept hitting Ollama
Selection keyed on routing_mode=='cloud', but an operator-requested model
(send_task(model=...)) sets routing_mode='local' (line 887), so pinned cloud
models silently used OllamaChatTransport and 400'd. Selection now keys on the
model's provider prefix: any '<Provider>/<model>' with a non-ollama prefix
rides the OpenAI-compatible wire; ollama-prefixed and bare names keep the
proven path. Deterministic — no router, ladder, or escalation change.
Regression tests: pinned cloud → OpenAI-compat; local/bare → Ollama.
2026-09-12 04:08:13 +01:00
conductor 46e74110ad chore(release): auto-bump version to 0.66.16 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-12 03:40:49 +01:00
Nick c669e37a3d fix(runtime): pin cloud models by bare model id — qualified name 400s on the wire
The runtime passes '<Provider>/<model>' to the transport; the provider API
wants the bare model id. Observed live: every pinned-Verboo PL1 held-out
attempt 400'd because the wire carried 'Verboo Code/glm-5.3-flash'.
Regression test proves the wire now carries 'glm-5.3-flash'. 1296 green.
2026-09-12 03:40:28 +01:00
conductor 7f4a6262ae chore(release): auto-bump version to 0.66.15 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-12 03:09:58 +01:00
Nick 34d5ab74b7 feat(runtime): OpenAI-compatible transport for cloud-pinned operator execution
Merges prototype/openai-compat-transport (7b268e1). The operator's execution
substrate had exactly one transport (OllamaChatTransport, localhost:11434) —
send_task(model='<Provider>/<model>') posted cloud model names to Ollama's
/api/chat and 400'd (observed live: Verboo Code/glm-5.3-flash, 0.2s). The
supported model= override could not execute ANY cloud provider.

OpenAICompatTransport speaks the OpenAI wire format (/chat/completions) and
returns Ollama-shaped responses (LocalToolRuntime loop unchanged). Selection
is deterministic on routing_mode=='cloud' — no router, ladder, or escalation
change. Provider config resolved from the same source of truth the mimo CLI
uses (mimocode.jsonc baseURL + auth.json key).

Translation unit tests (6) + live smoke against the real Verboo API
(TRANSPORT-SMOKE-OK). Umbrella manifest updated. Stray experiment files
removed. 1295 tests green; ratchet 352/80; henxels clean.
2026-09-12 03:09:17 +01:00
Nick 7b268e17fe prototype: OpenAI-compatible transport for cloud-pinned operator execution (NOT RELEASED)
Local branch only — preserved per directive 2026-09-12: the PL1 held-out
strong-provider rerun is BLOCKED_BY_EXECUTION_SUBSTRATE (operator's only
transport is Ollama; send_task(model='Verboo Code/glm-5.3-flash') 400s).
This prototype makes the supported override executable but is NOT authorized
for release. Translation unit tests + live smoke (TRANSPORT-SMOKE-OK) pass.
2026-09-12 02:29:15 +01:00
Nick da61fd7d44 docs: webhook delivery test marker 2 2026-09-12 00:31:12 +01:00
Nick 7342d77e6f docs: webhook delivery test 2 2026-09-12 00:31:02 +01:00
Nick 436f760675 docs: webhook delivery test marker 2026-09-12 00:28:42 +01:00
Nick d62b717542 test: deliberate lint failure (wait/resume Part 14) 2026-09-12 00:14:41 +01:00
Nick 97de570b27 test: deliberate lint failure fixture (wait/resume failure experiment) 2026-09-12 00:13:41 +01:00
Nick 22aebbb102 test: intentionally broken syntax for W/R failure experiment 2026-09-12 00:13:27 +01:00
Nick 7e33294527 docs: wait/resume live experiment marker (branch) 2026-09-12 00:07:52 +01:00
conductor fcc9989393 chore(release): auto-bump version to 0.66.14 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-11 22:54:16 +01:00
Nick ead4a24866 fix(ci): allow the reconciliation JSON authority in top-level docs henxel 2026-09-11 22:53:48 +01:00
conductor cf51f7fd7c chore(release): auto-bump version to 0.66.13 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-11 22:51:10 +01:00
Nick f182ab8601 feat(reconciliation): canonical issue reconciliation artifact + consistency checker (T15 Parts J/K/L)
- docs/GITEA_ISSUE_RECONCILIATION.md: human-readable projection (states,
  bug-label audit with per-issue evidence, open-issue reconciliation table)
- docs/gitea_issue_reconciliation.json: machine-readable authority
  (72 records; all open issues covered; single live defect #324).
  Placed under docs/ because state/ is the gitignored runtime dir.
- scripts/gitea_reconciliation_check.py: deterministic drift check —
  state/label/coverage invariants; bug-label invariant applies to OPEN
  issues (closed labels are historical); exit 1 with itemized drift.
- Part K audit: closed #139 #157 (FIXED_VERIFIED with evidence comments);
  bug labels removed from #204 #145 #126 #37 #16 (not defects) and the
  stuck label on closed #314. Open bug-labelled: 8 → 1.
- 1289 tests green; ratchet 352/80; henxels clean.
2026-09-11 22:50:44 +01:00
conductor 5f9ba5784c chore(release): auto-bump version to 0.66.12 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-11 22:33:27 +01:00
Nick 9a05fdfa1f fix(convergence): decision JSON omits boundary_sha — consumers re-derive it from git
Every debug session of the release pipeline (T15 Part F forensics included)
had to re-derive the release boundary by hand. The decision JSON now
carries boundary_sha on every return path.
2026-09-11 22:33:10 +01:00
Nick 2298768353 docs: D7 resolved — release-pipeline root causes recorded (experiment B trigger)
Records the three root causes (corrupted shell fragment, unwired release
boundary, per-surface commit granularity) with live proof of the fix.
2026-09-11 22:23:52 +01:00
conductor a4afc77d53 chore(release): auto-bump version to 0.66.11 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-11 22:14:49 +01:00
Nick d68fd1e94d fix(release): ChangeFiles content must be base64 (ContentBase64) 2026-09-11 22:14:17 +01:00
Nick 470d82f307 fix(release): single-commit bump via ChangeFiles (blob API 404 on Gitea 1.27)
git-data blob/tree creation endpoints are not implemented on this Gitea
build (404). ChangeFiles (POST /contents with files[] = ChangeFilesOptions)
is the supported multi-file single-commit primitive. One bump = one commit.
2026-09-11 22:08:10 +01:00
Nick 7a988cbaff fix(release): refs API returns a list — take the master entry 2026-09-11 22:00:57 +01:00
Nick 12c3c488be fix(release): commit all version surfaces as ONE commit (phantom duplicate bumps root-caused)
The per-file contents PUT created one commit per version surface — five
same-version bump commits per real bump. Every 'duplicate bump cascade'
since 0.66.2 was this: 5 surface-commits per bump, misread as queue
drain/recursion. Root-caused T15 Part F via run 6791 log forensics
(5 'committed <surface>' lines, one AUTO_BUMPED). Now: Git data API
(ref → blobs → tree → commit → CAS ref update) — one bump commit.
Loop guard makes any losing race converge instead of re-bumping.
2026-09-11 21:54:15 +01:00
conductor 247c5b3936 chore(release): auto-bump version to 0.66.10 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-11 21:22:04 +01:00
conductor 946b8366ef chore(release): auto-bump version to 0.66.10 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-11 21:22:01 +01:00
conductor 5e539f7da3 chore(release): auto-bump version to 0.66.10 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-11 21:21:57 +01:00
conductor 83960c541d chore(release): auto-bump version to 0.66.10 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-11 21:21:55 +01:00
conductor 980fcd364f chore(release): auto-bump version to 0.66.10 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-11 21:21:53 +01:00
Nick c35018f543 fix(release): numeric semver comparison — lexicographic order skipped warranted bumps
_version_lt(): '0.66.9' < '0.66.10' is False lexicographically ('9' > '1'),
so a legitimate patch bump after v0.66.9 surfaced as
version_ahead_of_target and the release was silently skipped (run 6781,
2026-09-11). Both comparison sites (test-injection + production) now
compare numerically per segment. Regression tests added; 1284 green.
2026-09-11 21:21:23 +01:00
Nick d2600dff29 fix(ci): allow test_gitea_auth.py fake token in secrets henxel exception
The unit-test fixture constant ('unit-test-secret-token-value') trips
the hardcoded-credential detector. It is not a secret; the sanctioned
path (matching test_gitea_provision.py) is the henxel except list.
2026-09-11 21:05:55 +01:00
Nick 5b268fde8e fix(ci+release): format new auth test; repair f-string backslash in release idempotency check
- tests/test_gitea_auth.py: ruff format (CI format-gate on added files)
- auto-version.yml release step: f-string with escaped quotes is a
  SyntaxError on py<3.12 runners; compute tag name without backslash
  escapes (release job exit 22, run 6776)
2026-09-11 20:59:39 +01:00
Nick 9e0b85534a fix(release): boundary grep must match subjects only, not bodies
git --grep matches the commit BODY by default: a fix commit whose body
mentions 'chore(release)' was misdetected as the release boundary,
swallowing its own warranted bump (observed live: d01df79 boundary
detection). Anchor the pattern to the subject with --extended-regexp
and re-verify via is_release_commit(). Also drop unrecognized
--fixed-strings=False flag (fatal on this git version).
2026-09-11 20:50:46 +01:00
Nick d01df797c1 fix(release): wire release boundary into convergence (duplicate-bump root cause)
release_convergence() never assigned  from
last_release_boundary() — the production path classified ALL commits
(959+) as unreleased, so the warranted bump (minor, from an ancient
feat) never converged and every queued push wrote its own bump commit
(5x 0.66.9 observed 2026-09-11 20:21). Now the boundary is the one
source of truth: last chore(release) commit, falling back to the
latest tag. Post-boundary subjects only.

Also: local path was NOT reached when _boundary_subject was injected;
test_cli_prints_plan_json expectation updated to boundary semantics
(feat below the tag no longer warrants minor).
2026-09-11 20:34:30 +01:00
conductor 95bac995a3 chore(release): auto-bump version to 0.66.9 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-11 20:21:21 +01:00
conductor 1afadfddfc chore(release): auto-bump version to 0.66.9 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-11 20:21:06 +01:00
conductor 54ab4d9e64 chore(release): auto-bump version to 0.66.9 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-11 20:21:02 +01:00
conductor f4c73d5142 chore(release): auto-bump version to 0.66.9 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-11 20:21:00 +01:00
conductor bad13ceb57 chore(release): auto-bump version to 0.66.9 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-11 20:20:57 +01:00
Nick c35b604976 fix(release): repair corrupted shell in auto-version push path (D7 root cause)
c2528c1 left the tail of the replaced WARRANTED= line dangling after the
new converged-check fi (edit collision): 'fi | python3 -c ...)' — a shell
syntax error that kills the release job with exit 2 before any bump.
Release jobs have failed since c2528c1 (D7 'ROOT_CAUSE_UNKNOWN_DEFERRED'
resolved: not a Pi/environment issue). Loop-guard exit-0 paths never
reached the corrupted line, masking the defect until the first
substantive-convergence push after it.
2026-09-11 20:20:29 +01:00
Nick 4eefc15837 fix(lifecycle+auth): canonical gitea auth path, terminalization helper, fault-injection gaps (T15 Parts A-E)
- scripts/gitea_auth.py: single credential ladder (env -> 0600 token file ->
  git credential fill); 6 consumers migrated off direct os.environ reads
- rune_operator: consolidate 5 duplicated failure blocks into
  _terminalize_execution_failure; fix 3 fault-injection gaps:
  (1) dual-module PreparedTool identity split crashed approval-path saves,
  (2) fallback-model failure escaped send_task (created/pending orphan),
  (3) running-transition save uncaught (running-with-no-owner)
- envelope task.status now agrees with canonical ledger (awaiting_approval)
- orphan task_ac35f4e287c8 terminalized failed with durable evidence
- tests: gitea auth ladder (6), lifecycle fault matrix (9 boundaries +
  restart/reload + helper contract); 1280 green in ci-venv; ratchet 352/80
2026-09-11 20:15:57 +01:00
Nick 2bf43eafcd test: #314 forced association regression + Gitea auth helper + lifecycle tests
- tests/test_recall_mode_regression.py: deterministic fixture proving
  association-merged entries carry mode=association_merged (fails on old
  impl). #314 closed FIXED_VERIFIED.
- scripts/gitea_auth.py: canonical Gitea API auth helper (GITEA_TOKEN env
  or git credential fill, never remote URL parsing)
- tests/test_task_lifecycle.py: fault injection at route/model_selection/
  execute boundaries — all terminalize, no immortal RUNNING
- tests/test_route_isolation.py: task-scoped route instruction isolation
- tests/test_release_convergence.py: correct target-version algorithm

1268 tests green; ratchet 352/80; henxels clean.
2026-09-11 18:17:17 +01:00
Nick ca4f7593d7 feat(corrections): #314 defect fix, credential rotation, release guard, task lifecycle, route scoping, PL1 records + metrics
CORRECTION 1: #314 reopened — recall_with_associations mode field defect
CONFIRMED in current source and FIXED (mode: association_merged).

CORRECTION 3: Gitea credential removed from remote URL (credential helper).
TOKEN EXPOSED: yes (in diagnostic output). TOKEN ROTATED: not yet (requires
Gitea web UI access). Remote URL now shows username only, no secret.

CORRECTION 4: duplicate-release-commit defect ROOT CAUSE: convergence
computed warranted bump from commits-since-tag without checking if master
version already satisfies the bump. FIX: already-converged guard in
version_convergence.py (master version > last tag → no commit). Repo-aware
(args.repo passed to read_version/latest_tag).

CORRECTION 6: lifecycle terminalization — execution exception now
guarantees task terminalizes as failed with evidence (no immortal RUNNING).

CORRECTION 7: route instruction task-scoped on RuneTask.route_instruction
(NOT shared operator state). Read-only leading-verb override. Isolation
tests prove no cross-contamination between interleaved tasks.

PL1-01/02/03/05: pl1_records.py (route resolution, proof level, failure
class, candidate status), metrics with honest NOT_YET_MEASURABLE semantics,
route-instruction learning loop (PE-1789102658-0269 SEED).

1253 tests green; ratchet 352/80 (shrink); henxels clean.
2026-09-11 15:36:08 +01:00
Nick 24537e46e7 fix(release): already-converged version guard (prevents duplicate same-version release commits)
The duplicate-release-commit defect: each queued push ran the release
workflow from its own pre-bump checkout, computed the same warranted bump,
and created another identical-version commit. The convergence script now
checks if master __version__ > last tag — if so, already converged, no
commit needed. This is the definitive fix for the 5x 0.66.8 defect.
2026-09-11 15:06:34 +01:00
Nick 52d810d358 chore: Gitea reconciliation + PL1 held-out + remote truth + metric honesty
Part A-J: 15 issues closed (HISTORICAL_EVIDENCE/SUPERSEDED/ACCEPTED_LIMITATION)
with evidence. Bug label cleaned (24→8 open). #259/#258 updated to current
architecture. Remote tracking fixed (master tracks gitea/master). PL1 metrics
corrected to NOT_YET_MEASURABLE where evidence doesn't support numbers.
D7 recorded as ROOT_CAUSE_UNKNOWN_DEFERRED. Clean recursion experiment:
version converges (0.66.8 stable) but 5 duplicate bump commits per logical
change (queue-drain artifact). PL1 held-out task 1: LOCAL_FIX route correct,
task genuinely running on deployed 3B model (slow but alive).
2026-09-11 14:05:25 +01:00
conductor 7ea4a62960 chore(release): auto-bump version to 0.66.8 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-11 13:22:08 +01:00
conductor e7e4541d47 chore(release): auto-bump version to 0.66.8 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-11 13:22:05 +01:00
conductor 92b6f47ccf chore(release): auto-bump version to 0.66.8 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-11 13:22:02 +01:00
conductor d90a79a231 chore(release): auto-bump version to 0.66.8 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-11 13:21:57 +01:00
conductor 29390534d9 chore(release): auto-bump version to 0.66.8 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-11 13:21:55 +01:00
Nick a8ae37df21 fix(pl1): document RUNE_EXPERIENCE_LEDGER env override on ledger default 2026-09-11 13:21:33 +01:00
conductor fa81f4bd4f chore(release): auto-bump version to 0.66.7 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-11 05:59:23 +01:00
conductor 81edc1356c chore(release): auto-bump version to 0.66.7 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-11 05:59:19 +01:00
conductor 6dcea9dbc7 chore(release): auto-bump version to 0.66.7 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-11 05:59:15 +01:00
conductor 885bfc181a chore(release): auto-bump version to 0.66.7 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-11 05:59:14 +01:00
conductor 0e1e7ce94a chore(release): auto-bump version to 0.66.7 — earned by # (minor: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-11 05:59:12 +01:00
Nick a125c023e6 feat(PL1): first tranche — structured records, failure classification, route-instruction learning loop, metrics
PL1-01: scripts/pl1_records.py — compact structured Experience evidence from
canonical task state + route.jsonl (route resolution by task_id+timestamp,
proof level, failure class, candidate status).
PL1-02: failure classes in the PL0 vocabulary, evidence-grounded; UNKNOWN
valid; research_dispatch never failure.
PL1-03: first learning loop — recurring prose-instead-of-mutation family →
structural correction (route-driven instruction appended to the user context
block for mutation routes) + replay contract (NOT_COMPLETED gate) —
recorded as PE-1789102658-0269 (SEED; held-out = next deployed mutation tasks).
PL1-05: metrics module (first_pass_accepted, false_completion_rate=0.0
structurally, mutation_failures, research_dispatches, candidate/evidence split).

Intent state updated: PL1 first tranche live; ADAPT-LIVE acceptance proven on
deployed runtime; remaining ADAPT obligations deferred to their epics.
2026-09-11 05:58:47 +01:00
Nick 20e68b793f docs: restore corrected intent state (174e11f) + record D7 release-job defect 2026-09-11 05:35:11 +01:00
conductor 1163a13e13 chore(release): auto-bump version to 0.66.6 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-11 04:57:19 +01:00
conductor a4b0bd6f55 chore(release): auto-bump version to 0.66.6 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-11 04:57:11 +01:00
conductor 76f215f9ab chore(release): auto-bump version to 0.66.6 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-11 04:57:02 +01:00
conductor dc5757ff04 chore(release): auto-bump version to 0.66.6 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-11 04:57:00 +01:00
conductor fc12bb5b44 chore(release): auto-bump version to 0.66.6 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-11 04:56:49 +01:00
Nick a620171524 fix(canaries): canary_p1_01/p1_06 fixtures carry mutating tool evidence (completion-truth contract) 2026-09-11 04:56:26 +01:00
conductor 4486ea4558 chore(release): auto-bump version to 0.66.5 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-11 04:17:10 +01:00
conductor 996d0d9cb1 chore(release): auto-bump version to 0.66.5 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-11 04:17:06 +01:00
conductor 4e3b4be67b chore(release): auto-bump version to 0.66.5 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-11 04:17:02 +01:00
conductor a872abd962 chore(release): auto-bump version to 0.66.5 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-11 04:17:00 +01:00
conductor be136de452 chore(release): auto-bump version to 0.66.5 — earned by # (patch: converged release (push-to-master bump))
Promotion record: (unknown)
2026-09-11 04:16:57 +01:00
Nick afa276aaf4 fix(deploy): startup canary runs in CANDIDATE mode with --stage (gate fail-closed correctly but never tested the candidate after the two-mode refactor) 2026-09-11 04:16:31 +01:00
Nick b0dbb80778 chore(lint): re-baseline BLE001 353->352 (legitimate shrink from noqa documentation) 2026-09-11 04:01:06 +01:00
Nick 0018fe8c39 chore: deployment canary verification probe (no release warranted) 2026-09-11 03:37:53 +01:00
776 changed files with 193979 additions and 6294 deletions

No files matched your search

BIN
View File
Binary file not shown.
+35 -9
View File
@@ -1,16 +1,46 @@
---
name: Bug Fix
about: Fix a bug or issue
about: Demonstrate currently incorrect behaviour — plain English first, proof required
title: "[BUG] "
labels: bug
assignees: conductor
---
## Plain summary
<!-- 2-4 sentences, NON-TECHNICAL: what's broken and why it matters. -->
<restate the issue title here in everyday words — this heading IS the
plain-English summary; no meta-labels like "plain English" in it>
<!-- The heading above carries the summary itself — a scan of issue
headings alone should tell the whole story of the board. TOP PRIORITY:
if a technical detail below contradicts this section, the issue is
buggy — fix the issue. -->
<!-- SUBMITTED_BODY -->
## Example
<!-- A concrete before/after: "Doing X currently produces Y; it should produce Z." -->
What is broken: <what a person observes going wrong>
What should happen instead: <the correct behaviour>
How often / when: <always | after X | since change Y>
## Proof it is broken (required — no proof, no bug)
<!-- A bug is DEMONSTRATED currently incorrect behaviour. Nothing else.
If this section cannot be filled, file it as a question, not a bug. -->
- [ ] Reproduction command or steps (deterministic where possible)
- [ ] The exact wrong output observed: <paste/log excerpt>
- [ ] Where the evidence lives: <log path, fixture, session id>
## Steps to reproduce
<!-- How to trigger the bug -->
## What would let us close this
- [ ] The reproduction command now shows correct behaviour
- [ ] A regression test exists that fails before the fix and passes after
- [ ] No other behaviour changed (or changes are listed and justified)
## Version impact (declared at submission — verified at merge)
<!-- A bug fix is USUALLY a patch. Pick major or minor only with a reason. -->
- [ ] patch — same behaviour, done correctly (usual for bugs)
- [ ] major — the bug was in a published contract and fixing it breaks consumers (justify)
- [ ] minor — fixing revealed a missing capability that had to be added (justify)
## Technical details
<!-- WHAT (the bug) / WHERE (files) / EVIDENCE (how it was confirmed). -->
@@ -29,10 +59,6 @@ assignees: conductor
- [ ] Canary passes (name)
- [ ] Closed with a properly formatted closing comment + commit references
## Steps to reproduce
<!-- How to trigger the bug -->
## Cognitive invariants (memory/cognition issues — both handoffs)
<!-- Complete ONLY if this issue touches memory, learning, or self-model state. -->
- [ ] **Owner** — which existing subsystem owns this (audit before creating modules)
+33 -8
View File
@@ -1,18 +1,44 @@
---
name: Feature Request
about: New feature or improvement — DESCRIPTION GATE v4 format (plain summary + pipeline requirements)
about: New feature or improvement — plain English first, verifiable close conditions, version intent
title: "[FEATURE] "
labels: feature
assignees: conductor
---
## Plain summary
<!-- 2-4 sentences, NON-TECHNICAL: what this does and why it matters. Nick should
understand the goal without decoding internals. -->
<restate the issue title here in everyday words — this heading IS the
plain-English summary; no meta-labels like "plain English" in it>
<!-- The heading above carries the summary itself — a scan of issue
headings alone should tell the whole story of the board. TOP PRIORITY:
if a technical detail below contradicts this section, the issue is
buggy — fix the issue. A non-technical reader must be able to retell this
section. 3-6 sentences, no jargon. -->
<!-- SUBMITTED_BODY -->
What is this about: <what>
Why do we need it: <the itch — what happens today that shouldn't, or what becomes possible>
Why is it still open: <"not started yet" | "part done, X remains" | "deliberately parked as a future idea">
## Example
<!-- A concrete example of the intended behavior, in plain terms:
"If X happens, the system will Y instead of Z." -->
<!-- A concrete before/after in plain terms: "If X happens, the system will Y instead of Z." -->
## What would let us close this
<!-- Checkable statements, verifiable by looking at something that EXISTS —
a file, a log line, a passing test. Not "when appropriate". -->
- [ ] <condition 1 — observable>
- [ ] <condition 2>
## Version impact (declared at submission — verified at merge)
<!-- The pipeline derives the real bump from merged conventional commits and
compares against this declaration. A mismatch is flagged, not fatal:
either the declaration was wrong or the work grew. Both facts matter. -->
- [ ] major — breaking: changes a contract, schema, or interface others depend on
- [ ] minor — new capability: something becomes possible that wasn't
- [ ] patch — repair: same behaviour, done correctly
- [ ] none — touches no released artifact (docs, memory, process notes)
## Technical details
<!-- WHAT — one-line objective.
@@ -37,7 +63,6 @@ DEPENDENCIES — parent epic + preceding stage/plan refs. -->
- [ ] Canary passes (name)
- [ ] Closed with a properly formatted closing comment + commit/PR references
## Cognitive invariants (memory/cognition issues — both handoffs)
<!-- Complete ONLY if this issue touches memory, learning, or self-model state. -->
- [ ] **Owner** — which existing subsystem owns this (audit before creating modules)
@@ -69,4 +94,4 @@ Hard invariants: derived cognition preserves evidentiary ancestry · epistemic c
- [ ] **P0 — critical** — breaks the spine / core correctness, or blocks other work
- [ ] **P1 — high** — material user value or a real defect (money, correctness bugs, next-stage dependency)
- [ ] **P2 — medium** — quality/consolidation improvement (check the fold-into mapping first)
- [ ] **P3 — low** — measurement / benchmark / deferred policy
- [ ] **P3 — low** — measurement / benchmark / deferred policy
+76
View File
@@ -0,0 +1,76 @@
---
name: Research Submission
about: Buy down uncertainty before building — question, falsifier, budget, durable findings
title: "[RESEARCH] "
labels: research
assignees: conductor
---
<restate the issue title here in everyday words — this heading IS the
plain-English summary; no meta-labels like "plain English" in it>
<!-- The heading above carries the summary itself — a scan of issue
headings alone should tell the whole story of the board. TOP PRIORITY:
if a technical detail below contradicts this section, the issue is
buggy — fix the issue. -->
<!-- SUBMITTED_BODY -->
The question: <what we're trying to learn, one sentence>
Why we're asking: <what decision this research will inform — a name, an issue
number, or "exploratory: none yet">
What we believe today: <the current assumption, stated so it can be proven wrong>
## The shape of an answer
- [ ] What evidence would settle the question: <observation, benchmark, or spike>
- [ ] What evidence would KILL the current assumption (the falsifier): <be specific —
this is stated BEFORE starting so the research cannot become a search for confirmation>
- [ ] Budget: <time/effort cap — when research must stop and report back>
## What would let us close this
- [ ] Findings written to a durable document: <path, e.g. research/issue-NNN/> —
a comment thread is not a durable finding
- [ ] The decision the research informs is recorded: made / deferred / changed
- [ ] If a follow-up build issue was minted: <#N or "none needed">
## Version impact (declared at submission — verified at merge)
- [ ] none — research changes no released artifact (usual)
- [ ] minor/major — only if a code spike is being merged as part of this (justify)
## Technical detail
<!-- Candidate approaches, prior art in the repo, related issues, constraints,
rebuildable-projection or authority requirements if findings touch canonical state. -->
## Pipeline requirements
- [ ] Findings committed under the stated durable path
- [ ] Every citation verified against a real source (no fabricated references)
- [ ] Closed with a properly formatted closing comment: findings summary + decision
## Cognitive invariants (memory/cognition research — both handoffs)
<!-- Complete ONLY if findings touch memory, learning, or self-model state. -->
- [ ] **Owner** — which existing subsystem owns this (audit before proposing modules)
- [ ] **Read/write authority** — which canonical state is affected
- [ ] **Provenance** — findings traceable to evidence
- [ ] **Reversibility** — projections remain rebuildable; no unique truth moves into a derived index
- [ ] **No duplicate authority** — why extend vs create
Hard invariants: derived cognition preserves evidentiary ancestry · retrieval never increases utility · raw evidence is never destroyed by promotion.
## Related umbrella
- [ ] Memory
- [ ] Governance
- [ ] Identity
- [ ] Growth
- [ ] Perception
- [ ] Infrastructure
- [ ] Life (Nick's)
- [ ] Custodian
- [ ] Orchestration
## Priority (REQUIRED — the priority gate)
<!-- Pick exactly one. An issue without a priority is not filed. -->
- [ ] **P0 — critical** — blocks a decision that blocks other work
- [ ] **P1 — high** — informs a next-stage dependency
- [ ] **P2 — medium** — quality/consolidation understanding
- [ ] **P3 — low** — watchlist / deferred / exploratory
+30 -11
View File
@@ -58,9 +58,38 @@ jobs:
const managedLabels = new Set([
'memory', 'governance', 'identity', 'growth',
'perception', 'infrastructure', 'life', 'custodian',
'priority: high', 'bug', 'feature',
'priority: high', 'bug', 'feature', 'research',
]);
// Type label: DECLARED over GUESSED. The template spine
// (kind: bug|feature|research|epic|...) is authoritative.
// A recognized kind maps to its label; ANY other declared kind
// (e.g. epic) means NO type label and NO keyword guessing —
// epics are containers, not bugs. Keyword heuristics apply
// only to pre-template issues with no spine at all.
let isBug = false, isFeature = false, isResearch = false;
const kindMatch = body && body.match(/^kind:\s*([a-z_-]+)\s*$/m);
if (kindMatch) {
const kind = kindMatch[1];
isBug = kind === 'bug';
isFeature = kind === 'feature';
isResearch = kind === 'research';
} else {
const textBug = title.startsWith('[BUG]') || text.includes('bug') || text.includes('fix') || text.includes('broken');
isBug = textBug;
isFeature = !isBug && (title.startsWith('[FEATURE]') || text.includes('feature') || text.includes('improve') || text.includes('add'));
isResearch = !isBug && !isFeature && title.startsWith('[RESEARCH]');
}
if (isBug) {
desiredLabels.add('bug');
}
if (isFeature) {
desiredLabels.add('feature');
}
if (isResearch) {
desiredLabels.add('research');
}
// Umbrella labels
if (text.includes('memory') || text.includes('store') || text.includes('recall') || text.includes('consolidat')) {
desiredLabels.add('memory');
@@ -92,16 +121,6 @@ jobs:
desiredLabels.add('priority: high');
}
// Type labels
const isBug = title.startsWith('[BUG]') || text.includes('bug') || text.includes('fix') || text.includes('broken');
const isFeature = !isBug && (title.startsWith('[FEATURE]') || text.includes('feature') || text.includes('improve') || text.includes('add'));
if (isBug) {
desiredLabels.add('bug');
}
if (isFeature) {
desiredLabels.add('feature');
}
const issueNumber = context.payload.issue?.number || context.payload.pull_request?.number;
const current = await github.rest.issues.listLabelsOnIssue({
owner: context.repo.owner,
+40 -45
View File
@@ -71,7 +71,13 @@ jobs:
echo "HEAD is a release bump — loop guard, no re-bump"
exit 0
fi
WARRANTED=$(python3 scripts/version_convergence.py | python3 -c "import json,sys; print(json.load(sys.stdin).get('warranted_bump') or '')")
CONVERGENCE=$(python3 scripts/version_convergence.py)
WARRANTED=$(echo "$CONVERGENCE" | python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('warranted_bump') or '')")
CONVERGED=$(echo "$CONVERGENCE" | python3 -c "import json,sys; print(json.load(sys.stdin).get('converged', 'true'))")
if [ "$CONVERGED" = "True" ]; then
echo "Already converged — no bump needed"
exit 0
fi
echo "push convergence: warranted_bump=$WARRANTED"
if [ -z "$WARRANTED" ]; then
echo "No substantive commits since last tag — no bump needed"
@@ -179,56 +185,45 @@ jobs:
print(f" - {d}")
sys.exit(1)
# Commit each surface DIRECTLY to master (bookkeeping, not reviewable code)
msg_prefix = f"chore(release): auto-bump version to {NEW} — earned by #{PR_NUMBER}"
for path, (content, sha) in edited.items():
status, r = api(f"/contents/{path}", "PUT", {
"message": f"{msg_prefix} ({PR_TITLE[:80]})\n\nPromotion record: {promoting_url}",
"content": base64.b64encode(content.encode()).decode(),
"sha": sha,
"branch": "master",
})
if status not in (200, 201):
print(f" commit {path} failed ({status}): {str(r)[:200]}"); sys.exit(1)
print(f" committed {path} to master")
# Commit ALL surfaces as ONE commit via ChangeFiles
# (POST /contents with a files[] array). The per-file contents PUT
# created one commit per version surface — five same-version "bump
# commits" per release (the phantom duplicate-bump cascade,
# misdiagnosed as queue drain since 0.66.2; root-caused T15 Part F
# 2026-09-11). Git-data blob/tree creation is 404 on this Gitea
# build; ChangeFiles is the supported single-commit primitive.
msg = f"chore(release): auto-bump version to {NEW} — earned by #{PR_NUMBER} ({PR_TITLE[:80]})\n\nPromotion record: {promoting_url}"
ops = [{
"operation": "update",
"path": path,
"content": base64.b64encode(content.encode()).decode(), # ChangeFileOperation.content is ContentBase64
} for path, (content, _old_sha) in edited.items()]
status, r = api("/contents", "POST", {
"branch": "master",
"message": msg,
"files": ops,
})
if status not in (200, 201):
print(f"change-files failed ({status}): {str(r)[:300]}"); sys.exit(1)
commit_sha = (r.get("commit") or {}).get("sha", "?") if isinstance(r, dict) else "?"
print(f" committed {len(ops)} surfaces as ONE commit {str(commit_sha)[:7]}")
print(f"AUTO_BUMPED=true — version {NEW} live on master; TUI footer will render v{NEW}")
with open(os.environ["GITHUB_ENV"], "a") as env:
env.write(f"RELEASE_VERSION={NEW}\n")
env.write("AUTO_BUMPED=true\n")
PYBUMP
- name: Create release from merged pull request
- name: Create evidence-derived release (SCAFFOLD-TRANCHE-009B)
env:
GITEA_TOKEN: ${{ secrets.ROBOT_TOKEN }}
PR_TITLE: ${{ gitea.event.pull_request.title }}
PR_BODY: ${{ gitea.event.pull_request.body }}
RELEASE_API_URL: ${{ gitea.server_url }}/api/v1/repos/${{ gitea.repository }}/releases
LIST_API_URL: ${{ gitea.server_url }}/api/v1/repos/${{ gitea.repository }}/releases?limit=50
RELEASE_SERVER_URL: ${{ gitea.server_url }}
RELEASE_REPO: ${{ gitea.repository }}
run: |
# Skip idempotently if a release for this tag already exists (retry/replay safety).
if curl --fail --silent "$LIST_API_URL" \
-H "Authorization: token $GITEA_TOKEN" \
| python3 -c 'import json,sys,os; exists=[r for r in json.load(sys.stdin) if r.get("tag_name")==f"v{os.environ[\"RELEASE_VERSION\"]}"]; sys.exit(0 if exists else 1)'; then
echo "Release v$RELEASE_VERSION already exists — skipping creation"
exit 0
fi
python3 - <<'PY' > /tmp/rune-release.json
import json, os
version = os.environ["RELEASE_VERSION"]
body = f"## {os.environ['PR_TITLE']}\n\n{os.environ.get('PR_BODY', '')}"
print(json.dumps({
"tag_name": f"v{version}",
"target_commitish": "master",
"name": f"Rune v{version}",
"body": body,
"draft": False,
"prerelease": False,
}))
PY
curl --fail-with-body --silent --show-error \
-X POST \
-H "Authorization: token $GITEA_TOKEN" \
-H "Content-Type: application/json" \
--data-binary @/tmp/rune-release.json \
"$RELEASE_API_URL"
rm -f /tmp/rune-release.json
# ONE note-generation authority: the tested release_notes module.
# The old PR-title/body paste path (which produced empty '##'
# bodies on direct-push releases) is REMOVED — governed evidence
# from the scaffold store is the source, not PR prose.
python3 scripts/release_history_cli.py init \
--version "$RELEASE_VERSION" \
--server "$RELEASE_SERVER_URL" --repo "$RELEASE_REPO" \
--store store/scaffold/current.json
+57 -8
View File
@@ -286,12 +286,61 @@ jobs:
run: |
NEW="$(echo "${{ gitea.event.pull_request.head.ref }}" | sed 's|chore/auto-bump-||')"
python3 scripts/check_version_surfaces.py check --root . --version "$NEW"
- name: Publish protected-branch gate (full pipeline path)
if: ${{ !startsWith(gitea.event.pull_request.head.ref, 'chore/auto-bump') }}
- name: Publish protected-branch gate (full pipeline path — all needs green)
# RELEASE-SAFETY FIX (2026-09-13): the previous version of this step
# read /tmp/need_* files that no step ever writes and echoed success
# UNCONDITIONALLY — required-checks published green while type-check
# and unit-tests were red, and deploy promoted the red commits
# (observed live: 24413e4, fd6e9b4, de30cd9 promoted 0.66.28/29 with
# failing type-check). The verdict now comes from the needs context
# itself: this step runs ONLY when every required job succeeded.
if: >-
${{ !startsWith(gitea.event.pull_request.head.ref, 'chore/auto-bump')
&& needs.lint.result == 'success'
&& needs['unit-tests'].result == 'success'
&& needs.canary.result == 'success'
&& needs['best-practices'].result == 'success'
&& needs.documentation.result == 'success'
&& needs['type-check'].result == 'success'
&& needs['gitea-offline'].result == 'success' }}
run: echo "All required CI checks passed"
- name: Refuse promotion when any required check failed (fail-closed)
# Companion to the step above: if anything is not exactly success
# (failure, cancelled, skipped on a non-bump path), the required-checks
# context reports FAILURE — deploy_qualify then refuses promotion.
# Fail-closed: not verified → not deployable.
if: >-
${{ !startsWith(gitea.event.pull_request.head.ref, 'chore/auto-bump')
&& (needs.lint.result != 'success'
|| needs['unit-tests'].result != 'success'
|| needs.canary.result != 'success'
|| needs['best-practices'].result != 'success'
|| needs.documentation.result != 'success'
|| needs['type-check'].result != 'success'
|| needs['gitea-offline'].result != 'success') }}
run: |
# All needs must have succeeded (skipped deps = this is a bump PR, handled above)
FAILED=""
for job in lint unit-tests canary best-practices documentation type-check gitea-offline; do
RESULT=$(cat /tmp/need_$job 2>/dev/null || echo "")
done
echo "All required CI checks passed"
echo "::error::Required CI checks not green — refusing to publish required-checks success"
echo "lint=${{ needs.lint.result }} unit-tests=${{ needs['unit-tests'].result }} canary=${{ needs.canary.result }} best-practices=${{ needs['best-practices'].result }} documentation=${{ needs.documentation.result }} type-check=${{ needs['type-check'].result }} gitea-offline=${{ needs['gitea-offline'].result }}"
exit 1
notify-event-bridge:
# T16 §16C: post the CI completion WAKE to the local event bridge so
# event-driven waiters (deploy.yml → ci_event_wait.py) resume on the
# event instead of sleep-polling. ALWAYS runs (success or failure —
# a red CI must wake the waiter just as loudly as a green one). The
# wake is best-effort and never decides the verdict: the waiter
# re-reads the canonical Gitea state via deploy_qualify.py.
name: CI Pipeline / notify-event-bridge
runs-on: rune-ci-desktop
needs: [required-checks]
if: always()
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
fetch-depth: 1
- name: Wake event bridge (wake only — never completion truth)
env:
CI_SHA: ${{ gitea.sha }}
CI_RESULT: ${{ needs.required-checks.result }}
RUNE_EVENT_BRIDGE_URL: ${{ vars.RUNE_EVENT_BRIDGE_URL || 'http://127.0.0.1:8791' }}
run: python3 scripts/notify_event_bridge.py
+78 -17
View File
@@ -19,38 +19,74 @@ jobs:
with:
fetch-depth: 0
- name: Wait for CI qualification on this exact SHA
- name: Wait for CI qualification on this exact SHA (event-driven, T16 §16C)
# T16 §16C/§16D: the old sleep-30 → query → repeat loop is gone.
# The waiter registers a correlation on the W/R event bridge and
# yields in select() until ci.yml's notify-event-bridge job posts
# the completion WAKE; the verdict is then re-read from canonical
# Gitea (deploy_qualify.py). The 900s deadline is a FAILURE
# DETECTOR (lost-event recovery), never the scheduler.
env:
GITEA_SERVER: ${{ gitea.server_url }}
GITEA_REPO: ${{ gitea.repository }}
GITEA_TOKEN: ${{ secrets.ROBOT_TOKEN }}
# Shared bridge data root: the deploy step runs as the runner
# user while the daemon runs as nick — the rendezvous state
# (waits/events/resumes/leases) must be shared. §16C live
# finding: defaulting to the invoking user's home made the
# controller unable to create its FIFO (PermissionError) and
# the deploy failed fast+truthfully on both 0.66.63 pushes.
RUNE_WR_ROOT: /mnt/workdrive/wr-bridge
RUNE_WR_CODE: /home/nick/.local/share/mimo-wait-resume
run: |
DEPLOY_SHA=$(git rev-parse HEAD)
export DEPLOY_SHA
echo "Qualifying $DEPLOY_SHA"
DEADLINE=$((SECONDS + 900))
while [ $SECONDS -lt $DEADLINE ]; do
STATUS=$(python3 scripts/deploy_qualify.py)
echo "required-checks: $STATUS"
if [ "$STATUS" = "success" ]; then exit 0; fi
if [ "$STATUS" = "failure" ]; then
echo "::error::CI failed on $DEPLOY_SHA — deployment refused"
exit 1
fi
sleep 30
done
echo "::error::CI qualification timeout on $DEPLOY_SHA — deployment refused"
exit 1
echo "Qualifying $DEPLOY_SHA (event-driven)"
# READINESS BEFORE ACTION (§16U): fail with a clear message if
# the bridge rendezvous is not writable in THIS user's context,
# instead of a stack trace at FIFO creation time.
if ! touch /mnt/workdrive/wr-bridge/resumes/.write-probe 2>/dev/null; then
echo "::error::RUNE_WR_ROOT not writable by $(id -un) — bridge data root misconfigured"
exit 1
fi
rm -f /mnt/workdrive/wr-bridge/resumes/.write-probe
python3 scripts/ci_event_wait.py --sha "$DEPLOY_SHA" --deadline 900
- name: Stage, verify, promote
- name: Stage, verify, promote (monotonic)
env:
GITEA_TOKEN: ${{ secrets.ROBOT_TOKEN }}
GITEA_SERVER: ${{ gitea.server_url }}
GITEA_REPO: ${{ gitea.repository }}
run: |
python3 scripts/deploy_stage.py
- name: Post-deploy runtime verification (the consuming path)
- name: Promotion truthfulness check
id: promotion_truth
run: |
SHA=$(git rev-parse HEAD)
CURRENT_TARGET=$(readlink /mnt/workdrive/rune-code/current || true)
if [ "$CURRENT_TARGET" = "/mnt/workdrive/rune-code/${SHA:0:12}" ]; then
echo "PROMOTED: current == candidate ($SHA)"
echo "promoted=true" >> "$GITEA_OUTPUT"
else
# Not promoted. deploy_stage exit 0 + non-matching current =
# NOOP_ALREADY_CURRENT or STALE_SUPERSEDED — truthful non-error
# terminal states (a newer build already won). Do NOT claim
# promotion; the runtime-verification step below only runs for
# real promotions.
echo "NOT PROMOTED: current -> $CURRENT_TARGET (superseded/noop — current is authoritative)"
echo "promoted=false" >> "$GITEA_OUTPUT"
fi
- name: Post-deploy runtime verification (only for real promotions)
if: ${{ success() }}
run: |
SHA=$(git rev-parse HEAD)
CURRENT_TARGET=$(readlink /mnt/workdrive/rune-code/current || true)
if [ "$CURRENT_TARGET" != "/mnt/workdrive/rune-code/${SHA:0:12}" ]; then
echo "SKIP runtime verification: this job did not promote (superseded/noop)"
exit 0
fi
# Exactly what the launcher execs: cd <current>/src, import rune.
RUNE_HOME=/mnt/workdrive/rune RUNE_MEMORY_DIR=/home/nick/.config/opencode/memory \
/home/nick/.venvs/memory/bin/python3 -c "
@@ -62,3 +98,28 @@ jobs:
assert rune.__version__ == info['version']
print('RUNTIME VERIFIED:', info)
"
- name: Release-history convergence fallback (SCAFFOLD-TRANCHE-0012C)
# The PRIMARY convergence mechanism is deploy_stage.py's out-of-lock
# publisher (publishes from CURRENT deployment authority, §14B/§14C).
# This step is a non-blocking FALLBACK: if the primary publish failed
# (e.g. missing Gitea config), this retries. NEVER fails the job —
# documentation failure never outweighs deployment validity.
if: ${{ success() && steps.promotion_truth.outputs.promoted == 'true' }}
continue-on-error: true
env:
GITEA_TOKEN: ${{ secrets.ROBOT_TOKEN }}
RELEASE_SERVER_URL: ${{ gitea.server_url }}
RELEASE_REPO: ${{ gitea.repository }}
run: |
VERSION=$(python3 -c "import sys; sys.path.insert(0,'src'); import rune; print(rune.__version__)" 2>/dev/null || echo "")
if [ -z "$VERSION" ]; then
echo "SKIP: cannot determine version"
exit 0
fi
python3 scripts/release_history_cli.py refresh \
--version "$VERSION" \
--server "$RELEASE_SERVER_URL" --repo "$RELEASE_REPO" \
--store "$GITHUB_WORKSPACE/store/scaffold/current.json" \
--release-sha "$(git rev-parse HEAD)" \
--deployed-sha "$(git rev-parse HEAD)" \
|| echo "::warning::release-history fallback refresh FAILED — in-lock hook may have already converged; retry converges"
+4 -1
View File
@@ -22,9 +22,12 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Run all canaries
# T16 §16Q reconciliation: the glob looped shared/canary_*.py —
# real canaries live in src/rune/ (canary_native.MODULES is the
# registry authority). The old job silently no-opped.
run: |
FAILED=0
for canary in shared/canary_*.py; do
for canary in src/rune/canary_*.py; do
if [ -f "$canary" ]; then
echo "Running $canary..."
python3 "$canary" || FAILED=$((FAILED + 1))
+3
View File
@@ -11,3 +11,6 @@ build/
.env
.venv/
state/
# Runtime artifacts (cwd-local event journal + capability index)
index/
journal/
+23
View File
@@ -58,3 +58,26 @@ fix, full pipeline re-entry (suite + ratchet + ruff + canaries + henxels;
gates for anything beyond a mechanical minor), regression tests frozen forever,
discharge recorded finding → test → commit. Symptom patches are rejected at
review. To escape: edit `henxels.yaml` or this file — visibly.
## Issue organisation standard (binding, 2026-09-19)
One open note per idea. Issues use the template spine (kind, subsystem,
version intent) with a plain-English heading that restates the subject —
no meta-labels. Before minting a standalone issue, check whether the work
belongs inside an existing parent:
- **Parked ideas under a blocked/future epic** are filed as checklist items
in the parent's "Absorbed children" section, NOT as standalone issues.
Absorption is reversible — re-mint standalone when the idea becomes live.
- **Live, dependency-tracked, or starting work** gets a standalone issue.
- **Closures state the reason as data**: `closed_because` in the spine
(completed / superseded-by-#N / absorbed-into-#N / wont-do / duplicate),
plus a standard closing comment (plain summary first).
- The reconciliation checker (`scripts/gitea_reconciliation_check.py`) must
stay green after any issue state change; the artifact is updated in the
same change that moves issues.
## Async continuation final flow proofs (R13/M9) — 2026-09-19
PR-flow live proof marker: harmless documentation addition exercising the
canonical single-continuation path on the PC-local forge. No code change.
+1 -1
View File
@@ -1,6 +1,6 @@
# Rune
**Current release: v0.66.4**
**Current release: v0.87.5**
**Rune is a persistent personal agent designed to accumulate experience, develop reusable competence, and remain recognisably the same agent even when its underlying foundation model changes.**
+196
View File
@@ -0,0 +1,196 @@
"""completion_file.py — REAL_ASYNC_BRIDGE: durable completion-file delivery
with inotify wake. Replaces FIFO+lease for process-wait delivery.
DESIGN:
Producer (bridge/daemon/notify):
1. Validates operation identity
2. Atomically writes a completion file:
resumes/<operation_id>.done
containing the event/verdict JSON (write to tmp, rename for atomicity)
Waiter (ci_event_wait / any continuation consumer):
1. Checks if the completion file already exists (event-before-waiter)
2. If not: registers inotify watch on the resumes/ directory
3. Re-checks after watch registration (closes the registration race)
4. Blocks in kernel on inotify — zero CPU, zero timer
5. On file-created event: reads the file, verifies authority, returns
The event is a WAKE SIGNAL. Authority still decides terminal truth.
The completion file is durable — survives daemon and waiter restarts.
WHY NOT FIFO:
FIFO is one-shot (token consumed), requires lease management, and
fails under session-busy guards. A completion file is atomic, durable,
and works across restarts. inotify wakes the process with zero CPU
cost and zero latency between file creation and wake.
WHY NOT POLLING:
Polling introduces an arbitrary interval. inotify is a kernel callback
that fires exactly when the filesystem changes — the latency tracks
the real completion event, not a configured interval.
"""
from __future__ import annotations
import json
import os
import select
import struct
import time
from pathlib import Path
def _wr_bridge() -> Path:
# WR_ROOT = daemon/infra convention; RUNE_WR_ROOT = repo/scripts
# convention. Both honored (WR_ROOT wins) so the daemon, the waiter,
# and any isolated test root always resolve the SAME directory.
root = os.environ.get("WR_ROOT") or os.environ.get("RUNE_WR_ROOT") or "/mnt/workdrive/wr-bridge"
return Path(root)
def _resumes_dir() -> Path:
return _wr_bridge() / "resumes"
# inotify constants (Linux)
IN_CREATE = 0x100
IN_CLOSE_WRITE = 0x8
IN_MOVED_TO = 0x80
def completion_path(operation_id: str) -> Path:
return _resumes_dir() / f"{operation_id}.done"
def write_completion(operation_id: str, event: dict) -> Path:
"""Atomically write a durable completion file. The rename(2) ensures
the waiter never sees a partial file."""
_resumes_dir().mkdir(parents=True, exist_ok=True)
target = completion_path(operation_id)
tmp = target.parent / f".{target.name}.tmp.{os.getpid()}"
tmp.write_text(json.dumps(event, sort_keys=True) + "\n")
os.rename(str(tmp), str(target)) # atomic on same filesystem
os.chmod(str(target), 0o666) # cross-user bridge
return target
def read_completion(operation_id: str) -> dict | None:
"""Read a durable completion file. Returns None if absent."""
p = completion_path(operation_id)
if not p.is_file():
return None
try:
return json.loads(p.read_text())
except (OSError, ValueError):
return None
def completion_exists(operation_id: str) -> bool:
return completion_path(operation_id).is_file()
def _inotify_init_and_add_watch(directory: str) -> int:
"""Create an inotify instance and add a watch on the directory.
Returns the inotify fd."""
libc = __import__("ctypes").CDLL(None, use_errno=True)
fd = libc.inotify_init()
if fd < 0:
raise OSError("inotify_init failed")
# IN_CREATE | IN_MOVED_TO: catch both direct creation and atomic rename
mask = IN_CREATE | IN_MOVED_TO
wd = libc.inotify_add_watch(fd, directory.encode(), mask)
if wd < 0:
os.close(fd)
raise OSError(f"inotify_add_watch failed for {directory}")
return fd
def _inotify_read(fd: int, timeout_secs: float | None = None) -> list[str]:
"""Read pending inotify events. Returns list of filenames that were
created/moved-to. Blocks until at least one event or timeout."""
poll = select.poll()
poll.register(fd, select.POLLIN)
events = []
buf = os.read(fd, 4096)
pos = 0
while pos < len(buf):
# struct: wd(i32), mask(u32), cookie(u32), name_len(u32)
wd, mask, cookie, name_len = struct.unpack_from("iIII", buf, pos)
pos += 16
name = buf[pos : pos + name_len].rstrip(b"\x00").decode("utf-8", "replace")
pos += name_len
if mask & (IN_CREATE | IN_MOVED_TO):
events.append(name)
return events
def wait_for_completion(operation_id: str, *, timeout_secs: float | None = None, poll_callback=None) -> dict | None:
"""Block until a completion file exists for this operation.
Uses inotify for zero-latency, zero-CPU wake. Falls back to
polling_callback (if provided) when inotify is unavailable.
The completion file is a WAKE SIGNAL. The caller must still verify
canonical authority after reading it.
Returns the event dict from the completion file, or None on timeout.
"""
target = completion_path(operation_id)
# 1. check-before-watch (event may have arrived before we started)
existing = read_completion(operation_id)
if existing is not None:
return existing
_resumes_dir().mkdir(parents=True, exist_ok=True)
try:
fd = _inotify_init_and_add_watch(str(_resumes_dir()))
except OSError:
# inotify unavailable: fall back to polling callback
if poll_callback:
return poll_callback(operation_id, timeout_secs)
return None
try:
# 2. re-check after watch registration (closes the race between
# the initial check and the watch being active)
existing = read_completion(operation_id)
if existing is not None:
return existing
# 3. block in kernel on inotify — zero CPU, exact latency
import select as _select
poll = _select.poll()
poll.register(fd, _select.POLLIN)
deadline = (time.monotonic() + timeout_secs) if timeout_secs else None
while True:
remaining = None
if deadline is not None:
remaining = max(0.1, deadline - time.monotonic())
if remaining <= 0.1:
return None # timeout
events = poll.poll(remaining * 1000 if remaining else None)
if not events:
continue # poll timeout, re-check
names = _inotify_read(fd)
if target.name in names:
# 4. file appeared — read it
existing = read_completion(operation_id)
if existing is not None:
return existing
# partial/corrupt: keep watching
finally:
os.close(fd)
return None
def clear_completion(operation_id: str) -> None:
"""Remove a consumed completion file (idempotent cleanup)."""
p = completion_path(operation_id)
try:
p.unlink()
except OSError:
pass
+799
View File
@@ -0,0 +1,799 @@
#!/usr/bin/env python3
"""daemon.py — Gitea webhook receiver + reconciliation + resume driver (v0.2).
W/R-v0.2 invariants implemented here:
A. SINGLE-FLIGHT PER SESSION — per-session lease (waitstore.acquire_lease,
/proc-validated, atomic) + in-process inflight set. A second READY wait
for the same session stays queued until the lease releases.
B. BUSY SESSION PROTECTION — before spawning, /proc is scanned for a live
`mimo run -s <sid>`-shaped process not owned by our lease. Found → skip
launch (wait stays READY). No invented MiMo APIs; the lease is the
conservative floor against W/R-created concurrency.
C. ATOMIC SESSION LEASE — persisted {session_id, wait_id, pid, pgid,
pid_starttime, acquired_at, state}; O_EXCL create, steal only on /proc
evidence of a dead owner.
D. PROCESS TREE OWNERSHIP — workers spawn with start_new_session=True (own
process group). Watch timeout ⇒ SIGTERM group → bounded grace → SIGKILL
group → verify zero surviving group members → release lease → truthful
READY_TO_RETRY (never terminal-on-timeout).
E. TIMEOUT IS NOT SUCCESS — rc==0 maps to verdict terminal
(COMPLETED/FAILED); rc!=0 or unverifiable ⇒ RESUME_UNVERIFIED
(not schedulable, operator-requeueable); timeout ⇒ READY_TO_RETRY.
F. STALE RESUMING RECOVERY — on startup, every RESUMING record is
inspected: live lease owner ⇒ adopted and monitored; otherwise ⇒
RESUME_UNVERIFIED (+ stale lease released). Never auto-relaunched.
G. MULTIPLE WAITS, SAME SESSION — schedulable() orders oldest-first; one
continuation finishes before the next starts.
H. PIDFILE CORRECTNESS — singleton enforced by flock on daemon.pid; the
lock dies with the process, so stale pidfiles (incl. SIGKILL) cannot
admit a second daemon.
The resume command is configurable (WR_RESUME_CMD, JSON list with
{session_id}/{msg} placeholders) so the test harness can use a stub; the
default is the real mechanism: `mimo run -s <sid> -m <model> <msg>`.
"""
from __future__ import annotations
import fcntl, json, os, signal, subprocess, sys, threading, time
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent))
import waitstore
import verify
import completion_file # REAL_ASYNC_BRIDGE R3: durable completion-file delivery
RESUME_MODEL = "Verboo Code/glm-5.3-flash"
RECONCILE_SECS = int(os.environ.get("WR_RECONCILE_SECS", "60"))
RECONCILE_EVERY_TICKS = max(1, int(os.environ.get("WR_RECONCILE_TICKS", "3")))
WAKE_MIN_AGE_SECS = float(os.environ.get("WR_WAKE_MIN_AGE_SECS", "5"))
WAKE_RETRIES = int(os.environ.get("WR_WAKE_RETRIES", "3"))
WAKE_RETRY_SECS = float(os.environ.get("WR_WAKE_RETRY_SECS", "4"))
DRIVE_LOOP_SECS = int(os.environ.get("WR_DRIVE_SECS", "20"))
# REAL_ASYNC_BRIDGE §4: a RESUMING wait older than this grace without
# progress is an orphaned resume flow (thread died between lease acquire
# and release). Must exceed the longest legitimate in-flight watch
# (WATCH_SECS); default 3x. Env-overridable for deterministic tests.
WATCH_SECS = int(os.environ.get("WR_WATCH_SECS", "600"))
# REAL_ASYNC_BRIDGE §4: a RESUMING wait older than this grace without
# progress is an orphaned resume flow (thread died between lease acquire
# and release). Must exceed the longest legitimate in-flight watch
# (WATCH_SECS); default 3x. Env-overridable for deterministic tests.
ORPHAN_GRACE_SECS = int(os.environ.get("WR_ORPHAN_GRACE_SECS", str(3 * WATCH_SECS)))
TERM_GRACE_SECS = int(os.environ.get("WR_TERM_GRACE_SECS", "10"))
MAX_ATTEMPTS = int(os.environ.get("WR_MAX_ATTEMPTS", "3"))
_WR_ROOT = Path(os.environ.get("WR_ROOT", "") or Path(__file__).resolve().parent)
PIDFILE = _WR_ROOT / "daemon.pid"
LOG = _WR_ROOT / "daemon.log"
DEFAULT_RESUME_CMD = ["mimo", "run", "-s", "{session_id}", "-m", RESUME_MODEL, "{msg}"]
def log(msg: str) -> None:
with open(LOG, "a") as f:
f.write(f"{time.strftime('%H:%M:%S')} {msg}\n")
def resume_cmd(session_id: str, msg: str, wait_id: str = "", override: list | None = None) -> list[str]:
"""T15 §15D: per-wait override wins; placeholders {session_id}/{msg}/
{wait_id}. A synthetic controller session (Scaffolding stage driver)
is not a MiMo session — the global default cannot resume it, which is
exactly why fixed-sleep polling crept back into T12-T14."""
if override:
return [
c.replace("{session_id}", session_id).replace("{msg}", msg).replace("{wait_id}", wait_id) for c in override
]
tmpl = os.environ.get("WR_RESUME_CMD")
cmd = json.loads(tmpl) if tmpl else DEFAULT_RESUME_CMD
return [c.replace("{session_id}", session_id).replace("{msg}", msg).replace("{wait_id}", wait_id) for c in cmd]
# ── process-tree evidence & ownership ─────────────────────────────────────
def pgid_members(pgid: int) -> list[int]:
out = []
for d in Path("/proc").iterdir():
if not d.name.isdigit():
continue
try:
stat = (d / "stat").read_text()
fields = stat.rsplit(")", 1)[1].split()
# zombies: killed but not yet reaped. Counting them makes the
# survivor check report the direct child we just KILLed before
# communicate() reaps it (observed live 2026-09-12).
if fields[0] == "Z":
continue
if int(fields[2]) == pgid:
out.append(int(d.name))
except (OSError, IndexError, ValueError):
continue
return out
def terminate_tree(pgid: int) -> list[int]:
"""TERM → bounded grace → KILL. Returns surviving members (must be [])."""
try:
os.killpg(pgid, signal.SIGTERM)
except ProcessLookupError:
pass
deadline = time.time() + TERM_GRACE_SECS
while time.time() < deadline:
if not pgid_members(pgid):
return []
time.sleep(0.2)
try:
os.killpg(pgid, signal.SIGKILL)
except ProcessLookupError:
pass
for _ in range(50): # up to 10s for KILL to land
if not pgid_members(pgid):
return []
time.sleep(0.2)
return pgid_members(pgid)
def stray_worker_pids(session_id: str, exclude_pgids: set[int] = ()) -> list[int]:
"""Live `mimo run -s <sid>`-shaped processes not owned by our workers."""
out = []
for d in Path("/proc").iterdir():
if not d.name.isdigit():
continue
try:
parts = [p.decode(errors="replace") for p in (d / "cmdline").read_bytes().split(b"\0") if p]
except OSError:
continue
if not parts:
continue
joined = " ".join(parts)
if session_id not in joined or "-s" not in parts:
continue
if "mimo" not in joined.lower() and "@mimo-ai" not in joined.lower():
continue
try:
if os.getpgid(int(d.name)) in exclude_pgids:
continue
except OSError:
continue
out.append(int(d.name))
return out
# ── verification → transition (unchanged authority model) ─────────────────
def _authoritative_verify(rec: dict) -> tuple[str, dict]:
"""Authoritative verification with a deterministic test seam.
Production (WR_VERIFY_STUB unset): real Gitea API via verify.py — the
ONLY source of success/failure truth. Test (WR_VERIFY_STUB=path to
JSON {"<run_ref-or-sha>": verdict, "default": verdict}): stubbed
verdicts so invariant tests never touch the network. The stub is a
test fixture, not an alternate authority — no production path sets it.
"""
stub_path = os.environ.get("WR_VERIFY_STUB", "")
if stub_path:
try:
spec = json.loads(Path(stub_path).read_text())
except Exception:
return "pending", {"stub_error": "unreadable stub"}
key = str(rec.get("run_ref", "") or rec.get("sha", ""))
verdict = spec.get(key, spec.get("default", "pending"))
return verdict, {"stub": True, "key": key}
import verify
if rec.get("wait_kind") == "RELEASE_DEPLOY":
return verify.verify_release_deploy(rec.get("sha", ""), rec.get("repo_root", ""), rec.get("deployed_link", ""))
return verify.verify_run(rec.get("run_ref", ""), rec.get("sha", ""), rec.get("expected", "success"))
def try_transition(rec: dict, event: dict | None = None) -> dict:
if rec["status"] != "WAITING_EXTERNAL":
return rec
if rec.get("wait_kind") == "PROCESS_EVENT":
# T15 §15D: the matching event IS the authority. The notifier
# wrapper observed the real process exit; exit_code decides the
# verdict. No Gitea lookup applies. A duplicate event never
# reaches here (match applies only to WAITING_EXTERNAL waits).
if not event:
return rec # no event → nothing authoritative happened
try:
exit_code = int(event.get("exit_code"))
except (TypeError, ValueError):
exit_code = None
if exit_code is None:
return rec # malformed event: stay WAITING (15E hostile case)
verdict = "success" if exit_code == 0 else "failure"
evidence = {"process_event": True, "exit_code": exit_code, "operation_id": event.get("run_ref", "")}
log(f"verify {rec['wait_id']}: {verdict} {json.dumps(evidence)[:120]}")
rec["status"] = "READY_TO_RESUME"
rec["verdict"] = verdict
if verdict == "failure":
rec["failure_evidence"] = evidence
rec["process_event_evidence"] = evidence
waitstore.save(rec)
return rec
verdict, evidence = _authoritative_verify(rec)
log(f"verify {rec['wait_id']}: {verdict} {json.dumps(evidence)[:120]}")
if verdict == "success":
rec["status"] = "READY_TO_RESUME"
rec["verdict"] = "success"
elif verdict == "failure":
rec["status"] = "READY_TO_RESUME"
rec["verdict"] = "failure"
rec["failure_evidence"] = verify.failed_job_evidence(rec.get("run_ref", ""))
else:
return rec # pending/unknown → stay WAITING
waitstore.save(rec)
return rec
def continuation_msg(rec: dict) -> str:
c = rec["continuation"]
if rec.get("verdict") == "success":
return (
f"External wait satisfied (wait {rec['wait_id']}).\n"
f"Original objective: {c.get('objective', '')}\n"
f"Waited for: {c.get('waited_for', '')}\n"
f"Authoritative result: workflow success verified via Gitea API.\n"
f"SHA/run: {rec.get('sha', '')}/{rec.get('run_ref', '')}\n"
f"Verify: {c.get('verify_when_woken', '')}\n"
f"Continue from: {c.get('on_success', '')}"
)
ev = json.dumps(rec.get("failure_evidence", {}))[:400]
return (
f"External wait finished with FAILURE (wait {rec['wait_id']}).\n"
f"Original objective: {c.get('objective', '')}\n"
f"Authoritative result: workflow FAILURE verified via Gitea API.\n"
f"Failed job evidence: {ev}\n"
f"SHA/run: {rec.get('sha', '')}/{rec.get('run_ref', '')}\n"
f"Do NOT treat this as success. Continue from: {c.get('on_failure', '')}"
)
# ── resume driver (single-flight, tree-owned) ─────────────────────────────
def resume(rec: dict) -> None:
"""Run one continuation to completion. Runs on a dedicated worker thread.
Preconditions: caller verified no inflight worker for this session."""
sid, wid = rec["session_id"], rec["wait_id"]
# REAL_ASYNC_BRIDGE §2 invariant: a successful authority-verified
# operation completion must NEVER be overwritten or downgraded by a
# legacy session/FIFO delivery failure. Terminal operation state
# (COMPLETED/FAILED — stamped by the waiter's own authority
# verification) is owned by the OPERATION domain; this function owns
# only SESSION-DELIVERY. Re-read from disk: the in-memory copy may be
# stale relative to the waiter's terminal stamp.
fresh = waitstore.load(wid)
if fresh and fresh.get("status") in waitstore.TERMINAL:
log(
f"resume {wid}: skipped — operation already terminal "
f"({fresh['status']}); delivery worker never overrides "
f"operation truth"
)
return
rec = fresh or rec
msg = continuation_msg(rec)
# B: busy-session guard before touching the lease
strays = stray_worker_pids(sid)
if strays:
rec["status"] = "READY_TO_RESUME"
rec["resume_note"] = f"queued: target session busy (stray pids {strays})"
waitstore.save(rec)
log(f"queued {wid}: session busy {strays}")
return
# pre-register the lease owner as THIS daemon so acquisition is atomic
lease = waitstore.acquire_lease(sid, wid, os.getpid(), os.getpid())
if lease is None:
live = waitstore.read_lease(sid)
rec["status"] = "READY_TO_RESUME"
rec["resume_note"] = f"queued: lease held by wait {live and live.get('wait_id')}"
waitstore.save(rec)
log(f"queued {wid}: lease held")
return
rec["status"] = "RESUMING"
rec["resume_attempts"] = rec.get("resume_attempts", 0) + 1
waitstore.save(rec)
try:
proc = subprocess.Popen(
resume_cmd(sid, msg, wid, rec.get("resume_cmd")),
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
start_new_session=True,
)
except Exception as e:
waitstore.release_lease(sid, wid)
rec["status"] = "READY_TO_RETRY" # spawn failed pre-delivery → retryable
rec["resume_note"] = f"spawn failed: {e}"
waitstore.save(rec)
log(f"spawn {wid} failed pre-delivery: {e}")
return
pgid = proc.pid # start_new_session ⇒ pgid == child pid
waitstore.update_lease(sid, wait_id=wid, pid=proc.pid, pgid=pgid, pid_starttime=waitstore._pid_starttime(proc.pid))
log(f"launched {wid}: pid={proc.pid} pgid={pgid} attempt={rec['resume_attempts']}")
timed_out = False
try:
stdout, stderr = proc.communicate(timeout=WATCH_SECS)
rc = proc.returncode
except subprocess.TimeoutExpired:
timed_out = True
survivors = terminate_tree(pgid)
try:
stdout, stderr = proc.communicate(timeout=30)
except Exception:
stdout, stderr = "", ""
rc = proc.returncode
if survivors:
log(f"ERROR {wid}: group {pgid} survivors after KILL: {survivors}")
waitstore.release_lease(sid, wid)
if timed_out:
# D+E: timeout is NOT success. Tree terminated; retry truthfully.
if rec["resume_attempts"] >= MAX_ATTEMPTS:
rec["status"] = "RESUME_UNVERIFIED"
rec["resume_note"] = (
f"watch timeout x{rec['resume_attempts']}; process group {pgid} terminated; attempts exhausted"
)
else:
rec["status"] = "READY_TO_RETRY"
rec["resume_note"] = f"watch timeout; process group {pgid} terminated (TERM→KILL, verified); will retry"
log(f"timeout {wid}: tree {pgid} terminated, rc={rc}")
elif rc == 0:
# COMPLETION TRUTH (constraint 4): rc==0 means the headless worker
# EXITED CLEANLY — the strongest terminal evidence the supported CLI
# provides. Timeout/cancel can never reach this branch. The evidence
# chain (rc, output tail, timing) is recorded on the wait record.
terminal = "COMPLETED" if rec.get("verdict") == "success" else "FAILED"
rec["status"] = terminal
rec["resume_evidence"] = {
"kind": "worker_exited_rc0",
"rc": 0,
"output_tail": (stdout or "")[-400:],
"finished_at": waitstore.now(),
}
log(f"resumed {wid}: rc=0 → {terminal}")
else:
# Nonzero rc: delivery/completion unproven. Honest, not schedulable.
rec["status"] = "RESUME_UNVERIFIED"
rec["resume_evidence"] = {
"kind": "worker_exited_nonzero",
"rc": rc,
"output_tail": ((stdout or "") + (stderr or ""))[-400:],
"finished_at": waitstore.now(),
}
rec["resume_note"] = f"resume rc={rc}; delivery unverified"
log(f"resumed {wid}: rc={rc} → RESUME_UNVERIFIED")
waitstore.save(rec)
# ── startup recovery (invariant F) ────────────────────────────────────────
def startup_recovery() -> None:
for rec in waitstore.all_waits():
if rec.get("status") != "RESUMING":
continue
sid, wid = rec["session_id"], rec["wait_id"]
lease = waitstore.read_lease(sid)
if lease and lease.get("wait_id") == wid and waitstore._owner_alive(lease):
# Adopt the live worker and monitor it to a bounded conclusion.
pgid = lease["pgid"]
log(f"recover {wid}: adopted live worker pgid={pgid}")
deadline = time.time() + WATCH_SECS
while time.time() < deadline and pgid_members(pgid):
time.sleep(2)
survivors = terminate_tree(pgid) if pgid_members(pgid) else []
waitstore.release_lease(sid, wid)
rec["status"] = "RESUME_UNVERIFIED"
rec["resume_note"] = "adopted post-restart; outcome unverifiable" + (
f"; survivors killed: {survivors}" if survivors else ""
)
waitstore.save(rec)
log(f"recover {wid}: adopted worker ended → RESUME_UNVERIFIED")
else:
if lease:
waitstore.release_lease(sid, wid) # stale
rec["status"] = "RESUME_UNVERIFIED"
rec["resume_note"] = "recovered at daemon startup: no live owner; delivery unverifiable"
waitstore.save(rec)
log(f"recover {wid}: no live owner → RESUME_UNVERIFIED")
# ── reconciler + drive loop (invariant G: deterministic queue) ────────────
_inflight: dict[str, threading.Thread] = {}
_inflight_lock = threading.Lock()
def drive_ready() -> None:
for rec in waitstore.schedulable():
sid = rec["session_id"]
# CONTENTION POLICY (constraint 2): MiMo exposes NO supported
# busy/idle session signal (verified 2026-09-12: `mimo session list
# --format json` has no status field; no `session status` command;
# no status column in the session schema; no documented ACP/serve
# endpoint). Therefore automatic injection into interactive sessions
# is NOT YET SAFE and stays disabled. Only waits explicitly declared
# target_kind="headless" (disposable/owned sessions) auto-dispatch.
if rec.get("target_kind") != "headless":
if not rec.get("hold_reason"):
rec["hold_reason"] = (
"INTERACTIVE_AUTO_RESUME = NOT YET SAFE: "
"no supported MiMo busy/idle signal; "
"queued until operator releases"
)
waitstore.save(rec)
continue
if rec.get("ext", {}).get("resume_mode") == "self":
# REAL_ASYNC_BRIDGE §3: self-resuming wait (completion-file /
# inotify waiter owns its continuation). The daemon has NO
# delivery role here — dispatching a delivery worker would
# stamp a phantom rc!=0 over the waiter's own truthful
# terminal state (the canonical-state contradiction).
# NB: keyed on the explicit self marker, NOT on resume_cmd
# absence — records without inline resume_cmd may still be
# dispatchable via the WR_RESUME_CMD env template.
continue
with _inflight_lock:
t = _inflight.get(sid)
if t is not None and t.is_alive():
continue # single-flight: session already being driven
# B: never launch into a busy session
strays = stray_worker_pids(sid)
if strays:
log(f"drive: {rec['wait_id']} held, session busy {strays}")
continue
th = threading.Thread(target=resume, args=(rec,), daemon=True, name=f"resume-{rec['wait_id']}")
_inflight[sid] = th
# start INSIDE the lock: a just-created thread is not yet
# is_alive() until start() runs — starting outside the lock let
# the same drive cycle dispatch a second worker for the session
# (single-flight race, caught by the T2 invariant test).
th.start()
log(f"drive: dispatched {rec['wait_id']} (session {sid})")
def reconcile_once() -> None:
for rec in waitstore.pending():
if rec["status"] != "WAITING_EXTERNAL":
continue
created = rec.get("created_at", "")
try:
import calendar
age = time.time() - calendar.timegm(time.strptime(created, "%Y-%m-%dT%H:%M:%SZ"))
except ValueError:
continue
if age > RECONCILE_SECS:
try_transition(rec)
_tick = 0
def orphan_sweep() -> int:
"""REAL_ASYNC_BRIDGE §4: permanent mid-run orphan-lease recovery.
FAILURE DETECTION ONLY — never involved in normal completion
scheduling. A wait stuck in RESUMING past ORPHAN_GRACE_SECS means the
resume flow died between lease acquire and release (worker thread
lost, exception mid-watch). Reconcile exactly as startup_recovery
would have: release the lease, stamp RESUME_UNVERIFIED truthfully
(delivery unverifiable), never auto-relaunch.
"""
import calendar as _cal
healed = 0
for rec in waitstore.all_waits():
if rec.get("status") != "RESUMING":
continue
try:
updated = _cal.timegm(time.strptime(rec.get("last_updated", ""), "%Y-%m-%dT%H:%M:%SZ"))
except ValueError:
continue
if time.time() - updated < ORPHAN_GRACE_SECS:
continue # legitimate in-flight watch (up to WATCH_SECS)
wid, sid = rec["wait_id"], rec["session_id"]
lease = waitstore.read_lease(sid)
owner_dead = lease is not None and not waitstore._owner_alive(lease)
daemon_owned = lease is not None and lease.get("pid") == os.getpid()
if lease is None or owner_dead or daemon_owned:
if lease is not None:
waitstore.release_lease(sid, wid)
if rec.get("resume_attempts", 0) >= MAX_ATTEMPTS:
rec["status"] = "RESUME_UNVERIFIED"
else:
rec["status"] = "READY_TO_RETRY"
rec["resume_note"] = (
"orphaned mid-run: resume flow died between lease acquire "
"and delivery ("
+ ("lease owner dead" if owner_dead else "resume thread lost" if daemon_owned else "no lease")
+ "); orphan sweep recovered"
)
waitstore.save(rec)
log(f"orphan-sweep {wid}: {rec['status']} — {rec['resume_note']}")
healed += 1
return healed
def reconciler() -> None:
global _tick
while True:
# v0.3: the local-runner wake is the fast path; periodic
# authoritative verification demotes to a slower fallback
# (missed-event + daemon-restart recovery), not API polling.
_tick += 1
if _tick % RECONCILE_EVERY_TICKS == 0:
try:
reconcile_once()
except Exception as e:
log(f"reconcile error: {e}")
try:
orphan_sweep() # §4 failure detection — bounded, periodic
except Exception as e:
log(f"orphan-sweep error: {e}")
try:
drive_ready()
except Exception as e:
log(f"drive error: {e}")
with _inflight_lock:
for sid, t in list(_inflight.items()):
if not t.is_alive():
del _inflight[sid]
time.sleep(DRIVE_LOOP_SECS)
# ── webhook receiver (wake signal only) ───────────────────────────────────
def wake_sweep(event: dict, eid: str) -> dict:
"""Sweep WAITING_EXTERNAL waits through authoritative verification.
Runs on a background thread (the hook's HTTP response returns
instantly, minimising the runner's offline window). If any verified
wait got 'pending' — the normal case for a job that finished
microseconds ago: the post-task hook fires after results are reported
but before the runner's final task acknowledgement flips server-side
status — retry on a BOUNDED event-triggered schedule (default 4s x3),
never a polling loop. The final ack lands milliseconds after the hook
exits, so the first retry almost always sees the terminal state.
"""
arrival = time.time()
log(f"local wake {eid}: {json.dumps(event)[:140]}")
import calendar
def sweep() -> tuple[int, int, int]:
verified = advanced = pending = 0
for rec in waitstore.pending():
if rec["status"] != "WAITING_EXTERNAL":
continue
try:
age = time.time() - calendar.timegm(time.strptime(rec.get("created_at", ""), "%Y-%m-%dT%H:%M:%SZ"))
except ValueError:
continue
if age < WAKE_MIN_AGE_SECS:
continue
verified += 1
before = rec["status"]
try_transition(rec)
if rec["status"] != before and rec["status"] == "READY_TO_RESUME":
advanced += 1
elif rec["status"] == "WAITING_EXTERNAL":
pending += 1
return verified, advanced, pending
verified, advanced, pending = sweep()
log(
f"local wake {eid}: verified={verified} advanced={advanced} "
f"pending={pending} sweep_ms={int((time.time() - arrival) * 1000)}"
)
for attempt in range(1, WAKE_RETRIES + 1):
# Retry while the sweep didn't conclusively advance anything:
# pending verdicts (ack-window) AND fresh-wait skips (age gate).
# Bounded, event-triggered — not a polling loop.
if not pending and verified:
break
time.sleep(WAKE_RETRY_SECS)
verified, advanced, pending = sweep()
log(
f"local wake {eid}: retry{attempt} verified={verified} "
f"advanced={advanced} pending={pending} "
f"total_ms={int((time.time() - arrival) * 1000)}"
)
return {"event_id": eid}
class Handler(BaseHTTPRequestHandler):
def do_POST(self):
if self.path == "/process-event":
# T15 §15D: process-exit events from builder/controller
# notifiers. Minimal dedicated endpoint — the Gitea webhook
# path stays untouched. Payload: {operation_id, exit_code,
# completed_at} + OPTIONAL provider/event_type/sha (T16
# §16C/§16E: the CI adapter registers as provider="gitea",
# event_type="ci_completed"; defaults preserve the T15 builder
# identity so existing notifiers are unaffected). The event is
# a WAKE, never truth — resumed controllers re-read canonical
# authority before any verdict.
length = int(self.headers.get("Content-Length", 0))
body = self.rfile.read(length)
try:
payload = json.loads(body) if body else {}
except json.JSONDecodeError:
self.send_response(400)
self.end_headers()
return
event = {
"provider": str(payload.get("provider", "builder")),
"event_type": str(payload.get("event_type", "builder_exit")),
"run_ref": str(payload.get("operation_id", "")) or None,
"sha": payload.get("sha"),
"exit_code": payload.get("exit_code"),
"completed_at": payload.get("completed_at") or "",
}
event = {k: v for k, v in event.items() if v is not None}
eid = waitstore.record_event(event)
log(f"process-event {eid}: {json.dumps(event)[:140]}")
# REAL_ASYNC_BRIDGE (R3): durable completion-file delivery.
# Every event reaching the bridge is written as
# resumes/<operation_id>.done so inotify waiters wake on the
# kernel event (R4) with no FIFO/lease machinery, and the
# event survives daemon AND waiter restarts (R9). Atomic
# rename; duplicate events rewrite identical content (R10).
_op_id = str(payload.get("operation_id", ""))
if _op_id:
try:
# Stable identity only: duplicate deliveries of the
# same logical event must produce byte-identical
# completion files (R10 idempotence by construction).
# completed_at is volatile and lives in the durable
# event log; the file is a WAKE SIGNAL, never truth.
_stable = {
k: event.get(k)
for k in ("provider", "event_type", "run_ref", "sha", "exit_code")
if event.get(k) is not None
}
completion_file.write_completion(_op_id, _stable)
except Exception as e: # noqa: BLE001 — delivery best-effort; wait-record transition + watchdog recovery still cover the lost file
log(f"process-event {eid}: completion-file write failed: {e}")
matched = 0
for rec in waitstore.pending():
if rec["status"] == "WAITING_EXTERNAL" and waitstore.match(rec, event):
matched += 1
try_transition(rec, event)
# matched READY controller waits are dispatched IMMEDIATELY
# (event-driven, no floor). Guard: only never-resumed waits —
# a duplicate/late event must not double-dispatch (15E);
# single-flight lease + this guard together make resume
# idempotent.
for rec in waitstore.pending():
if rec["status"] == "READY_TO_RESUME" and rec.get("resume_cmd") and rec.get("resume_attempts", 0) == 0:
threading.Thread(target=resume, args=(rec,), daemon=True, name=f"resume-{rec['wait_id']}").start()
matched += 1
try:
self.send_response(200)
self.end_headers()
self.wfile.write(json.dumps({"event_id": eid, "matched": matched}).encode())
except (BrokenPipeError, ConnectionResetError):
pass
return
if self.path == "/wake":
length = int(self.headers.get("Content-Length", 0))
body = self.rfile.read(length)
try:
payload = json.loads(body) if body else {}
except json.JSONDecodeError:
self.send_response(400)
self.end_headers()
return
event = {
"provider": "gitea-local-runner",
"task_id": str(payload.get("task_id", "")) or None,
"run_id": str(payload.get("run_id", "")) or None,
"repository": str(payload.get("repository", "")) or None,
"job_result": str(payload.get("job_result", "")) or None,
}
event = {k: v for k, v in event.items() if v}
eid = waitstore.record_event(event)
# Respond instantly; sweep on a worker thread. The hook is
# fire-and-forget (curl -m 2) — a broken pipe on write is
# harmless and must not propagate.
try:
threading.Thread(
target=wake_sweep, args=(event, eid), daemon=True, name=f"wake-{payload.get('task_id', '?')}"
).start()
except Exception as e:
log(f"wake spawn error: {e}")
try:
self.send_response(200)
self.end_headers()
self.wfile.write(json.dumps({"queued": True, "event_id": eid}).encode())
except (BrokenPipeError, ConnectionResetError):
pass
return
if self.path != "/webhook":
self.send_response(404)
self.end_headers()
return
length = int(self.headers.get("Content-Length", 0))
body = self.rfile.read(length)
try:
payload = json.loads(body)
except json.JSONDecodeError:
self.send_response(400)
self.end_headers()
return
action = payload.get("action") or payload.get("event_type") or ""
wf = payload.get("workflow_run") or {}
event = {
"provider": "gitea",
"event_type": f"workflow.{action}" if wf else action,
"sha": (wf.get("head_sha") or payload.get("sha") or "")[:12] or None,
"run_ref": str(wf.get("id") or payload.get("run_number") or "") or None,
}
event = {k: v for k, v in event.items() if v}
eid = waitstore.record_event(event)
log(f"webhook event {eid}: {json.dumps(event)[:140]}")
matched = 0
for rec in waitstore.pending():
if rec["status"] == "WAITING_EXTERNAL" and waitstore.match(rec, event):
matched += 1
try_transition(rec)
self.send_response(200)
self.end_headers()
self.wfile.write(json.dumps({"event_id": eid, "matched": matched}).encode())
def do_GET(self):
if self.path == "/health":
self.send_response(200)
self.end_headers()
self.wfile.write(b'{"ok":true}')
return
self.send_response(404)
self.end_headers()
def log_message(self, *a):
pass
def main() -> int:
port = int(sys.argv[1]) if len(sys.argv) > 1 else 8791
# H (constraint 1): flock is the SINGLETON AUTHORITY. daemon.pid's
# content is diagnostic metadata only — it never gates startup, never
# implies liveness, and is overwritten after the exclusive lock is held.
# Stale pid content (incl. SIGKILL debris) is thus harmless by design.
PIDFILE.parent.mkdir(parents=True, exist_ok=True)
lock_fd = os.open(PIDFILE, os.O_CREAT | os.O_RDWR, 0o644)
try:
fcntl.flock(lock_fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
except OSError:
log("refusing start: another daemon holds the pidfile flock")
print("daemon already running (pidfile flock held)", file=sys.stderr)
return 1
os.ftruncate(lock_fd, 0)
os.write(lock_fd, f"{os.getpid()}\n".encode()) # diagnostic, lock held for life
startup_recovery()
t = threading.Thread(target=reconciler, daemon=True)
t.start()
log(f"daemon starting on :{port}")
srv = ThreadingHTTPServer(("0.0.0.0", port), Handler)
try:
srv.serve_forever()
except KeyboardInterrupt:
pass
return 0
if __name__ == "__main__":
sys.exit(main())
+246
View File
@@ -0,0 +1,246 @@
#!/usr/bin/env python3
"""verify.py — authoritative Gitea verification (webhook ≠ success).
Queries the Gitea API for the TRUE state of the run/job/commit the wait
references. Returns (verdict, evidence). verdict ∈ {success, failure,
pending, unknown}. Only this module may move a wait out of
WAITING_EXTERNAL.
"""
from __future__ import annotations
import json, subprocess
from pathlib import Path
HOST = "https://gitea.thingscouldgetdicey.online"
REPO = "conductor/rune"
def _token() -> str:
# Canonical ladder without importing Rune: env → token file → git store
import os
tok = os.environ.get("GITEA_TOKEN", "").strip()
if tok:
return tok
tf = os.path.expanduser("~/.config/opencode/secrets/gitea-token")
if os.path.isfile(tf):
return open(tf).read().strip()
r = subprocess.run(
["git", "credential", "fill"],
input="protocol=https\nhost=gitea.thingscouldgetdicey.online\nusername=conductor\n\n",
capture_output=True,
text=True,
timeout=10,
)
for line in r.stdout.splitlines():
if line.startswith("password="):
return line[9:]
raise RuntimeError("no gitea credential available")
def _api(path: str) -> tuple[int, object]:
import urllib.request
req = urllib.request.Request(f"{HOST}/api/v1/repos/{REPO}{path}", headers={"Authorization": f"token {_token()}"})
try:
with urllib.request.urlopen(req, timeout=20) as r:
return r.status, json.loads(r.read())
except urllib.error.HTTPError as e:
return e.code, {"error": e.read().decode()[:200]}
def _jobs_list(run_ref: str):
"""GET jobs for a run, unwrapping the {'jobs': [...]} envelope."""
s, data = _api(f"/actions/runs/{run_ref}/jobs")
if s != 200:
return s, None
if isinstance(data, dict):
data = data.get("jobs", [])
return s, data if isinstance(data, list) else None
def _resolve_run_id(run_ref: str, sha: str) -> str:
"""Task-list ids are NOT run ids. If run_ref lookup 404s, resolve the
real run id by head SHA via /actions/runs (T15: run 6907 vs task 15743)."""
if run_ref:
s, jobs = _jobs_list(run_ref)
if s == 200 and jobs:
return run_ref
if sha:
s, runs = _api(f"/actions/runs?limit=30")
items = runs.get("workflow_runs", []) if isinstance(runs, dict) else (runs if isinstance(runs, list) else [])
# One SHA fans out to multiple runs (lint + deploy-only). Prefer a
# substantive (non-skipped) run; a skipped-only run proves nothing.
fallback = ""
for r in items:
if str(r.get("head_sha", "")).startswith(sha):
rid = str(r.get("id"))
if r.get("conclusion") != "skipped":
return rid
fallback = fallback or rid
return fallback
return ""
def verify_run(run_ref: str, sha: str, expected: str) -> tuple[str, dict]:
"""run_ref = actions run id (or task id — resolved via SHA lookup).
Defect fixed 2026-09-12 (surfaced by W/R-v0.3 live proof, run 7110):
the jobs query here used raw _api + isinstance(jobs, list), but this
Gitea wraps jobs in the {"jobs": [...]} envelope — the check always
failed, so EVERY EXACT_WORKFLOW verdict silently fell through to the
aggregate commit-status fallback, where unrelated runs on the same
SHA (multi-run fan-out: ci.yml + deploy-only) poison the verdict.
Use _jobs_list (unwraps the envelope), same as _resolve_run_id."""
run_ref = _resolve_run_id(run_ref, sha)
if run_ref:
s, jobs = _jobs_list(run_ref)
if s == 200 and isinstance(jobs, list) and jobs:
conclusions = {j.get("name"): j.get("conclusion") for j in jobs}
statuses = {j.get("status") for j in jobs}
if statuses <= {"completed"}:
verdict = "success" if set(conclusions.values()) <= {"success", "skipped"} else "failure"
return verdict, {"run_ref": run_ref, "jobs": conclusions}
return "pending", {"run_ref": run_ref, "statuses": sorted(statuses)}
if sha:
s, st = _api(f"/commits/{sha}/status")
if s == 200 and isinstance(st, dict):
state = st.get("state", "unknown") # success|error|failure|pending|warning
rid = _resolve_run_id("", sha) # attach run id so failure evidence works
if state == "success":
return "success", {"sha": sha, "state": state, "run_ref": rid}
if state in ("error", "failure"):
return "failure", {"sha": sha, "state": state, "run_ref": rid}
return "pending", {"sha": sha, "state": state}
return "unknown", {"run_ref": run_ref, "sha": sha}
def failed_job_evidence(run_ref: str, sha: str = "") -> dict:
"""For failure continuations: exact failing job + conclusion."""
run_ref = _resolve_run_id(run_ref, sha)
if not run_ref:
return {}
s, jobs = _jobs_list(run_ref)
if s != 200 or not isinstance(jobs, list):
return {}
bad = [j for j in jobs if j.get("conclusion") not in ("success", "skipped", None)]
return {
"failed_jobs": [
{"name": j.get("name"), "conclusion": j.get("conclusion"), "url": j.get("url", "")} for j in bad
]
}
# ── RELEASE_DEPLOY verification (W/R v0.1, overnight handoff Part 2) ──────
# Aggregate commit status is NOT a valid completion authority for Rune's
# release/deploy flow: the release successor SHA, not the source SHA, is what
# converges (observed live: wr-1789179026 stranded on pending while 0.66.15
# was deployed). The authority chain is:
# source SHA → source runs terminal → release successor commit (descendant)
# → successor runs success → deployed/current identity converges.
def _git(args: list[str], repo_root: str) -> str:
import subprocess
r = subprocess.run(["git"] + args, capture_output=True, text=True, cwd=repo_root or None, timeout=15)
if r.returncode != 0:
raise RuntimeError(f"git {' '.join(args[:2])}: {r.stderr.strip()[:120]}")
return r.stdout
def _runs_for_sha(sha: str) -> list[dict]:
s, runs = _api("/actions/runs?limit=50")
items = runs.get("workflow_runs", []) if isinstance(runs, dict) else []
return [r for r in items if str(r.get("head_sha", "")).startswith(sha)]
def _sha_verdict_from_runs(runs: list[dict]) -> tuple[str, dict]:
"""success | failure | pending from a SHA's workflow runs.
Terminal verdict ONLY when every run is completed — mixed states
(some success, some still in flight) must stay PENDING (observed live:
a SHA with 1 completed-success + 1 queued + 1 in-progress was judged
success mid-flight; wr-1789182522 2026-09-12)."""
if not runs:
return "pending", {"note": "no runs found"}
non_terminal = [r for r in runs if r.get("status") != "completed"]
if non_terminal:
return "pending", {"in_flight": len(non_terminal)}
conclusions = {r.get("name"): r.get("conclusion") for r in runs}
bad = {n: c for n, c in conclusions.items() if c == "failure"}
if bad:
return "failure", {"failed": bad}
return "success", {"runs": conclusions}
def verify_release_deploy(source_sha: str, repo_root: str = "", deployed_link: str = "") -> tuple[str, dict]:
"""RELEASE_DEPLOY authority chain. Returns (verdict, evidence)."""
source_sha = (source_sha or "")[:12]
ev: dict = {"source_sha": source_sha, "kind": "RELEASE_DEPLOY"}
# 1. Source SHA's own runs must be terminal and healthy.
src_runs = _runs_for_sha(source_sha)
src_verdict, src_ev = _sha_verdict_from_runs(src_runs)
ev["source"] = src_ev
if src_verdict != "success":
return src_verdict, ev
# 2. Release successor: first chore(release) commit descending from source.
if not repo_root:
return "pending", {**ev, "note": "no repo_root — cannot check lineage"}
try:
out = _git(
[
"log",
"--format=%H %s",
"--reverse",
f"{source_sha}..master",
"--grep=^chore\\(release\\)",
"--extended-regexp",
],
repo_root,
)
except RuntimeError as e:
return "pending", {**ev, "note": str(e)}
successors = [l for l in out.splitlines() if l.strip()]
if not successors:
return "pending", {**ev, "note": "no release successor yet"}
succ_line = successors[0]
succ_sha_full, _, succ_subject = succ_line.partition(" ")
succ_sha = succ_sha_full[:12]
ev["successor"] = {"sha": succ_sha, "subject": succ_subject[:80]}
# Ancestry is guaranteed by the range, but verify explicitly (deterministic
# lineage over title guessing):
try:
_git(["merge-base", "--is-ancestor", source_sha, succ_sha_full], repo_root)
except RuntimeError:
return "failure", {**ev, "note": "successor is not a descendant of source"}
# 3. Successor runs must be terminal and healthy.
succ_runs = _runs_for_sha(succ_sha)
succ_verdict, succ_ev = _sha_verdict_from_runs(succ_runs)
ev["successor"]["runs"] = succ_ev
if succ_verdict != "success":
return succ_verdict, ev
# 4. Deployed identity convergence. A mismatch is FAILURE only when the
# successor's runs are ALL completed — if any is still running/queued the
# deploy may simply not have propagated yet → PENDING (observed live:
# reconciler checked mid-deploy, verdict failure, deployment converged
# ~2 min later; wr-1789182522 2026-09-12).
if deployed_link:
link = Path(deployed_link)
if link.is_symlink() or link.is_dir():
deployed = str(link.resolve())
deployed_id = Path(deployed).name
ev["deployed"] = deployed_id
if not deployed_id.startswith(succ_sha[:12]):
still = [r for r in _runs_for_sha(succ_sha) if r.get("status") != "completed"]
if still:
return "pending", {**ev, "note": "deploy propagating (runs in flight)"}
return "failure", {**ev, "note": f"deployed {deployed_id} != successor {succ_sha} (all runs terminal)"}
else:
return "failure", {**ev, "note": f"deployed link missing: {deployed_link}"}
return "success", ev
+337
View File
@@ -0,0 +1,337 @@
#!/usr/bin/env python3
"""waitstore.py — wait/resume state machine v0.2 (developer tooling, NOT Rune).
States:
RUNNABLE → WAITING_EXTERNAL → READY_TO_RESUME → RESUMING → COMPLETED | FAILED
↑ │
│ ├─(watch timeout, tree killed)
│ └─(rc!=0 / unverifiable)
READY_TO_RETRY ←─────┘
RESUME_UNVERIFIED : delivery after crash/timeout cannot be proven.
TERMINAL-ish — never auto-scheduled; explicit
`requeue()` required to make it READY_TO_RESUME.
TIMED_OUT : external event never arrived within the wait budget.
Waits persist as waits/<wait_id>.json (atomic tmp+rename).
Leases persist as leases/<session_id>.lease.json (atomic tmp+rename,
validated against /proc so a dead or PID-reused owner is stealable).
"""
from __future__ import annotations
import fcntl, json, os, tempfile, time, uuid
from pathlib import Path
ROOT = Path(os.environ.get("WR_ROOT", "") or Path(__file__).resolve().parent)
WAITS = ROOT / "waits"
EVENTS = ROOT / "events"
LEASES = ROOT / "leases"
SCHEDULABLE = {"READY_TO_RESUME", "READY_TO_RETRY"}
VALID_STATES = {
"RUNNABLE",
"WAITING_EXTERNAL",
"READY_TO_RESUME",
"RESUMING",
"COMPLETED",
"FAILED",
"READY_TO_RETRY",
"RESUME_UNVERIFIED",
"TIMED_OUT",
}
TERMINAL = {"COMPLETED", "FAILED", "RESUME_UNVERIFIED", "TIMED_OUT"}
def _atomic_write(path: Path, data: dict) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
fd, tmp = tempfile.mkstemp(dir=str(path.parent), prefix=".tmp-")
try:
with os.fdopen(fd, "w") as f:
json.dump(data, f, indent=1, sort_keys=True)
os.replace(tmp, path)
# T17 17C: the bridge root is SHARED across users (deploy waiter
# runs as the runner user; daemon as nick). mkstemp creates 0600 —
# daemon re-saves locked the runner user out of records it must
# read (waitstore.load in await_resume_event; find_matching_event
# replay scan silently skipped them). 0644: owner writes, all read.
os.chmod(path, 0o644)
except BaseException:
if os.path.exists(tmp):
os.unlink(tmp)
raise
def now() -> str:
return time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
def new_wait(
*,
session_id: str,
provider: str,
event_type: str,
repo: str,
sha: str = "",
run_ref: str = "",
expected: str = "success",
wait_kind: str = "EXACT_WORKFLOW",
target_kind: str = "interactive",
repo_root: str = "",
deployed_link: str = "",
objective: str = "",
waited_for: str = "",
verify_when_woken: str = "",
on_success: str = "",
on_failure: str = "",
resume_cmd: list | None = None,
) -> dict:
wid = f"wr-{int(time.time())}-{uuid.uuid4().hex[:6]}"
rec = {
"wait_id": wid,
"session_id": session_id,
"created_at": now(),
"provider": provider,
"event_type": event_type,
"repo": repo,
"sha": sha,
"run_ref": run_ref,
"expected": expected,
# T15 §15D: PROCESS_EVENT — a wait whose authoritative verdict is
# the matching process-exit event itself (exit_code carried on the
# event), e.g. a builder/controller process completing. The event
# IS the authority here (the notifier wrapper observed the real
# process exit); no Gitea lookup applies.
"wait_kind": wait_kind
if wait_kind in ("EXACT_WORKFLOW", "RELEASE_DEPLOY", "PROCESS_EVENT")
else "EXACT_WORKFLOW",
# CONTENTION POLICY: "interactive" (default, conservative) never
# auto-dispatches — MiMo exposes NO supported busy/idle session
# signal, so injecting into a possibly-busy interactive session is
# NOT YET SAFE. Only explicitly declared headless/disposable
# targets ("headless") are auto-resumed.
"target_kind": target_kind if target_kind in ("headless", "interactive") else "interactive",
"repo_root": repo_root,
"deployed_link": deployed_link,
# T15 §15D: per-wait resume command override (placeholder template,
# same substitution as WR_RESUME_CMD: {session_id}/{msg}/{wait_id}).
# A synthetic controller session (e.g. a Scaffolding stage driver)
# is NOT a MiMo session — the global mimo-shaped default cannot
# resume it, which is exactly why fixed-sleep polling crept back
# in T12-T14. Per-wait override makes ANY registered continuation
# target resumable through the same bridge.
"resume_cmd": list(resume_cmd) if resume_cmd else None,
"status": "WAITING_EXTERNAL",
"last_verified": "",
"resume_attempts": 0,
"continuation": {
"objective": objective,
"waited_for": waited_for,
"verify_when_woken": verify_when_woken,
"on_success": on_success,
"on_failure": on_failure,
},
}
_atomic_write(WAITS / f"{wid}.json", rec)
return rec
def load(wid: str) -> dict | None:
p = WAITS / f"{wid}.json"
return json.loads(p.read_text()) if p.is_file() else None
def save(rec: dict) -> None:
assert rec.get("status") in VALID_STATES, rec.get("status")
rec["last_updated"] = now()
_atomic_write(WAITS / f"{rec['wait_id']}.json", rec)
def all_waits() -> list[dict]:
out = []
for p in WAITS.glob("*.json"):
try:
out.append(json.loads(p.read_text()))
except json.JSONDecodeError:
continue
return out
def pending() -> list[dict]:
return [r for r in all_waits() if r.get("status") in {"WAITING_EXTERNAL"} | SCHEDULABLE]
def schedulable() -> list[dict]:
"""READY waits, oldest first — deterministic queue order."""
rs = [r for r in all_waits() if r.get("status") in SCHEDULABLE]
rs.sort(key=lambda r: (r.get("created_at", ""), r.get("wait_id", "")))
return rs
def requeue(wid: str, note: str) -> dict | None:
"""Operator-explicit requeue of a RESUME_UNVERIFIED/RESUME_FAILED wait."""
rec = load(wid)
if not rec:
return None
rec["status"] = "READY_TO_RESUME"
rec["resume_note"] = note
save(rec)
return rec
# ── events (wake signals, idempotent) ─────────────────────────────────────
def record_event(event: dict) -> str:
import hashlib
body = json.dumps(event, sort_keys=True)
eid = hashlib.sha256(body.encode()).hexdigest()[:16]
f = EVENTS / f"{eid}.json"
if not f.is_file():
_atomic_write(f, {"event_id": eid, "received_at": now(), "event": event})
return eid
def match(rec: dict, event: dict) -> bool:
if rec.get("provider") != event.get("provider"):
return False
if rec.get("event_type") and event.get("event_type") and rec["event_type"] != event["event_type"]:
return False
if rec.get("sha") and event.get("sha") and rec["sha"] != event["sha"]:
return False
if rec.get("run_ref") and event.get("run_ref") and rec["run_ref"] != event["run_ref"]:
return False
return True
# ── leases (per-session single-flight, /proc-validated) ───────────────────
#
# Invariant 3 (PID reuse): liveness is NEVER "PID exists". The lease records
# pid + pgid + process starttime (/proc/<pid>/stat field 22); all three must
# match or the owner is a different process wearing a recycled PID.
#
# Invariant 1 (flock as authority): the lease file's flock serializes
# read-modify-write across processes and dies with its holder, so a crashed
# daemon can never wedge the lock. The lease JSON + /proc decide who OWNS the
# session; the flock only prevents racing acquirers from double-stealing.
_lease_fds: dict[str, int] = {} # session_id → open fd holding the flock
def _pid_starttime(pid: int) -> str | None:
"""Field 22 of /proc/<pid>/stat — distinguishes PID reuse."""
try:
stat = Path(f"/proc/{pid}/stat").read_text()
return stat.rsplit(")", 1)[1].split()[19]
except (OSError, IndexError):
return None
def _owner_alive(lease: dict) -> bool:
pid = lease.get("pid")
if not pid or not Path(f"/proc/{pid}").is_dir():
return False
if _pid_starttime(pid) != lease.get("pid_starttime"):
return False # PID reused by an unrelated process
try:
if os.getpgid(pid) != lease.get("pgid"):
return False
except OSError:
return False
return True
def lease_path(session_id: str) -> Path:
# T16 §16C finding (observed live in daemon.log): session ids like
# "controller-<op>-Verboo Code/glm-5.3-flash" contain "/" — the raw
# embed made lease creation raise FileNotFoundError, so resume
# delivery for those waits could never succeed. Sanitize to a flat
# filesystem-safe name; the hash suffix prevents collisions between
# ids that sanitize identically.
import hashlib as _hashlib
import re as _re
safe = _re.sub(r"[^A-Za-z0-9._-]+", "_", session_id)[:80]
digest = _hashlib.sha256(session_id.encode()).hexdigest()[:10]
return LEASES / f"{safe}-{digest}.lease.json"
def read_lease(session_id: str) -> dict | None:
p = lease_path(session_id)
if not p.is_file():
return None
try:
return json.loads(p.read_text())
except json.JSONDecodeError:
return None
def _locked_lease_fd(session_id: str) -> int | None:
"""Open the lease file and take its flock (non-blocking). The fd stays
open (lock held) until release_lease closes it."""
if session_id in _lease_fds:
return _lease_fds[session_id] # already hold it
LEASES.mkdir(parents=True, exist_ok=True)
fd = os.open(lease_path(session_id), os.O_CREAT | os.O_RDWR, 0o600)
try:
fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
except OSError:
os.close(fd)
return None # another process holds the lock — mid-acquire
_lease_fds[session_id] = fd
return fd
def _write_lease_locked(session_id: str, lease: dict) -> None:
fd = _lease_fds[session_id]
os.ftruncate(fd, 0)
os.lseek(fd, 0, os.SEEK_SET)
os.write(fd, json.dumps(lease, indent=1, sort_keys=True).encode())
os.fsync(fd)
def acquire_lease(session_id: str, wait_id: str, pid: int, pgid: int) -> dict | None:
"""Atomically create or steal the session lease. Returns the lease dict,
or None if a live owner holds it (or another process is mid-steal).
Staleness is decided by /proc identity evidence, never by age alone."""
fd = _locked_lease_fd(session_id)
if fd is None:
return None
existing = read_lease(session_id)
if existing and _owner_alive(existing):
_lease_fds.pop(session_id, None)
os.close(fd)
return None # live worker owns this session
lease = {
"session_id": session_id,
"wait_id": wait_id,
"pid": pid,
"pgid": pgid,
"pid_starttime": _pid_starttime(pid),
"acquired_at": now(),
"state": "RESUMING",
}
_write_lease_locked(session_id, lease)
return lease
def update_lease(session_id: str, **fields) -> None:
lease = read_lease(session_id) or {}
lease.update(fields)
_write_lease_locked(session_id, lease)
def release_lease(session_id: str, wait_id: str) -> bool:
"""Release only if the current lease belongs to this wait (no stealing
a successor's lease during a slow shutdown path). Closes the flock fd."""
lease = read_lease(session_id)
if not (lease and lease.get("wait_id") == wait_id):
return False
fd = _lease_fds.pop(session_id, None)
if fd is not None:
try:
fcntl.flock(fd, fcntl.LOCK_UN)
except OSError:
pass
os.close(fd)
lease_path(session_id).unlink(missing_ok=True)
return True
+56
View File
@@ -0,0 +1,56 @@
import type { Hooks } from "@mimo-ai/plugin"
// event-wait-guard — RETIRED (T21.5 §6/§8, 2026-09-17).
//
// HISTORY: this hook was the T21 §21B-3 runtime interception layer that
// blocked model-generated sleep→poll continuation (T20 regression), and
// later carried the T21.1 §21.1C cwd guard. Both were DOWNSTREAM patches:
// they corrected the model's output instead of fixing the generator.
//
// ROOT-CAUSE FIX (T21.5 §2-§5): the generator was ci_event_wait's
// wait loop returning nonterminal control to the model — caused by a
// single hard-coded master-deploy authority that was blind to branch/PR
// operations. T21.5 fixed this upstream:
// - OPERATION_SPECS: per-operation-type completion authority
// (branch_ci/pull_request_checks -> own Actions runs;
// master_ci/deploy/release -> deploy qualification);
// - SINGLE LOGICAL AWAIT: all nonterminal conditions re-arm inside
// ci_event_wait.run(); the model sees only terminal results;
// - structured PendingOperation envelopes (op_type, authority,
// internal_rearm_count) propagate to the controller.
//
// With the generator fixed, runtime interception is retired per the
// tranche rule FIXED UPSTREAM BEHAVIOUR > DOWNSTREAM GUARD CORRECTION.
// Regression prevention lives in the test suite:
// tests/test_single_logical_await.py (no model re-arm contract)
// tests/test_ci_event_wait.py (watchdog=recovery, event=wake)
// tests/test_wait_guard_corpus.py (canonical wait-pattern corpus)
// NOT as a permanent runtime block. The hook file stays installed as a
// documented no-op so canonical-source/install parity (test_hook_drift,
// test_hook_parity) continues to prove the installed runtime matches
// this repository's canonical state.
export const EventWaitGuard: Hooks = {
"tool.execute.before": async (_input, _output) => {
// RETIRED — no interception. See history above.
return
},
}
export const CwdGuard: Hooks = {
"tool.execute.before": async (_input, _output) => {
// RETIRED (T21.5 §8) — the harness/construction execution boundary
// now resolves project context upstream (execution-context binding).
// No runtime refusal. See tests/test_auto_execution_context.py.
return
},
}
export const CombinedGuards: Hooks = {
"tool.execute.before": async (input, output) => {
// Kept as the default export shape; both sub-guards are retired.
return
},
}
export default CombinedGuards
+92
View File
@@ -0,0 +1,92 @@
import { tool } from "@mimo-ai/plugin"
import { execSync } from "child_process"
export default tool({
description: "Wait for an external operation (CI, deploy, release) to complete. Call this when you cannot make progress until an external process finishes. You do NOT need to know the sha, op_type, or duration — Rune's controller resolves those from the bound PendingOperation. Just call this when you want to wait.",
args: {
operation_id: tool.schema.string().optional().describe("Optional: the operation to wait for. If omitted, the controller resolves the current pending operation automatically."),
task_id: tool.schema.string().optional().describe("Optional: the active task id (e.g. T4). When provided, resolution is scoped to operations bound to this task — stale global operations are never consulted."),
sha: tool.schema.string().optional().describe("OPTIONAL HINT — non-authoritative. The controller uses this only to help resolve which operation you mean."),
op_type: tool.schema.string().optional().describe("OPTIONAL HINT — non-authoritative. The controller derives the canonical operation type from repository/Gitea state."),
deadline_secs: tool.schema.number().optional().describe("OPTIONAL HINT — non-authoritative. The controller applies governed policy timing. Real user deadlines must be stated in conversation."),
},
async execute(args) {
// INTENT NORMALIZATION — model output is intent; the controller
// owns execution semantics. All model args are hints recorded for
// observability; canonical truth comes from the bound operation.
const parts = []
if (args.operation_id) parts.push(`--operation-id ${args.operation_id}`)
if (args.task_id) parts.push(`--task-id ${args.task_id}`)
if (args.sha) parts.push(`--sha ${args.sha}`)
if (args.op_type) parts.push(`--model-op-type ${args.op_type}`)
if (args.deadline_secs) parts.push(`--model-deadline ${args.deadline_secs}`)
const normCmd = `python3 /mnt/workdrive/issue161-harness/scripts/await_intent_cli.py normalize ${parts.join(" ")}`
let norm: any
try {
const normOut = execSync(normCmd, {
cwd: "/mnt/workdrive/issue161-harness",
encoding: "utf-8" as const,
timeout: 120000,
env: { ...process.env, RUNE_WR_ROOT: "/mnt/workdrive/wr-bridge" },
})
norm = JSON.parse(normOut.trim().split("\n").find((l: string) => l.startsWith("{")) || "{}")
} catch (e: any) {
return JSON.stringify({ ok: false, stage: "normalization", error: (e.stderr || e.message || "?").slice(0, 300) })
}
if (norm.normalized === "AMBIGUOUS") {
return JSON.stringify({ ok: false, stage: "normalization", ...norm })
}
if (!norm.normalized) {
return JSON.stringify({ ok: false, stage: "normalization", ...norm })
}
// canonical continuation: stored/derived op_type + POLICY deadline
// (the sha for the wait comes from the normalization resolution,
// NOT from the model's args)
const waitSha = norm.sha_for_wait || args.sha || ""
if (!waitSha) {
return JSON.stringify({ ok: false, stage: "resolution", error: "no sha resolved for the pending operation", norm })
}
const cmd = `python3 /mnt/workdrive/issue161-harness/scripts/ci_event_wait.py --sha ${waitSha} --deadline ${norm.deadline_secs} --op-type ${norm.op_type}`
try {
const result = execSync(cmd, {
cwd: "/mnt/workdrive/issue161-harness",
timeout: (norm.deadline_secs + 60) * 1000,
encoding: "utf-8" as const,
env: { ...process.env, DEPLOY_SHA: waitSha, RUNE_WR_ROOT: "/mnt/workdrive/wr-bridge", RUNE_WR_CODE: "/home/nick/.local/share/mimo-wait-resume" },
})
const jl = result.trim().split("\n").find((l: string) => l.startsWith("{"))
const envelope = jl ? JSON.parse(jl) : { ok: false, error: "no output" }
return JSON.stringify({
...envelope,
normalization: {
model_deadline_ignored: norm.model_deadline_ignored,
model_op_type_ignored: norm.model_op_type_ignored,
model_sha_ignored: !!args.sha && args.sha !== waitSha,
canonical_op_type: norm.op_type,
canonical_authority: norm.authority,
deadline_provenance: norm.deadline_provenance,
matched_by: norm.matched_by || norm.evidence || "auto-resolved",
},
})
} catch (e: any) {
const lines = (e.stdout || "").trim().split("\n")
const jl = lines.find((l: string) => l.startsWith("{"))
if (jl) {
const envelope = JSON.parse(jl)
return JSON.stringify({
...envelope,
normalization: {
model_deadline_ignored: norm.model_deadline_ignored,
model_op_type_ignored: norm.model_op_type_ignored,
model_sha_ignored: !!args.sha && args.sha !== waitSha,
canonical_op_type: norm.op_type,
canonical_authority: norm.authority,
deadline_provenance: norm.deadline_provenance,
matched_by: norm.matched_by || norm.evidence || "auto-resolved",
},
})
}
return JSON.stringify({ ok: false, stage: "wait", error: (e.stderr || e.message || "?").slice(0, 300) })
}
},
})
+167
View File
@@ -0,0 +1,167 @@
// bash — executes a shell command. PROCESS-OWNERSHIP CONTRACT (v2):
//
// MODE A (tool-owned): the child is launched in its own process group;
// stdout/stderr are CAPTURED pipes (never the TUI tty). On timeout or
// failure the ENTIRE process group is signalled (SIGTERM, grace,
// SIGKILL) so grandchildren cannot survive the invocation, then the
// result is finalized. After finalization NO descendant retains a
// writer into MiMo's streams.
//
// MODE B (explicitly detached): a command suffixed with " &" that the
// user/model intends to outlive the tool (nohup/setsid/disown-style)
// is executed via the detached helper: stdin=/dev/null, stdout/stderr
// -> durable log file, own session (setsid), no MiMo PTY inheritance.
// The tool returns the log path as the durable handle.
//
// Wait-intent compilation (sleep/check/poll aimed at a pending operation)
// is preserved: interception happens at the SEMANTIC level via
// await_intent route-bash, and a NO-OP for anything that is not a genuine
// continuation of a live pending operation. Arbitrary shell syntax
// (quotes, pipes, semicolons) passes through untouched — the router
// response is only trusted when it carries normalized=true AND
// ContinuePendingOperation with a concrete operation bound.
import { tool } from "@mimo-ai/plugin"
import { spawn, execFile } from "child_process"
const REPO = "/mnt/workdrive/issue161-harness"
const WR_ROOT = "/mnt/workdrive/wr-bridge"
// ── MODE A: process-group-owned capture execution ──────────────────────
interface OwnedResult { stdout: string; stderr: string; status: number; timedOut: boolean }
function runOwned(command: string, timeoutMs: number): Promise<OwnedResult> {
return new Promise((resolve) => {
// /bin/sh -c "command" in its OWN process group (detached:true makes
// the child a session/group leader we can signal as a WHOLE).
const child = spawn("/bin/sh", ["-c", command], {
cwd: REPO,
stdio: ["ignore", "pipe", "pipe"], // NEVER inherit the TUI tty
env: process.env,
detached: true, // own process group
})
let stdout = "", stderr = ""
let timedOut = false
let settled = false
const outChunks: Buffer[] = []
const errChunks: Buffer[] = []
child.stdout!.on("data", (d) => outChunks.push(d))
child.stderr!.on("data", (d) => errChunks.push(d))
const killGroup = (sig: NodeJS.Signals) => {
try { process.kill(-child.pid!, sig) } catch { /* already gone */ }
}
const finalize = (status: number) => {
if (settled) return
settled = true
clearTimeout(timer)
// detach listeners, then resolve — no late listeners remain
child.stdout!.removeAllListeners()
child.stderr!.removeAllListeners()
resolve({ stdout: Buffer.concat(outChunks).toString(), stderr: Buffer.concat(errChunks).toString(), status, timedOut })
}
const timer = setTimeout(() => {
timedOut = true
killGroup("SIGTERM")
// bounded grace for clean shutdown, then SIGKILL the group
setTimeout(() => killGroup("SIGKILL"), 2000)
// the exit/close event settles; a hard stop-guard settles anyway
setTimeout(() => finalize(124), 4000)
}, timeoutMs)
child.on("error", (e) => finalize(-1))
child.on("close", (code) => finalize(code ?? -1))
})
}
// ── MODE B: explicit detachment for "cmd &" invocations ────────────────
function runDetached(command: string): Promise<string> {
return new Promise((resolve) => {
const logPath = `/tmp/mimo-detached-${Date.now()}-${Math.floor(Math.random() * 1e6)}.log`
const out = `exec >>"${logPath}" 2>&1; exec 0</dev/null; ${command}`
const child = spawn("/bin/sh", ["-c", `setsid /bin/sh -c '${out.replace(/'/g, `'\\''`)}'`], {
cwd: REPO,
stdio: "ignore", // child rebinds its own fds — no PTY inheritance
env: process.env,
detached: true,
// unref: MiMo's event loop does not wait for it
})
child.unref()
resolve(JSON.stringify({
detached: true,
log: logPath,
note: "process detached (setsid, own fds); output streams to the log file only; fd 0/1/2 do NOT reference the MiMo tty",
}))
})
}
// ── wait-intent routing (semantic level, preserved from v1) ────────────
async function tryCompileWaitIntent(command: string): Promise<string | null> {
let routeOut: string
try {
routeOut = await new Promise<string>((resolve, reject) => {
execFile("python3", [`${REPO}/scripts/await_intent_cli.py`, "route-bash", "--command", command], {
cwd: REPO, timeout: 60000, encoding: "utf-8",
env: { ...process.env, RUNE_WR_ROOT: WR_ROOT },
maxBuffer: 8 * 1024 * 1024,
}, (err, stdout) => { if (err && !stdout) reject(err); else resolve(stdout || "") })
})
} catch {
return null // router unavailable: normal execution (never block on routing)
}
const jl = routeOut.trim().split("\n").find((l) => l.startsWith("{"))
if (!jl) return null
let norm: any
try { norm = JSON.parse(jl) } catch { return null }
// STRICT gate: compile ONLY a normalized, concrete continuation.
if (!(norm.normalized === true &&
norm.action === "ContinuePendingOperation" &&
norm.operation_id && norm.sha_for_wait)) return null
const waitCmd = `python3 ${REPO}/scripts/ci_event_wait.py --sha ${norm.sha_for_wait} --deadline ${norm.deadline_secs} --op-type ${norm.op_type}`
const r = await runOwned(waitCmd, (norm.deadline_secs + 60) * 1000)
const jline = r.stdout.trim().split("\n").find((l) => l.startsWith("{"))
if (jline) {
return JSON.stringify({
...JSON.parse(jline),
intent_compilation: {
raw_command_kind: norm.raw_command_kind || "sleep_poll",
literal_sleep_executed: false,
operation_id: norm.operation_id,
canonical_op_type: norm.op_type,
authority: norm.authority,
},
})
}
return JSON.stringify({ ok: false, stage: "compiled-wait", error: (r.stderr || "no output").slice(0, 300) })
}
export default tool({
description: "Run a shell command. If the command expresses external wait intent (sleep/check/poll aimed at CI, deploy, or release operations with pending operations), it is automatically compiled to Rune's event-driven continuation — you do not need to manage wait mechanics. Plain local commands execute normally. Commands ending in ' &' run detached with output logged to a file.",
args: {
command: tool.schema.string().describe("Shell command to run"),
},
async execute(args) {
// 1. wait-intent compilation (semantic, strict-gated)
try {
const compiled = await tryCompileWaitIntent(args.command)
if (compiled !== null) return compiled
} catch { /* fall through to normal execution */ }
// 2. MODE B: explicit detachment for backgrounded invocations
const cmd = args.command
if (/\b(nohup|setsid)\b/.test(cmd) || /&\s*$/.test(cmd)) {
return await runDetached(cmd)
}
// 3. MODE A: tool-owned, group-killed, captured execution
const r = await runOwned(cmd, 120000)
const text = r.stdout + (r.stderr ? `\n[stderr]\n${r.stderr}` : "")
if (r.timedOut) {
return `exit timed-out (process group terminated): ${text.slice(0, 500)}`
}
if (r.status !== 0) {
return `exit ${r.status}: ${text.slice(0, 500) || "?"}`
}
return text || "(no output)"
},
})
+269 -220
View File
@@ -1,223 +1,272 @@
{
"_comment": "Umbrella impact map \u2014 the change-propagation graph. Every src/rune/*.py and shared/*.py module MUST appear in exactly one umbrella's modules list (enforced by the umbrella_manifest_is_complete henxel; debt-tracked modules allowed via docs/module-coverage-debt.md). depends_on: when umbrella U changes, its dependents' canaries are required gates. mirrors: files that must travel together in the same PR (enforced by scripts/umbrella_impact.py unless the PR carries 'Propagation-waived: <reason>').",
"umbrellas": {
"memory": {
"description": "Storing, retrieving, and managing knowledge",
"modules": [
"memory_store",
"memory_consolidation",
"memory_env",
"shard_manager",
"query_memory",
"graph_memory",
"warm_neuron_store",
"abstraction",
"cache",
"recall_router",
"drift_cache",
"drift_compression",
"tier_manager",
"graph_shard_bridge",
"memory_selector",
"retrieval_benchmark"
],
"canaries": [
"canary_query_memory",
"canary_memory_synthesis",
"canary_full_system"
],
"depends_on": [
"governance"
]
},
"governance": {
"description": "Quality control, drift detection, promotion, audit",
"modules": [
"drift_core",
"drift_observability",
"drift_ledger",
"audit_ledger",
"curator",
"claim_audit",
"contracts",
"build_pipeline_policy",
"failure_auto_filer"
],
"canaries": [
"canary_full_system",
"canary_schema_migration"
],
"depends_on": []
},
"identity": {
"description": "Who the agent is \u2014 persona, voice, anchors",
"modules": [
"persona_definition",
"persona_gate",
"identity_anchors",
"voice_hybrid",
"voice_sync",
"voicebox",
"voice_injector",
"behavior",
"prompt_sync"
],
"canaries": [
"canary_full_system"
],
"depends_on": [
"governance"
]
},
"growth": {
"description": "Learning and improvement",
"modules": [
"self_improve",
"subconscious_pass",
"goal",
"elastic_cognition",
"growth_delta",
"autonomy_loop",
"cognitive_loop",
"dream_cycle",
"growth_simulator"
],
"canaries": [
"canary_full_system"
],
"depends_on": [
"memory",
"governance"
]
},
"perception": {
"description": "Input processing and context assembly",
"modules": [
"context_broker",
"context_pressure",
"attention_capsule",
"auto_context",
"auto_tasks",
"witness",
"salience_gate",
"cognitive_budgeter",
"complexity_scorer"
],
"canaries": [
"canary_context_broker",
"canary_full_system"
],
"depends_on": [
"memory"
]
},
"capability": {
"description": "Tool selection and execution authority",
"modules": [
"capability_broker",
"tool_executor",
"tool_protocol",
"local_tool_runtime",
"forge_client",
"message_queue",
"connection_pool",
"adaptive_router",
"route_risk_flags",
"evidence_probe",
"builder_bridge",
"builder_bridge_cli",
"recall_uplift"
],
"canaries": [
"canary_p1_01",
"canary_p0_05",
"canary_native"
],
"depends_on": [
"memory"
]
},
"inference": {
"description": "Model routing and outbound requests",
"modules": [
"model_routing",
"model_profiles",
"model_registry",
"model_connect",
"provider_registry",
"provider_budget",
"standardized_providers",
"inference_trace",
"response_adapter",
"token_optimizer"
],
"canaries": [
"canary_p1_06",
"canary_p1_02",
"canary_resource_authority"
],
"depends_on": [
"capability"
]
},
"orchestration": {
"description": "Task lifecycle, operator, TUI presentation",
"modules": [
"rune_operator",
"rune_tui",
"rune_graphic",
"rune_spinner",
"rune_profiler",
"chat_bubble",
"message_widgets",
"tui_validator",
"microkernel",
"event_bus",
"event_envelope",
"hook_engine",
"system_registry",
"cron_engine",
"task_gate",
"task_persist",
"work_manager",
"parallel_processor",
"tiered_executor",
"time_awareness",
"night_mode",
"pins",
"progressive_escalation",
"safety_override",
"sleep_time",
"verification_layer",
"outcome_ledger",
"warm_router",
"subsystem_health",
"build_mode",
"dependency_tracker",
"auto_detect",
"build_orchestrator",
"custodian",
"gitea_auth",
"gitea_pipeline",
"gitea_provision",
"umbrella_update"
],
"canaries": [
"canary_p1_07",
"canary_orchestration_foundation",
"canary_conversation_state",
"canary_gitea_pipeline",
"canary_tui_drift",
"canary_cognitive_strata",
"canary_surface_parity"
],
"depends_on": [
"perception",
"capability",
"inference",
"identity",
"growth"
]
}
"_comment": "GENERATED by rune.spine \u2014 compatibility view for legacy umbrella consumers. DO NOT EDIT: structural truth lives in store/spine/current.json; edits here are flagged by spine drift.",
"_generated_by_spine": true,
"generated_at": "2026-09-16T18:23:38Z",
"umbrellas": {
"capability": {
"description": "Tool selection and execution authority",
"modules": [
"adaptive_router",
"builder_bridge",
"builder_bridge_cli",
"capability_broker",
"connection_pool",
"evidence_probe",
"forge",
"forge_client",
"intent_continuity",
"local_tool_runtime",
"message_queue",
"openai_compat_transport",
"provider_context",
"recall_uplift",
"route_risk_flags",
"tool_executor",
"tool_protocol"
],
"depends_on": [
"memory"
],
"mirrors": [],
"canaries": [
"canary_native",
"canary_p0_05",
"canary_p1_01"
]
},
"governance": {
"description": "Quality control, drift detection, promotion, audit",
"modules": [
"audit_ledger",
"build_pipeline_policy",
"claim_audit",
"contracts",
"curator",
"drift_core",
"drift_ledger",
"drift_observability",
"failure_auto_filer",
"programme_gates"
],
"depends_on": [],
"mirrors": [],
"canaries": [
"canary_full_system",
"canary_schema_migration"
]
},
"growth": {
"description": "Learning and improvement",
"modules": [
"autonomy_loop",
"cognitive_loop",
"dream_cycle",
"elastic_cognition",
"goal",
"growth_delta",
"growth_simulator",
"self_improve",
"subconscious_pass"
],
"depends_on": [
"governance",
"memory"
],
"mirrors": [],
"canaries": [
"canary_full_system"
]
},
"identity": {
"description": "Who the agent is \u2014 persona, voice, anchors",
"modules": [
"behavior",
"identity_anchors",
"persona_definition",
"persona_gate",
"prompt_sync",
"voice_hybrid",
"voice_injector",
"voice_sync",
"voicebox"
],
"depends_on": [
"governance"
],
"mirrors": [],
"canaries": [
"canary_full_system"
]
},
"inference": {
"description": "Model routing and outbound requests",
"modules": [
"inference_trace",
"model_connect",
"model_profiles",
"model_registry",
"model_routing",
"provider_budget",
"provider_registry",
"response_adapter",
"standardized_providers",
"token_optimizer"
],
"depends_on": [
"capability"
],
"mirrors": [],
"canaries": [
"canary_p1_02",
"canary_p1_06",
"canary_resource_authority"
]
},
"memory": {
"description": "Storing, retrieving, and managing knowledge",
"modules": [
"abstraction",
"cache",
"drift_cache",
"drift_compression",
"graph_memory",
"graph_shard_bridge",
"memory_consolidation",
"memory_env",
"memory_selector",
"memory_store",
"query_memory",
"recall_router",
"retrieval_benchmark",
"shard_manager",
"tier_manager",
"warm_neuron_store"
],
"depends_on": [
"governance"
],
"mirrors": [],
"canaries": [
"canary_full_system",
"canary_memory_synthesis",
"canary_query_memory"
]
},
"orchestration": {
"description": "Task lifecycle, operator, TUI presentation",
"modules": [
"auto_detect",
"build_mode",
"build_orchestrator",
"chat_bubble",
"cron_engine",
"custodian",
"dependency_tracker",
"event_bus",
"event_envelope",
"gitea_auth",
"gitea_pipeline",
"gitea_provision",
"hook_engine",
"message_widgets",
"microkernel",
"night_mode",
"outcome_ledger",
"parallel_processor",
"pins",
"progressive_escalation",
"rune_graphic",
"rune_operator",
"rune_profiler",
"rune_spinner",
"rune_tui",
"safety_override",
"sleep_time",
"subsystem_health",
"system_registry",
"task_gate",
"task_persist",
"tiered_executor",
"time_awareness",
"tui_validator",
"umbrella_update",
"verification_layer",
"warm_router",
"work_manager"
],
"depends_on": [
"capability",
"growth",
"identity",
"inference",
"perception"
],
"mirrors": [],
"canaries": [
"canary_cognitive_strata",
"canary_conversation_state",
"canary_gitea_pipeline",
"canary_orchestration_foundation",
"canary_p1_07",
"canary_surface_parity",
"canary_tui_drift"
]
},
"perception": {
"description": "Input processing and context assembly",
"modules": [
"attention_capsule",
"auto_context",
"auto_tasks",
"behaviour_ledger",
"build_basis",
"capability_fit",
"capability_ledger",
"cognitive_budgeter",
"construction_activation",
"construction_commands",
"construction_decision",
"construction_depth",
"construction_intent",
"construction_interface",
"construction_mode",
"construction_pattern",
"construction_patterns_builtin",
"construction_projection",
"context_broker",
"context_pressure",
"drift_resume",
"event_wait",
"failure_recovery",
"graph_projection",
"impact_preview",
"iteration",
"layout_contract",
"programme_continuation",
"project_registry",
"release_notes",
"salience_gate",
"scaffold",
"spine",
"stage_guards",
"structural_migration",
"structural_model",
"structural_store",
"testing_mode",
"toolchain",
"tui_backlog",
"wait_guard",
"wait_guard_corpus",
"witness"
],
"depends_on": [
"memory"
],
"mirrors": [],
"canaries": [
"canary_context_broker",
"canary_full_system"
]
}
}
}
+225
View File
@@ -0,0 +1,225 @@
{
"_comment": "Umbrella impact map \u2014 the change-propagation graph. Every src/rune/*.py and shared/*.py module MUST appear in exactly one umbrella's modules list (enforced by the umbrella_manifest_is_complete henxel; debt-tracked modules allowed via docs/module-coverage-debt.md). depends_on: when umbrella U changes, its dependents' canaries are required gates. mirrors: files that must travel together in the same PR (enforced by scripts/umbrella_impact.py unless the PR carries 'Propagation-waived: <reason>').",
"umbrellas": {
"memory": {
"description": "Storing, retrieving, and managing knowledge",
"modules": [
"memory_store",
"memory_consolidation",
"memory_env",
"shard_manager",
"query_memory",
"graph_memory",
"warm_neuron_store",
"abstraction",
"cache",
"recall_router",
"drift_cache",
"drift_compression",
"tier_manager",
"graph_shard_bridge",
"memory_selector",
"retrieval_benchmark"
],
"canaries": [
"canary_query_memory",
"canary_memory_synthesis",
"canary_full_system"
],
"depends_on": [
"governance"
]
},
"governance": {
"description": "Quality control, drift detection, promotion, audit",
"modules": [
"drift_core",
"drift_observability",
"drift_ledger",
"audit_ledger",
"curator",
"claim_audit",
"contracts",
"build_pipeline_policy",
"failure_auto_filer"
],
"canaries": [
"canary_full_system",
"canary_schema_migration"
],
"depends_on": []
},
"identity": {
"description": "Who the agent is \u2014 persona, voice, anchors",
"modules": [
"persona_definition",
"persona_gate",
"identity_anchors",
"voice_hybrid",
"voice_sync",
"voicebox",
"voice_injector",
"behavior",
"prompt_sync"
],
"canaries": [
"canary_full_system"
],
"depends_on": [
"governance"
]
},
"growth": {
"description": "Learning and improvement",
"modules": [
"self_improve",
"subconscious_pass",
"goal",
"elastic_cognition",
"growth_delta",
"autonomy_loop",
"cognitive_loop",
"dream_cycle",
"growth_simulator"
],
"canaries": [
"canary_full_system"
],
"depends_on": [
"memory",
"governance"
]
},
"perception": {
"description": "Input processing and context assembly",
"modules": [
"context_broker",
"context_pressure",
"attention_capsule",
"auto_context",
"auto_tasks",
"witness",
"salience_gate",
"cognitive_budgeter",
"complexity_scorer"
],
"canaries": [
"canary_context_broker",
"canary_full_system"
],
"depends_on": [
"memory"
]
},
"capability": {
"description": "Tool selection and execution authority",
"modules": [
"capability_broker",
"tool_executor",
"tool_protocol",
"local_tool_runtime",
"intent_continuity",
"openai_compat_transport",
"forge_client",
"message_queue",
"connection_pool",
"adaptive_router",
"route_risk_flags",
"evidence_probe",
"builder_bridge",
"builder_bridge_cli",
"recall_uplift"
],
"canaries": [
"canary_p1_01",
"canary_p0_05",
"canary_native"
],
"depends_on": [
"memory"
]
},
"inference": {
"description": "Model routing and outbound requests",
"modules": [
"model_routing",
"model_profiles",
"model_registry",
"model_connect",
"provider_registry",
"provider_budget",
"standardized_providers",
"inference_trace",
"response_adapter",
"token_optimizer"
],
"canaries": [
"canary_p1_06",
"canary_p1_02",
"canary_resource_authority"
],
"depends_on": [
"capability"
]
},
"orchestration": {
"description": "Task lifecycle, operator, TUI presentation",
"modules": [
"rune_operator",
"rune_tui",
"rune_graphic",
"rune_spinner",
"rune_profiler",
"chat_bubble",
"message_widgets",
"tui_validator",
"microkernel",
"event_bus",
"event_envelope",
"hook_engine",
"system_registry",
"cron_engine",
"task_gate",
"task_persist",
"work_manager",
"parallel_processor",
"tiered_executor",
"time_awareness",
"night_mode",
"pins",
"progressive_escalation",
"safety_override",
"sleep_time",
"verification_layer",
"outcome_ledger",
"warm_router",
"subsystem_health",
"build_mode",
"dependency_tracker",
"auto_detect",
"build_orchestrator",
"custodian",
"gitea_auth",
"gitea_pipeline",
"gitea_provision",
"umbrella_update"
],
"canaries": [
"canary_p1_07",
"canary_orchestration_foundation",
"canary_conversation_state",
"canary_gitea_pipeline",
"canary_tui_drift",
"canary_cognitive_strata",
"canary_surface_parity"
],
"depends_on": [
"perception",
"capability",
"inference",
"identity",
"growth"
]
}
}
}
+9 -12
View File
@@ -104,15 +104,15 @@
},
{
"path": "src/rune/attention_capsule.py",
"role": "AttentionCapsule — the typed ledger of admitted blocks the model receives (to_messages re-derives the runtime payload)",
"role": "AttentionCapsule \u2014 the typed ledger of admitted blocks the model receives (to_messages re-derives the runtime payload)",
"disposition": "retain-authority",
"evidence": "P1-02 (#25): the capsule IS the product the model receives — the broker renders admitted blocks into it, the safety override mutates its user block in place (re-measured), runtime.run consumes capsule.to_messages(), and the trace v4 capsule_messages/capsule_content_hashes prove the logged capsule EXACTLY equals the sent payload. Legacy create_capsule/to_prompt (string-trim fake budgeting) deprecated with no live callers."
"evidence": "P1-02 (#25): the capsule IS the product the model receives \u2014 the broker renders admitted blocks into it, the safety override mutates its user block in place (re-measured), runtime.run consumes capsule.to_messages(), and the trace v4 capsule_messages/capsule_content_hashes prove the logged capsule EXACTLY equals the sent payload. Legacy create_capsule/to_prompt (string-trim fake budgeting) deprecated with no live callers."
},
{
"path": "src/rune/inference_trace.py",
"role": "Durable per-run inference trace (tokens served/estimated, output, latency, per-block visibility)",
"disposition": "migrate-adapter",
"evidence": "P0-07 (#23): persists what ContextBroker (#19) assembled and what the transport served — builds FROM the broker trace, never re-measures; store state/inference_traces.jsonl."
"evidence": "P0-07 (#23): persists what ContextBroker (#19) assembled and what the transport served \u2014 builds FROM the broker trace, never re-measures; store state/inference_traces.jsonl."
}
]
},
@@ -160,13 +160,13 @@
"path": "src/rune/capability_broker.py",
"role": "Authoritative capability selector (select_for_job + verified floor + find_capability escape hatch)",
"disposition": "retain-authority",
"evidence": "P1-01 (#24): select_for_job is the single selection authority — its ordered decision feeds LocalToolRuntime(tools=) at both construction sites and the _contributor_tools prompt block; degrade-not-crash falls back to full TOOLS with a tier-1 record_failure."
"evidence": "P1-01 (#24): select_for_job is the single selection authority \u2014 its ordered decision feeds LocalToolRuntime(tools=) at both construction sites and the _contributor_tools prompt block; degrade-not-crash falls back to full TOOLS with a tier-1 record_failure."
},
{
"path": "memory/index/capability_cards.json",
"role": "Capability-card index (rebuilt on empty/stale/corrupt; native cards synthesized from TOOLS metadata)",
"disposition": "migrate-adapter",
"evidence": "P1-01 (#24): load_cards validates and rebuilds — the packaged empty array no longer passes as an index; cards carry risk/preconditions/side_effects copied from tool_executor.TOOLS."
"evidence": "P1-01 (#24): load_cards validates and rebuilds \u2014 the packaged empty array no longer passes as an index; cards carry risk/preconditions/side_effects copied from tool_executor.TOOLS."
},
{
"path": "src/rune/local_tool_runtime.py",
@@ -486,12 +486,6 @@
"disposition": "retain-authority",
"evidence": "Defines the owner-approved canary-first Gitea sequence."
},
{
"path": "src/rune/plugins/build_mode/__init__.py",
"role": "Checkpoint/ledger state-machine primitive used by current governed builds",
"disposition": "migrate-adapter",
"evidence": "Persists checkpoints but encodes an older phase order."
},
{
"path": "src/rune/build_mode.py",
"role": "Separate BuildManager and worktree engine",
@@ -504,6 +498,9 @@
"disposition": "archive-candidate",
"evidence": "Reports fixed success strings for phases without executing their claimed effects."
}
],
"notes": [
"T17 17U: plugin BuildStateMachine deleted (zero importers; second parallel orchestrator)"
]
},
{
@@ -540,4 +537,4 @@
]
}
]
}
}
+141
View File
@@ -0,0 +1,141 @@
# Gitea Issue Reconciliation — canonical record
_Generated T15 Part J/K/L (2026-09-11). Machine-readable companion:
`docs/gitea_issue_reconciliation.json` (single authority; this doc is the
human-readable projection). Consistency checker: `scripts/gitea_reconciliation_check.py`
compares live Gitea state against the JSON and fails on drift._
Reconciliation states (closed vocabulary):
`VALID_OPEN | FIXED_VERIFIED | SUPERSEDED | DUPLICATE | HISTORICAL_EVIDENCE |
ACCEPTED_LIMITATION | NEEDS_REVALIDATION | DEFERRED_FUTURE`
## Bug-label audit (Part K)
`bug` = demonstrated currently incorrect behavior. Nothing else.
### Issues labelled `bug` at audit time
| # | live defect | evidence | final label | reconciliation state |
|---|---|---|---|---|
| 324 | **YES** | MessageAbortedError reproduces every aborted worker session (15+ checkpoints, including this session's predecessor) | bug (kept) | VALID_OPEN |
| 204 | NO | Forge-orchestrated pipeline = feature request (P1 feature); no demonstrated incorrect behavior | bug removed | VALID_OPEN (feature) |
| 157 | NO | capture_failure.py + tests/fixtures/production/ + manifest.json shipped and exercised (plan 2026-09-07-157) | bug removed | FIXED_VERIFIED (closed) |
| 145 | NO | P0-07 follow-up work item (tracing coverage), not a defect report | bug removed | VALID_OPEN (work item) |
| 139 | NO | Hand-maintained allowlist replaced by declarative classification (tui_validator.py cites #139); `tui_validator.py check` → passed, exit 0 | bug removed | FIXED_VERIFIED (closed) |
| 126 | NO | Silent-handler sweep = refactor program (S110/BLE001 ratchet governs), not a defect | bug removed | VALID_OPEN (work item) |
| 37 | NO | Personality corpus compilation = P2 feature | bug removed | VALID_OPEN (feature) |
| 16 | NO | v1 course-correction EPIC | bug removed | VALID_OPEN (epic) |
### Issues whose `bug` label was removed in the prior cleanup (Part D, earlier session)
16 targeted: #301 #300 #292 #284 #314 #181 #166 #165 #163 #159 #154 #141 #40 #32 #31 #27.
Verification (live API, this session): all confirmed bug-free EXCEPT #314 — its
removal had failed (the API-False defect) and the label persisted on a closed
issue. Removed this session by label-ID DELETE (204). #314 is closed
FIXED_VERIFIED (mode:association_merged regression shipped in 2bf43ea).
### Totals
- bug-labelled before audit: 8 open (+ #314 closed-but-labelled)
- bug-labelled after audit: **1** (#324, live defect, evidence above)
- issues closed by this audit: #139, #157 (both FIXED_VERIFIED with evidence comments)
- NEEDS_REVALIDATION count: 0 among bug-labelled issues (each resolved on evidence)
## Open-issue reconciliation (Part J)
Subsystems derived from labels. States per closed vocabulary. `next action` is
the single next concrete step; `_` = none until its tranche opens.
| # | subsystem | state | current evidence | next action |
|---|---|---|---|---|
| 324 | engine/checkpoint | VALID_OPEN | live repro (15+ sessions) | fix writer abort handling |
| 316 | ADAPT-1/research | VALID_OPEN | B3-v2 research task | await ADAPT tranche |
| 315 | ADAPT-1/wiring | VALID_OPEN | B2-v2 standard task | await ADAPT tranche |
| 311 | ADAPT-1/wiring | VALID_OPEN | superseded-by #315 (kept open as spec anchor until 315 delivers) | close when #315 closes |
| 301 | FINAL-12/benchmarks | NEEDS_REVALIDATION | dependency list silently grew (operator-path telemetry, bridge overhead) without issue update | re-scope before PL1 metrics work |
| 300 | ADAPT-11 | VALID_OPEN | acceptance = real escalation demo; blocked on ADAPT-LIVE telemetry | demo after PL1 held-out |
| 299 | ADAPT-10 | VALID_OPEN | harness legibility audit | _ |
| 297 | ADAPT-8 | VALID_OPEN | deterministic-first QUALIFY | _ |
| 296 | ADAPT-7 | VALID_OPEN | DESIGN consolidation experiment | _ |
| 295 | ADAPT-6 | VALID_OPEN | evidence capsule / context minimization | _ |
| 294 | ADAPT-5 | VALID_OPEN | budgets + stop conditions | _ |
| 293 | ADAPT-4 | VALID_OPEN | DESIGN-LITE shipped (STANDARD_CHANGE lane live) | acceptance demo, then close |
| 292 | ADAPT-3 | VALID_OPEN | LOCAL_FIX lane shipped | acceptance demo, then close |
| 284 | ADAPT epic | VALID_OPEN | epic tracks ADAPT-LIVE + PL1; body updated with detour record | update after PL1 |
| 259 | Scaffolding | VALID_OPEN | redefined: safe repeatable construction protocol (T15 §C) | Scaffolding v1 after PL1 |
| 258 | State-aware processes | VALID_OPEN | redefined: low-compute architectural self-awareness; SA1-8 superseded by distributed concerns | deferred research |
| 204 | forge/pipeline | VALID_OPEN | P1 feature: forge-orchestrated coordination | _ |
| 183–176 | memory-foundation futures | DEFERRED_FUTURE | P3 research futures (typed temporal semantics, prior-art audit, curiosity, lineage) | memory-foundation tranche |
| 175/181 | memory epics | DEFERRED_FUTURE | evidence-grounded continuity epics | same |
| 166 | research watchlist | DEFERRED_FUTURE | external research tracking | periodic review |
| 165/164 | research spikes | DEFERRED_FUTURE | SimpleMem/A-MEM, HippoRAG 2 | memory-foundation tranche |
| 163 | graph backend spike | NEEDS_REVALIDATION | P1 spike; LadybugDB evaluation partially done in prior research artifacts | revalidate against current graph.db-missing state |
| 162 | Qdrant spike | NEEDS_REVALIDATION | P1 spike; prior research artifacts exist (issue-162/) | revalidate after #316 outcome |
| 159 | conceptual topology | DEFERRED_FUTURE | P3 future | _ |
| 158 | wiring-status report | VALID_OPEN | P2: generated architecture-truth report | _ |
| 156 | mutation guards | VALID_OPEN | P1: cognitive-state mutation guards | _ |
| 155 | e2e activation trace | VALID_OPEN | P1: credit-assignment trace | overlaps PL1 outcome work — potential duplicate of #300's telemetry; review at PL1 close |
| 154/153 | learned-state / experience encoding | VALID_OPEN | P2 | PL1-adjacent |
| 152/151 | break-it / adversarial | VALID_OPEN | P0: adversarial procedures after nominal green | post-PL1 tranche |
| 145 | P0-07 follow-up | VALID_OPEN | tracing coverage gaps | _ |
| 141 | ContextBroker compaction | VALID_OPEN | P1: rolling-compaction persistence | _ |
| 139 | tui_validator drift | FIXED_VERIFIED | declarative classification shipped; check passes | closed |
| 131/130/129 | reviewer program | VALID_OPEN | P0: local reviewer + calibration + rubric | post-PL1 tranche |
| 126 | silent-handler sweep | VALID_OPEN | P0 refactor program; ratchet enforces ceiling | ongoing |
| 125 | decompose monoliths | VALID_OPEN | P2 | _ |
| 49–35 | v1-course-correction P2/P3 | DEFERRED_FUTURE | epic #16 manifest items (P2-01..09, P3-01..06) | per epic #16 sequencing |
| 33–27 | v1-course-correction P1 | VALID_OPEN | epic #16 manifest P1 items | per epic #16 sequencing |
| 16 | v1 epic | VALID_OPEN | consolidation epic; 33 manifest issues | per epic sequencing |
| 13 | TUI message graph | VALID_OPEN | P1 | _ |
| 3 | financial tracking | NEEDS_REVALIDATION | non-Rune issue (different project era) | transfer to correct repo or close |
| 2 | cognitive loop wiring | NEEDS_REVALIDATION | predates current TUI architecture | revalidate against current TUI |
| 1 | personality injection | NEEDS_REVALIDATION | overlaps #37's newer scope | merge into #37 or close |
## Reconciliation decisions this session (Part K deltas)
- CLOSED: #139, #157 (FIXED_VERIFIED, evidence comments posted)
- BUG LABEL REMOVED: #204, #145, #126, #37, #16 (audit: not defects)
- BUG LABEL REMOVED (stuck from prior cleanup): #314 (closed issue)
- OPEN BUGS: 8 → 1 (#324 only — genuine live defect)
## Part L — consistency check
`scripts/gitea_reconciliation_check.py` (deterministic, no governance
subsystem): fetches live issue state, compares to
`docs/gitea_issue_reconciliation.json`, flags:
- closed issue recorded VALID_OPEN / DEFERRED_FUTURE / NEEDS_REVALIDATION (open states)
- open issue recorded FIXED_VERIFIED / SUPERSEDED / DUPLICATE / HISTORICAL_EVIDENCE without being closed
- `bug` label present on any issue not recorded as a live defect (or missing on #324)
- issue missing from the artifact
- record lacking a required field
Exit 0 = consistent; exit 1 = drift listed. CI-eligible (read-only).
## PL1 held-out era reconciliation (2026-09-12)
Fresh-session reconciliation of the ADAPT family against deployed 0.66.22
@ 1497c85 + live PL1 held-out evidence (tasks task_2661189c9073,
task_6e4885031355; ledger PE-9207213099-0270). Resolves the recorded tension:
"ADAPT-LIVE complete → return target PL1" (the bounded tranche authorized
2026-09-10 is complete) while numbered ADAPT issues remain open (the larger
backlog was never in the ADAPT-LIVE tranche scope).
| # | state | evidence / basis |
|---|---|---|
| 284 | VALID_OPEN | epic tracker for the remaining sub-items below |
| 292 | FIXED_VERIFIED (closed) | LOCAL_FIX fast path live (rune_operator.py:522,541); live-proven twice by the held-out tasks |
| 293 | FIXED_VERIFIED (closed) | DESIGN-LITE implemented (rune_operator.py:660, cites #293), wired to STANDARD_CHANGE; suite+canary green |
| 294 | DEFERRED_FUTURE | canonical remaining-obligations list ("ADAPT-5 budgets... for later epics") |
| 295 | DEFERRED_FUTURE | canonical remaining-obligations list |
| 296 | DEFERRED_FUTURE | canonical remaining-obligations list |
| 297 | FIXED_VERIFIED (closed) | task_gate implemented (src/rune/task_gate.py) + broker wiring + canary registration |
| 299 | DEFERRED_FUTURE | canonical remaining-obligations list |
| 300 | VALID_OPEN | escalation mechanism exists (_probe_and_escalate); fresh deployed acceptance evidence pending |
| 301 | DEFERRED_FUTURE | canonical remaining-obligations list (FINAL-12) |
| 315 | VALID_OPEN | not started; ADAPT-1 sub-item (no canonical deferral authority) |
| 316 | VALID_OPEN | not started; ADAPT-1 sub-item (no canonical deferral authority) |
Consistency checker: `scripts/gitea_reconciliation_check.py` → exit 0
(72 records, 100 live issues in window) after these updates.
+53
View File
@@ -0,0 +1,53 @@
# Rune Semantic Release Policy (T20 §20B)
Pre-1.0 convention. Scaffolding "V1" does NOT mean Rune 1.0.
## Bump kinds
**PATCH** (0.66.80 → 0.66.81):
- bug fix, correction, implementation/internal maintenance
- no meaningful new user/system capability
**MINOR** (0.66.80 → 0.67.0):
- meaningful new Rune capability
- new subsystem functionality
- materially expanded system behaviour
- significant new supported workflow
**MAJOR**: reserved for Rune 1.0+ compatibility/public-contract semantics.
## How the machinery expresses this (no manual version edits)
The existing machinery already maps commit shape → bump kind:
- `semver_bump.next_version` (PR titles): feat→minor, else patch
- `version_convergence.highest_warranted_bump` (push ranges):
feat/breaking→minor, fix/perf→patch, else None
**Tranche-level rule (20B)**: a feature tranche lands its feature
commits (`feat(...)`), and the convergence machinery bumps MINOR at
the tranche's release boundary. Patch-only follow-ups (fix/perf)
warrant only PATCH — the machinery cannot accidentally re-minor
because `highest_warranted_bump` takes the max over the *post-
boundary* range, and a fix-only range yields "patch".
## Why T20 → 0.67.0
T20 is a feature-level tranche (Rune-wide retrofit: structural
taxonomy, capability/behaviour ledgers, rune graph, /testing backlog,
Spine modernization, semantic release). The release is classified
MINOR under this policy, earned through the governed convergence
machinery — never a manual version edit.
## T20 0.67.0 release record
T20 classified MINOR under this policy: Rune-wide retrofit (structural
taxonomy, capability/behaviour ledgers, rune graph, /testing backlog,
Spine modernization, semantic release) = new subsystem functionality +
materially expanded system behaviour. Earned through the governed
convergence machinery (feat-bearing range → minor), never a manual edit.
## Root cause record (T20, 2026-09-16)
semver_bump re-derived the bump kind from the SYNTHESIZED title text —
"minor: converged release" matched nothing → patch. Feature tranches
T18/T19/T20 downgraded to 0.66.77-83. Fixed: MINOR_PREFIX_RE carries the
convergence kind through; first push after the fix with a feat-bearing
range lands 0.67.0 through the normal machinery.
+45 -2
View File
@@ -52,9 +52,11 @@ This detour is complete when:
- [x] ADAPT intent recovered and reconciled (this artifact, Part B)
- [ ] **THIS TRANCHE**: the ADAPT status matrix disposition is agreed and the next tranche selected (Part D)
## RETURN TARGET
## RETURN TARGET / CURRENT: PL1 Process Learning — FIRST TRANCHE LIVE (2026-09-11)
**PL1 Process Learning** (T9). ADAPT-LIVE closed the route-execution gap; PL1's input (route accuracy, probe outcomes, escalation evidence, verification results, task characteristics) is now produced live by the operator spine. The matrix in the ADAPT RECONCILIATION section stands, updated: LOCAL_FIX/STANDARD_CHANGE paths = BUILT_AND_LIVE; probe = BUILT_AND_LIVE (verification-driven); escalation/downgrade = BUILT_AND_LIVE. Remaining ADAPT obligations for later epics: ADAPT-5 budgets, ADAPT-6 evidence capsule, ADAPT-7 DESIGN consolidation, ADAPT-10 legibility, FINAL-12 cross-track benchmark.
PL1-01 structured Experience records: `scripts/pl1_records.py` (task_id, route resolved from route.jsonl, proof level, failure class, candidate status). PL1-02 failure classification in the PL0 vocabulary (research_dispatch, NOT_COMPLETED_NO_MUTATION_EVIDENCE, verification_failure, model_refusal, UNKNOWN). PL1-03 first learning loop: recurring prose-instead-of-mutation family → structural correction (route-driven instruction in the user context block) + replay contract (NOT_COMPLETED gate) — record PE-1789102658-0269 (SEED 2026-09-11 → VALIDATED 2026-09-12: two fresh deployed held-out mutation tasks completed-with-evidence — task_2661189c9073 + task_6e4885031355, LOCAL_FIX, Verboo-pinned, mutation + exit-code verification, ledger PE-9207213099-0270; substrate corrections 6965fc7 flat-ChatMessage contract + a2463ad resume transport selection applied between; caveat: corrections developer-applied structurally, not autonomous self-modification; PROMOTED requires repetition/soak). PL1-04 promotion discipline: SEED→CANDIDATE→VALIDATED→PROMOTED via process_experience; structural fixes preferred. PL1-05 metrics: first_pass_accepted, mutation_failures, research_dispatches, false_completion_rate (0.0 — structurally prevented), candidates vs evidence-only split.
Remaining ADAPT obligations for later epics: ADAPT-5 budgets, ADAPT-6 evidence capsule, ADAPT-7 DESIGN consolidation, ADAPT-10 legibility, FINAL-12 cross-track benchmark, D7 release-job-on-Pi.
## OPEN OBLIGATIONS (deferred defects — recorded, NOT chased)
@@ -144,3 +146,44 @@ Reasoning from recovered obligations, not momentum:
5. Update epic #284 with the detour record + this matrix; close the gap between tracker and reality.
Then: **PL1** (T9), with the intent-continuity spine as PL1's first or second deliverable (it is an experience-system product, not a separate architecture project).
## GITEA RECONCILIATION (2026-09-11)
Part A-J executed. 15 issues closed (HISTORICAL_EVIDENCE/SUPERSEDED/ACCEPTED_LIMITATION) with evidence. Bug label cleaned: 16 misleading labels removed (open bugs 24→8). #259/#258 updated to current architecture. Remote tracking fixed (master tracks gitea/master, not stale origin). PL1 metrics corrected (NOT_YET_MEASURABLE where evidence doesn't support numbers). D7: bump works, release job fails on Pi — ROOT_CAUSE_UNKNOWN_DEFERRED. Automation noise: 5 duplicate bump commits per logical change (queue-drain artifact, not live recursion — version converges, commit history doesn't).
## DEFECT D7 (2026-09-11): RESOLVED — release-job failures root-caused
History: the release job failed on every push since 03:16 (c2528c1).
Superseded diagnosis: "Pi-side backup step logs Failed to connect to
127.0.0.1:3000" was a red herring — the Pi backup step was never the
failing job.
Root causes (live-proven T15 Part F, 2026-09-11 evening):
1. c2528c1 left a corrupted shell fragment after the converged-check fi
in auto-version.yml — the release job died at bash parse time (exit 2)
before any bump. Fixed in c35b604.
2. release_convergence() never assigned the release boundary — all 959+
commits classified as unreleased, so the warranted bump never
converged and queued runs each wrote their own bump commit. Fixed in
e395ee1 (boundary wiring) + 9e0b855 (boundary grep must match subjects
only, not bodies) + c35018f (numeric semver comparison: '0.66.9' <
'0.66.10' is False lexicographically, which silently skipped warranted
bumps as version_ahead_of_target).
3. The per-file contents PUT committed one commit per version surface —
five same-version bump commits per real bump (the "duplicate bump
cascade" since 0.66.2, misdiagnosed as queue drain). Fixed in 470d82f
+ d68fd1e (single ChangeFiles commit).
Live proof: experiment A (trigger d68fd1e, warranted patch) → exactly one
bump commit a4afc77 (0.66.11), all five surfaces in one commit, queue
drained, zero delayed duplicates, zero workflow failures.
## Local CI tooling (developer-side, NOT Rune runtime): W/R-v0.3 reactive wake (2026-09-12)
The desktop gitea-runner (v3.3.0) now runs `host.post_task_script` = `/usr/local/bin/gitea-wr-wake.sh`
after every job: a sub-second fire-and-forget POST to the local W/R daemon (`127.0.0.1:8791/wake`),
which sweeps waiting external waits through AUTHORITATIVE Gitea verification (bounded retry for the
reporter-ack window; 60s reconciler demoted to fallback). Runner event ≠ success proof. Config:
`/etc/gitea-desktop-runner/config.yaml` (backup: config.yaml.pre-wr03). Measured: terminal→verified
wait transition ~2s (was 0-30s polling). INTERACTIVE_AUTO_RESUME remains NOT YET SAFE (no supported
MiMo busy/idle signal) — headless-only dispatch, unchanged.
+275
View File
@@ -0,0 +1,275 @@
# Scaffolding V1 — Tranche 1
_2026-09-12. Scaffolding is the controlled need-to-capability system: NEED →
DISCOVERY → GAP → REUSE/ACQUIRE/BUILD → IMPACT+PLAN → SAFE IMPLEMENTATION →
VERIFICATION → PROVISIONAL USE → TRUST/REVISE/RETIRE → REUSABLE CAPABILITY.
Tranche 1 is deliberately narrower: make Rune stop rediscovering how Rune is
built every time Rune changes._
## Tranche 1 contract
`scripts/scaffold_projection.py` — a PROJECTION over existing authorities,
never a new one:
| question | authority projected |
|---|---|
| what subsystem owns X? | `config/umbrellas.json` (umbrella manifest + henxel-enforced completeness) |
| what does X depend on? | AST import graph over `src/rune/*.py` (incl. relative/lazy imports) |
| who consumes X? | reverse import edges |
| what changes if X changes? | mirrors + `depends_on` umbrellas + consumers |
| what proof obligations arise? | unit-test file, canary registry, umbrella gates, suite/lint/henxels |
| which are satisfied? | filesystem + registry evidence (static); suite/ratchet/henxels are runtime-check commands |
Commands: `component <module>` · `impact <module>` · `obligations <module>` ·
`all [outfile]`. If the projection disagrees with an authority, fix the
authority — never the projection.
## Mechanism audit (2026-09-12, deployed 0.66.22)
| mechanism | verdict | basis |
|---|---|---|
| Umbrella manifest + impact map + propagation gate | KEEP | ownership/impact authority; henxel-enforced completeness; consumed by projection |
| Henxels structural contract | KEEP | cross-cutting obligations (silent-handler ratchet, registries, coverage debt) |
| Canary registry (`canary_native.MODULES` + per-track canaries) | KEEP | per-subsystem proof obligations; consumed by projection |
| CI/deploy contract (required checks, TUI startup canary, atomic promote) | KEEP | deployment proof chain live-proven repeatedly |
| Version surfaces + auto-version + semver | KEEP | bump fast lane + push convergence working (0.66.22 earned this session) |
| Lint/pyright/coverage ratchets | KEEP | shrinking-baseline gates, all green |
| Authority map + dead-subnet ledger (D6) | EVOLVE | static doc today; Scaffolding projections make it derivable; D6 retire-disposition still owed |
| Issue reconciliation artifact + checker | KEEP | tracker truth with drift detection |
| PL1 experience ledger | KEEP | the trust/revise/retire input for future capability crystallisation |
| Intent continuity ledger | KEEP | PART 6 state machine, 7 invariants |
| `MIMO_AUTOMATIC_RESUME` / W/R interactive injection | KEEP (bounded) | headless single-flight proven; interactive auto-resume NOT YET SAFE until a supported busy signal exists |
| Duplicate authorities risk | REPLACE (avoided) | Scaffolding v1 adds NO new registry — projections only |
## Real-change proof (this tranche)
Change: context discovery hit Ollama's `/api/show` with cloud-pinned model
names — `400 invalid model name` noise on every cloud task + 8192 misbudget
for a 131072-window model (observed live in every PL1 Task A/B run).
1. BEFORE mutation: `scaffold_projection.py impact local_tool_runtime`
derived — subsystem `capability`; consumers `rune_operator`; gates:
full suite, lint ratchet, henxels, inference+orchestration canaries;
unit-test obligation `tests/test_local_tool_runtime.py` (exists).
2. Change made: `is_cloud_pinned` — THE provider-prefix rule, single
authority in `openai_compat_transport.py`; consumed by context discovery
(new) and transport selection (deduped); red-first regression tests.
3. Obligations tracked: suite 1314 green · lint ratchet PASS · henxels exit 0
· the projection itself caught two gaps mid-flight (relative imports
hidden consumers; a broad except biting the lint ratchet) — both fixed at
the source the projection pointed to.
4. Deploy: normal release chain → deployed identity verified.
## Maturity (honest)
- Projection engine: **UNIT-PROVEN** + proven on one real change.
- Not yet: CI integration of `scaffold_projection.py all` (drift detection),
capability discovery / gap recognition / reuse-before-build / external
acquisition / provisional-trust lifecycle — FOUNDATIONAL ONLY (architecture
does not block them; the projection source-list is the extension surface).
- Deferred with reasons recorded: none blocked by Tranche 1.
---
# Scaffolding V1 — Tranche 2: Construction Substrate (2026-09-13)
_Tranche 2 (contract SCAFFOLD-TRANCHE-001) built the construction substrate
itself: a shared structural-store primitive, the Project Scaffold layer over
it, and durable Construction Contracts — Rune's first build tracked by the
system it builds._
## Architecture
src/rune/structural_store.py shared generic primitive — NO Rune constants
↓ ↓
src/rune/spine.py src/rune/scaffold.py
(Rune Spine — canonical (Project Scaffold — canonical
structural self-model) construction/structural truth
about EXTERNAL projects)
Authority map (no duplicates):
| fact | authority | others |
|---|---|---|
| Rune's structure | `spine.py` + `store/spine/current.json` | scaffold only references |
| external project structure | `scaffold.py` store | Spine holds bridge facts only |
| content history / rollback | Git | both reference commits |
| coordination (issues/PRs/CI) | Gitea | scaffold stores observations |
| why work exists | Task/Intent | contracts reference task ids |
Construction Contract = ONE durable object (`contract:<id>`, kind
`construction_contract`) with plain `phase`/`status` fields governed by a
small legal-transition map (draft → approved → building → verifying →
migrating → superseding → closed; failed/abandoned terminal-or-retry). No
workflow engine. Resumability = store durability, proven across real
process boundaries.
## Mechanics
- **Repo binding** (`bind_repo`): forge/owner/name/branch/root/placement as
scaffold DATA. No secrets — schema rejects secret-named fields AND every
`save()` recursively redacts credential-named keys (defense in depth in
the shared core, so Spine inherits it too).
- **Scope check** (`check_scope`): changed files vs approved scope paths →
green / red / **unknown** (an unscoped contract is never silently green).
Out-of-scope change = RED until explicitly amended; amendments recorded,
original RED preserved in history.
- **Predicted vs observed**: frontier snapshot at approval; observed impact
captured at closure from INDEPENDENT evidence (git, tests) — never from
re-walking the prediction's own graph. Missed entities become CANDIDATE
corrections awaiting evidence.
- **Drift**: authority-owned facts that fail re-observation go STALE —
never silently fresh, never force-reverted. Reality wins.
- **Bridge** (`spine_bridge_entity`): identity + repo surface only. Project
internals NEVER leak into Rune Spine (test-enforced). Contract evidence
may cite `spine://` URIs — citations are inert on the referenced
authority.
## Real proof (this tranche on itself)
SCAFFOLD-TRANCHE-001 migrated from its pre-scaffold JSON into the new
store, advanced through phases with evidence checkpoints, closed with
predicted-vs-observed from git/test evidence, scope check caught the
store's own runtime artifacts (RED → explicit amendment → green, history
kept), and construction provenance attached into Rune Spine without
duplicating authority. A fresh interpreter answers what/why/state/
evidence/changed/next from the store alone — no transcripts.
## Maturity (honest)
| component | state |
|---|---|
| structural_store core | EXERCISED (unit-proven + real use) |
| Rune Spine after refactor | LIVE_PROVEN behavior-neutral (68 tests + identical rebuild) |
| Project Scaffold | EXERCISED |
| Construction Contract | EXERCISED (resumability proven cross-process) |
| repo binding (identity model) | UNIT-PROVEN (local git fixture) |
| external-repo live proof | BLOCKED ON USER REPO SELECTION |
| Scaffolding overall | substrate only — capability-fit discovery, gap decisions, toolchain selection, patterns, maintenance TUI all NOT BUILT (data seams exist) |
---
# Scaffolding Tranche 4 — Live Need → Decision → Construction Contract (2026-09-13)
_The adoption tranche: a real Need now flows automatically through the
Tranche 2/3 mechanisms and produces a governed Construction Contract. The
model no longer has to remember the procedure — it is durable Scaffolding._
## Live flow
NEED (reference to Task/Intent — pointer, never a copy)
↓ normalization (gaps recorded, never invented)
↓ structural discovery + fit + resolution (Spine + Project Scaffold)
↓ toolchain decision (existing project toolchain wins)
↓ layout obligations (USER-LOCKED authority inherited)
↓ user-approval gate (material changes require approval; approved
bounded work never re-asks)
↓ DecisionTrace (durable, model-independent)
↓ generated Construction Contract → existing build/verify pipeline
## Authority map (unchanged — the path CONNECTS, never duplicates)
| authority | owns |
|---|---|
| Task/Intent | why work exists |
| Rune Spine | Rune structural truth |
| Project Scaffold | external-project structural/construction truth |
| Layout Contract | desired interface constraints (USER-LOCKED = user authority) |
| Construction Contract | governed build obligations/history |
| Git / Gitea | history / execution |
## Boundary honesty
- **ADAPT/research**: the live path records a research ROUTE
(TARGETED_EVIDENCE_PROBE / FULL_RESEARCH_PIPELINE) when evidence is
insufficient — a seam, NOT an executed pipeline call. No fake
integration claimed.
- **BUILD_NEW** is never a fallback: insufficient evidence blocks it;
normalization gaps block it; merge precedence across authorities
requires every consulted authority to agree.
- **No second task engine**: one decision function + one trace object.
## Contract-quality repair (Tranche 3 defects)
Closure now distinguishes:
predicted_existing_affected planned changes to existing entities
expected_new entities the build PLANNED to create
correctly_predicted predicted AND independently observed
predicted_but_unaffected predicted, NOT observed
expected_new_observed planned creation happened
expected_new_missing planned creation did NOT happen
genuinely_unexpected_new observed, planned by neither list
Prediction cannot self-certify observation: the observed set comes ONLY
from caller evidence (git/tests/build/deploy). Legacy keys (missed/
needless/observed) preserved — old contracts readable without migration.
## Layout-obligation inheritance
A change touching a UI component/region/implementation inherits its Layout
Contract as a build obligation. USER-LOCKED obligations state that changing
placement requires explicit user authorization. Unrelated backend changes
inherit nothing. USER-LOCKED drift is never reconciled by editing the
contract — code adapts.
## Maturity (honest)
- Need intake: EXERCISED (real live proof)
- decision orchestration: LIVE-PROVEN for the bounded live flow
- capability discovery adoption: EXERCISED
- fit/gap adoption: EXERCISED
- toolchain adoption: EXERCISED
- contract generation: LIVE-PROVEN (one real generated contract)
- contract-quality prediction: EXERCISED (repaired semantics, one live closure)
- layout-obligation inheritance: UNIT-PROVEN (fixtures) + real TUI binding
- Scaffolding overall: adoption path live for one bounded flow — NOT
general autonomous construction, NOT universal discovery/toolchain
intelligence, NOT Scaffolding complete.
---
# Scaffolding Tranche 9 — Release History + Evidence Correction (2026-09-13)
_Gitea Releases are now an evidence-derived human-readable history of
Rune's evolution. Plus the Tranche 8 builder-evidence correction._
## Release semantics (audited)
| surface | meaning |
|---|---|
| VERSION | semver in pyproject/init (e.g. 0.66.44) |
| TAG | v<VERSION>, created by auto-version at the BUMP commit |
| release commit | the auto-bump SHA — NOT necessarily final state |
| converged deployed identity | last commit deployed under the same VERSION |
Same-version convergence commits (closure/accounting/lock fixes landing and
deploying after the bump) are normal; the notes record BOTH the tag commit
and the final deployed identity, distinction exposed honestly.
## Mechanism
`release_notes.py`: deterministic evidence extraction from governed records
(closed contracts, resolved maintenance, contract-quality records) →
structured ReleaseNote → Markdown → Gitea API (POST create / PATCH update).
Idempotent: publishing twice for a tag UPDATES, never duplicates. Notes are
historical documentation — NOT Memory, NOT structural authority.
## T8 evidence correction (§1)
The T8 report claimed a close-from-verifying refusal + reactive superseding
transition. Durable checkpoints show NO superseding transition and the
phase map permits verifying→closed; live output showed first-attempt close
success. The claim was RETRACTED with full provenance (original claim,
correction, reason, evidence preserved in the contract record) and
recorded as process-defect:unsupported-causal-claim. MiMo adoption
maturity survives on the SUPPORTED evidence: scope constrained file edits,
pattern obligations forced preservation proof, interface-reported
observations, fresh resume.
## Maturity
Release-note generator: LIVE-PROVEN (real Gitea, 10 releases). Backfill:
0.66.35→0.66.44 carrying historical-backfill provenance. Pre-0.66.35
history: skipped (weak evidence — honest limitation).
+79
View File
@@ -0,0 +1,79 @@
# SCAFFOLDING IMPLEMENTATION AUDIT + V1 GAP MATRIX (T18 §18B)
_Every claim classified against evidence. Scale: LIVE_PROVEN (production
evidence) / TEST_PROVEN (suite green, no production exercise) /
IMPLEMENTED_UNPROVEN / PARTIAL / PLANNED / ABSENT / LEGACY / DUPLICATE._
## Kernel claims
| Claim | Status | Evidence |
|---|---|---|
| Contract lifecycle + legal transitions | LIVE_PROVEN | 28 contracts driven through real flow; refusal envelopes observed |
| classify_mode (one classifier) | LIVE_PROVEN | gates TUI /build (17G), operator hook, tests 62+ |
| Conversational intent layer | TEST_PROVEN | 22+ held-outs incl. unseen paraphrases; 17R live exercise (one real conversational proof) |
| Programme continuation | LIVE_PROVEN | 17E 4-stage proof on real bridge; restart/dup/failure held-outs |
| Event-driven waits (builder) | LIVE_PROVEN | T15 15Q real model build; T17E async stage |
| Event-driven waits (CI) | LIVE_PROVEN | T16 16D deadline path ×2 + T17 natural wake (mode=event, 112.5s) |
| Event replay (before-registration) | TEST_PROVEN + production-realistic exercise | 17C 4.6s vs real completed CI; natural-cycle confirmation: the 17Z wake arrived mid-wait, replay path itself not yet hit naturally |
| Cross-user bridge delivery | LIVE_PROVEN | 17C repro as runner user (2.05s) + production deploys |
| Provider boundary | TEST_PROVEN (structural guard) + observed loud-failure | 16F/G suites; no silent fallback observed in production runs |
| Builder cannot self-certify | LIVE_PROVEN | T14 closure refusals ×2; phase-gated close |
| Completion truth evidence-driven | LIVE_PROVEN | contract checkpoints; verify_test_truth refusals |
| Interruption/resume | LIVE_PROVEN | T14E SIGKILL; 17E restart held-outs |
| Impact preview (visible, pre-build) | ABSENT → T18 | nothing renders structured impact before build today |
| Structural project model (first-class) | PARTIAL | stores are spine-shaped (entities/rels) but projects model CONTRACTS, not architecture; no domain/subsystem/interface nesting for arbitrary projects |
| Structural queries/impact closure for projects | PARTIAL | spine.impact_frontier exists for Rune; project stores lack query API |
| Research→Build Basis (durable, versioned) | ABSENT → T18 | research output today stays in transient context/artifacts |
| Research-depth decision at construction entry | PARTIAL | ADAPT routes task classes; no explicit construction-stage research gate |
| OUTWARD prior-art-first pass | PARTIAL | stage exists in Research Core; not strengthened to precedent-first ordering |
| Schema versioning + consent-gated migration | PARTIAL | stores carry schema_version=1; no migration machinery/consent flow |
| Environment/runtime model | PARTIAL | deployment_surface exists in Spine; project scaffolds don't model envs |
| Workspace lifecycle (worktree per contract) | PARTIAL | BuildManager worktrees exist (legacy adapter); not wired to contracts |
| Forge abstraction | ABSENT (Gitea-coupled scripts) | deploy/qualify call Gitea API directly |
| Structural drift for project scaffolds | PARTIAL | drift_resume (16P) covers checkpoint-vs-reality; no file/entity-level drift detection |
| Graph projection for visualisation | ABSENT → T18 | Spine has snapshots; no stable read-only graph projection |
| Memory/Substrate | ABSENT (BY DESIGN — out of scope) | rule L |
## V1 North Star gap matrix (this tranche's targets)
| North Star capability | Gap | T18 action |
|---|---|---|
| Research-led construction (early research, Build Basis) | ABSENT Build Basis | 18C: build_basis.py + ADAPT depth hook |
| OUTWARD precedent-first | PARTIAL | 18D: strengthen stage contract + real research run |
| First-class structural Scaffold | PARTIAL (contract-shaped) | 18E: structural_model.py over structural_store core |
| Structure→scope→governance | PARTIAL | 18F: queries + impact closure feeding contracts |
| Visible impact preview | ABSENT | 18G: impact_preview projection |
| Structural drift | PARTIAL | 18H: extend drift_resume with entity-level checks |
| Schema versioning + consent | PARTIAL | 18I: migration + consent flow + tests |
| Environment/runtime model | PARTIAL | 18J: env entities + verification distinction |
| Workspace lifecycle | PARTIAL (legacy adapter) | 18K: workspace contract on the BuildManager adapter |
| Forge boundary | ABSENT | 18L: forge.py adapter interface (Gitea impl) |
| Full route convergence | PARTIAL (classify shared; backends differ) | 18M: audit + smallest fix |
| Generalisation (not phrase list) | TEST_PROVEN | 18N: adversarial paraphrase families |
| Self-scaffold | PARTIAL (contracts only) | 18O: structural model of Scaffolding itself |
| Upgrade-via-Scaffold proof | ABSENT | 18P: one real upgrade driven by the scaffold |
| Graph projection | ABSENT | 18Q: versioned read-only projection |
## T19 additions (post-T18 classifications)
| Capability | Status | Evidence |
|---|---|---|
| Project/Scaffold Registry | TEST_PROVEN | registry tests; boundaries proven (no truth in index, no Spine leak) |
| /build governance fail-closed | LIVE_PROVEN | 19A: T18 degradation paths removed; failure-path held-outs |
| Capability Ledgers | TEST_PROVEN | lifecycle+history+packet tests |
| Surgical context packets | LIVE_PROVEN | 19R: packet bound exactly 1 file for a real change |
| Behaviour/Test Specs + hardening lifecycle | TEST_PROVEN | ledger suites incl. generation history |
| Selective invalidation | TEST_PROVEN | 19S-2/5/9/10 held-outs |
| Predictive vs descriptive impact | TEST_PROVEN | delta persistence tests |
| Post-change obligations | TEST_PROVEN | machine-derived from structural truth |
| /testing backend + aggregate | TEST_PROVEN + LIVE (19R) | testing_mode suites; command wired in real TUI |
| Observation→closure (user-confirm gate) | TEST_PROVEN | closure requires retest AND user confirm |
| Forge failure never rewrites truth | TEST_PROVEN | 19S-14 held-out |
| Self-hosted T19 change | LIVE_PROVEN | contract 19r-testing-command, 11-step scaffold-driven flow |
## Kernel exceptions required (rule B record)
None yet. Every T18 plan so far EXTENDS (new modules consuming
structural_store) rather than modifying frozen kernel behavior. Any
exception discovered during implementation will be recorded here with
evidence that the V1 requirement could not be met otherwise.
+153
View File
@@ -0,0 +1,153 @@
# SCAFFOLDING V1 DEFINITION (T18 §18B)
_Plane-English + technical definition of Scaffolding as it ACTUALLY
exists at tranche T18 start (master 29570f4). Companion artifact:
SCAFFOLDING_IMPLEMENTATION_AUDIT (evidence classification per claim)._
## What Scaffolding is (plain English)
Scaffolding is Rune's **construction authority**: the governed process
by which software gets built or changed. It takes an authorized need,
classifies what kind of construction it is, proportionally governs the
work through a durable contract (with legal lifecycle transitions),
derives scope from structural reality, drives builders, waits on events
(not sleeps), refuses self-certified completion, verifies from
canonical reality, and records evidence on durable objects so any
future session can resume without a transcript.
It is NOT a scheduler, NOT a memory system, NOT a provider selector,
NOT a research engine, NOT a release system. It is the layer that
decides *whether, how, and with what obligations* construction happens
— and whether it actually finished.
## What it owns
- **Construction classification** (`construction_mode.classify_mode` —
the ONE classifier: NOT_CONSTRUCTION / LOCAL_CHANGE /
EXISTING_PROJECT_CHANGE / PROJECT_BUILD / UNKNOWN; never silently
chooses; unknown surfaces probe questions)
- **Conversational interpretation** (`construction_intent.py` —
meaning/referents/authorization; DISCUSSION→PROPOSAL→USER_APPROVED;
feeds the ONE classifier, never deepens)
- **Project Scaffold + Contracts** (`scaffold.py` — legal phase map
draft→approved→building→verifying→…→closed/failed/abandoned; scope;
obligations; checkpoints; predicted-vs-observed at close)
- **Programme continuation** (`programme_continuation.py` —
run_construction_programme: stages 1:1 to contracts, persist→canary→
next; "task done ≠ programme done")
- **Impact/scope machinery** (construction_decision, completeness
gates, affected-surface propagation)
- **Stage guards** (`stage_guards.py` — readiness blocks, liveness
proves progress, exit canary proves effect; verify_test_truth refuses
false greens)
- **Failure taxonomy** (`failure_recovery.py` — 7 classes incl.
PROVIDER_UNAVAILABLE; retry budgets; PERMANENT/APPROVAL never retry)
- **Builder interface** (`construction_interface.py` — ONE builder
boundary; JSON envelopes; builder identity recorded-but-inert;
discover_active_contract; capabilities())
## What it does NOT own
- **Provider/model selection** (provider layer owns; ambient context
via `provider_context.require_model`; structural guard test)
- **Research competence** (Research Core owns; Scaffolding invokes and
consumes — see 18C integration)
- **Asynchronous wait/resume machinery** (W/R event bridge owns;
`event_wait.py` is the repo-side adapter: event drives continuation,
watchdog detects failure, durable record is truth)
- **Release/deployment** (deploy_stage/promotion/qualify + Gitea
workflows own it; Scaffolding records evidence)
- **Rune's structural self-model** (Spine owns — `spine.py` over
`structural_store.py`; Scaffolding stores use the SAME generic core)
- **Long-horizon relevance/memory** (future Substrate — not built;
seam exists: construction_projection + construction_commands)
- **The TUI** (client; sends text, renders projections)
## How the flows work
**New build (PROJECT_BUILD)**: conversational/explicit intent →
classify_mode (+ project-existence evidence) → activate() bootstraps a
provisional Project Scaffold (identity before repository, UNKNOWN
fields explicit) → contract draft→approved (user provenance) →
building (builder under event wait) → verifying (exit canary;
independent evidence) → closed with predicted-vs-observed.
**Existing-project change**: intent → classify (scoped/file/target
evidence; proportional) → attach to existing authority → light or full
contract by depth → same lifecycle, proportionate ceremony.
**Research-led construction (V1 target — CORRECTED 2026-09-15, Nick):**
> THE RESEARCH PLAN ITSELF IS CONTEXTUALLY GENERATED. There is NO
> permanent research-topic checklist. For every request:
> REQUEST/INTENT → understand target/current reality → identify material
> unknowns/decisions/risks → generate a context-specific research plan →
> perform proportional INWARD/OUTWARD/deeper research. OUTWARD asks what
> already exists relevant to THIS specific intent (adopt/adapt/combine/
> reject/gaps/innovation). The categories researched are selected from
> context; deeper technical research is driven by unresolved questions
> and consequence level, never performed mechanically.
`build_basis.generate_research_plan()` implements this: topics are
synthesized from THIS intent's material unknowns/decisions/risks;
the held-out suite proves unrelated intents produce materially
different plans and that no canned category list exists.
**Future upgrades (V1 target)**: authorized need → research-depth
decision (ADAPT) → Research Core pass → durable Build Basis →
structural Scaffold consult/construct → impact closure + visible
preview → contract with structurally-derived scope → isolated
workspace → governed build/verify → merge/release → structural
Scaffold updated. (Parts of this chain are new in T18 — see audit.)
**Interruption/resume**: SIGKILL-safe. Durable contract + programme
records + wait records are the truth; fresh process resumes from
identity alone; duplicate signals idempotent (live-proven T14E/T17E).
**Deployment/release participation**: Scaffolding does not run the
pipeline; it consumes qualified CI/deploy evidence, records deployed
identity on contracts, and refuses closure without it where contracted.
## T19 layer model (the general engineering system)
> "The Scaffold should let the LLM operate with surgical precision
> locally, while preserving global awareness of what else must be
> checked or changed."
>
> "Lower active cognitive load without losing the whole idea."
- **STRUCTURAL MODEL** tells Rune what the project contains / how it connects.
- **CAPABILITY LEDGER** provides compact local re-entry context (stable IDs
across moves; history preserved through supersede/retire).
- **BEHAVIOUR VALIDATION LEDGER** tells Rune what intended behaviour is
actually confirmed — generation-aware, selective invalidation, automated
green never implies USER_CONFIRMED.
- **PROJECT REGISTRY** tells Rune which Scaffolds/projects exist
(discovery/index only — not structural truth, not Spine).
- **ITERATION ENGINE** (predictive→descriptive impact, impact-delta
records, machine-derived obligations) makes quicksand protection
STANDARD behaviour of every construction route.
- **/TESTING** is a dependency-aware hardening programme: dynamic queue,
fix-for-B-may-reopen-A, closure requires retest AND user confirmation.
- **FORGE** provides workflow/history projection (failure never rewrites
canonical validation truth).
- **FUTURE SUBSTRATE** will coordinate sequencing/current focus/pause-
resume but does NOT own structural or validation truth.
## How Spine relates
Spine = Rune's canonical structural self-model (structural_store
generic core, maturity ladder, impact_frontier). Scaffolding's project
stores share the SAME generic core (zero Rune constants) — one graph
discipline, two scopes: Spine models Rune; project Scaffolds model
their projects. No duplicate truth: a project's structural model lives
in its own store; Rune's lives in Spine. Later retrofit will modernise
Spine using the discipline V1 generalises (18K relationship).
## How Substrate will interact (without owning internals)
Read: versioned outbound projection (construction_projection,
SCHEMA_VERSION=1). Write: bounded validated commands
(construction_commands — 6 commands, lifecycle-validated, idempotent,
no direct storage mutation). Substrate asks; Scaffolding decides.
Memory graph explicitly out of scope (T18 rule L).
+73
View File
@@ -0,0 +1,73 @@
# Rune Structural Map
_Maintained structural projection — the fast re-entry surface (T16 §16N).
Companion to the Spine store (`store/spine/current.json`, structural
authority) and `store/evidence/t16/16M_inventory.md` (full classification
record). Update this map when authority or canonical routes change; do
not copy the repo here._
## What is Rune?
A self-hosting coding agent: TUI client over an operator core, with a
structural self-model (Spine), a construction authority (Scaffolding),
an event-driven wait/resume bridge (W/R), a research pipeline, and a
fail-closed release/deployment pipeline that builds, tests, releases,
and deploys Rune itself to `/mnt/workdrive/rune-code/current`.
## Where things happen (canonical routes only)
| Concern | Authority | State |
|---|---|---|
| Structural self-model | `src/rune/spine.py` | `store/spine/current.json` |
| Construction (build lifecycle) | `src/rune/scaffold.py` + `construction_*.py` | scaffold store (`<dir>/.rune/scaffold`) |
| Builder sessions | `scripts/t15_builder_session.py` (event-driven successor; T14 is legacy) | contract + wait records |
| Provider/model selection | `rune_operator` final decider; ambient context via `provider_context.require_model` | `state/model_routing_profiles.json` |
| Wait/resume (any long op) | `src/rune/event_wait.py` + W/R daemon (out-of-repo snapshot at `~/.local/share/mimo-wait-resume`, data root `/mnt/workdrive/wr-bridge` — PIN `RUNE_WR_ROOT`: unpinned consumers get a loud warning, never a silent split-brain) | waits/events/leases/resumes JSON |
| Programme continuation | `src/rune/programme_continuation.py` (WIRED T17: `run_construction_programme` binds stages to Scaffolding contracts) | scaffold store `programmes/` |
| Conversational construction | `src/rune/construction_intent.py` (meaning/referents/authorization) → `construction_mode.classify_mode` (the ONE classifier) | intents are transient; contracts durable |
| CI qualification verdict | `scripts/deploy_qualify.py` (two legs, fail-closed) | Gitea commit status + runs |
| Release/deploy | `scripts/deploy_stage.py` → `deploy_promotion.py` (monotonic, flock) | deploy root + `current`/`last-good` symlinks |
| Research | `scripts/research_task_tree.py` (authority; labels are projection) | `research/issue-<N>/` |
| Task completion truth | `verification_layer.py` + `orchestration/conversation_state.py` | durable event store + checkpoints |
| Routing (task class) | `src/rune/adaptive_router.py` | `routes/route.jsonl` |
| Canary registry | `src/rune/canary_native.MODULES` | observed by Spine |
| Structural health | `henxels_checks.py` + `henxels.yaml` | repo root |
## Known non-canonical / duplicate routes (do not extend; reconcile via 16Q)
- `build_mode.BuildManager` (legacy /build) — superseded by builder_bridge
+ event-driven sessions; still wired.
- `scripts/t14_builder_session.py` — superseded by t15 event-driven driver.
- Provider selection entry points ×5 (`model_routing.rank`,
`model_connect route`, `model_registry get`, `provider_registry`,
`work_manager`) — operator is the de-facto final decider.
- Task-ish state ×4 (task-tool DB, `task_persist` persisted.json,
`memory_store.working`, orchestration event store).
- Maintenance ledgers ×3 (scaffold maintenance_item, tui_backlog, drift_ledger).
## Unfinished / blocked / deprecated
- programme_continuation.py: WIRED (T17 17D — run_construction_programme
is the canonical multi-stage driver; 17E live-proven).
- maintenance.yml canary-suite job: loops `shared/canary_*.py` — wrong
dir (real canaries in `src/rune/`), job likely no-ops (LEGACY).
- daemon out-of-repo: the W/R daemon is deployed from
`~/.local/share/mimo-wait-resume` with its own git snapshot —
packaging debt, no CI coverage of the deployed copy.
- Substrate: NOT BUILT. Scaffolding exposes the seam
(`construction_projection.py`, `construction_commands.py`); mock
client proves compatibility (`tests/test_substrate_seam.py`).
## Fresh-session quick answers
- Is a claim true? → Spine store + evidence_refs, never commit messages.
- Is construction allowed? → scaffold contract phase + LEGAL_TRANSITIONS.
- How does a long wait work? → register on the W/R bridge, yield on the
FIFO event; watchdog is failure detection, never scheduling; the event
is a WAKE — authority is re-read after resume.
- Who picks the provider? → the user layer, via ambient context;
construction never does (`test_provider_ownership.py` enforces).
- What runs where? → CI on `rune-ci-desktop` runner; deploy stages to
`/mnt/workdrive/rune-code/<sha>`; data home pinned at
`/mnt/workdrive/rune` (RUNE_HOME); implementation worktree
`/mnt/workdrive/issue161-harness`.
File diff suppressed because it is too large. Load diff
+1
View File
@@ -9,6 +9,7 @@ new surface._
|---|---|---|
| `rune_tui.py` | The main Textual application — chat pane, work pane, status bar (version label + refresh), footer, dialogs | The known giant (file-size debt tracked in henxels); composition root for all UI |
| `tui_validator.py` | Import-allowlist validation for TUI code | Drift defect tracked in #139 (allowlist vs `__future__`/relative imports) |
| `tui_backlog.py` | Not a surface — the durable TUI Upgrade Backlog ledger (outstanding projection/control work per backend feature) | SCAFFOLD-TRANCHE-007; ledger only, never structural authority |
## Adding a TUI surface
+4
View File
@@ -0,0 +1,4 @@
wait/resume experiment marker 23:07:52
wr delivery test 23:28:42
delivery test 2 23:31:02
wr delivery test 2 23:31:12
+3 -3
View File
@@ -1,7 +1,7 @@
settings:
warn_about_similar_files:
above: 0.85
ignore: ["docs/review-lessons.yaml", "docs/v1/**", "docs/wiki/**"]
ignore: ["docs/review-lessons.yaml", "docs/v1/**", "docs/wiki/**", "store/spine/**"]
henxels:
- henxel: "Canaries live at the repo's canary slot and are registered in CI"
@@ -10,7 +10,7 @@ henxels:
- henxel: "No secrets in tracked files"
no_secrets: true
except: ["./tests/test_gitea_provision.py", "./.ci-venv/**", "./.test-venv/**", "./.canary-venv/**", "./backups/**"]
except: ["./tests/test_gitea_provision.py", "./tests/test_gitea_auth.py", "./.ci-venv/**", "./.test-venv/**", "./.canary-venv/**", "./backups/**"]
- henxel: "Plans are markdown, one per build"
in: ./plans
@@ -20,7 +20,7 @@ henxels:
- henxel: "Top-level docs are markdown or yaml references"
in: ./docs/*
allowed_filetypes: [.md, .yaml]
except: ["./docs/v1/**", "./docs/wiki/**"]
except: ["./docs/v1/**", "./docs/wiki/**", "./docs/gitea_issue_reconciliation.json"]
- henxel: "The known giant stays visible — file-size debt is tracked, not silent"
in: ./src/rune/*
+3 -3
View File
@@ -1,4 +1,4 @@
{
"BLE001": 353,
"S110": 80
}
"BLE001": 347,
"S110": 75
}
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "rune"
version = "0.66.4"
version = "0.87.5"
description = "Rune — a stateful coding assistant with persistent memory, orchestration, and TUI"
requires-python = ">=3.10"
+2 -2
View File
@@ -1,5 +1,5 @@
{
"errorCount": 120,
"warningCount": 465,
"errorCount": 117,
"warningCount": 454,
"informationCount": 0
}
+33 -28
View File
@@ -1,29 +1,34 @@
{
"typeCheckingMode": "standard",
"pythonVersion": "3.14",
"reportMissingImports": "warning",
"reportMissingModuleSource": "none",
"reportMissingTypeStubs": "none",
"reportUnknownArgumentType": "none",
"reportUnknownParameterType": "none",
"reportUnknownVariableType": "none",
"reportUnknownMemberType": "none",
"reportMissingTypeArgument": "none",
"reportUntypedFunctionDecorator": "none",
"reportUntypedClassDecorator": "none",
"reportUntypedBaseClass": "none",
"reportPrivateUsage": "none",
"reportOptionalMemberAccess": "warning",
"reportUnnecessaryIsInstance": "warning",
"reportUnnecessaryComparison": "warning",
"reportUnnecessaryTypeIgnoreComment": "warning",
"reportPossiblyUnboundVariable": "error",
"reportUndefinedVariable": "error",
"reportAttributeAccessIssue": "warning",
"include": ["src/rune"],
"exclude": [
"src/rune/__pycache__",
"**/node_modules",
"**/__pycache__"
]
}
"typeCheckingMode": "standard",
"pythonVersion": "3.14",
"reportMissingImports": "warning",
"reportMissingModuleSource": "none",
"reportMissingTypeStubs": "none",
"reportUnknownArgumentType": "none",
"reportUnknownParameterType": "none",
"reportUnknownVariableType": "none",
"reportUnknownMemberType": "none",
"reportMissingTypeArgument": "none",
"reportUntypedFunctionDecorator": "none",
"reportUntypedClassDecorator": "none",
"reportUntypedBaseClass": "none",
"reportPrivateUsage": "none",
"reportOptionalMemberAccess": "warning",
"reportUnnecessaryIsInstance": "warning",
"reportUnnecessaryComparison": "warning",
"reportUnnecessaryTypeIgnoreComment": "warning",
"reportPossiblyUnboundVariable": "error",
"reportUndefinedVariable": "error",
"reportAttributeAccessIssue": "warning",
"include": [
"src/rune"
],
"exclude": [
"src/rune/__pycache__",
"**/node_modules",
"**/__pycache__"
],
"extraPaths": [
"scripts"
]
}
+7 -7
View File
@@ -1,5 +1,5 @@
# This file was autogenerated by uv via the following command:
# uv pip compile pyproject.toml -o requirements-ci.txt --extra dev --extra memory --python-version 3.11
# uv pip compile pyproject.toml -o /tmp/req_new.txt --extra dev --extra memory --python-version 3.11
aiohappyeyeballs==2.7.1
# via aiohttp
aiohttp==3.14.3
@@ -18,7 +18,7 @@ certifi==2026.7.22
# httpx
chardet==7.6.0
# via diff-cover
coverage==7.16.0
coverage==7.16.1
# via rune (pyproject.toml)
diff-cover==10.5.1
# via rune (pyproject.toml)
@@ -34,7 +34,7 @@ httpcore==1.0.9
# via httpx
httpx==0.28.1
# via rune (pyproject.toml)
idna==3.19
idna==3.20
# via
# anyio
# httpx
@@ -56,7 +56,7 @@ mdit-py-plugins==0.6.1
# via textual
mdurl==0.1.2
# via markdown-it-py
multidict==6.8.0
multidict==6.9.0
# via
# aiohttp
# yarl
@@ -64,13 +64,13 @@ nodeenv==1.10.0
# via pyright
packaging==26.3
# via pytest
platformdirs==4.11.8
platformdirs==4.11.11
# via textual
pluggy==1.6.0
# via
# diff-cover
# pytest
propcache==0.5.2
propcache==0.5.4
# via
# aiohttp
# yarl
@@ -118,5 +118,5 @@ typing-extensions==4.16.0
# textual-autocomplete
websockets==17.1
# via rune (pyproject.toml)
yarl==1.24.5
yarl==1.25.1
# via aiohttp
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,47 @@
# 00 — ISSUE SCOPE (#376 R1)
## Core question
What does Complementary Learning Systems (CLS) actually establish about fast episodic acquisition, slower generalization, consolidation, replay, schemas, interference, reconsolidation, and retention — and which of those mechanisms should or should not inform Rune's Memory architecture?
## Subquestions
1. What did the original CLS theory actually claim?
2. Which claims were empirical vs computational/theoretical?
3. What has changed since the original theory?
4. Which mechanisms survived later evidence?
5. Which were weakened or substantially revised?
6. How does schema learning change "fast vs slow"?
7. What is known about replay selection?
8. What is known about destructive interference?
9. What is known about memory transformation during consolidation?
10. What is known about reconsolidation?
11. Does consolidation necessarily imply transformation?
12. When is rapid integration possible?
13. What evidence exists against a simple dual-store interpretation?
14. What competing theories explain the same observations?
15. What parts are biological constraints rather than general learning principles?
16. Which properties transfer to software agents?
17. Which do NOT transfer?
18. Does Rune already implement analogous behavior?
19. What would materially alter Rune's target architecture?
20. What remains experimental?
## Hypotheses under test (from R0, NOT accepted)
H1: fast exact episodic storage + slow generalized knowledge is the right Rune split.
H2: two stores / two writers is the software form.
H3: schema-gated fast consolidation is justified.
H4: consolidation should be utility-prioritized, not recency-based.
H5: covering episodes must be retained after generalization.
H6: reconsolidation has a software analogue in supersession.
H7: independent-evidence corroboration should gate promotion.
H8: destructive consolidation must be rejected (append-only).
H9: evidence→episode→observation→belief→procedure is the right progression.
## Falsifiers
- F1: If deeper evidence shows no useful fast/slow separation outside biological constraints, the CLS architectural analogy is weakened or rejected.
- F2: If schema-rapid-integration findings fail replication or are explained by simpler mechanisms, H3 falls.
- F3: If replay prioritization evidence is task-specific (rodent navigation) with no general principle, H4 weakens to speculation.
- F4: If reconsolidation's boundary conditions prove so biological that no software analogue preserves the useful property, H6 falls.
- F5: If retained-episodes practice has no measured benefit in AI systems (consolidation without retention works as well), H5 is a preference, not a requirement.
## Stopping criterion
Evidence saturation: new sources repeat known mechanisms/criticisms, add only detail.
@@ -0,0 +1,32 @@
# 01 — INWARD: Current Rune reality (evidence-first)
_Evidence hierarchy: observed runtime > persisted canonical state > independent tests > source existence > design docs. Sources: T0 gates, T0.1 reconciliation, R0 artifact, direct store inspection (this tranche, read-only)._
## What Rune already does (PROVEN, T0/T0.1)
- **Fast exact capture:** every entry append-only with created_at; dedupe/supersede gate with receipts (T0 PROVEN_PRESENT). 924 canonical entries; supersession preserves prior rows (56 superseded retained).
- **Slow derived layer:** knowledge.json consolidation (PROVEN to run; single inspectable writer `memory_consolidation.py`); source-attributed (memory/abstraction/neuron/graph provenance counts in T0 map).
- **Trust lifecycle:** provisional/validated/locked + HMAC audit ledger (PROVEN — but T0.1: trust does NOT gate retrieval today).
- **Dual-write discipline:** episodic writes synchronous via `memory_store.py add_entry`; consolidation runs offline. Two writers exist structurally (agent path vs consolidation path).
- **Failure learning:** wash_count/use history, promotion_eligible flag (PROVEN fields; promotion gate semantics = design, not exercised at scale).
## What is DESIGNED but not proven
- `derived_from` links: ABSENT (T0.1/M: "what depended on X" unanswerable).
- Utility-prioritized or schema-gated consolidation: ABSENT (consolidation = full sweep; trigger non-deterministic — T0.1 R5: no cron/timer exists, agent-invoked).
- Reconsolidation loop: ABSENT (locked is terminal; retrieved beliefs are not re-litigated).
- Case layer (episode→case→procedure): ABSENT.
- Independent-evidence corroboration test: ABSENT (promotion_eligible driven by wash_count = frequency, not independence).
## What is BROKEN/DORMANT
- Sleep-time transcript mining: BROKEN (stale DB path, T0).
- Warm tier: vestigial (all 924 rows tier='warm'; T0.1 R4).
- Graph projection: dormant (last edge 2026-08-26).
- 439/838 active entries unindexed (embedder silent failure — T0.1 R3): the fast layer itself is LEAKY.
## R0 CLS claims (to reconcile, not accept)
R0 (families/complementary_learning_systems.md) claimed CLS supports: H1-H9 above, classifications COVERED (two-store split), ADAPT (utility qualification, shadow-mode, schema fast-path, reconsolidation loop, utility-prioritized consolidation), REJECT (recency-based priority, destructive consolidation). T1-impact flag: YES (three missing mechanisms).
## Where R0 made implementation leaps
1. R0 said "utility (retrieved-and-used count)" as qualification signal — but Rune's wash_count IS a retrieved-use count and T0 evidence shows it was never validated as a quality signal (it's frequency, gameable, and the T0.1 store shows superseded entries with high wash counts).
2. R0's "schema-gated fast path" assumed schema detection is tractable — no Rune mechanism for schema-matching exists (abstraction.db has 59 facts; no matching machinery).
3. R0's reconsolidation analogue assumed retrieval-triggered lability maps to supersession — but Rune supersession is write-triggered, not retrieval-triggered; the mapping was asserted, not derived.
4. R0 did not distinguish which CLS claims are empirical vs computational assumptions (e.g. d≈0.5 decay is a fit parameter, not a law).
@@ -0,0 +1,6 @@
# 02 — OUTWARD (populated by the deep-research actor; verified by controller)
Files: historical_foundations.md, modern_cls.md, consolidation_and_replay.md,
schema_learning.md, reconsolidation.md, interference_and_forgetting.md,
competing_models.md, criticism_and_limitations.md, software_and_ai_analogues.md
+ sources.md (ledger) + claims.json (machine-readable).
@@ -0,0 +1,8 @@
# Competing theories (researched from critics, not just CLS advocates)
- **MTT vs standard consolidation** (Nadel & Moscovitch 1997/2000 vs Squire & Alvarez 1995): retrograde amnesia gradients exist in BOTH directions depending on lesion/method; meta-analyses of patient data show inconsistent gradient temporality. Status: genuinely UNRESOLVED.
- **Hippocampal indexing vs store-and-transfer:** Teyler & Rudy 2007 (DOI 10.1002/hipo.20350); Ryan/Tonegawa 2015 engram work (DOI 10.1126/science.aaa5542) favors trace-persistence + retrieval-dependence over physical transfer. 2025 reassessment preprint exists (Authorea).
- **Consolidation skeptics / old-memory hippocampal engagement:** Nadel, Hupbach, Gomez & Newman-Smith 2012 (Neurosci Biobehav Rev) — hippocampus remains active for remote memories; Bontempi et al. 1999 (J Neurosci); Frankland et al. 2004, Science 304. DOI 10.1126/science.1094804 — remote memories shift cortical systems (ACC) but hippocampal damage still disrupts DETAILED remote recall; Squire camp counters deficits reflect detail/quality not necessity (Squire, Genzel, Wixted & Morris 2015, CSH Perspect Biol). **This is the field's fault line on transformation-vs-retention.**
- **Trace Transformation Theory:** R0's "Winsneski/Bhatt" DOES NOT EXIST. Verified anchors: Moscovitch & Gilboa 2021 preprint (OSF, DOI 10.31234/osf.io/yxbrs) + Sekeres/Winocur/Moscovitch 2018.
- **Bayesian/latent-cause:** Gershman, Blei & Niv 2010, Psych Review 117:197 — reconsolidation/extinction phenomena emerge from latent-cause inference; reconsolidation = belief-updating special case. This is the strongest competing FRAMEWORK for Rune: it explains the same data without a biological consolidation story.
- **CLS v2 (McClelland et al. 2020)** absorbs schema effects and responds to MTT — the live theoretical front.
@@ -0,0 +1,13 @@
# Consolidation & replay
**Foster & Wilson 2006, Nature 440:680. DOI 10.1038/nature04587.** Reverse replay of behavioral sequences in awake hippocampal place cells.
**Carr, Jadhav & Frank 2011, Nat Neurosci 14:147. DOI 10.1038/nn.2732.** Awake replay serves BOTH retrieval and consolidation — unresolved dual role.
**Ambrose, Pfeiffer & Foster 2016, Neuron 91:1342. DOI 10.1016/j.neuron.2016.07.047.** Awake reverse replay gated by changing reward — precursor evidence for prioritization.
**Mattar & Daw 2018, Nat Neurosci 21:1609. DOI 10.1038/s41593-018-0232-z.** Computational model: replay prioritized by EXPECTED FUTURE UTILITY (gain = value of replaying; need = state relevance), NOT recency; replays benefit FUTURE learning. Makes replay prospective/selective — biological analog of prioritized experience replay, and a direct constraint on CLS's replay-as-teacher loop.
**Tanrıverdi et al. 2023, J Cogn Neurosci. DOI 10.1162/jocn_a_02021.** In humans, MORE awake hippocampal-cortical co-reactivation predicted MORE forgetting of details — co-reactivation may reorganize/gist-ify rather than preserve.
**Method validity caveat:** "Evaluating hippocampal replay without a ground truth" (eLife 2023, DOI 10.7554/eLife.85635.sa0) + 2024 dopamine-signaling exchange (eLife): replay DECODING methods still contested — treat specific replay-content claims as method-dependent.
@@ -0,0 +1,10 @@
# Negative evidence / limitations
1. **Fenn et al. 2009** (DOI 10.1101/lm.1500808): sleep REDUCED false memories — direct counter-result to Payne 2009. The gist-consolidation direction is not settled.
2. **Tanrıverdi et al. 2023** (DOI 10.1162/jocn_a_02021): replay-like co-reactivation associated with FORGETTING — consolidation-as-helping is not monotone.
3. **RIF reliability** (European Psychologist 2011, DOI 10.1027/1016-9040/a000040; Frontiers 2014, DOI 10.3389/fpsyg.2014.01343; Camp/Pecher/Schmidt 2007 cue-independent tests): effect size unstable across labs/cues; inhibition interpretation often fails.
4. **Reconsolidation human failures:** prediction-error boundary (Sevenster/Kindt) means many "reactivation" protocols fail to destabilize — numerous human nulls (Exton-McGuinness & Reichelt review).
5. **Sharon/Moscovitch/Gilboa 2011** (PNAS, DOI 10.1073/pnas.1005238108): rapid acquisition of arbitrary associations WITHOUT hippocampus — counterevidence to strict hippocampal necessity for fast learning.
6. **Ryan/Tonegawa engram line** (DOI 10.1126/science.aaa5542): retrograde amnesia without trace loss — behavioral "forgetting after consolidation disruption" can be RETRIEVAL failure, not trace destruction; weakens lesion-based consolidation arguments in BOTH directions.
7. **Hoffman et al. 2024, Memory & Cognition. DOI 10.3758/s13421-024-01576-x:** "Awake targeted memory reactivation doesn't work" — a named negative result.
8. **Two R0-brief references do not exist** (McClelland/Whyte 1994; Winsneski/Bhatt) — flagged and excluded (see sources.md).
@@ -0,0 +1,7 @@
# Historical foundations (API-verified citations)
**McClelland, McNaughton & O'Reilly 1995, "Why there are complementary learning systems in the hippocampus and neocortex," Psych Review 102(3):419-457. DOI 10.1037/0033-295X.102.3.419.**
Claims verified: (1) catastrophic interference in backprop-style networks — new arbitrary associations sharing representations destroy old ones; (2) forces slow, interleaved, small-step statistical learning in neocortex; (3) structurally separate hippocampus with sparse representations provides fast episodic learning and later acts as TEACHER via replay; (4) episodes become neocortical gist. Computational assumptions: hippocampal sparseness (pattern separation), neocortical overlap (generalization), replay-driven consolidation.
NOTE: the "McClelland/McNaughton/Whyte 1994 bitter-tracing paper" from the R0 brief DOES NOT EXIST (Crossref/OpenAlex/arXiv searched) — likely conflation of the 1995 review with animal rapid-learning studies. Flagged; excluded from ledger.
**Squire 1992 (Archives of Neurology); Squire & Alvarez 1995 (Curr Opin Neurobiol).** Declarative-memory background; hippocampal involvement TEMPORARY; systems consolidation = neocortex gradually sufficient. This is the position CLS inherits — and the main target of MTT critics.
@@ -0,0 +1,9 @@
# Interference / forgetting / generalization hazards
**McCloskey & Cohen 1989 (Psychol Learn Motiv 24:109); Ratcliff 1990 (JEP:General 119:195).** Catastrophic interference — the motivating phenomenon for CLS; robust in simulation.
**O'Reilly & Norman 2002, TiCS 6. DOI 10.1016/s1364-6613(02)02005-3; Norman & O'Reilly 2003, Psych Review 109. DOI 10.1037/0033-295x.110.4.611.** REC model: hippocampal pattern SEPARATION (prevents interference/false memories) vs pattern COMPLETION (retrieval); computational trade-off explains age-related and amnesic distortions. Robust computationally; hippocampal-subfield fMRI support (Lacy/Yassa/Stark line, e.g. 2011 Learn Mem, DOI 10.1101/lm.1971111).
**False memories via gist:** Payne et al. 2009, Neurobiol Learn Mem. DOI 10.1016/j.nlm.2009.03.007 — sleep INCREASED DRM false memory (gist consolidation). **BUT Fenn et al. 2009, Learn Mem. DOI 10.1101/lm.1500808 found the OPPOSITE** (sleep reduced false memories). Flag: the gist-consolidation claim is directly contested at the effect level. Ledger records the PAIR.
**Retrieval-induced forgetting:** Anderson, Bjork & Bjork 1994, JEP:LMC 20:1063. DOI 10.1037/0278-7393.20.5.1063. Meta-analytically real on average — Murayama et al. 2014, Psych Bull. DOI 10.1037/a0037505 — but strong cue-dependence; the INHIBITION interpretation contested (interference accounts; Raaijmakers-school critiques); reliability concerns documented (European Psychologist 2011, DOI 10.1027/1016-9040/a000040; Frontiers in Psychology 2014, DOI 10.3389/fpsyg.2014.01343). Effect real; mechanism and cross-lab reliability of the inhibitory version unsettled.
@@ -0,0 +1,13 @@
# Modern CLS (CLS v1 → v2)
**Nadel & Moscovitch 1997 (Hippocampus 7:217); Nadel et al. 2000 (Psych Review 107:66).** MTT: each retrieval creates a new hippocampal trace; episodic memories stay hippocampus-dependent FOREVER; only semanticized gist becomes neocortex-dependent. Direct challenge to standard consolidation and CLS's teacher-transfer picture.
**Teyler & DiScenna 1986; Teyler & Rudy 2007 (Hippocampus, DOI 10.1002/hipo.20350).** Hippocampal indexing theory: hippocampus stores an INDEX only; cortical representations reinstated at retrieval — consolidation is index elaboration, not trace transfer.
**Ryan, Roy, Pignatelli, Arons & Tonegawa 2015, Science 348:1007. DOI 10.1126/science.aaa5542.** Optogenetic reactivation of hippocampal engram cells rescued memory expression after anisomycin-induced amnesia; silent engrams later matured (Roy et al. 2017 PNAS, DOI 10.1073/pnas.1714248114). Bearing: dissociates trace STORAGE from trace RETRIEVAL — amnesia is often retrieval failure, undermining simple "consolidation = strengthening" readings used by BOTH CLS and its critics.
**Winocur & Moscovitch 2011 (JINS 17:766); Sekeres et al. 2018 (Hippocampus).** Transformation hypothesis: remote memories are TRANSFORMED (episodic→semantic; vivid→schematic), not copied.
**Kumaran, Hassabis & McClelland 2016, TiCS 20(7). DOI 10.1016/j.tics.2016.05.004.** CLS updated: rapid neocortical integration via schema-consistency, episodic control, deep-learning interpretation; explicitly reconciles Tse findings with CLS. Robust as framework paper; each added claim inherits its own evidence base.
**McClelland, McNaughton & Lampinen 2020, Phil Trans R Soc B 375. DOI 10.1098/rstb.2019.0637.** CLS v2: schema consistency, replay gating, explicit MTT responses.
@@ -0,0 +1,11 @@
# Reconsolidation
**Nader, Schafe & LeDoux 2000, Nature 406:722. DOI 10.1038/35021052.** Anisomycin in lateral amygdala after retrieval blocks subsequent expression of an already-consolidated fear memory — consolidated memories re-enter a labile state. Method: Pavlovian fear conditioning + post-reactivation infusion.
**Tronson & Taylor 2007, Nat Rev Neurosci 8. DOI 10.1038/nrn2090.** Canonical review: successful replications across tasks/species AND wildly heterogeneous boundary conditions.
**Boundary conditions (the crucial ledger part):** Sevenster, Beckers & Kindt 2014, Learn Mem 21. DOI 10.1101/lm.035493.114 — destabilization requires sufficient PREDICTION ERROR (violated expectation); a mere reminder does not. Exton-McGuinness, Lee & Reichelt 2015 (Neurosci Biobehav Rev, DOI 10.1016/j.bbr.2014.10.011) + Lee 2009 (Trends Neurosci): memory strength and age limit labilization (weak/very old memories resist).
**Framing:** reconsolidation is best understood as UPDATING WITH A GATE (prediction error), not automatic restabilization. Whether it differs from ordinary updating only in timing: UNRESOLVED. Replication: rodent amygdala robust; human literature mixed (benzodiazepine/propranolol inconsistencies).
**Adversarial canon (see 05_adversarial.md):** Rudy et al. 2006 (Learn Mem 13:1-3, anisomycin non-specificity); Lattal & Abel 2004 (PNAS 101:4667, deficits REVERSE with time = retrieval failure); Morris et al. 2006 (Neuron 50:479, nonspecific effects). Nader & Hardt 2009 (Nat Rev Neurosci 10:224-234) is the PRO case — the phenomenon requires a "case for" paper.
@@ -0,0 +1,10 @@
# Schema learning
**Tse et al. 2007, Science 313:76 (neuroscience pages 1130-1133 of that issue). DOI 10.1126/science.1135935.** Rats: flavor-place paired associates over weeks; schema-CONSISTENT new pairs learned in one trial and became hippocampal-lesion-insensitive (neocortical immediate-early gene markers); schema-INCONSISTENT pairs needed weeks + hippocampal replay. Strongest single result for schema-gated rapid integration — the finding that forced McClelland to revise CLS.
**Tse et al. 2011, Science 333:891. DOI 10.1126/science.1205274.** Immediate-early gene activation in neocortex for schema-consistent encoding.
**McClelland 2013, JEP:General 142(4):1190. DOI 10.1037/a0033812.** Principled CLS revision: schema consistency permits small neocortical weight changes that don't cross interference thresholds.
**Replication status:** core effect replicated in Morris lab (2010/2011); human echo: Audrain & McAndrews 2022, Nature Communications. DOI 10.1038/s41467-022-33517-0 (fMRI scaffold-for-integration). BUT the neocortex-alone/hippocampal-independence interpretation is CONTESTED: Sharon, Moscovitch & Gilboa 2011, PNAS 108:17263-17268. DOI 10.1073/pnas.1005238108 (rapid arbitrary associates WITHOUT hippocampus); hippocampal damage still slows many rapid-learning tasks (Warren, Duff & Cohen line — "Fast mappers, slow learners," Cognitive Neuroscience 2019, DOI 10.1080/17588928.2019.1593120). Consolidation skeptics note schema effects may reflect inferential/RETRIEVAL processes rather than consolidation speed.
NOTE: the R0-brief "Warren et al. 2020-2021 schema replication" is UNVERIFIED — nearest verified Warren items are 2019 Cognitive Neuroscience and 2014 hippocampus/word-learning work.
@@ -0,0 +1,15 @@
# Software / AI analogues
**Schaul, Quan, Antonoglou & Silver 2016, "Prioritized Experience Replay," ICLR (arXiv 1511.05952).** TD-error-prioritized sampling beats uniform on 41/49 Atari games. Relationship to Mattar & Daw: Schaul's priority ≈ "gain" (prediction error); Mattar-Daw adds "need" (utility). Caveats from adversarial pass: PER needs importance-sampling correction; Fedus et al. ICML 2020 (arXiv 2007.06700) — uniform replay often MATCHES PER, freshness dominates; Song & Qian 2024 (Sci Rep 53117) — single-criterion prioritization unstable.
**Shin et al. 2017, "Continual Learning with Deep Generative Replay," NeurIPS (arXiv 1705.08690).** Generative replay mitigates catastrophic forgetting — direct computational CLS instantiation.
**Blundell et al. 2016 (arXiv 1606.04460); Pritzel et al. 2017, "Neural Episodic Control" (arXiv 1703.01988).** Semi-tabular episodic buffers give one-shot value updates — the FAST system as the missing piece of slow-gradient deep RL. Validated as engineering lever.
**Kauvar et al. 2023, "Curious Replay for Model-based Adaptation," ICML (arXiv 2306.15934).** Curiosity-prioritized replay for world models — direct translational echo of Mattar-Daw.
**Kumaran, Summerfield, Hassabis & Botvinick 2016, Neuron 92** (Neuroscience-Inspired AI program statement); **Marblestone, Wayne & Kording 2016, Front Comput Neurosci** (constructive critique: biological plausibility gaps).
**Kumaran, Hassabis & McClelland 2016, TiCS** — the pro-CLS-for-agents anchor the adversarial side must answer; De Lange et al. 2021 (IEEE TPAMI) establishes catastrophic interference as REAL in ML — CLS's distinctive content transfers as interference management.
Bearing: in ML, fast/slow split and replay prioritization are VALIDATED AS ENGINEERING LEVERS; the contested part is whether biological replay does what the algorithms assume.
@@ -0,0 +1,77 @@
# Sources Ledger (#376 R1)
_Format: source_id | citation | DOI/arXiv | peer-reviewed | primary/secondary | read depth | bearing. All "(verified)" DOIs were confirmed via Crossref/OpenAlex/arXiv APIs during the outward pass._
## Foundations
- S001 | McClelland, McNaughton & O'Reilly 1995, Psych Review 102(3):419-457 | 10.1037/0033-295X.102.3.419 | yes | primary (theory) | RELEVANT_SECTIONS | canonical fast/slow split; catastrophic-interference motivation
- S002 | Squire 1992, Archives of Neurology; Squire & Alvarez 1995, Curr Opin Neurobiol | — | yes | primary | RELEVANT_SECTIONS | standard-consolidation position CLS inherits
- X001 | "McClelland/McNaughton/Whyte 1994 bitter-tracing" | NOT FOUND in Crossref/OpenAlex/arXiv | — | — | — | UNVERIFIABLE — excluded from ledger
## Schema learning
- S003 | Tse et al. 2007, Science 313:1130-1133 | 10.1126/science.1135935 | yes | primary | RELEVANT_SECTIONS | schema-gated rapid integration (rats)
- S004 | Tse et al. 2011, Science 333:891 | 10.1126/science.1205274 | yes | primary | ABSTRACT/SECTIONS | neocortical gene activation
- S005 | McClelland 2013, JEP:General 142(4):1190 | 10.1037/a0033812 | yes | primary (theory) | RELEVANT_SECTIONS | CLS schema revision
- S006 | Audrain & McAndrews 2022, Nature Communications | 10.1038/s41467-022-33517-0 | yes | primary | ABSTRACT | human fMRI echo
- S007 | Sharon, Moscovitch & Gilboa 2011, PNAS 108:17263-17268 | 10.1073/pnas.1005238108 | yes | primary | RELEVANT_SECTIONS | rapid learning WITHOUT hippocampus
- S008 | Warren & Duff 2014, Hippocampus 24(8):920-932; Warren et al. 2014, J Neurosci 34(22); Warren et al. 2019, Cognitive Neuroscience | 10.1080/17588928.2019.1593120 | yes | primary | ABSTRACT/SECTIONS | amnesic fast-mapping failures; vmPFC schema locus
- X002 | "Warren et al. 2020-2021 schema replication" | NOT FOUND as named | — | — | — | UNVERIFIABLE — nearest verified items listed above
## Replay
- S009 | Foster & Wilson 2006, Nature 440:680 | 10.1038/nature04587 | yes | primary | ABSTRACT | reverse replay discovery
- S010 | Carr, Jadhav & Frank 2011, Nat Neurosci 14:147 | 10.1038/nn.2732 | yes | review/primary | RELEVANT_SECTIONS | dual retrieval/consolidation role
- S011 | Ambrose, Pfeiffer & Foster 2016, Neuron 91:1342 | 10.1016/j.neuron.2016.07.047 | yes | primary | ABSTRACT | reward-gated replay
- S012 | Mattar & Daw 2018, Nat Neurosci 21:1609 | 10.1038/s41593-018-0232-z | yes | primary (model) | RELEVANT_SECTIONS | utility-prioritized replay (gain+need)
- S013 | Tanrıverdi et al. 2023, J Cogn Neurosci | 10.1162/jocn_a_02021 | yes | primary | RELEVANT_SECTIONS | co-reactivation ↔ FORGETTING
- S014 | eLife 2023 ground-truth evaluation + 2024 dopamine exchange | 10.7554/eLife.85635.sa0 | yes | editorial/primary | ABSTRACT | replay-decoding methods contested
## Reconsolidation
- S015 | Nader, Schafe & LeDoux 2000, Nature 406:722 | 10.1038/35021052 | yes | primary | RELEVANT_SECTIONS | reconsolidation anchor (rodent amygdala)
- S016 | Tronson & Taylor 2007, Nat Rev Neurosci 8 | 10.1038/nrn2090 | yes | review | RELEVANT_SECTIONS | boundary-condition heterogeneity
- S017 | Sevenster, Beckers & Kindt 2014, Learn Mem 21 | 10.1101/lm.035493.114 | yes | primary | RELEVANT_SECTIONS | prediction-error gate
- S018 | Rudy et al. 2006, Learn Mem 13:1-3 | — | yes | primary (critique) | RELEVANT_SECTIONS | anisomycin non-specificity
- S019 | Lattal & Abel 2004, PNAS 101(13):4667 | — | yes | primary | RELEVANT_SECTIONS | deficits REVERSE with time
- S020 | Morris et al. 2006, Neuron 50(3):479 | — | yes | primary | ABSTRACT | nonspecific anisomycin effects
- S021 | Nader & Hardt 2009, Nat Rev Neurosci 10:224-234 | — | yes | review (PRO) | ABSTRACT | "a single standard" — pro-reconsolidation case
- S022 | Exton-McGuinness, Lee & Reichelt 2015, Neurosci Biobehav Rev | 10.1016/j.bbr.2014.10.011 | yes | review | ABSTRACT | update-gate framing
## Competing theories
- S023 | Nadel & Moscovitch 1997, Hippocampus 7:217; Nadel et al. 2000, Psych Review 107:66 | — | yes | primary (theory) | RELEVANT_SECTIONS | MTT
- S024 | Teyler & Rudy 2007, Hippocampus | 10.1002/hipo.20350 | yes | primary (theory) | RELEVANT_SECTIONS | indexing theory
- S025 | Ryan et al. 2015, Science 348:1007 (+ Roy 2017 PNAS) | 10.1126/science.aaa5542 | yes | primary | RELEVANT_SECTIONS | engram persistence vs retrieval
- S026 | Winocur & Moscovitch 2011, JINS 17(5):766; Moscovitch et al. 2016, Ann Rev Psych 67 | — | yes | review/theory | RELEVANT_SECTIONS | transformation hypothesis
- S027 | Frankland et al. 2004, Science 304 | 10.1126/science.1094804 | yes | primary | ABSTRACT | remote-memory cortical shift + detail loss
- S028 | Moscovitch & Gilboa 2021 OSF preprint | 10.31234/osf.io/yxbrs | no (preprint) | theory | ABSTRACT | TTT verified anchor
- S029 | Gershman, Blei & Niv 2010, Psych Review 117:197 | — | yes | primary (theory) | RELEVANT_SECTIONS | latent-cause: reconsolidation = belief updating
- X003 | "Winsneski/Bhatt TTT" | NOT FOUND | — | — | — | UNVERIFIABLE — replaced by S028
## Generalization / interference
- S030 | McCloskey & Cohen 1989; Ratcliff 1990 | — | yes | primary | RELEVANT_SECTIONS | catastrophic interference
- S031 | O'Reilly & Norman 2002, TiCS; Norman & O'Reilly 2003, Psych Review 109 | 10.1016/s1364-6613(02)02005-3 | yes | primary (model) | RELEVANT_SECTIONS | pattern separation/completion (REC)
- S032 | Payne et al. 2009, Neurobiol Learn Mem | 10.1016/j.nlm.2009.03.007 | yes | primary | ABSTRACT | sleep increases false memory
- S033 | Fenn et al. 2009, Learn Mem | 10.1101/lm.1500808 | yes | primary | ABSTRACT | OPPOSITE: sleep reduces false memory
- S034 | Anderson, Bjork & Bjork 1994, JEP:LMC 20:1063 | 10.1037/0278-7393.20.5.1063 | yes | primary | RELEVANT_SECTIONS | RIF discovery
- S035 | Murayama et al. 2014, Psych Bull | 10.1037/a0037505 | yes | meta-analysis | ABSTRACT | RIF real on average, boundaries
- S036 | RIF reliability papers (Eur Psychologist 2011, DOI 10.1027/1016-9040/a000040; Frontiers 2014, DOI 10.3389/fpsyg.2014.01343) | — | yes | meta/replication | ABSTRACT | reliability concerns
## AI analogues
- S037 | Schaul et al. 2016, ICLR (PER) | 1511.05952 | yes (conference) | primary | RELEVANT_SECTIONS | prioritized replay in RL + bias caveat
- S038 | Fedus et al. 2020, ICML | 2007.06700 | yes | primary | RELEVANT_SECTIONS | uniform replay often matches PER
- S039 | Song & Qian 2024, Scientific Reports 53117 | — | yes | review | ABSTRACT | prioritization instability
- S040 | Shin et al. 2017, NeurIPS | 1705.08690 | yes | primary | ABSTRACT | generative replay
- S041 | Blundell et al. 2016 (1606.04460); Pritzel et al. 2017 (1703.01988) | — | yes (conference) | primary | ABSTRACT | episodic control — fast store as engineering lever
- S042 | Kauvar et al. 2023, ICML | 2306.15934 | yes | primary | ABSTRACT | curious replay for world models
- S043 | Kumaran, Hassabis & McClelland 2016, TiCS 20(7) | 10.1016/j.tics.2016.05.004 | yes | review (theory) | RELEVANT_SECTIONS | CLS-for-agents anchor (pro)
- S044 | McClelland, McNaughton & Lampinen 2020, Phil Trans R Soc B | 10.1098/rstb.2019.0637 | yes | review (theory) | RELEVANT_SECTIONS | CLS v2
- S045 | De Lange et al. 2021, IEEE TPAMI 44(7) | — | yes | survey | RELEVANT_SECTIONS | catastrophic interference REAL in ML
- S046 | Dacrema et al. 2019, RecSys | 1907.06902 | yes | primary (critique) | RELEVANT_SECTIONS | simple baselines beat complexity (adversarial)
- S047 | O'Neil et al. 1996, Acta Informatica 33(4):351-385 (LSM-tree) | — | yes | primary | RELEVANT_SECTIONS | two-stores-as-engineering (adversarial)
- S048 | Baria & Cross 2021, arXiv 2107.14042; Weisberg et al. 2008, J Cogn Neurosci 20(3) | — | mixed | critique | ABSTRACT | neuro-metaphor seduction (adversarial)
- S049 | Lam et al. 2026, SSGM | 2603.11768 | no (preprint) | primary | RELEVANT_SECTIONS | semantic drift + immutable ledger fix
- S050 | TRUSTMem 2026 | 2606.25161 | no (preprint) | primary | ABSTRACT | consolidation-pipeline corruption measured
- S051 | Ólafsdóttir, Bush & Barry 2018, Curr Biol 28(1) | — | yes | review | RELEVANT_SECTIONS | replay dynamics load-bearing (adversarial)
- S052 | Maynez et al. 2020, ACL | — | yes | primary | ABSTRACT | summarization hallucination (adversarial)
- S053 | Roediger & McDermott 1995, JEP:LMC 21(4):803 | — | yes | primary | RELEVANT_SECTIONS | DRM gist falsification
- S054 | Greshake et al. 2023 | — | yes | primary | ABSTRACT | indirect injection (adversarial, corroboration justification)
- S055 | Candea & Fox 2003 HotOS (crash-only, context) | — | yes | primary | ABSTRACT | engineering pattern context
Totals: primary sources 40+; reviews/surveys 6; competing theories 4 (MTT, indexing, latent-cause, TTT); negative/contrary sources 9; recent (2023-2026) 8; software analogues 8. Unverifiable R0 references excluded: 3 (X001-X003).
@@ -0,0 +1,56 @@
# 03 — APPLICABILITY (Rune-specific, per surviving mechanism)
_Mandate questions 1-15 answered per mechanism. Cheapest-mechanism rule enforced._
## M1: Two-layer split (fast exact / slow generalized) — CLS-R1-C001
1. Original problem: catastrophic interference in overlapping-representation learners.
2. Rune's problem: REAL but milder — LLM consolidation rounds corrupt (C007), not gradient interference. Interference arrives via semantic drift, not weight overlap.
3. Non-transferring biology: replay dynamics, sleep, neuromodulation, decay constants (d≈0.5 is a fit parameter to rodent data, S001).
4. Computational differences: Rune's "fast store" is a database; perfect fidelity, zero decay — better than a hippocampus.
5. Rune already solves it: YES — append-only entries + separate consolidation writer (T0 PROVEN). CLS adds justification, not mechanism.
6-7. Complexity check: copying CLS's neural machinery (sparseness, decay curves) = unnecessary. Simplest capture: the existing two-writer design + drift guards (C007).
8-9. Preserves exact evidence + provenance: YES (append-only + source columns).
10. LLM dependence: unchanged. 11. Offline: YES. 12. Century-scale: YES (append-only is archival-friendly, child U).
13. Event-driven conflict: none. 14. Owner: Memory (whole). 15. Cheapest mechanism: current design + index repair.
## M2: Schema-gated fast path — CLS-R1-C002
1. Original problem: weeks-long consolidation latency for schema-consistent info.
2. Rune's problem: PARTIAL — consolidation lag exists but is not user-painful (nightly); urgency unproven.
3-4. Non-transferring: schema detection in biology is implicit/in learned representations; Rune would need EXPLICIT schema matching (a new classifier) — the biological mechanism does not transfer, only the outcome.
5. Rune already solves: NO (uniform consolidation).
6. Copying increases complexity: YES — schema classifier = new LLM/deterministic component with its own error rate.
7. Simpler capture: promotion-gate with independence check (C006) approximates the benefit without schema detection.
8-12. Preserves evidence/provenance: yes if shadow-mode; offline yes; century-scale yes.
13. Event-driven: compatible (consolidation trigger can be event-driven).
14. Owner: Memory consolidation. 15. Cheapest: defer fast path until consolidation lag is measured as a real problem; shadow-mode experiment first.
## M3: Utility-prioritized consolidation — CLS-R1-C003
1. Original: finite replay budget in navigation.
2. Rune: consolidation compute is cheap; the REAL constraint is lesson QUALITY (bad generalizations are expensive).
3-4. Non-transferring: "need" signals (state relevance) are navigation-specific; Rune's equivalent ("what will shape future behavior") is unmeasurable without an outcome stream.
5. Rune already solves: NO (full sweeps).
6. Complexity: moderate — a utility estimator is a new component.
7. Simpler: dedup + diversity + contradiction-targeting (from child E replay findings) captures most value without a utility model.
8-12. Preserves evidence: yes. 10. LLM: can REDUCE (fewer consolidation calls). 11. Offline: yes.
14. Owner: Memory consolidation. 15. Cheapest: diversity+contradiction sampling; utility model only if that fails.
## M4: Retained covering episodes — CLS-R1-C004
Already Rune doctrine (append-only). Applicability: total. Cheapest: current design. The R1 change is the RATIONALE (drift-correction, not reconsolidation) and the added obligation: drift tests comparing consolidated output against retained sources.
## M5: Reconsolidation framing — CLS-R1-C005
REJECTED as framing. The transferable atom: S017's prediction-error gate — update memories when reality VIOLATES them (contradiction detected), not on mere retrieval. That's just Rune's supersession trigger refined: supersede on contradiction, not on schedule. Owner: Memory write path.
## M6: Independence-gated promotion — CLS-R1-C006
Problem proven (wash_count gameable/unvalidated). Cheapest mechanism: promotion requires entries from ≥2 distinct sessions/sources touching the same content + no contradiction at promotion time. No new subsystem — a gate rule.
## M7: Drift guards on consolidation — CLS-R1-C007
Cheapest: (a) consolidate from immutable source text only (never from prior summaries) — already Rune doctrine, now load-bearing; (b) spot-check: N sampled claims per consolidation run verified against sources (existing claim_audit machinery); (c) drift metric: factual-consistency rate per run, logged. Owner: consolidation pipeline.
## M8: Stage progression — CLS-R1-C008
Keep stages as LABELS on one store (they already exist as kind/status fields); do NOT create separate stores per stage. Owner: Memory.
## M9: Shadow-mode — CLS-R1-C009
Cheap version: generalized beliefs enter with status=provisional and `acted_on=false` until independence gate passes; retrieval MAY surface them but marked. Owner: Memory entry status.
## Boundary assignments (Q14)
All mechanisms above: Memory authority. Nothing here belongs to Spine (structural truth), Substrate (execution), Persona (identity spec), or World Model (current-state belief) — with one note: consolidation's OUTPUT that describes the environment (facts about services/config) feeds the WM projection, but the belief-update authority stays in Memory.
@@ -0,0 +1,42 @@
# 04 — INNOVATION (falsifiable hypotheses only; systems integration counts; novelty not manufactured)
## I1: Drift-metered consolidation (closest prior art: SSGM 2603.11768, TRUSTMem 2606.25161)
- Difference: SSGM prescribes immutable ledgers; Rune ADDS a measured drift metric per consolidation run (factual-consistency rate of sampled claims vs immutable sources) gating whether the run's output is accepted.
- Mechanism: post-consolidation, sample N derived claims, verify against source episodes (existing claim_audit machinery); acceptance threshold; failed runs re-run or discarded.
- Predicted advantage: consolidation corruption (C007, S050: 79%/50% reduction when guarded) caught before entering the belief layer.
- Cost: N verification calls per run. Failure mode: verification LLM hallucinates agreement — mitigate with exact-quote checks.
- Benchmark: drift rate per run before/after; retraction rate of accepted beliefs.
- Rejection criterion: if drift rate is <1% unguarded across 10 runs, the meter is overhead — drop it.
- Classification: EXPERIMENT. Evidence: EXTERNALLY_ESTABLISHED (drift) → RUNE_HYPOTHESIS (meter).
## I2: Independence-gated promotion (closest prior art: dedup+recency recommenders, S046)
- Difference: recommendation systems gate on statistical ensembles; Rune gates on SOURCE-GRAPH independence (distinct sessions, distinct evidence chains) + contradiction absence — a check available only because Rune keeps exact provenance.
- Mechanism: promotion_eligible requires ≥2 independent evidence chains + zero active contradictions (using existing supersession graph).
- Predicted advantage: eliminates frequency-gamed promotions (observed T0.1).
- Cost: none — query over existing data. Failure mode: over-strict gate starves promotion (measure promotion latency).
- Benchmark: promoted-belief retraction rate vs old wash_count gate.
- Rejection criterion: if retraction rates equal, revert to simple gate.
- Classification: ADAPT. Evidence: RUNE_APPLICABLE.
## I3: Contradiction-triggered consolidation (event-driven, from S017's prediction-error gate via M5)
- Difference: consolidation runs on DRIFT/CONTRADICTION events (new evidence contradicting an existing belief), not on timers — unifying Rune's event-driven mandate (req 34) with CLS's update-gate.
- Mechanism: write-path contradiction detection (cross-encoder prefilter, child AC) emits consolidation-trigger events; consolidation processes affected beliefs, not the whole store.
- Predicted advantage: timely belief updates (T0.1's non-deterministic trigger replaced); reduced LLM consumption (targeted runs).
- Cost: contradiction detector errors (false positives → consolidation churn; rate-limit).
- Benchmark: belief-update latency; LLM calls per belief-update; churn rate.
- Rejection criterion: if targeted consolidation misses updates the sweep catches, hybrid (event + periodic sweep).
- Classification: EXPERIMENT. Evidence: RUNE_HYPOTHESIS.
## I4: Shadow-mode generalizations (closest prior art: TiMem dual-buffer probation; SSGM staging)
- Difference: probation tied to the independence gate (I2) with `acted_on=false` semantics — beliefs are retrievable-but-marked, and the promotion decision is auditable in the ledger.
- Predicted advantage: overgeneralization caught before behavior; audit trail of WHY a belief was promoted (req 24).
- Cost: status complexity. Failure mode: shadow beliefs leak into behavior unmarked.
- Benchmark: retraction rate of shadow-vs-direct promotions.
- Rejection criterion: if no retraction-rate difference across 50 promotions, drop shadow mode.
- Classification: EXPERIMENT. Evidence: RUNE_HYPOTHESIS.
## I5: Two-lane consolidation benchmark (from CLS-R1-C010 refinement)
- The innovation is METRIC-FIRST: before any prioritization scheme, implement the measurement (lesson quality: retraction rate, contradiction rate at promotion, independence depth) — then let data pick recency vs utility vs diversity.
- Classification: EXPERIMENT (protocol). Evidence: RUNE_APPLICABLE (problem proven).
No manufactured novelty: I1/I4 have close published prior art (SSGM, TiMem); I2 is integration of existing Rune provenance with standard hygiene; I3 is Rune's own event-driven mandate applied to CLS's update gate; I5 is measurement design. Each claims integration, not new mechanism.
@@ -0,0 +1,30 @@
# 05 — ADVERSARIAL (independent research pass; actor general-31)
_Mandate: assume the emerging CLS→Rune conclusions are WRONG. Find the strongest cited evidence. Honest failed attacks recorded._
## Attack 1 — "Two stores / two writers": LARGELY SUCCESSFUL
The dual-store pattern exists in engineering WITHOUT neuroscience and predates CLS-as-software: the LSM-tree (memtable + immutable SSTables + background compaction) is exactly "fast volatile store, slow durable store, consolidation pass" — O'Neil, Cheng, Gawlick & O'Neil, *Acta Informatica* 33(4):351-385, 1996. What CLS would add beyond cache+DB is the DYNAMICS: sharp-wave-ripple replay during sleep, interleaved training, slow integration — software Rune has none (Ólafsdóttir, Bush & Barry, *Current Biology* 28(1):R37-R50, 2018: the biological consolidation story rests on those dynamics). Metaphor critique: Baria & Cross, arXiv:2107.14042 (2021); Weisberg et al., "The seductive allure of neuroscience explanations," *J Cogn Neurosci* 20(3):470-477, 2008. **Strength: high.** Honest counter: CLS's distinctive content is INTERFERENCE MANAGEMENT — catastrophic interference is a real software phenomenon (De Lange et al. 2021) — but that doesn't rescue "two stores" specifically, which is not where CLS does work.
## Attack 2 — Tse 2007 schema gating: SUCCESSFUL
Tse et al., *Science* 313:1130-1133, 2007: rats only, food-reward flavor-place paired-associate task, WEEKS of training on six PAs before one-trial new-PA learning (paradigm per Hasan et al., *PLoS Biology* 17(12):e3000564, 2019, which concedes "difficult to map the concept of mental schema precisely onto existing neurobiological models"). Mechanism contested at publication: "Does assimilation into schemas involve systems or cellular consolidation?" (*Neurobiol Learn Mem* 2007) — an encoding-level prior-knowledge benefit is an equally live explanation. Human translation: Warren & Duff, *Hippocampus* 24(8):920-932, 2014 — amnesics fail to benefit from fast-mapping routes; Warren et al., *J Neurosci* 34(22), 2014 — schema influence located in vmPFC, not a hippocampus-bypassing speedup; Sharon/Moscovitch/Gilboa, *PNAS* 108:17263-17268, 2011 — rapid acquisition via a DIFFERENT route (rapid neocortical acquisition independent of hippocampus). **Strength: high** for animal-paradigm confinement; **medium** for the encoding-effect alternative (no paper cleanly rules it out).
## Attack 3 — Mattar & Daw prioritized replay → utility-prioritized consolidation: SUCCESSFUL
Mattar & Daw, *Neuron* 99(5):944-966, 2018 models utility-driven replay in simulated MAZE NAVIGATION. Ólafsdóttir et al. (2018): replay literature rests "mainly, but not exclusively, on rodents"; human replay evidence indirect. **No published evidence prioritized replay transfers to semantic-memory consolidation.** Closest analog (RL PER) is cautionary: Schaul et al. ICLR 2016 (PER needs importance-sampling correction for bias); Fedus et al. ICML 2020 — uniform replay often MATCHES PER, buffer freshness dominates; Song & Qian, *Scientific Reports* 53117, 2024 — single-criterion prioritization unstable across environments. **Strength: high** ("no transfer evidence"); PER pathologies make transfer worse.
## Attack 4 — retained covering episodes: **FAILED** (conclusion survives; rationale replaced)
The biology supports the attack: transformation theory (Winocur & Moscovitch, *JINS* 17(5):766-780, 2011; Moscovitch et al., *Ann Rev Psych* 67:1-36, 2016) holds the brain ROUTINELY DISCARDS details — retention of source episodes is not what biological consolidation does. Generative Agents (Park et al., UIST 2023) and MemGPT (Packer et al. 2023) run reflection/summarization without retained originals. **But the strongest engineering evidence cuts the other way**: SSGM (Lam et al., arXiv:2603.11768, 2026) documents SEMANTIC DRIFT — lossy iterative summarization progressively distorting stored facts ("likes mild spicy food" → "loves very spicy") — and prescribes an immutable episodic ledger reconciled against the mutable store. **Retention is justified by DRIFT-CORRECTION, not reconsolidation; the CLS conclusion survives on engineering grounds, losing its biological rationale.**
## Attack 5 — reconsolidation → supersession: SUCCESSFUL
Pharmacological foundation contested: Rudy, Biedenkapp, Moineau & Bolding, *Learn Mem* 13(1):1-3, 2006 — anisomycin has non-specific effects producing TEMPORARY amnesia unrelated to re-stabilization; Lattal & Abel, *PNAS* 101(13):4667-4672, 2004 — deficits REVERSE with time (retrieval-failure signature, not erasure); Morris et al., *Neuron* 50(3):479-489, 2006 — intrahippocampal anisomycin "nonspecific effects unconnected with reconsolidation." Alternative mechanisms (extinction facilitation: Myers & Davis 2002; Fischer et al. 2004) explain the same data. Tronson & Taylor, *Nat Rev Neurosci* 8:352-365, 2007 — wildly heterogeneous boundary conditions. **Correction to the R0 assumption: Hardt & Nader are on the PRO side** — Nader & Hardt, "A single standard for memory: the case for reconsolidation," *Nat Rev Neurosci* 10:224-234, 2009 — which is itself telling: the phenomenon requires a "case for" paper. **Strength: high.** Mapping Rune supersession to a phenomenon whose existence is pharmacology-dependent is speculation.
## Attack 6 — corroboration gating: PARTIAL SUCCESS
Dacrema, Cremonesi & Jannach, "Are we really making much progress?" *RecSys 2019* (1907.06902): 11 of 18 neural recommenders failed to beat well-tuned simple baselines — simple mechanisms (dedup, recency, linear) match added complexity; "corroboration" is structurally ensemble voting / confirmation-weighted averaging — standard hygiene needing no memory theory. **However, partially fails:** for single-user stores exposed to prompt injection and hallucinated inputs (Greshake et al. 2023, indirect injection), write-path validation has a distinct justification beyond dedup/recency. Corroboration-as-hygiene: yes; corroboration-as-redundant: unproven.
## Attack 7 — workload mismatch: MIXED
De Lange et al., *IEEE TPAMI* 44(7), 2021; Abel et al., *NeurIPS 2023*: agent settings are never-stationary, never-i.i.d. streams — nothing like hippocampal encoding at fixed event boundaries; MemGPT demonstrates top-down OS-style design working without neuro-anchoring; timescales differ by orders of magnitude. **Failed part:** Kumaran, Hassabis & McClelland, "What learning systems do efficient agents need?" *TiCS* 20(7):512-534, 2016 IS a peer-reviewed argument that CLS maps directly onto agent ML — the strongest pro-position the adversarial side must answer; and catastrophic interference (real, per De Lange) gives CLS teeth.
## Attack 8 — consolidation damages exactness: SUCCESSFUL
Maynez et al., "On faithfulness and factuality in abstractive summarization," *ACL 2020*: "substantial amounts of hallucinated content in all model generated summaries" — summarization (consolidation's software form) systematically injects error. Roediger & McDermott 1995 (DRM): gist compression GENERATES false content. Agent-specific: SSGM (2603.11768) places "semantic drift during consolidation updates" among top three failure modes; **TRUSTMem (arXiv:2606.25161, 2026) measures omission/corruption/hallucination introduced BY the consolidation pipeline itself** and cuts these 79.1%/50.0% vs baselines — direct evidence consolidation rounds degrade exactness an exact store wouldn't.
## Bottom line
**Strongest kills:** #5 (contested pharmacological foundation), #3 (no transfer evidence + fragile RL analog), #2 (rat food-reward paradigm, contested mechanism, human translation failures), #8 (documented consolidation-introduced corruption). **Attack #4 failed on the conclusion** (retention is right) **but won on the rationale** (drift-correction, not reconsolidation). **#1 strongest** where it says two stores are trivial engineering (LSM 1996), weakest against interference-based CLS content. **#6, #7 genuinely mixed** — with Kumaran 2016 as the pro-CLS anchor any honest synthesis must answer.
@@ -0,0 +1,22 @@
# 06 — SYNTHESIS: mechanism matrix + reconciliation
## Mechanism matrix
| MECHANISM | ORIGINAL PURPOSE | EVIDENCE STRENGTH | LIMITATIONS | RUNE EQUIVALENT | RUNE GAP | TRANSFER VALIDITY | COST | FAILURE MODES | CLASSIFICATION | RUNE EVIDENCE LEVEL |
|---|---|---|---|---|---|---|---|---|---|---|
| Fast exact episodic store | evade catastrophic interference | STRONG (S001, S030, S045, S041) | biology's decay dynamics don't transfer; Rune's is better (perfect fidelity) | append-only entries (PROVEN) | index coverage (439 unindexed) | HIGH (as engineering; CLS adds interference rationale) | none | silent embedder failure (observed) | COVERED — repair | RUNE_PROVEN (store); index repair needed |
| Slow statistical/generalized layer | interference-free generalization | STRONG (S001, S044) | transformation loses detail (S026) | knowledge.json consolidation (PROVEN to run) | drift guards; source-only inputs | HIGH | verification calls | consolidation hallucination (S052, S050) | ADAPT (drift-metered) | RUNE_APPLICABLE |
| Two stores / two writers | separate update rates | STRONG as engineering (S047 LSM) / CLS content = interference mgmt (S045) | "two stores" trivial without dynamics (adversarial #1) | agent writer + consolidator (PROVEN) | none structural | HIGH | none | writer conflation | COVERED | RUNE_PROVEN |
| Schema-gated rapid integration | fast assimilation with prior knowledge | CONTESTED (S003 effect real in rats; mechanism contested S007/S008; adversarial #2) | animal paradigm; encoding-vs-consolidation confound; schema detection cost | none | schema detector would be NEW | MEDIUM | new classifier | wrong schema match → corrupt fast promotions | EXPERIMENT (deferred until lag measured) | RUNE_HYPOTHESIS |
| Utility-prioritized consolidation | finite replay budget, prospective value | MEDIUM (S012 model+converging ephys; navigation-specific) | no semantic-memory transfer evidence (adversarial #3); PER fragility (S038/S039) | none (full sweeps) | utility signal unmeasurable without outcome stream | MEDIUM | utility estimator | gamed/biased prioritization | EXPERIMENT (baseline-first) | RUNE_HYPOTHESIS |
| Retained covering episodes | reconsolidation substrate (R0 claim) → drift correction (R1) | STRONG engineering (S049/S050/S052) | storage cost; biology actually discards (S026) | append-only (PROVEN) | drift tests vs sources | HIGH | storage | none serious | ADOPT (rationale corrected) | RUNE_APPLICABLE |
| Reconsolidation → supersession | update-on-retrieval | CONTESTED (S015 rodent robust; S018-020 pharmacology contested) | write-vs-retrieval trigger mismatch | supersession (PROVEN, write-triggered) | prediction-error trigger refinement | LOW (framing) / MEDIUM (gate atom) | none | dogma without mechanism | REJECT framing; KEEP contradiction-triggered updates | RUNE_APPLICABLE (gate atom only) |
| Interference management (pattern separation/completion) | avoid false memories + enable retrieval | STRONG computational (S031) + fMRI support | separation/completion trade-off is architectural, not tunable | dedupe/supersede gate (PROVEN); exact quotes | contradiction detection (missing) | HIGH | cross-encoder prefilter | false contradiction detections | ADAPT | RUNE_APPLICABLE |
| Independent-evidence promotion gate | avoid premature generalization | MEDIUM (S017 gates; S046 simplicity warning) | nothing biological required | promotion_eligible (exists, frequency-driven — UNVALIDATED) | independence test | HIGH | none (query) | over-strict gate starves promotion | ADAPT | RUNE_APPLICABLE |
| Shadow-mode provisional beliefs | prevent premature influence | MEDIUM (interference-threshold logic; TiMem convergence) | state complexity | status field (exists) | acted_on semantics | MEDIUM | none | shadow leakage | EXPERIMENT | RUNE_HYPOTHESIS |
| Replay as teacher (offline re-processing) | neocortical learning from hippocampal record | MEDIUM (S012; decoding contested S014) | content-decoding methods disputed (S014); co-reactivation ↔ forgetting (S013) | consolidation as re-processing (PROVEN to run) | sampling policy | MEDIUM | none | replay amplifies poisoned content (child E) | COVERED (consolidation = Rune's replay; policy = experiments above) | RUNE_APPLICABLE |
| Gist consolidation creates false content | efficiency of gist | CONTESTED in biology (S032 vs S033); STRONG in software (S052, S049, S050) | — | LLM summarization | drift guards | HIGH | verification | silent corruption | ADOPT (guards) | RUNE_APPLICABLE |
## Synthesis narrative
CLS's load-bearing content for Rune is NOT the two-store anatomy (that's LSM-tree engineering, S047) and NOT the biological dynamics (replay/sleep — S051) and NOT reconsolidation (pharmacologically contested — S018-020). Three things transfer: (1) **the interference-management problem is real in software** (S045) and Rune's exact store + supersession is the pattern-separation answer; (2) **consolidation corrupts** (S049/S050/S052) — so the slow layer requires drift guards and retained sources as engineering requirements; (3) **updates are gated by prediction error, not schedules** (S017, reframed via S029's latent-cause account as plain belief-updating) — which lands Rune's consolidation trigger on events, not timers. The five-stage progression is Rune's own construct: keep it as labels, not stores. Competing theories (MTT, indexing, latent-cause) matter mostly as warnings: the biology does not settle what CLS's early readings assumed, and the latent-cause account explains reconsolidation phenomena as ordinary belief-updating — which is exactly the software form Rune should implement. Kumaran 2016 (S043) remains the strongest pro-CLS-for-agents argument and survives the adversarial pass on interference grounds.
@@ -0,0 +1,28 @@
# 07 — QUALIFICATION (#376 R1)
_Classification separate from evidence level. Each item: confidence, sources (for/against), assumptions, cost, failure modes, T1 impact, experiment, falsifier, rejection criterion. Evidence levels per claims.json._
## Qualified mechanisms
| # | Mechanism | Classification | Evidence level | Conf | For | Against | T1 impact | Experiment | Rejection criterion |
|---|---|---|---|---|---|---|---|---|---|
| Q1 | Two-layer split (exact episodes + generalized layer, two writers) | COVERED — keep; repair index coverage | EXTERNALLY_ESTABLISHED + RUNE_APPLICABLE (store RUNE_PROVEN) | HIGH | S001/S045/S041/S049 | S047 (trivial-engineering caveat — does not defeat interference content) | HIGH (retention/rotation decision) | index-repair + embedder loud-failure (not CLS but urgent) | single-store drift parity |
| Q2 | Drift guards on consolidation (source-only inputs, quote-checks, drift metric) | ADOPT | EXTERNALLY_ESTABLISHED + RUNE_APPLICABLE | HIGH | S049/S050/S052/S053 | S033 (biology direction contested — irrelevant to software) | HIGH | drift-rate measurement per run | drift <1% unguarded over 10 runs |
| Q3 | Retained covering episodes (append-only; rationale = drift correction) | ADOPT — already doctrine | RUNE_APPLICABLE | HIGH | S049 adversarial-confirmed | S026 (biology discards — explicitly not imitated) | MEDIUM | retention vs drift controlled test | consolidation-without-retention parity |
| Q4 | Independence-gated promotion (replaces wash_count frequency gate) | ADAPT | RUNE_APPLICABLE (problem RUNE_PROVEN via T0.1) | HIGH | S054 threat model; wash_count unvalidated | S046 simplicity | MEDIUM | promotion retraction-rate A/B | equal retraction rates |
| Q5 | Contradiction-triggered (event-driven) consolidation | ADAPT | RUNE_HYPOTHESIS | MEDIUM | S017 gate atom; S029 latent-cause framing | trigger-churn risk | MEDIUM | targeted-vs-sweep update latency | missed updates vs sweep |
| Q6 | Shadow-mode provisional generalizations | EXPERIMENT | RUNE_HYPOTHESIS | MEDIUM | TiMem convergence; interference logic | complexity | MEDIUM | shadow-vs-direct retraction rates | no difference over 50 promotions |
| Q7 | Utility-prioritized consolidation | EXPERIMENT (refined from R0) | RUNE_HYPOTHESIS (transfer unproven) | LOW-MED | S012/S011 | adversarial#3; S038/S039 | LOW-MED | lesson-quality A/B vs dedup+diversity baseline | no improvement over baseline |
| Q8 | Schema-gated fast path | EXPERIMENT (DEFERRED until consolidation lag measured as real) | CONTESTED externally | LOW-MED | S003/S005 | S007/S008; adversarial#2 | LOW | lag measurement first; then shadow fast path | fast-path retraction rate higher |
| Q9 | Five-stage progression (episode→observation→belief→procedure) | ADAPT (as labels on one store) | RUNE_APPLICABLE (transitions RUNE_PROVEN) | MEDIUM | S001/S044 stage logic | over-engineering risk (meta-review) | LOW-MED | friction vs lesson-quality | collapse to 2-stage if no benefit |
| Q10 | Reconsolidation framing for supersession | REJECT (framing); KEEP prediction-error-gated updates | CONTESTED | HIGH (in the reject) | S015/S017/S029 | S018/S019/S020; adversarial#5 | LOW | — | — |
## Evidence-level discipline (mandate §17)
No mechanism above is RUNE_PROVEN beyond what T0/T0.1 already established (two-writer structure, append-only, promotion-gate existence). Everything new — drift guards, independence gates, event triggers, shadow mode — is RUNE_HYPOTHESIS until Rune experiments run. Q1's store layer is the only RUNE_PROVEN item, and its gap (index coverage) is operational, not architectural.
## Evidence-level separation statement (G10)
Explicit separation of layers, per mandate:
- BIOLOGICAL MECHANISM (what the brain does): fast sparse hippocampal store, slow overlapping neocortex, replay-as-teacher, schema-gated integration, reconsolidation-with-prediction-error-gate. Established to varying degrees (S001-S031) — NOT Rune claims.
- SOFTWARE ANALOGY (what the mechanism becomes in software): two-layer store, consolidation pass, prioritized sampling, update-on-violation. Validated as engineering levers (S037-S041, S045) — still NOT Rune claims.
- RUNE PRESCRIPTION (what Rune should do): only items with RUNE_APPLICABLE or stronger levels in claims.json — the two-layer split (RUNE_PROVEN structure), drift guards (RUNE_APPLICABLE), independence gate (RUNE_APPLICABLE), contradiction-triggered updates (RUNE_HYPOTHESIS), shadow mode (RUNE_HYPOTHESIS). Every EXTERNALLY_ESTABLISHED claim that entered Rune prescription passed through an explicit applicability argument (03_applicability.md) and carries its Rune evidence level in claims.json. No biological finding is cited as Rune proof anywhere in this artifact set.
@@ -0,0 +1,46 @@
# #376 R1 — Complementary Learning Systems: FINAL (durable technical reference)
_This document is the domain's durable reference. It assumes the reader has the pipeline artifacts alongside: 00_issue_scope, 01_inward, 02_outward/ (9 files + sources.md + claims.json), 03_applicability, 04_innovation, 05_adversarial, 06_synthesis, 07_qualification, r0_reconciliation._
## 1. The domain in one page
Complementary Learning Systems (McClelland, McNaughton & O'Reilly 1995) claims cognition needs two learning systems: a fast, sparse, episodic store (hippocampus) that learns instantly but interferes catastrophically when asked to generalize, and a slow, overlapping, statistical store (neocortex) that generalizes well but must learn slowly and interleaved. The hippocampus acts as a teacher: replay of episodes drives slow neocortical integration. Thirty years of development produced: schema-gated rapid integration (Tse 2007; McClelland 2013 — the theory's biggest self-revision), utility-prioritized replay (Mattar & Daw 2018), reconsolidation (Nader 2000 — with a contested pharmacological foundation), transformation theory (memories are transformed, not copied — Winocur/Moscovitch), and serious competitors (MTT, hippocampal indexing, latent-cause/Bayesian accounts). In ML, the pattern is validated as engineering: episodic control buffers, experience/generative replay, and catastrophic interference are all real (S037-S045).
## 2. What transfers to Rune, and what does not
**Transfers (as engineering, with Rune evidence):**
- The two-layer split with separate update rates. Rune has it structurally (RUNE_PROVEN); its urgency comes from consolidation corruption (S049/S050), not from CLS.
- Retention of exact sources. NOT because reconsolidation needs them (the biology discards — S026) but because iterative summarization measurably drifts (S049) and the consolidation pipeline itself corrupts (S050).
- Update gating by prediction error. When new evidence contradicts a belief, update; mere retrieval changes nothing. (S017's gate, reframed through S029's latent-cause account as ordinary belief-updating.)
- Interference management. Catastrophic interference is real in ML (S045); Rune's exact store + supersession + dedupe is the pattern-separation answer.
**Does not transfer:**
- The biological dynamics (replay during sleep, decay constants, neuromodulation). Rune has no sleep; its "fast store" is a database with perfect fidelity.
- Reconsolidation as a phenomenon to imitate. Pharmacologically contested (S018-020); the useful atom (update-on-violation) is captured by plain belief-updating.
- Schema detection as a mechanism. In biology it is implicit in learned representations; in Rune it would be an explicit, error-prone classifier.
- Utility signals without an outcome stream. Mattar-Daw "need" requires measuring future value; Rune cannot measure that yet.
## 3. The corrected rationale for Rune's pipeline
R0 said: CLS justifies episode→observation→belief→procedure with a schema fast path, utility prioritization, and reconsolidation-style updates. R1 corrects: the pipeline is justified by (a) drift-correction economics (exact sources are the only defense against measured consolidation corruption), (b) interference management (dedupe/supersede/exact quotes), (c) prediction-error-gated updates (contradiction-triggered, event-driven), and (d) independence-gated promotion (because frequency is gameable and unvalidated). Schema fast paths and utility prioritization are experiments, not architecture.
## 4. Experiments this domain requires (in order)
1. **Drift-metered consolidation**: measure factual-consistency of derived claims vs immutable sources per run. Rejection criterion: drift <1% unguarded → drop the meter.
2. **Promotion-gate A/B**: independence-gated vs wash_count-gated promotion; metric = promoted-belief retraction rate.
3. **Consolidation trigger A/B**: event-driven (contradiction-triggered) vs periodic sweep; metrics = update latency, missed updates, LLM calls.
4. **Prioritization A/B**: recency vs utility vs dedup+diversity sampling; metric = lesson quality (retraction/contradiction rates).
5. **Shadow mode**: shadow-vs-direct promotion retraction comparison over 50 promotions.
## 5. What would change this conclusion
- A credible "summarize-and-discard works fine" result (would force re-examination of retention).
- Consolidation-lag evidence showing nightly updates are user-painful (would revive the schema fast path).
- An outcome-stream making utility measurable (would upgrade C003 from experiment to design input).
- Replication of schema-acceleration as consolidation-specific (would strengthen C002).
## 6. Remaining unknowns (bounded)
- Whether Rune's consolidation is atomically checkpointed end-to-end (code verification, not research).
- Optimal independence-test depth (2 chains? 3?) — needs the promotion A/B.
- Whether interval-confidence elicitation helps on local models (child Q's open question, shared).
## 7. Production implementation
NONE. This tranche is research only. Everything above enters T1 as design input and experiment protocol.
@@ -0,0 +1,125 @@
{
"note": "Narrow, falsifiable claims. external_status: EXTERNALLY_ESTABLISHED|CONTESTED|WEAK. rune_status: RUNE_APPLICABLE|RUNE_HYPOTHESIS|RUNE_EXPERIMENTALLY_SUPPORTED|RUNE_PROVEN.",
"claims": [
{
"claim_id": "CLS-R1-C001",
"claim": "Fast exact episodic capture + slow statistical generalization is the right two-layer split for Rune",
"evidence_for": ["S001 core CLS logic", "S045 catastrophic interference REAL in ML", "S041 episodic fast store validated as engineering lever", "S049 semantic drift from lossy consolidation documents what happens without the split"],
"evidence_against": ["S047 two-stores is trivial engineering (LSM-tree) needing no CLS", "S048 neuro-metaphor seduction", "S051 biological dynamics (replay/sleep) not present in software"],
"external_status": "EXTERNALLY_ESTABLISHED (as engineering pattern; CLS's interference-management content adds justification)",
"rune_status": "RUNE_APPLICABLE (T0: two writers exist structurally; T0.1 leak = implementation gap not design gap)",
"architecture_impact": "HIGH",
"falsifier": "F1: if single-store designs match two-store on drift+interference metrics at Rune scale, the split is preference",
"experiment_required": true,
"classification": "COVERED (architecture) — implement cleanly"
},
{
"claim_id": "CLS-R1-C002",
"claim": "Schema-gated rapid consolidation (fast path) is justified for Rune",
"evidence_for": ["S003 Tse 2007 (rats, replicated in-lab)", "S005 McClelland 2013 principled revision", "S006 human fMRI echo"],
"evidence_against": ["S007 rapid learning WITHOUT hippocampus (alternative route)", "S008 amnesic failures of fast mapping", "adversarial#2: encoding-level prior-knowledge benefit equally live; food-reward rat paradigm; mechanism contested at publication"],
"external_status": "CONTESTED (effect real; MECHANISM and hippocampal-independence interpretation contested)",
"rune_status": "RUNE_HYPOTHESIS",
"architecture_impact": "MEDIUM",
"falsifier": "F2: if fast-path promotions show higher retraction rates than slow-path, revert",
"experiment_required": true,
"classification": "EXPERIMENT (fast path with shadow-mode + retraction-rate kill criterion)"
},
{
"claim_id": "CLS-R1-C003",
"claim": "Consolidation should be utility-prioritized (expected future value), not recency/frequency-based",
"evidence_for": ["S012 Mattar & Daw: prioritization by gain+need, NOT recency", "S011 reward-gating precursor", "S037 PER validates prioritization as lever (with bias caveat)"],
"evidence_against": ["adversarial#3: model is maze-navigation-specific; NO transfer evidence to semantic consolidation", "S038 uniform replay often matches PER", "S039 single-criterion prioritization unstable", "Rune's own wash_count (frequency) never validated as quality signal (T0.1)"],
"external_status": "EXTERNALLY_ESTABLISHED (in navigation/RL) / TRANSFER_UNPROVEN (to semantic memory consolidation)",
"rune_status": "RUNE_HYPOTHESIS",
"architecture_impact": "MEDIUM",
"falsifier": "F3: if utility-weighted consolidation produces no measurable lesson-quality improvement over recency+dedup baselines, use the simple version",
"experiment_required": true,
"classification": "EXPERIMENT (utility signal must be measured, not assumed; simple baseline first)"
},
{
"claim_id": "CLS-R1-C004",
"claim": "Covering episodes must be retained after generalization (no destructive consolidation)",
"evidence_for": ["S026 transformation theory: details are LOST — retention fights biology but preserves verifiability", "S049 SSGM: semantic drift from lossy summarization; immutable ledger is the fix", "S050 TRUSTMem: consolidation pipeline itself corrupts (79%/50% reduction when guarded)", "S052 summarization hallucination", "S053 DRM gist falsification"],
"evidence_against": ["adversarial#4 FAILED: no 'summarize-and-discard works fine' evidence found; biology discards freely (S026)", "storage cost is real"],
"external_status": "EXTERNALLY_ESTABLISHED (as engineering requirement — drift correction; NOT as biological requirement)",
"rune_status": "RUNE_APPLICABLE (append-only entries already PROVEN in Rune)",
"architecture_impact": "HIGH",
"falsifier": "F5: if consolidation-without-retention shows no drift/corruption in controlled Rune test, retention is preference",
"experiment_required": false,
"classification": "ADOPT (already Rune doctrine; rationale CORRECTED from reconsolidation to drift-correction)"
},
{
"claim_id": "CLS-R1-C005",
"claim": "Reconsolidation (retrieval-triggered lability) maps to Rune supersession",
"evidence_for": ["S015 anchor phenomenon", "S017 prediction-error gate is a real mechanism", "S029 latent-cause framing: reconsolidation = belief updating"],
"evidence_against": ["S018/S019/S020 pharmacological foundation contested (temporary amnesia, reversal with time, nonspecific effects)", "adversarial#5: mapping to a phenomenon whose existence is pharmacology-dependent is speculation", "Rune supersession is WRITE-triggered not retrieval-triggered — the analogy was asserted in R0, not derived"],
"external_status": "CONTESTED (rodent robust; human mixed; pharmacology-dependent)",
"rune_status": "RUNE_HYPOTHESIS (weak)",
"architecture_impact": "LOW",
"falsifier": "F4: if reconsolidation's useful property (update-on-retrieval) is fully captured by plain belief-updating (S029), drop the neuroscience framing entirely",
"experiment_required": false,
"classification": "REJECT the reconsolidation FRAMING; KEEP plain belief-updating with prediction-error gating (S017's gate is the transferable part)"
},
{
"claim_id": "CLS-R1-C006",
"claim": "Independent-evidence corroboration should gate promotion (not frequency/wash_count)",
"evidence_for": ["S017 prediction-error/independence gates exist in biology", "S054 injection threat makes write-path validation distinct from dedup", "Rune wash_count demonstrably unvalidated (T0.1: superseded entries with high counts)"],
"evidence_against": ["S046 11/18 neural recommenders failed vs simple baselines", "adversarial#6: corroboration = ensemble voting hygiene, no memory theory needed"],
"external_status": "EXTERNALLY_ESTABLISHED (as hygiene)",
"rune_status": "RUNE_APPLICABLE (problem proven: frequency gating is gameable and unvalidated)",
"architecture_impact": "MEDIUM",
"falsifier": "If dedup+recency matches corroboration-gated promotion on lesson quality, use simple version",
"experiment_required": true,
"classification": "ADAPT (independence test as promotion criterion; simple implementation first)"
},
{
"claim_id": "CLS-R1-C007",
"claim": "Consolidation introduces errors an exact store wouldn't have (gist hallucination/drift)",
"evidence_for": ["S052 summarization hallucination (ACL 2020)", "S053 DRM", "S049 SSGM drift documented", "S050 TRUSTMem measured consolidation corruption"],
"evidence_against": ["S033 sleep REDUCED false memories (biology direction contested)", "none in software — drift is well-documented"],
"external_status": "EXTERNALLY_ESTABLISHED (in software)",
"rune_status": "RUNE_APPLICABLE (Rune consolidates via LLM summarization — same mechanism)",
"architecture_impact": "HIGH",
"falsifier": "none plausible — mitigation is the question, not existence",
"experiment_required": false,
"classification": "ADOPT mitigations: consolidate from immutable sources only; quote-verification before promotion; drift tests"
},
{
"claim_id": "CLS-R1-C008",
"claim": "Evidence→episode→observation→belief→procedure progression with deterministic state transitions and LLM-only content operations",
"evidence_for": ["S001/S044 CLS stage structure", "S029 latent-cause: updating = inference (LLM content ops) over deterministic state", "S041 episodic control (fast layer engineering-validated)", "Rune T0: state transitions already deterministic; promotion gate exists"],
"evidence_against": ["stage boundaries are Rune's construct, not CLS's — CLS has two stores, not five stages", "over-engineering risk (meta-review #3)"],
"external_status": "EXTERNALLY_ESTABLISHED (as two-layer); the 5-stage elaboration is RUNE-designed",
"rune_status": "RUNE_APPLICABLE (transitions already deterministic; T0 PROVEN)",
"architecture_impact": "MEDIUM",
"falsifier": "if 5-stage bookkeeping adds friction without measurable lesson quality, collapse to 2-stage (episodes + consolidated)",
"experiment_required": true,
"classification": "ADAPT (keep progression but treat intermediate stages as labels on one store, not separate stores)"
},
{
"claim_id": "CLS-R1-C009",
"claim": "Shadow-mode provisional generalizations (behavioral-only until corroborated by independent episodes)",
"evidence_for": ["S003/S005 interference-threshold logic supports probation", "S050 consolidation corruption risk argues for pre-promotion probation", "TiMem dual-buffer probation (prior closure O) — convergent design"],
"evidence_against": ["no biological analog needed — this is engineering", "adds state complexity"],
"external_status": "RUNE_HYPOTHESIS (engineering design informed by interference thresholds)",
"rune_status": "RUNE_HYPOTHESIS",
"architecture_impact": "MEDIUM",
"falsifier": "if shadow-mode beliefs never differ from direct promotion outcomes in retrospective analysis, drop the mode",
"experiment_required": true,
"classification": "EXPERIMENT"
},
{
"claim_id": "CLS-R1-C010",
"claim": "Recency-based consolidation priority should be rejected",
"evidence_for": ["S012 replay NOT recency-biased in biology", "S013 co-reactivation ↔ forgetting", "R0 rationale holds"],
"evidence_against": ["S038 freshness dominates in RL replay buffers (recency has value!)", "adversarial#3: no transfer evidence either direction for semantic consolidation"],
"external_status": "CONTESTED",
"rune_status": "RUNE_HYPOTHESIS",
"architecture_impact": "LOW",
"falsifier": "if recency-weighted consolidation matches utility-weighted on lesson quality, the rejection is dogma",
"experiment_required": true,
"classification": "REFINED — reject recency-ONLY; do not assume utility-weighting either; benchmark both against dedup+diversity baseline"
}
]
}
@@ -0,0 +1,22 @@
# R0 → R1 Reconciliation (#376 CLS)
_Every material R0 claim, revisited. R0 source: memory-atlas/families/complementary_learning_systems.md_
| R0 claim | R1 verdict | Why |
|---|---|---|
| Fast exact episodic storage + slow generalized knowledge is the right split | **CONFIRMED** (with rationale correction) | Survives adversarial pass as ENGINEERING pattern (S047 caveat noted); interference management (S045) is the transferable content, not the anatomy. Rune's gap is operational (index coverage), not architectural. |
| Two stores / two writers analogy | **CONFIRMED** | Already RUNE_PROVEN structurally (T0); CLS adds justification via interference content; adversarial "it's just LSM" accepted as caveat, not defeat. |
| Schema-gated fast path | **REFINED → DEFERRED-EXPERIMENT** | R0 said "justified by CLS"; R1: mechanism CONTESTED externally (encoding-vs-consolidation confound, S007/S008; adversarial#2), schema detection is a new error-prone component, and consolidation lag is unmeasured. Reclassified EXPERIMENT with a precondition (measure lag first). Evidence level downgraded from implied-strong to RUNE_HYPOTHESIS. |
| Utility-prioritized consolidation | **REFINED** | R0 accepted Mattar-Daw transfer; R1: transfer to semantic consolidation UNPROVEN (adversarial#3), PER has documented fragilities (S038/S039), and Rune's own frequency signal was never validated. Reclassified: benchmark utility vs dedup+diversity baseline before any adoption; recency-only rejection itself downgraded to "benchmark it" (C010). |
| Retained covering episodes | **CONFIRMED (rationale replaced)** | Adversarial#4 FAILED to kill the conclusion but SUCCEEDED against the rationale: not reconsolidation — DRIFT CORRECTION (S049/S050). Evidence level upgraded: RUNE_APPLICABLE with software evidence, not biological analogy. |
| Shadow-mode provisional beliefs | **CONFIRMED as EXPERIMENT** | R0 hypothesis; R1 adds convergence (TiMem) + falsifiable kill criterion + leakage failure mode. |
| Reconsolidation → supersession mapping | **OVERTURNED** | R0 asserted the mapping; R1: pharmacological foundation contested (S018-020), trigger mismatch (write vs retrieval), and S029's latent-cause account explains the same data as ORDINARY belief-updating — the neuroscience framing adds nothing. Keep supersession; keep the prediction-error GATE atom; drop the framing. (Also corrected: Nader & Hardt are PRO-reconsolidation — R0's assumption was inverted.) |
| Independent-evidence corroboration gate | **CONFIRMED (evidence strengthened)** | R0 hypothesis; R1 adds: wash_count PROVEN unvalidated (T0.1), injection threat makes write-path validation distinct from dedup (S054), and the gate is implementable over existing provenance at zero schema cost. Still needs the retraction-rate experiment. |
| Destructive consolidation rejection | **CONFIRMED (upgraded)** | R0 rejected on principle; R1: drift/corruption is MEASURED in software (S049/S050/S052) — the strongest evidence in the entire domain, and it's engineering evidence, not analogy. |
| Recency-based consolidation rejection | **REFINED** | R0 rejected recency citing S012; R1: S038 shows freshness dominates in RL buffers — recency has documented value; the honest position is benchmark recency vs utility vs diversity, not dogma. |
| Evidence→episode→observation→belief→procedure progression | **REFINED** | Keep the stages as LABELS on one store (T0-proven fields); do NOT materialize separate stores per stage. Over-engineering guard from meta-review. |
| T1 impact = YES (three missing mechanisms) | **REFINED** | The three R0 mechanisms become: drift guards (ADOPT), independence gate (ADAPT), event-triggered consolidation (EXPERIMENT). Schema fast-path dropped from T1 scope to deferred-experiment. |
Tally: CONFIRMED 4 · REFINED 5 · OVERTURNED 1 · STILL_UNKNOWN 0 (all bounded into experiments).
Honest note: R0 was directionally right on every claim — but three of its rationale chains did not survive contact with the primary literature, and one mechanism (schema fast path) was prematurely promoted toward T1. That is exactly what R1 exists to catch.
@@ -0,0 +1,3 @@
# Sources Ledger (#376 R1)
Columns: source_id | title | authors | year | venue | DOI/arXiv/URL | peer-reviewed | primary/secondary | version | research question | mechanism | method | claims supported | claims contradicted | limitations | Rune relevance | confidence | read depth (ABSTRACT_ONLY/RELEVANT_SECTIONS/FULL_PAPER/CODE_AUDITED/REPLICATED)
@@ -0,0 +1,16 @@
# AA — Security / Memory Poisoning: R1 Domain Master
## #402
**Executive summary:** TMA-NM (2606.24322) is the design law — content- and lineage-based trust are both launderable; trust MUST be bound at write time from input channel, elevated only via human/Sybil-resistant processes. MemCollusion (2608.01637) proves per-record trust scoring is unsound — taint must propagate to derived records.
**Attack landscape:** AgentPoison (NeurIPS 2024, >80% ASR <0.1% poison rate); PoisonedRAG (USENIX 2025, 90% ASR from 5 texts in 1M corpus); InjecMEM (COLM 2026, single-interaction injection); MemCollusion/Salami (81.3% save rate, 75% ASR — kills individual-record defenses); MPBench (systematic taxonomy — aggressive agents more exploitable); eTAMP (environment-observation-only poisoning); Sleeper poisoning (60-89% action success, dormant).
**Defenses:** TMA-NM origin binding (provable, machine-checked); CaMeL 2503.18813 (control/data-flow separation — memory reads are untrusted data, never trigger state mutations); trust-aware retrieval with temporal decay (2601.05504 — but thresholds brittle); forensic trajectory detection (2606.30566 — AUC 0.99 but 25-53% benign FPR; warning against recall-signal auto-quarantine); GRAB-RAG — sufficiency-based confidence cannot substitute for source-based trust.
**Design invariants for Rune:** (1) channel-bound trust, never laundered by summarization; (2) elevation only via human review or Sybil-resistant corroboration; (3) taint propagation through derived memories; (4) time-bounded re-verification; (5) quarantine as visible state, not silent deletion.
**SQLite transfer (highest of all domains):** origin_channel, trust_level (write-time bound), taint set, quarantined_at, supersession/rollback rows.
**Classification:** ADOPT (TMA-NM origin binding, CaMeL data-flow separation, taint propagation, quarantine-as-state); EXPERIMENT (temporal decay trust, forensic trajectory detection); REJECT (per-record trust scoring, sufficiency-based abstention for security). Evidence: EXTERNALLY_ESTABLISHED.
**R0:** CONFIRMED 3 · REFINED 2 · OVERTURNED 0 · Sum = 5.
@@ -0,0 +1,14 @@
# AB — Multimodal / Artifact Memory: R1 Domain Master
## #403
**Executive summary:** Literature multimodal "memory" is never a second store — it is either a shared embedding space (Nomic Embed Vision 2406.18587 explicitly shares latent space with nomic-embed-text) or distilled artifacts (Voyager 2305.16291 code skills; Agent Workflow Memory 2409.07429 abstracted routines, +24.6%/+51.1% relative success). Screenshots in GUI agents are INPUT, not retained memory.
**Verdicts:**
- **ADOPT**: artifact memory as metadata (path, hash, MIME, mtime, provenance — ledger already does this)
- **ADAPT**: code-artifact distillations tied to outcomes (Voyager/AWM pattern)
- **REJECT**: storing screenshots/images as memory entries (zero payoff evidence for text-first agent, real token/storage cost)
- **FUTURE**: nomic-embed-vision into the EXISTING index (no second store) if a concrete "I saw that file/error before" retrieval failure appears — EXPERIMENT only then
**Evidence grades:** CLIP 2103.00020, Voyager, AWM, CogAgent = A (peer-reviewed); Nomic Embed Vision, OS-Copilot, surveys = B.
**R0 reconciliation:** CONFIRMED 2 · REFINED 1 · OVERTURNED 0 · Sum = 3.
@@ -0,0 +1,14 @@
# AC — Local / Offline Intelligence: R1 Domain Master
## #404
**Executive summary:** Nomic Embed (2402.01613, TMLR) achieves cloud-parity embeddings locally — Rune's local embedding is evidence-backed, not convenience. BUT: no A/B evidence exists that small local models match cloud on consolidation-style summarization — that gap is the crux.
**Verdicts:**
- **ADOPT**: local embedding (nomic-embed-text via Ollama — verified parity with Ada-002/emb-3-small on MTEB 2210.07316)
- **REJECT**: local LLM consolidation (summarize/merge/rewrite facts) with small models — silent quality loss, unmeasurable without ground truth
- **EXPERIMENT**: small local models for MECHANICAL ops only (dedup clustering, tag/title extraction, tool-call classification — MobileLLM 2402.14905 ICML 2024 covers exactly this class)
- **FUTURE**: quantized consolidation; revisit when an ≤8B A/B study on memory-consolidation quality exists
**Evidence:** QLoRA 4-bit NF4 preserves task performance (2305.14314, NeurIPS 2023); quantization degradation predictable not chaotic (2103.13630); layer-pruning headroom (2403.17887, ICLR 2025). Asymmetry doctrine: consolidation is a rare background op — cloud for judgment-heavy, local for mechanical.
**R0 reconciliation:** CONFIRMED 2 · REFINED 1 · OVERTURNED 0 · Sum = 3.
@@ -0,0 +1,14 @@
# AD — Hardware / Resource Placement: R1 Domain Master
## #405
**Executive summary:** "Memory-resident vs disk-backed" is VACUOUS below ~10^5 entries. All ANN-placement literature (HNSW 1603.09320 TPAMI 2018; DiskANN 2105.09613; SPANN 2111.08566 — both NeurIPS 2021) is calibrated at 10^6–10^9 points. vstash (2604.15484): vector+FTS5 hybrid in a single SQLite file at 20.9ms median latency at 50,000 chunks — 54× Rune's count.
**Rune arithmetic:** 924 × 768-dim float32 ≈ 2.7MB. Brute-force cosine is sub-millisecond. SQLite on NVMe + OS page cache = effectively memory-resident (sqlite.org/mmap.html); mmap optional copy-avoidance with documented failure modes.
**Verdicts:**
- **ADOPT**: whole-store memory-residency as a side effect (SQLite on NVMe + page cache; optional mmap_size)
- **REJECT**: DiskANN/SPANN-style disk-backed ANN (design point 10^9, not 10^3) and any dedicated vector database
- **REJECT**: Pi placement for memory operations — no model capacity, no measurable benefit; current split (PC: Gitea/CI/Ollama; Pi: TLS/backup) matches the doctrine that placement follows capability
- **FUTURE**: revisit only if the store crosses ~10^5 entries (vstash shows the SQLite stack holds well past that)
**R0 reconciliation:** CONFIRMED 1 · REFINED 2 · OVERTURNED 0 · Sum = 3.
@@ -0,0 +1,17 @@
# AE — Memory Evaluation / Benchmark Science: R1 Domain Master
## #406
**Executive summary:** R0's LoCoMo critique CORROBORATED (6.4% wrong answer key; ~63–64% judge wrong-accept — directional, via secondary reporting; full-context baseline ~73% J beats Mem0's best ~68% per Zep's released eval code). New failure mode beyond R0: scoring-target noninvariance (2605.24060) flips benchmark conclusions on 83–94% of shared LoCoMo/LongMemEval queries depending on which derived form gets retrieval credit.
**Minimal viable evaluation for a single-user store with no ground truth:**
1. Hand-curated ~50–100 question probe set over Rune's own history (abstention questions verifiable with zero ground truth) — LongMemEval 2410.10813 ICLR 2025 taxonomy: temporal, update, abstention
2. Ledger-derived end-task outcome metrics — τ-bench pattern (2406.12045): compare final DB state vs goal state; pass^k reliability
3. Hybrid-retrieval disagreement as continuous label-free health signal (vstash: 74.5% of queries produce top-10 disagreement between lexical and dense lanes)
**Verdicts:**
- **REJECT**: running LoCoMo/MemBench (wrong population: multi-persona synthetic chat, not coding traces; known scoring pathologies)
- **ADAPT**: LongMemEval question taxonomy; judge use only with FairEval position calibration (2305.17926: ordering alone flips 66/80 verdicts; MT-Bench 2306.05685: ~80% agreement with position/verbosity bias)
- **ADOPT**: the three-part minimal eval above
- **EXPERIMENT**: pass^k reliability across repeated sessions
**R0 reconciliation:** CONFIRMED 2 · REFINED 2 · OVERTURNED 0 · Sum = 4.
@@ -0,0 +1,68 @@
# #377 R1 — 00_issue_scope.md
## Core question
What distinctions and mechanisms established by human memory and cognitive-science
research are genuinely useful for Rune's Memory architecture, and which should be
rejected as biological detail, misleading metaphor, or human failure mode?
## Investigative scope (30 areas per mandate)
1. episodic memory; 2. semantic memory; 3. autobiographical memory;
4. prospective memory; 5. working memory; 6. procedural memory;
7. source memory; 8. familiarity vs recollection; 9. cue-dependent recall;
10. context-dependent recall; 11. temporal memory; 12. prospective
obligations/reminders; 13. encoding vs storage vs retrieval failure;
14. consolidation; 15. reconsolidation/update; 16. interference;
17. forgetting; 18. retrieval-induced forgetting; 19. spacing effects;
20. testing/retrieval-practice effects; 21. false memories;
22. misinformation effects; 23. source-monitoring errors;
24. confidence/metamemory boundaries; 25. salience/emotion (mechanics only);
26. memory transformation over time; 27. schema effects (delta only vs #376);
28. distortions from repeated summarization/reconstruction;
29. prospective cues and event-triggered remembering;
30. unavailable vs inaccessible vs forgotten vs overwritten.
## R0 hypotheses under re-evaluation (NOT accepted)
H1: prospective memory → typed obligation rows with trigger field.
H2: episodic vs semantic → entry-kind distinctions.
H3: autobiographical → session/task narrative records.
H4: source memory → mandatory origin fields.
H5: recollection/familiarity → exact/lexical vs semantic retrieval analogy.
H6: cue/context recall → task/session scoping.
H7: reconsolidation → supersession analogue (ALREADY OVERTURNED by #376 R1:
reconsolidation framing rejected; prediction-error-gated updating kept).
H8: spacing → reactivation-driven consolidation priority.
H9: confidence → evidence-linked rather than self-reported.
H10: RIF → reject imitation.
H11: false-memory research → anti-pattern/design constraint.
H12: source-monitoring errors → provenance requirement.
H7 incorporates #376's correction: the reconsolidation→supersession mapping
is dead. This tranche must not reintroduce it; the prediction-error-gate atom
survives independently (Sevenster/Beckers/Kindt 2014 via #376).
## Falsifiers
F1: If episodic/semantic/autobiographical are descriptive human taxonomies
rather than computationally distinct processes, Rune must not materialize
them as separate stores.
F2: If prospective-memory findings primarily concern biological attentional
limitations Rune does not share, they do not by themselves justify an
"obligation memory" subsystem.
F3: If familiarity/recollection evidence does not transfer cleanly to
lexical/vector retrieval, reject that analogy.
F4: If spacing/testing effects depend strongly on human neural learning
rather than information availability, do not use them as consolidation policy.
F5: If human forgetting mechanisms mostly exist because biology is
resource-limited in ways Rune is not, Rune should solve overload with
indexing, cooling and paging instead of imitating forgetting.
F6: If human metamemory confidence is systematically unreliable, do not map
human confidence mechanisms directly to Rune trust.
## Stopping criterion
Evidence saturation: new sources repeat known mechanisms/criticisms, add
only detail. No arbitrary paper-count target — but a few paragraphs and a
handful of citations are NOT sufficient for a foundational field.
@@ -0,0 +1,85 @@
# #377 R1 — 01_inward.md
## Current Rune mechanisms mapped to human-memory questions (evidence-first)
_Source: direct read-only inspection of memory.db (924 entries) + T0/T0.1
archaeology. Status vocabulary: PROVEN / IMPLEMENTED_UNPROVEN /
DESIGNED / DORMANT / ABSENT / BROKEN._
### Canonical entries and kinds
- kinds present: `fact` (729), `neuron` (195). NO episodic/semantic/
autobiographical/procedural/prospective kinds exist. Memory_type column
exists but R0 found only `associative` populated.
- Status: PROVEN (counts), but kind coverage is NARROW — H2 (entry-kind
distinctions) would be NEW schema, not a rename.
### Facts vs neurons
- Neurons (195) = warm-neuron activation rows with wash_count history;
facts (729) = durable content. 304 entries have wash_count>0.
- Status: PROVEN. Use-history exists but T0.1 found it unvalidated as
quality signal (superseded entries carry high wash counts).
### Retrieval lanes
- Dense: 420/924 entries have vectors (sqlite-vec, 256-d). FTS5/BM25:
560 rows. Hybrid recall dense+BM25+RRF+floor: PROVEN (T0).
- T0.1 R3: 439/838 active entries retrievable by NEITHER index.
- Recollection/familiarity analogy (H5) would map to exact/lexical vs
vector lanes — lanes exist (PROVEN), the ANALOGY is untested.
### Temporal fields
- valid_from non-null on all 924; valid_until on 56 (supersession-derived).
- Status: IMPLEMENTED_UNPROVEN for tri-timestamp semantics — fields exist,
retention policy and record-time query path unproven (T0 AS-IS).
### Provenance/source/method
- Columns: `source`, `method` (values: curator 679, dedupe_policy 165,
directive 34, migrate_blocks 22, warm_router 6, record 5). NO `origin`
column — R0's "mandatory origin field" (H4) is DESIGNED, not present.
- `derived_from` edge: ABSENT (#376 R1 finding).
- Confidence column exists (IMPLEMENTED_UNPROVEN — calibration unknown).
### Trust
- NO `trust_level` column — trust lifecycle (provisional/validated/locked)
lives in governance scripts, not as entry state. UNKNOWN state: ABSENT.
- H9 (evidence-linked confidence): DESIGNED.
### Supersession
- 56 superseded rows retained; valid_until set. PROVEN. Write-triggered
(not retrieval-triggered) — #376 R1 overturned the reconsolidation
mapping; prediction-error gate atom survives.
### Obligations/task systems
- No obligation entry kind. Task system (auto_tasks.db, 2 tasks) and
PendingOperation machinery exist SEPARATELY from Memory.
- H1 (obligation rows in Memory) would be NEW — the boundary question
(§10) is live: obligation-as-Memory vs Memory-as-evidence-for-tasks.
### Persona/relationship memory
- No dedicated persona/relationship kinds. Persona lives in constitution
files; relationship memory is implicit in facts.
- Status: ABSENT as memory kinds.
### Consolidation and failure learning
- Consolidation → knowledge.json: PROVEN to run; trigger non-deterministic
(agent-invoked; no cron — T0.1 R5).
- promotion_eligible flag exists; wash_count feeds it (unvalidated).
- knowledge.json: derived artifact, source-attributed.
### Warm Neurons
- 195 neuron rows; tier='warm' on ALL 924 rows = vestigial (T0.1 R4).
- Wash/use history PROVEN; activation ≠ truth doctrine stated but the
scoring (wash_count+importance) is frequency-only (NFU-like per #376/#385).
## Where R0 renamed software without proving transfer
1. "Episodic vs semantic → entry kinds": Rune has NO such kinds; calling
facts-vs-chronicles "episodic/semantic" would rename an ABSENT
distinction. Transfer must be EARNED, not asserted.
2. "Recollection/familiarity → exact/vector": lanes exist, but dual-process
theory adds nothing until a retrieval-routing decision cites it.
3. "Cue/context recall → task scoping": scoping exists (session/task keys);
Godden & Baddeley add no mechanism.
4. "Spacing → reactivation priority": wash_count already counts
reactivation; Cepeda adds nothing unless a spacing SCHEDULE is proposed.
5. "Prospective memory → obligation rows": the boundary question is
unresolved; R0 assumed the answer (Memory) without arguing against
task-system ownership.
@@ -0,0 +1,9 @@
# 02 — OUTWARD (populated by deep-research actor; verified by controller)
Files: taxonomy_of_memory.md, episodic_semantic_memory.md,
autobiographical_memory.md, prospective_memory.md, source_memory.md,
working_memory.md, procedural_memory.md, cue_context_retrieval.md,
temporal_memory.md, forgetting_interference.md, false_memory_source_errors.md,
spacing_testing_learning.md, consolidation_retrieval_update.md,
competing_models.md, criticisms_replication.md, software_transfer.md
+ sources.md (ledger) + claims.json (machine-readable).
@@ -0,0 +1,6 @@
# Autobiographical memory
Conway & Pleydell-Pearce (2000) SMS: generative construction yoked to identity goals. Adversarial #6 SUCCEEDS: this is the confabulation engine a truth-preserving store must NOT imitate (identity-flattering reconstruction, telescoping, goal-consistent distortion).
Rune use: session/task narratives exist (COVERED as chronicles); any "life-story synthesis" must be fenced from the evidence store and labeled generated. Take only a warning label.
@@ -0,0 +1,8 @@
# Competing models / disputes
- Systems vs processes: Foster & Jelicic 1999; Roediger/Buckner/McDermott 1999-style process critiques; Schacter & Tulving 1994. Psychologists' own failure to agree on system count = evidence software should not hard-code one taxonomy (adversarial #8).
- Unitary vs dual-process recognition: Wixted 2007 / Dunn 2004 / Wixted & Mickes 2010 vs Yonelinas 1994. Live dispute; software mapping built on it is sand.
- Working memory: Baddeley boxes vs Cowan activation vs Engle attention. Active contest.
- Inhibition vs interference (RIF mechanism); storage-loss vs retrieval-failure; reconstructive (Bartlett) vs trace views; modularity (Squire) vs distributed processing.
- Functional accounts: Nairne survival-processing; Henke 2010 processing-modes — dissolve store boundaries into processes/functions.
@@ -0,0 +1,6 @@
# Consolidation / retrieval / updating (delta vs #376)
No deep duplication of #376 CLS per mandate. #376 R1 already: overturned reconsolidation→supersession mapping; kept prediction-error-gated updating; confirmed retained covering episodes (rationale = drift correction); rejected destructive consolidation.
Human-memory additions from this tranche: Fuzzy Trace verbatim/gist opponent processes (Brainerd & Reyna) — store both, expect gist to outlive detail; Bartlett schema-assimilation across retellings — minimize re-encoding retrieved outputs; reconsolidation boundary conditions (Sevenster prediction-error gate, via #376) — update-on-violation, not on retrieval.
@@ -0,0 +1,9 @@
# Criticisms / replication / negative evidence
- RIF: small effect + publication bias (Murayama 2014); reliability weak (Potts 2012; Eur Psychologist 2011; Frontiers 2014); inhibition signature often fails (Camp 2007).
- Misinformation boundaries: McCloskey & Zaragoza 1985; recent high-powered boundary work.
- Godden & Baddeley 1975: N=18, small-N legacy; Smith & Vela 2001: small/fragile overall.
- DRM ecological validity (Pezdek & Lam 2007); Shaw & Porter 2015 rate disputes.
- WEIRD populations; lab-vs-naturalistic prospective-memory gaps; measurement confounds (remember/know, ROC procedures).
- Consolidation-hallucination links contested/mixed (Darsaud; Calvillo 2016).
@@ -0,0 +1,12 @@
# Retrieval: cues, context, recognition
**Encoding specificity: Tulving & Thomson (1973), Psych Review 80(5) (~4690 cites).** Retrieval succeeds to the degree cues reinstate encoding conditions. ROBUST principle, boundaries debated. Bearing: store encoding context alongside content; match on cues present at write.
**Availability vs accessibility: Tulving & Pearlstone (1966, JVLVB).** Unrecallable-under-one-cue items become available under another — failure is often accessibility, not erasure. ROBUST; designated THE key distinction. Bearing: default to retrieval-failure hypothesis before deletion; forgetting policy gates on demonstrated inaccessibility across cues, never single failed recall.
**Context-dependence: Godden & Baddeley (1975, BJP 66:325-331)** — divers, N=18, WEAK-evidence legacy. **Smith & Vela (2001)** synthesis: overall effect small/fragile; reinstatement helps mainly with impoverished cues. CONTESTED/small-effect. State-dependence similarly fragile. Bearing: context tags help; expect small gains; never rely on context match alone.
**Recognition vs recall; recollection vs familiarity:** Yonelinas (1994) dual-process vs Wixted unitary-strength (2007; Wixted & Mickes 2010). CONTESTED — both fit much data; measurement confounds. Adversarial #4 SUCCEEDS: do not reify two hardware systems; keep two retrieval GRADES (detail-bearing vs bare signal) as outputs; track confidence separately. Bearing: the lexical/vector mapping inherits a live dispute — justify hybrid retrieval by IR engineering only.
**Retrieval competition, temporal order, partial cues:** cue-overload competition ROBUST; temporal-order memory error-prone/reconstructive; partial cues help only when encoding-compatible (encoding-specificity corollary).
@@ -0,0 +1,6 @@
# Episodic / semantic memory
See taxonomy (Tulving 1972/1985/2002). Status: ROBUST descriptive; CONTESTED as strict neural systems (adversarial #1: Henke 2010 processing-modes; systems-vs-processes debate; Vargha-Khadem 1997 amnesic dissociations preserve a weak distinction).
Bearing for Rune: strongest candidate for two store-types (event records with source/context vs distilled durable claims) — but as QUERY-TIME TAGS, never schema partition (adversarial verdict). F1 falsifier stands: descriptive taxonomy ≠ computational process split.
@@ -0,0 +1,18 @@
# False memory / source errors
**DRM: Roediger & McDermott (1995, JEP:LMC 21(4):803-814; Deese 1959).** Lure recalled ~40-55%, recognized at studied-item rates, ~72% "remember" judgments. ROBUST, heavily replicated; ecological-validity critiques (Pezdek & Lam 2007). Bearing: associative retrieval generates confident false positives — penalize gist-only matches lacking verbatim support.
**Fuzzy Trace Theory: Brainerd & Reyna (2002, Curr Dir Psych Sci 11(5):164-169; 2005 OUP book).** Parallel verbatim (decays fast) + gist (persists) traces; false memory = gist-supported + verbatim-unsuppressed; signature predictions: delay increases false memory while true decays; developmental reversal (older show MORE DRM false memory). ROBUST alternative to unitary-trace views. Bearing: store BOTH verbatim detail and gist; expect gist to outlive detail; gist-vs-verbatim contradiction should trigger verification, not averaging.
**Reconstruction: Bartlett (1932, Remembering).** Repeated reproduction rationalizes toward schemas. Foundational; direct replication difficult (Bergman & Roediger 1999 partial), schema-consistent distortion ROBUST via successors. Bearing: each retrieval-rewrite cycle risks schema assimilation — minimize re-encoding retrieved outputs as new entries without provenance.
**Rich false memories: Shaw & Porter (2015, Psych Sci 26:291-301)** — whole-event implantation possible with suggestive pressure (~70%, coding-dependent). CONTESTED rates, ROBUST possibility.
**Misinformation: Loftus & Palmer (1974, JVLVB 13(5):585-589); Loftus, Miller & Burns (1978).** Post-event narrative blends with/overwrites original; grows with delay, lowers with discrepancy detection. ROBUST core; CONTESTED mechanism (McCloskey & Zaragoza 1985: modified tests reduce apparent impairment). Bearing: post-event inputs (corrections, restatements, tool outputs) can corrupt originals — keep original vs amendment separated with source tags.
**Confidence-accuracy: Wixted & Wells (2017) eyewitness family; Koriat metamemory.** Confidence malleable (feedback, repetition), often miscalibrated. ROBUST dissociation. Bearing: never confidence-as-accuracy-proxy; track calibration separately.
**Cryptomnesia/reality monitoring/false fame (Jacoby et al. 1989, JPSP):** ROBUST demonstrations of origin confusion. Bearing: generation events labeled self-generated at write time.
All converge on: append-only + supersession-linking beats destructive consolidation (adversarial #10 FAILED as attack — Maynez 2020 + SSGM 2026 corroborate).
@@ -0,0 +1,8 @@
# Forgetting / interference
Interference (proactive/retroactive) ROBUST since Underwood/McGeoch; pure trace-decay WEAK as sole account — most forgetting = cue-dependent inaccessibility + competition. Directed forgetting ROBUST as control phenomenon. Adaptive/intentional forgetting (Anderson & Hanslmayr) CONTESTED as unified mechanism.
**RIF: Anderson, Bjork & Bjork (1994, JEP:LMC 20(5):1063-1087).** ~10-13% effect; inhibition account. Status CONTESTED — real but fragile: Murayama et al. (2014, Psych Bulletin) meta-analysis small effect + publication bias; Raaijmakers/Verde interference alternatives; Potts et al. (2012) reliability weak; cue-independence (inhibition signature) often fails (Camp et al. 2007).
Bearing: do NOT implement inhibition-as-deletion — retrieval practice suppressing neighbors is exactly what a memory system must avoid; treat RIF as hazard (retrieval narrows access), not feature. Adversarial #7 SUCCEEDS: keep tiered storage; ban "forgetting" vocabulary; the one transferable rule = never delete, only de-index (availability vs accessibility).
@@ -0,0 +1,4 @@
# Procedural memory
Squire declarative/nondeclarative split (ROBUST coarse). "How I do X" ≠ "what happened" — supports separating procedure traces from statable entries. NOT_RELEVANT as memory-store mechanism (skill runtime concern); relevant as taxonomy boundary.
@@ -0,0 +1,12 @@
# Prospective memory
**Einstein & McDaniel (1990, JEP:LMC 16:717-726).** Event vs time-based; external event cues beat self-initiated time monitoring; age deficits larger for time tasks. **Sellen et al. (1997, Memory 4:483-507)** in-situ confirmation. ROBUST.
**Monitoring costs — PAM vs multiprocess:** Smith (2003) PAM (capacity-consuming preparatory monitoring; ongoing-task slowing) vs McDaniel & Einstein (2000 Applied Cog Psych; 2005) multiprocess (monitoring + spontaneous retrieval; salient/focal cues pop without cost); Reese & Cherry (2002) against constant monitoring (~2% reported thinking of intention). CONTESTED coexistence; pure-PAM rejected for mundane tasks.
**Interruption/resumption: Altmann & Trafton (2002)** goal-activation model: interruptions decay activation; resumption lag grows with length; reminders restore. **McDaniel et al. (2004, Applied Cog Psych 18:533-547):** delays degrade performance; external reminders eliminate interruption cost. ROBUST practical findings.
**Implementation intentions: Gollwitzer (1999, American Psychologist 54:493-503).** If-then plans substantially raise follow-through. ROBUST, large literature.
Bearing: prefer event-anchored triggers over pure time; time intentions need external scaffolding; support both spontaneous firing (salient cues) AND costly watch (non-focal); store intentions as cue→action pairs with explicit triggers + reminder scaffolding. BUT adversarial #2 (Risko & Gilbert 2016 offloading) says obligations belong OUTSIDE memory in a commitment authority — the obligation-entry-kind question is NOT settled by this literature (see 03_applicability).
@@ -0,0 +1,4 @@
# Software transfer (placeholder — full chain in 03_applicability)
Transfer rule: HUMAN FINDING → GENERAL COMPUTATIONAL PRINCIPLE → SOFTWARE ANALOGUE → RUNE APPLICABILITY → RUNE PRESCRIPTION. If one arrow cannot be justified, stop the chain. Full treatment in 03_applicability.md; key results: availability/accessibility → retrieval-failure-before-deletion policy; encoding specificity → store encoding context; Fuzzy Trace verbatim/gist → dual representation with verification on conflict; offloading literature → obligations OUTSIDE memory; testing effect → reactivation-as-durability (not ranking).
@@ -0,0 +1,6 @@
# Source memory / monitoring
**Johnson, Hashtroudi & Lindsay (1993, Psych Bulletin 114(1):3-28).** Source attributions = decisions over features (perceptual, contextual, affective, cognitive-operations records), heuristic (fast) vs systematic (slow) judgments. External/internal/reality monitoring types. ROBUST/influential framework.
Bearing: every entry needs source features recorded at write; source judgments at READ are fallible decisions — provenance must be stored, not inferred. Adversarial #3: mechanism analogy backwards (Rune already has columns), but Johnson's cue inventory is a useful schema checklist; errors spike under similarity/time-pressure → predicts when retrieval needs provenance-weighted ranking.
@@ -0,0 +1,8 @@
# Spacing / testing / reactivation
**Spacing: Cepeda et al. (2006, Psych Bulletin 132(3):354-380).** 839 assessments: spaced > massed in 259/271. Lag effects (Glenberg; Kahana); Bahrick et al. (1993) 9-year retention (56-day gaps optimal there). ROBUST — among psychology's most replicated. Mechanism accounts (encoding variability, study-phase retrieval, deficient processing) CONTESTED; multifactor prevails.
**Testing: Roediger & Karpicke (2006, Psych Sci 17(3):249-255); Karpicke & Roediger (2008, Science 319:966-968).** Repeated testing beats restudying on delayed retention; Butler (2010) superior transfer. Dunlosky et al. (2013) rates practice testing + distributed practice highest-utility. ROBUST. **Desirable difficulties: Bjork (1994) family** — effortful retrieval aids retention.
Bearing (adversarial #5 verdict): re-exposure scheduling is the one human effect safe to import as POLICY — but frequency ≠ spacing; the wash_count question resolves toward SPACED re-presentation, not raw repetition count. Allow reactivation into retention/tiering decisions; FORBID (or heavily discount) in relevance ranking. Spacing is acquisition-side; ranking is a separate judgment.
@@ -0,0 +1,10 @@
# Taxonomy of memory (human literature)
**Tulving (1972)** episodic vs semantic (Organization of Memory; K.C. amnesic dissociations). Later: Tulving 1985 autonoetic/noetic; Tulving 2002 mental time travel. Status: ROBUST as descriptive distinction; CONTESTED as strict neural-systems claim.
**Squire (1992 Psych Review; Squire & Zola 1996 PNAS).** Declarative (hippocampal-dependent) vs nondeclarative (skills/habits/priming). ROBUST at coarse grain. Bearing: separate skill/procedure traces from statable entries.
**Conway & Pleydell-Pearce (2000, Psych Review 107(2):261-275).** Self-Memory System: autobiographical memory hierarchical (lifetime periods → general events → event-specific knowledge), reconstructed under working-self control; generative, not replay. ROBUST/influential. Bearing: warns against treating recalled episodes as verbatim logs.
**Baddeley & Hitch (1974); Baddeley (2000, TiCS 4(11), episodic buffer).** Dual-task interference basis. ROBUST framework, revised often. Competitor: **Cowan (1999)** embedded-processes (activated LTM + ~4-chunk focus); Engle executive-attention third pole. Active CONTEST. Bearing: do NOT hard-imitate slot buffers; transferable = capacity-limited active set + executive control (~4-chunk focus).
@@ -0,0 +1,4 @@
# Temporal memory
Tri-timestamps already adopted from Graphiti (prior closure; COVERED). This literature adds: temporal-order memory is reconstructive and error-prone — "as-of" queries must trust stored timestamps, never reconstructed order. No new mechanism beyond prior closure; cross-reference #376-adjacent schema work minimally per mandate (no deep duplication).
@@ -0,0 +1,4 @@
# Working memory
Baddeley & Hitch 1974 / Baddeley 2000 (above) vs Cowan 1999 vs Engle. Active contest; do not hard-imitate boxes. Transferable: capacity-limited active set + executive control. NOT_RELEVANT as store concern (context window / skill runtime).
@@ -0,0 +1,109 @@
# #377 R1 — 03_applicability.md
_For every surviving mechanism: the 19 applicability questions + the transfer
chain HUMAN FINDING → GENERAL PRINCIPLE → SOFTWARE ANALOGUE → RUNE
APPLICABILITY → RUNE PRESCRIPTION. Chain breaks are recorded, not smoothed._
## T1. Availability/accessibility distinction (Tulving & Pearlstone 1966)
- Human finding: unrecallable-under-one-cue items become available under
another — failure is often accessibility, not erasure.
- Principle: retrieval failure ≠ storage loss.
- Analogue: multi-cue retrieval + deletion gated on demonstrated
inaccessibility across cues.
- Rune: PROVEN problem (439/838 active entries unindexed — but those are
AVAILABILITY failures, worse). Prescription: default to retrieval-failure
hypothesis; forgetting/deletion policy requires demonstrated
inaccessibility across cues, never single failed recall.
- Owner: retrieval layer + deletion policy. LLM: none. Offline: yes.
Century: yes. Cheapest: deletion-gate rule. EXTERNALLY_ESTABLISHED → RUNE_APPLICABLE.
## T2. Encoding specificity (Tulving & Thomson 1973)
- Finding: retrieval succeeds to the degree cues reinstate encoding conditions.
- Principle: store the conditions, not just the content.
- Analogue: encoding-context metadata on entries (session/task/partition keys
already exist; extend to query-relevant cue fields).
- Rune: PARTIALLY solved (scoping exists). Prescription: extend stored context
fields; retrieval matches on write-present cues. Owner: retrieval layer.
## T3. Fuzzy Trace verbatim/gist (Brainerd & Reyna 2002/2005)
- Finding: parallel traces; gist persists, verbatim decays; false memory is
gist-supported + verbatim-unsuppressed.
- Principle: keep both representations; contradiction between them triggers
verification, not averaging.
- Analogue: store exact source text + distilled gist side by side (Rune
already stores text; gist = summary field).
- Rune prescription: verbatim/gist dual representation with
conflict-triggered verification. Owner: Memory. Cheap: schema fields.
EXTERNALLY_ESTABLISHED → RUNE_APPLICABLE. (Chain holds end to end.)
## T4. Source-monitoring cue inventory (Johnson 1993) — schema only
- Per adversarial #3: mechanism backwards, inventory useful. Prescription:
ensure origin/source/method/verbatim-detail/operation-record fields exist
(partially present; origin column ABSENT → add). Owner: Memory schema.
## T5. Prospective cues → task authority, NOT memory (adversarial #2 wins)
- Human finding: event cues beat time monitoring; monitoring costs are real;
implementation intentions (cue→action pairs) work.
- Principle: intentions need triggers + scaffolding.
- Analogue: commitment state machine with trigger conditions.
- Rune applicability: the OWNER is the task/commitment authority, NOT Memory
(Risko & Gilbert 2016 offloading: externalize intentions). R0's H1
(obligation rows IN Memory) is OVERTURNED as stated.
- Prescription: obligations live in task system with open/kept/broken states;
Memory holds evidence ABOUT commitments. Event-triggered remembering reuses
PendingOperation machinery where applicable. Owner: task system.
EXTERNALLY_ESTABLISHED → RUNE_APPLICABLE (with corrected owner).
## T6. Testing effect → durability signal only (adversarial #5 verdict)
- Finding: retrieval strengthens the trace (Roediger & Karpicke 2006).
- Principle: reactivation = durability event.
- Analogue: reactivation count feeds retention/tiering.
- Rune: allowed into retention decisions; FORBIDDEN in relevance ranking
(category jump: learning schedule ≠ relevance score; rich-get-richer).
- Owner: retention policy. Cheap: spaced-reactivation counter distinct from
wash_count.
## T7. Misinformation/DRM → anti-pattern constraints
- Findings: post-event blending (Loftus), gist false positives (DRM 40-55%
recall, 72% "remember"), schema assimilation across retellings (Bartlett).
- Principle: every transformation is a corruption opportunity.
- Analogues: consolidate from immutable sources only; original-vs-amendment
separation; penalize gist-only retrieval matches; minimize re-encoding
retrieved outputs.
- Rune: largely COVERED (append-only, supersession); ADD: gist-match penalty
in retrieval scoring; re-encoding guard. Owner: Memory + retrieval.
## T8. RIF → hazard, never feature
- Finding: retrieval practice suppresses competitors (~10-13%, fragile).
- Rune: retrieval must not narrow access to neighbors. Prescription: no
inhibition mechanism; monitor for retrieval-narrowing as a bug class.
- Owner: retrieval layer. REJECT imitation (adversarial #7 supports).
## T9. Confidence-accuracy dissociation → calibration discipline
- Finding: confidence malleable, miscalibrated (Wixted & Wells; Koriat).
- Principle: never confidence-as-accuracy.
- Analogue: evidence-linked confidence + separate calibration tracking.
- Rune: confidence column exists (IMPLEMENTED_UNPROVEN). Prescription:
calibration tracked per source/kind; self-reported confidence distrusted.
- Owner: Memory schema + governance.
## T10. Context-dependence → small-gain tags (expectations capped)
- Finding: real but small/fragile (Smith & Vela 2001); N=18 legacy.
- Prescription: keep context tags; never rely on context match alone;
measure gains before investing. Owner: retrieval.
## T11. Recognition grades without dual-process ontology
- Per adversarial #4: keep two retrieval outputs (detail-bearing vs bare
signal) + separate confidence; do NOT cite Yonelinas as architecture.
- Owner: retrieval layer. Justification: IR engineering (child H), not
psychology.
## T12. Autobiographical generativity → fence + label
- Finding: SMS construction yoked to identity goals (Conway 2000).
- Prescription: any life-story synthesis fenced from evidence store,
labeled generated. Owner: Persona/presentation layer, never canonical Memory.
## Authority assignments (Q19)
Memory owns: T1, T2, T3, T4, T6, T7, T8, T9, T10, T11. Task system owns: T5.
Persona/presentation owns: T12. Retrieval layer implements: T1, T2, T8, T10, T11.
No mechanism here belongs to Substrate, World Model, or Spine.
@@ -0,0 +1,57 @@
# #377 R1 — 04_innovation.md
_Falsifiable integration hypotheses only. Each: prior art, difference,
advantage, cost, failure mode, benchmark, kill criterion._
## I1. Availability-gated deletion (prior art: HSM tiering policies)
- Difference: deletion requires demonstrated inaccessibility across N
independent cue sets + time window, not age or single failed recall.
- Advantage: eliminates the worst deletion class (available-but-inaccessible).
- Cost: bookkeeping per deletion candidate. Failure: gate too strict →
unbounded growth (mitigate: tiering absorbs).
- Benchmark: zero wrongful deletions on synthetic available-but-inaccessible
probes. Kill: gate never fires in 6 months → simplify.
## I2. Verbatim/gist dual entries with conflict verification (prior art:
Fuzzy Trace Theory; Rune text+summary fields)
- Difference: explicit conflict detector — when gist contradicts verbatim
detail, verification fires instead of averaging.
- Advantage: catches consolidation drift at the representation level.
- Cost: dual storage + detector. Failure: detector false positives annoy.
- Benchmark: drift-detection rate on synthetic gist/verbatim conflicts.
- Kill: no conflicts detected in production over 6 months → keep schema,
drop detector.
## I3. Spaced-reactivation durability counter (prior art: Cepeda spacing;
Anki/SRS scheduling)
- Difference: separates durability counting (spaced re-presentations) from
relevance ranking (topical fit) — two counters, two consumers.
- Advantage: resolves the wash_count conflation T0.1 exposed.
- Cost: one new counter + scheduler. Failure: scheduler complexity.
- Benchmark: retention prediction accuracy vs wash_count.
- Kill: no retention-prediction gain → drop.
## I4. Gist-match penalty in retrieval (prior art: DRM literature; child H
reranking)
- Difference: retrieval scores down-weight matches supported only by
gist-level similarity without verbatim support, for factual queries.
- Advantage: directly attacks the 40-55% DRM-style false-positive class.
- Cost: scoring change. Failure: over-penalization hurts paraphrase recall
(tune on paraphrase-vs-lure test set).
- Benchmark: lure-rejection rate vs paraphrase-recall rate.
- Kill: paraphrase recall drops >5% → revert.
## I5. Commitment-evidence linking (prior art: GTD trusted-system concept;
Rune PendingOperation)
- Difference: task-system commitments carry memory-evidence pointers
(supporting entries), and memory entries ABOUT commitments link back —
bidirectional without co-location (respects adversarial #2's ownership
verdict).
- Advantage: obligations auditable against evidence without living in Memory.
- Cost: link maintenance. Failure: stale links.
- Benchmark: commitment audit completeness on synthetic set.
- Kill: links unused in 6 months → drop.
No manufactured novelty: I1 = HSM policy + Tulving distinction; I2 = FTT
applied to schema; I3 = SRS practice applied to counters; I4 = DRM
literature applied to scoring; I5 = GTD + existing Rune machinery.
@@ -0,0 +1,135 @@
# #377 R1 — 05_adversarial.md
_Independent pass (separate actor/context). Instruction: assume the emerging
human-memory → Rune conclusions are wrong. Verdicts: ATTACK SUCCEEDS / MIXED /
ATTACK FAILED. ✅ = tool-verified citations; ⚠️ = canonical references._
## 1. Episodic/semantic store separation — MIXED, leans SUCCEEDS
**Henke (2010, Nat Rev Neurosci)** ✅ — processing-modes (rapid-flexible vs
slow-rigid encoding) should replace the consciousness-based declarative split.
If right, an episodic/semantic table split reifies the wrong ontology: the
joint is at processing mode, not phenomenology. Backing: systems-vs-processes
debate (⚠️ Foster & Jelicic 1999; ⚠️ Roediger/Buckner/McDermott 1999-style
process critiques); ⚠️ Cabeza et al. 2008 (parietal = attention-to-memory, not
episodic module); ⚠️ Nairne/Thompson/Pandeirada 2007 (survival-processing
functional account). Patient dissociations (⚠️ Vargha-Khadem 1997, Science:
developmental amnesia sparing semantic learning) keep the distinction alive —
demoted to "one contested taxonomy," not neural fact.
**Software verdict: query-time tag, never schema partition.**
## 2. Obligation-as-memory — ATTACK SUCCEEDS (strongest in brief)
**Risko & Gilbert (2016, Trends Cogn Sci)** ✅ — cognitive offloading: agents
perform better EXTERNALIZING intentions than retaining them; intention-offloading
literature shows people set external triggers precisely because internal
prospective memory is unreliable. ⚠️ Allen (2001, GTD): "mind like water" via
capture into a trusted EXTERNAL system. Hostile inference: obligations are the
canonical case where science says DO NOT store as memory traces — they belong
in a commitment/task authority with state machines (open/kept/broken/
superseded), deadlines, reminders; memory holds only evidence ABOUT the
commitment. Putting obligations inside the memory store repeats the exact error
the offloading literature diagnoses.
**Verdict: obligations live outside Memory.**
## 3. Source-memory analogies — MIXED, leans FAILED
⚠️ Johnson/Hashtroudi/Lindsay 1993 (source-monitoring framework); ⚠️ Johnson &
Raye 1981 (reality monitoring): a brain doing forensic reconstruction from
impoverished cues because it has NO provenance bus. Rune already has
source/method columns — importing "source-monitoring processes" brings a candle
to a lit room. Honest admission: Johnson's diagnostic cue inventory (verbatim
detail, operation records, affective tags, contextual embedding) is a useful
SCHEMA checklist, and source errors spiking under similarity/time-pressure
predicts when retrieval needs provenance-weighted ranking.
**Verdict: analogy backwards as mechanism, useful as schema checklist.
Downgrade "implement source monitoring" → "store what source monitoring
wishes it had."**
## 4. Recollection/familiarity → lexical/vector mapping — ATTACK SUCCEEDS
Three verified kill-shots: **Wixted (2007, Psych Review)** ✅ — unitary
unequal-variance signal-detection model fits the ROC data dual-process
theorists claimed exclusively. **Dunn (2004, Psych Review)** ✅ —
remember/know dissociations fall out of unidimensional strength + decision
criteria. **Wixted & Mickes (2010, Psych Review)** ✅ — "continuous
dual-process" concedes recollection is graded, collapsing the categorical
joint the mapping leans on. (⚠️ Rotello et al. 2005 same point via
process-dissociation critiques.) Mapping BM25→familiarity/vectors→recollection
inherits a live dispute as settled architecture.
**Verdict: keep hybrid retrieval (it works), justify by IR engineering, never
by dual-process psychology. The mapping adds zero architectural force.**
## 5. Spacing/reactivation → activation scoring — MIXED, leans SUCCEEDS
⚠️ Cepeda et al. 2006 (Psych Bulletin): spacing framed as ACQUISITION/encoding
phenomenon (optimal inter-study intervals as function of retention interval).
Nothing licenses "reactivated often → rank higher at retrieval" — a category
jump from learning schedule to relevance score, smuggling frequency-past-use
into relevance where it swamps topical fit (rich-get-richer). Admission:
⚠️ Roediger & Karpicke 2006 (testing effect) proves retrieval IS an encoding
event — reactivation genuinely strengthens the trace.
**Verdict: reactivation allowed into retention/tiering decisions, FORBIDDEN
(or heavily discounted) in relevance ranking.**
## 6. Autobiographical-memory requirements — ATTACK SUCCEEDS
**Conway & Pleydell-Pearce (2000, Psych Review)** ✅ — autobiographical recall
is GENERATIVE CONSTRUCTION yoked to the "working self" and identity goals, not
playback. ⚠️ Conway 2005: coherence with self-goals constrains construction.
That is precisely the confabulation engine a truth-preserving store must NOT
imitate — importing SMS requirements invites identity-flattering
reconstruction, telescoping, goal-consistent distortion dressed as "rich
autobiographical context."
**Verdict: dangerous as design input. Take only a warning label: any
"life-story synthesis" feature must be fenced off from the evidence store and
labeled generated.**
## 7. Human forgetting → software cooling — ATTACK SUCCEEDS (one caveat)
Storage engineering solved tiering decades ago without psychology (HSM,
LRU/LFU/ARC, buffer pools — hit-rate math, no Ebbinghaus). "Cooling" that
merely demotes priority is eviction policy with a cardigan; calling it
"forgetting" licenses the one thing a single-user truth store must never do —
silent data loss — while adding no mechanism (no decay constant transfers to
SQLite rows). Caveat: the availability-vs-accessibility distinction maps to a
sound rule — never delete, only de-index.
**Verdict: keep tiered storage; ban the word "forgetting" from the codebase
vocabulary. The metaphor's expected value is negative.**
## 8. Cognitive-science terminology adds architecture — ATTACK SUCCEEDS
The field's own meta-literature: systems-vs-processes controversy plus "how
many systems?" stalemates (⚠️ Schacter & Tulving 1994; ⚠️ Foster & Jelicic
1999) — labels proliferating while predictions stay put. Adopting "episodic /
semantic / procedural / source / familiarity" imports five contested ontologies
and zero ranking functions, loss functions, or invariants.
**Gate: every borrowed noun must answer — what query does it change, what
invariant does it enforce, what test would falsify it? Failing that gate =
documentation perfume. Terminology guilty until proven mechanistic.**
## 9. Bonus: computer memory should NOT imitate humans — MIXED
⚠️ Schacter 1999 (American Psychologist: "seven sins") — a spec sheet for what
NOT to build. ⚠️ Norman 1986/1988 (gulfs of execution/evaluation) — bridge
limits with external structure, don't mirror them. Database/IR orthodoxy never
cites Atkinson–Shiffrin: durability, transactions, recall metrics come from
engineering. Admission: nobody wants to imitate FALLIBILITY — borrowings are
functional (separate concerns, provenance, tiering); biomimetic inspiration
constrained by benchmarks is legitimate.
**Verdict: "human memory is a terrible database" is true and worth posting on
the wall — kills naive imitation, not disciplined functional borrowing.**
## 10. Bonus: consolidation-hallucination — ATTACK FAILED
Backfired into corroboration. **Maynez et al. 2020 (ACL)** ✅ — widespread
hallucination in abstractive summarizers, direct analog of lossy LLM
consolidation rounds. **SSGM (2026 preprint)** ✅ — semantic drift across
evolving LLM memory updates as governed risk. Both support the FALSE-memory-
as-anti-pattern stance: each summarization round is a misinformation
opportunity; append-only + supersession-linking beats destructive
consolidation.
**Verdict: evidence sides with the main researcher.**
## Failed-attack rollup
- #3 partially failed: Johnson's cue inventory informs schema.
- #5 partially failed: testing effect legitimizes reactivation as durability
signal (not ranking signal).
- #9 partially failed: kills naive mimicry only.
- #10 fully failed: Maynez 2020 + SSGM 2026 corroborate append-only/supersede.
- #1 partially failed: amnesic dissociations preserve weak tag-level
episodic/semantic distinction.
Strongest clean kills: #2 (obligations out of memory), #4 (dual-process
mapping built on sand), #6 (autobiographical confabulation engine),
#7 (forgetting vocabulary), #8 (terminology without mechanism).
@@ -0,0 +1,44 @@
# #377 R1 — 06_synthesis.md
## Mechanism matrix
| MECHANISM | ORIGINAL PURPOSE | EVIDENCE STRENGTH | LIMITATIONS | RUNE EQUIVALENT | RUNE GAP | TRANSFER VALIDITY | COST | FAILURE MODES | CLASSIFICATION | RUNE EVIDENCE LEVEL |
|---|---|---|---|---|---|---|---|---|---|---|
| Episodic/semantic distinction | describe human memory kinds | STRONG descriptive; CONTESTED neural | Henke processing-modes; systems-vs-processes stalemate | none (no such kinds) | — | LOW as stores; MEDIUM as tags | none | reified wrong ontology | query-time TAGS, never schema partition | RUNE_HYPOTHESIS |
| Availability/accessibility | explain recall failure | STRONG (Tulving & Pearlstone) | — | none (no deletion gate) | deletion-gate rule | HIGH | bookkeeping | gate too strict | ADAPT | RUNE_APPLICABLE |
| Encoding specificity | explain cue effects | STRONG + boundaries | — | session/task scoping (partial) | cue-field extension | HIGH | schema fields | over-tagging | ADAPT | RUNE_APPLICABLE |
| Fuzzy Trace verbatim/gist | explain false memory + development | STRONG (developmental predictions confirmed) | — | text+summary (implicit) | conflict verification | HIGH | detector | false positives | ADAPT | RUNE_APPLICABLE |
| Source-monitoring inventory | explain source errors | STRONG framework | mechanism backwards for Rune | source/method cols (partial; origin ABSENT) | origin column | MEDIUM (schema only) | one column | omission under pressure | ADAPT (schema) | RUNE_APPLICABLE |
| Prospective cues | explain remembering-to-act | STRONG (event>time; monitoring costs; implementation intentions) | lab-vs-naturalistic gaps | task system + PendingOperation (separate) | commitment-evidence links | HIGH (with corrected owner) | links | stale links | task-system ADAPT; REJECT memory co-location | RUNE_APPLICABLE |
| Testing effect | explain retention | STRONG | acquisition-side only | wash_count (conflated) | spaced-durability counter | MEDIUM (durability only) | counter | scheduler complexity | ADAPT (durability); REJECT (ranking) | RUNE_HYPOTHESIS |
| Spacing | optimize learning schedules | STRONGEST in psychology | encoding-side; no ranking license | none | re-presentation policy | MEDIUM | scheduler | — | EXPERIMENT | RUNE_HYPOTHESIS |
| DRM/gist hazards | explain false recall | STRONG | word-list ecology | dedupe/supersede (partial) | gist-match penalty | HIGH | scoring change | paraphrase harm | ADAPT | RUNE_APPLICABLE |
| Misinformation blending | explain post-event corruption | STRONG core; mechanism contested | — | append-only + supersession | re-encoding guard | HIGH | guard | friction | ADAPT | RUNE_APPLICABLE |
| RIF | explain forgetting-after-retrieval | FRAGILE (small + bias) | inhibition contested; reliability weak | none (good) | monitoring as bug class | LOW (as mechanism) | none | implementing it | REJECT imitation | EXTERNALLY_ESTABLISHED (fragility) |
| Dual-process recognition | explain recognition ROCs | CONTESTED (Wixted/Dunn kill-shots) | — | hybrid lanes (exist) | nothing | NONE (mapping dead) | — | sand architecture | REJECT mapping; keep lanes on IR grounds | — |
| Autobiographical generativity | explain self-memory | STRONG (as description of construction) | — | narratives (exist) | fence + label | HIGH (as warning) | fence | confabulation leak | REJECT as design input | RUNE_APPLICABLE (warning) |
| Forgetting-as-deletion | explain loss | WEAK as sole account | — | tier flags (vestigial) | tiering without the word | HIGH (tiering) / NONE (word) | vocabulary change | silent loss license | REJECT word; ADAPT tiering | RUNE_APPLICABLE |
| Confidence-accuracy link | predict accuracy from confidence | DISSOCIATED (robust) | — | confidence col (unproven) | calibration tracking | HIGH (as discipline) | tracking | decoration | ADAPT | RUNE_APPLICABLE |
| Reconsolidation mapping | update-on-retrieval | CONTESTED (per #376) | trigger mismatch | supersession (write-triggered) | prediction-error gate | LOW (framing dead) | none | dogma | REJECT (per #376; not reintroduced) | — |
## Synthesis narrative
Human memory science gives Rune three kinds of value, in descending order:
(1) **Error catalogs** — DRM, misinformation, source confusion, schema
assimilation, confidence dissociation are a field-tested list of what goes
wrong in any reconstructive memory process, biological or software. Every one
maps to a concrete Rune guard, and the guards are cheap.
(2) **Policy-grade effects** — spacing, testing, availability/accessibility,
encoding specificity are acquisition/retention phenomena robust enough to
inform scheduling and deletion policy, with the strict boundary that none
licenses relevance ranking.
(3) **Warnings** — autobiographical generativity, forgetting vocabulary,
dual-process ontology, and the systems-vs-processes stalemate are what NOT
to import.
The single largest correction vs R0: obligations live in the task authority,
not Memory (Risko & Gilbert 2016 is load-bearing and verified). The single
largest confirmation: append-only + supersession beats destructive
consolidation (Maynez 2020 + SSGM 2026 corroborate from the software side).
The taxonomy question resolves to tags, never partitions (Henke 2010 +
Vargha-Khadem 1997 jointly: contested ontology, weak surviving distinction).
@@ -0,0 +1,26 @@
# #377 R1 — 07_qualification.md
_Classification separate from evidence level. No item above RUNE_APPLICABLE
except pre-existing RUNE_PROVEN infrastructure; everything new is hypothesis
until Rune experiments run._
| # | Mechanism | Classification | Evidence level | Conf | T1 impact | Experiment | Rejection criterion |
|---|---|---|---|---|---|---|---|
| Q1 | Episodic/semantic/autobiographical as query tags | ADAPT (tags) | RUNE_HYPOTHESIS | MED | LOW | tag-retrieval benefit test | no benefit → drop |
| Q2 | Obligations in task authority (NOT Memory) | REJECT co-location; ADAPT task commitments | RUNE_APPLICABLE | HIGH | HIGH | audit/completion parity test | parity → revisit |
| Q3 | Dual-process retrieval mapping | REJECT mapping | — (dead) | HIGH | LOW | — | — |
| Q4 | Reactivation in durability, banned in ranking | ADAPT / REJECT split | RUNE_APPLICABLE / RUNE_HYPOTHESIS | HIGH | MED | retention A/B | no gain → drop counter |
| Q5 | Forgetting vocabulary ban; engineering tiering | REJECT word; ADAPT tiering | RUNE_APPLICABLE | HIGH | LOW | — (costless) | — |
| Q6 | Autobiographical fence-and-label | REJECT input; ADAPT rule | RUNE_APPLICABLE | HIGH | MED | — | — |
| Q7 | Availability-gated deletion | ADAPT | RUNE_APPLICABLE | MED | MED | synthetic probes | gate never fires → simplify |
| Q8 | Verbatim/gist dual + conflict verification | ADAPT | RUNE_APPLICABLE | MED | MED | synthetic conflicts | no conflicts → keep schema, drop detector |
| Q9 | Gist-match penalty | EXPERIMENT | RUNE_HYPOTHESIS | MED | MED | lure vs paraphrase A/B | >5% paraphrase harm → revert |
| Q10 | Original/amendment separation + re-encoding guard | ADAPT | RUNE_APPLICABLE | HIGH | MED | — (largely covered) | — |
| Q11 | Calibration tracking (not self-report) | ADAPT | RUNE_APPLICABLE | MED | LOW | calibration measurement | — |
| Q12 | Mechanistic gate for borrowed nouns | ADAPT (process rule) | RUNE_APPLICABLE | HIGH | LOW | — | — |
## Evidence-level discipline
No biological finding is cited as Rune proof anywhere in this artifact set.
Every EXTERNALLY_ESTABLISHED claim that entered prescription passed through
an explicit applicability argument (03_applicability.md) with its Rune level
in claims.json. New prescriptions are RUNE_HYPOTHESIS until experiments run.
@@ -0,0 +1,71 @@
# #377 R1 — Human Memory / Cognitive Science: FINAL (durable technical reference)
_Companion artifacts: 00_issue_scope, 01_inward, 02_outward/ (16 sections +
sources.md with 44 entries + claims.json with 12 falsifiable claims),
03_applicability (12 transfer chains), 04_innovation (5 candidates),
05_adversarial (10 attacks), 06_synthesis (16-row matrix),
07_qualification (below), r0_reconciliation._
## 1. The domain in one page
Human memory science is a century of careful experiments on a system Rune
does not have: a biological organ with fixed capacity, no provenance bus, no
exact storage, and identity goals tangled into recall. Its value to Rune is
therefore asymmetric: ENORMOUS as an error catalog (every failure mode humans
exhibit — gist falsification, source confusion, misinformation blending,
schema assimilation, confidence dissociation — is a hazard any reconstructive
process faces, including LLM consolidation), MODERATE as policy (spacing,
testing, availability/accessibility inform scheduling and deletion rules),
and NEGATIVE as ontology (its taxonomies are contested; importing them as
schema partitions reifies one faction's vocabulary).
## 2. What transfers, what does not
**Transfers (with Rune evidence ≥ RUNE_APPLICABLE):** availability/
accessibility → deletion gating; encoding specificity → cue metadata;
Fuzzy Trace verbatim/gist → dual representation + conflict verification;
source-monitoring inventory → origin column; testing effect → durability
(not ranking); misinformation/DRM → anti-reconstruction guards;
confidence dissociation → calibration discipline; implementation
intentions → cue→action pairs (in the task system).
**Does not transfer:** store partitions from taxonomies; dual-process
recognition as retrieval architecture; spacing as ranking signal;
forgetting as deletion license; autobiographical generativity as design
input; reconsolidation as supersession rationale (per #376); obligations
as memory rows; cognitive-science nouns without mechanistic gates.
## 3. The corrected rationale for Rune's pipeline
R0 said: human memory justifies obligation rows, dual-process retrieval,
spacing-weighted activation, and store-partitioned kinds. R1 corrects:
human memory justifies ERROR GUARDS (append-only, supersession, provenance,
verbatim preservation, gist penalties), RETENTION POLICIES (spaced
re-presentation, availability-gated deletion), and OWNERSHIP DECISIONS
(obligations to tasks, generativity fenced from evidence). Everything else
is either IR engineering wearing a psychology costume or contested ontology.
## 4. Experiments required (in order)
1. Gist-penalty A/B: lure-rejection vs paraphrase-recall (kill: >5%
paraphrase harm).
2. Spaced-durability counter vs wash_count: retention-prediction accuracy.
3. Deletion-gate trial: availability-gated vs age-based on synthetic
available-but-inaccessible probes.
4. Verbatim/gist conflict detector: detection rate on synthetic conflicts.
## 5. What would change this conclusion
- A replication resolving dual-process recognition in its favor (would
reopen C003 — unlikely to change the IR justification either way).
- Evidence that co-located obligations outperform task-owned commitments
on audit/completion metrics (would reopen C002).
- Large-scale evidence that spacing schedules improve retrieval ranking
(would reopen C004's ranking ban).
## 6. Remaining unknowns (bounded)
- Optimal spaced-re-presentation schedule parameters (needs retention A/B).
- Gist/verbatim conflict-detector design (needs prototype).
- Whether event-triggered obligations can reuse PendingOperation without
new state (shared with #376's unknowns; needs code verification).
## 7. Production implementation
NONE. Research only. All prescriptions enter T1 as design input.
@@ -0,0 +1,188 @@
{
"note": "Narrow, falsifiable claims. external_status vs rune_status kept separate per R1 standard.",
"claims": [
{
"claim_id": "HM-R1-C001",
"claim": "Episodic/semantic/autobiographical distinctions should be query-time tags, never schema partitions",
"evidence_for": [
"Henke 2010 processing-modes",
"systems-vs-processes stalemate",
"Nairne functional accounts"
],
"evidence_against": [
"Vargha-Khadem 1997 amnesic dissociations (weak surviving distinction)"
],
"external_status": "CONTESTED (as neural systems)",
"rune_status": "RUNE_HYPOTHESIS",
"architecture_impact": "LOW",
"falsifier": "F1: if tag-based retrieval shows no benefit over untyped, drop tags",
"experiment_required": true,
"classification": "ADAPT (tags)"
},
{
"claim_id": "HM-R1-C002",
"claim": "Obligations belong in the task/commitment authority, NOT in Memory",
"evidence_for": [
"Risko & Gilbert 2016 offloading review",
"Allen GTD trusted-external-system premise",
"monitoring-cost literature (Smith PAM vs multiprocess)"
],
"evidence_against": [],
"external_status": "EXTERNALLY_ESTABLISHED",
"rune_status": "RUNE_APPLICABLE",
"architecture_impact": "HIGH",
"falsifier": "F2: if Memory-co-located obligations show audit/completion parity with task-owned in A/B, revisit",
"experiment_required": false,
"classification": "REJECT memory co-location; ADAPT task-system commitments with evidence links"
},
{
"claim_id": "HM-R1-C003",
"claim": "Recollection/familiarity must NOT justify the lexical/vector retrieval split",
"evidence_for": [
"Wixted 2007 UVSD fit",
"Dunn 2004 confidence account",
"Wixted & Mickes 2010 graded recollection"
],
"evidence_against": [],
"external_status": "CONTESTED (psychology unsettled)",
"rune_status": "RUNE_HYPOTHESIS (mapping dead)",
"architecture_impact": "LOW",
"falsifier": "F3 resolved: mapping rejected regardless",
"experiment_required": false,
"classification": "REJECT mapping; keep lanes on IR grounds"
},
{
"claim_id": "HM-R1-C004",
"claim": "Reactivation counts belong in retention/tiering decisions, NOT relevance ranking",
"evidence_for": [
"Cepeda 2006 (acquisition-side)",
"Roediger & Karpicke 2006 (retrieval-as-encoding)"
],
"evidence_against": [],
"external_status": "EXTERNALLY_ESTABLISHED (as acquisition)",
"rune_status": "RUNE_APPLICABLE (durability only)",
"architecture_impact": "MEDIUM",
"falsifier": "F4/F5: if ranking-with-reactivation beats ranking-without on topical-fit benchmarks, revisit with discount factor",
"experiment_required": true,
"classification": "ADAPT (durability counter); REJECT (ranking use)"
},
{
"claim_id": "HM-R1-C005",
"claim": "Human forgetting vocabulary must not enter the codebase; tiering is engineering",
"evidence_for": [
"HSM/cache/buffer-pool practice (no psychology needed)",
"availability/accessibility distinction as the sound core"
],
"evidence_against": [],
"external_status": "EXTERNALLY_ESTABLISHED (engineering)",
"rune_status": "RUNE_APPLICABLE",
"architecture_impact": "LOW",
"falsifier": "F5: none plausible \u2014 vocabulary ban is costless",
"experiment_required": false,
"classification": "REJECT word; ADAPT tiering"
},
{
"claim_id": "HM-R1-C006",
"claim": "Autobiographical generativity is a confabulation engine; fence life-story synthesis from evidence",
"evidence_for": [
"Conway & Pleydell-Pearce 2000 (generative, goal-yoked)",
"Conway 2005 (coherence constraints)"
],
"evidence_against": [],
"external_status": "EXTERNALLY_ESTABLISHED (as description)",
"rune_status": "RUNE_APPLICABLE (as warning)",
"architecture_impact": "MEDIUM",
"falsifier": "none plausible",
"experiment_required": false,
"classification": "REJECT as design input; ADAPT as fence-and-label rule"
},
{
"claim_id": "HM-R1-C007",
"claim": "Deletion requires demonstrated inaccessibility across cues (availability/accessibility)",
"evidence_for": [
"Tulving & Pearlstone 1966"
],
"evidence_against": [],
"external_status": "EXTERNALLY_ESTABLISHED",
"rune_status": "RUNE_APPLICABLE",
"architecture_impact": "MEDIUM",
"falsifier": "if gate never fires, simplify",
"experiment_required": false,
"classification": "ADAPT"
},
{
"claim_id": "HM-R1-C008",
"claim": "Store verbatim detail + gist side by side; verify on conflict (Fuzzy Trace)",
"evidence_for": [
"Brainerd & Reyna 2002/2005 + developmental predictions"
],
"evidence_against": [],
"external_status": "EXTERNALLY_ESTABLISHED",
"rune_status": "RUNE_APPLICABLE",
"architecture_impact": "MEDIUM",
"falsifier": "if no conflicts detected in 6 months, keep schema, drop detector",
"experiment_required": false,
"classification": "ADAPT"
},
{
"claim_id": "HM-R1-C009",
"claim": "Penalize gist-only retrieval matches lacking verbatim support (DRM guard)",
"evidence_for": [
"Roediger & McDermott 1995 (40-55% recall, 72% remember)"
],
"evidence_against": [
"paraphrase-recall harm risk"
],
"external_status": "EXTERNALLY_ESTABLISHED",
"rune_status": "RUNE_HYPOTHESIS",
"architecture_impact": "MEDIUM",
"falsifier": "paraphrase recall drops >5% \u2192 revert",
"experiment_required": true,
"classification": "EXPERIMENT"
},
{
"claim_id": "HM-R1-C010",
"claim": "Post-event inputs can corrupt originals; keep original-vs-amendment separated",
"evidence_for": [
"Loftus & Palmer 1974; Loftus/Miller/Burns 1978"
],
"evidence_against": [
"McCloskey & Zaragoza 1985 (mechanism dispute \u2014 blending vs interference)"
],
"external_status": "EXTERNALLY_ESTABLISHED (core)",
"rune_status": "RUNE_APPLICABLE",
"architecture_impact": "MEDIUM",
"falsifier": "none plausible",
"experiment_required": false,
"classification": "ADAPT (already largely covered; add re-encoding guard)"
},
{
"claim_id": "HM-R1-C011",
"claim": "Confidence must never proxy accuracy; track calibration separately",
"evidence_for": [
"Wixted & Wells 2017; Koriat metamemory"
],
"evidence_against": [],
"external_status": "EXTERNALLY_ESTABLISHED",
"rune_status": "RUNE_APPLICABLE",
"architecture_impact": "LOW",
"falsifier": "none plausible",
"experiment_required": false,
"classification": "ADAPT"
},
{
"claim_id": "HM-R1-C012",
"claim": "Cognitive-science nouns must pass the mechanistic gate (query changed? invariant enforced? falsifier?) or stay out of the architecture",
"evidence_for": [
"systems-vs-processes stalemate; Schacter & Tulving 1994; Foster & Jelicic 1999"
],
"evidence_against": [],
"external_status": "EXTERNALLY_ESTABLISHED (meta)",
"rune_status": "RUNE_APPLICABLE (process rule)",
"architecture_impact": "LOW",
"falsifier": "none \u2014 process discipline",
"experiment_required": false,
"classification": "ADAPT (as R1 process rule)"
}
]
}
@@ -0,0 +1,25 @@
# R0 → R1 Reconciliation (#377 Human Memory)
_R0 source: memory-atlas/families/human_memory_cognitive_science.md_
| R0 claim | R1 verdict | Why |
|---|---|---|
| Prospective memory → typed obligation rows (H1) | **OVERTURNED** | Risko & Gilbert 2016 (verified): offloading science says externalize intentions; obligations belong in task authority with state machines. R0 assumed Memory ownership without arguing it. Preserved: cue→action pairs, event-anchored triggers, reminder scaffolding — relocated to task system with memory-evidence links. |
| Episodic/semantic kinds (H2) | **REFINED → tags, not stores** | Henke 2010 + systems-vs-processes stalemate: contested ontology; Vargha-Khadem preserves weak distinction. R0's "entry kinds" would reify one faction's taxonomy. Downgraded to query-time tags. |
| Autobiographical narratives (H3) | **REFINED → chronicles kept, generativity fenced** | Chronicles exist (COVERED); Conway SMS shows recall is goal-yoked construction — R0 understated the danger. Added fence-and-label rule. |
| Source-memory provenance (H4) | **REFINED → schema checklist, not mechanism** | Adversarial #3: analogy backwards (columns already exist); Johnson's cue inventory still earns the origin column. Downgraded from "implement source monitoring" to "store what it wishes it had." |
| Recollection/familiarity analogy (H5) | **OVERTURNED** | Wixted 2007 / Dunn 2004 / Wixted & Mickes 2010 (all verified): psychology unsettled; mapping built on sand. Hybrid lanes kept on IR grounds only. |
| Cue/context scoping (H6) | **CONFIRMED (expectations capped)** | Encoding specificity + availability/accessibility stand; Godden & Baddeley capped at small-effect (N=18; Smith & Vela). |
| Reconsolidation mapping (H7) | **CONFIRMED OVERTURN** (per #376; not reintroduced) | #376 R1 killed the framing; this tranche independently keeps only prediction-error-gated updates. No regression. |
| Spacing priority (H8) | **REFINED → durability-only** | Cepeda robust as acquisition; adversarial #5 forbids ranking use (category jump). Split into spaced-durability counter (ADAPT) + ranking ban. |
| Confidence mechanism (H9) | **CONFIRMED (strengthened)** | Dissociation robust (Wixted & Wells; Koriat); added separate calibration tracking requirement. |
| RIF rejection (H10) | **CONFIRMED** | Fragility confirmed (Murayama meta + reliability literature); hazard framing kept. |
| False-memory anti-pattern (H11) | **CONFIRMED (strengthened)** | Maynez 2020 + SSGM 2026 corroborate from software side; added gist-penalty + re-encoding guard. |
| Source-monitoring protections (H12) | **CONFIRMED** | Origin column + verbatim-quote rules stand; generation-event labeling added (Jacoby). |
Tally: CONFIRMED 5 · REFINED 4 · OVERTURNED 2 · STILL_UNKNOWN 0.
Honest note: R0 was right about error prevention (its strongest half) and wrong
about ownership and ontology (obligations-in-memory, dual-process mapping,
store-partitioning). The adversarial pass did the most work in this domain —
five clean kills, four of them against R0's own conclusions.
@@ -0,0 +1,47 @@
# Sources Ledger (#377 R1)
| ID | Citation | Year | Venue | Peer? | Type | Read depth | Status | Rune relevance |
|---|---|---|---|---|---|---|---|---|
| S001 | Tulving 1972, episodic/semantic (Organization of Memory) | 1972 | book chapter | n/a | primary/theory | RELEVANT_SECTIONS | ROBUST descriptive; CONTESTED neural-systems | taxonomy validity |
| S002 | Tulving 1985 autonoetic/noetic; 2002 Ann Rev Psych | 1985/2002 | journal | yes | theory | ABSTRACT | revisions of S001 | taxonomy |
| S003 | Squire 1992 Psych Review; Squire & Zola 1996 PNAS | 1992/1996 | journal | yes | primary | RELEVANT_SECTIONS | ROBUST coarse | skill/procedure boundary |
| S004 | Conway & Pleydell-Pearce 2000, Psych Review 107(2) | 2000 | journal | yes | synthesis | RELEVANT_SECTIONS | ROBUST/influential | warning label (generative construction) |
| S005 | Baddeley & Hitch 1974; Baddeley 2000 TiCS | 1974/2000 | chapter/journal | yes | framework | RELEVANT_SECTIONS | ROBUST, revised | capacity-limited active set |
| S006 | Cowan 1999 embedded-processes; Engle executive attention | 1999 | chapter | yes | theory (competitor) | ABSTRACT | active CONTEST | ~4-chunk focus number |
| S007 | Tulving & Thomson 1973, encoding specificity | 1973 | journal | yes | primary | RELEVANT_SECTIONS | ROBUST + boundaries | store encoding context |
| S008 | Tulving & Pearlstone 1966, availability vs accessibility | 1966 | journal | yes | primary | RELEVANT_SECTIONS | ROBUST; key distinction | retrieval-failure-before-deletion |
| S009 | Godden & Baddeley 1975, divers | 1975 | journal | yes | primary | RELEVANT_SECTIONS | WEAK (N=18) | small-gain context tags |
| S010 | Smith & Vela 2001, context meta-analysis | 2001 | meta | yes | meta-analysis | ABSTRACT | small/fragile effect | context-match expectations |
| S011 | Yonelinas 1994 dual-process | 1994 | journal | yes | primary | RELEVANT_SECTIONS | CONTESTED | two retrieval GRADES (not systems) |
| S012 | Wixted 2007 Psych Review (unitary UVSD) | 2007 | journal | yes | theory | RELEVANT_SECTIONS | live dispute | kills lexical/vector mapping |
| S013 | Dunn 2004 Psych Review (remember/know = confidence) | 2004 | journal | yes | theory | RELEVANT_SECTIONS | live dispute | same |
| S014 | Wixted & Mickes 2010 (continuous dual-process) | 2010 | journal | yes | theory | RELEVANT_SECTIONS | concedes graded recollection | same |
| S015 | Einstein & McDaniel 1990, JEP:LMC | 1990 | journal | yes | primary | RELEVANT_SECTIONS | ROBUST | event-anchored triggers |
| S016 | Sellen et al. 1997, Memory | 1997 | journal | yes | primary (in-situ) | ABSTRACT | ROBUST | event cues > time cues |
| S017 | Smith 2003 PAM theory | 2003 | journal | yes | theory | ABSTRACT | CONTESTED coexistence | monitoring cost is real |
| S018 | McDaniel & Einstein 2000/2005 multiprocess | 2000/05 | journal | yes | framework | RELEVANT_SECTIONS | coexistence | spontaneous + watch |
| S019 | Altmann & Trafton 2002 goal-activation | 2002 | journal | yes | model | ABSTRACT | ROBUST practical | resumption-lag/reminders |
| S020 | McDaniel et al. 2004 (delays/reminders) | 2004 | journal | yes | primary | ABSTRACT | ROBUST | external reminders eliminate cost |
| S021 | Gollwitzer 1999 implementation intentions | 1999 | journal | yes | review | ABSTRACT | ROBUST, large lit | cue→action pairs |
| S022 | Risko & Gilbert 2016 offloading, TiCS | 2016 | journal | yes | review | RELEVANT_SECTIONS | verified, high-strength | obligations OUTSIDE memory |
| S023 | Johnson/Hashtroudi/Lindsay 1993 source monitoring | 1993 | journal | yes | framework | RELEVANT_SECTIONS | ROBUST | schema checklist, not mechanism |
| S024 | Loftus & Palmer 1974; Loftus/Miller/Burns 1978 | 1974/78 | journal | yes | primary | RELEVANT_SECTIONS | ROBUST core; mechanism CONTESTED | original-vs-amendment separation |
| S025 | McCloskey & Zaragoza 1985 | 1985 | journal | yes | primary (critique) | ABSTRACT | mechanism dispute | same |
| S026 | Wixted & Wells 2017 eyewitness; Koriat metamemory | 2017/1993 | journal | yes | review/primary | ABSTRACT | ROBUST dissociation | never confidence-as-accuracy |
| S027 | Jacoby et al. 1989 false fame/cryptomnesia | 1989 | journal | yes | primary | ABSTRACT | ROBUST | label generation events |
| S028 | Roediger & McDermott 1995 DRM | 1995 | journal | yes | primary | RELEVANT_SECTIONS | ROBUST, replicated | penalize gist-only matches |
| S029 | Brainerd & Reyna 2002/2005 Fuzzy Trace | 2002/05 | journal/book | yes | theory | RELEVANT_SECTIONS | ROBUST alternative | verbatim+gist dual representation |
| S030 | Bartlett 1932 Remembering | 1932 | book | n/a | foundational | RELEVANT_SECTIONS | foundational; replication partial (Bergman & Roediger 1999) | minimize re-encoding without provenance |
| S031 | Shaw & Porter 2015 | 2015 | journal | yes | primary | ABSTRACT | CONTESTED rates, ROBUST possibility | suggestive-pressure caution |
| S032 | Anderson/Bjork/Bjork 1994 RIF | 1994 | journal | yes | primary | RELEVANT_SECTIONS | CONTESTED/fragile | hazard, not feature |
| S033 | Murayama et al. 2014 RIF meta-analysis | 2014 | meta | yes | meta-analysis | ABSTRACT | small + publication bias | same |
| S034 | Cepeda et al. 2006 spacing meta-analysis | 2006 | meta | yes | meta-analysis | RELEVANT_SECTIONS | ROBUST (259/271) | spaced re-presentation policy |
| S035 | Roediger & Karpicke 2006; Karpicke & Roediger 2008 | 2006/08 | journal | yes | primary | RELEVANT_SECTIONS | ROBUST | retrieval-as-encoding (durability) |
| S036 | Bjork 1994 desirable difficulties | 1994 | chapter | yes | theory | ABSTRACT | ROBUST direction | effortful retrieval |
| S037 | Henke 2010 Nat Rev Neurosci (processing modes) | 2010 | journal | yes | theory | RELEVANT_SECTIONS | verified | tag-not-partition |
| S038 | Maynez et al. 2020 ACL faithfulness | 2020 | conference | yes | primary | RELEVANT_SECTIONS | corroborates anti-pattern | append-only over destructive |
| S039 | SSGM 2026 semantic drift | 2026 | preprint | no | primary | RELEVANT_SECTIONS | corroborates | same |
| S040 | Nairne/Thompson/Pandeirada 2007 survival processing | 2007 | journal | yes | primary | ABSTRACT | functional account | dissolve store boundaries |
| S041 | Vargha-Khadem et al. 1997 Science (developmental amnesia) | 1997 | journal | yes | primary | ABSTRACT | preserves weak distinction | tag-level distinction survives |
| S042 | Conway 2005 self/memory | 2005 | journal | yes | theory | ABSTRACT | goal-constrained construction | fence life-story synthesis |
| S043 | Lee & See 2004 trust calibration (via child Z) | 2004 | journal | yes | review | ABSTRACT | anchor | visible fixability |
@@ -0,0 +1,109 @@
# #378 R1 — 00_issue_scope.md
## Core question
Which mechanisms discovered through cognitive-architecture research genuinely
solve problems Rune has, which mechanisms should inform Memory/Substrate/
learning design, and which architecture concepts should be rejected as
unnecessary imitation?
## Research questions (40 per mandate)
1. Why were cognitive architectures developed?
2. What recurring architectural problems do they solve?
3. Which mechanisms independently recur across architectures?
4. Which mechanisms actually have empirical support?
5. Which are primarily theoretical engineering choices?
6. Which have failed to scale?
7. Which have survived decades of use?
8. Which architectures remain actively developed?
9. What happened to abandoned architectures?
10. What maintenance burden do full architectures create?
11. Do cognitive cycles provide useful properties or artificial rigidity?
12. Are declarative/procedural divisions computationally necessary?
13. What does activation actually accomplish?
14. What is the strongest evidence for ACT-R activation equations?
15. How does Soar semantic memory compare?
16. How do architectures prevent hub/fan effects?
17. What does spreading activation add beyond ordinary retrieval?
18. When is procedural compilation/chunking beneficial?
19. What is the utility problem?
20. Does impasse-driven learning outperform simple outcome learning?
21. How are failures represented?
22. How are stale procedures handled?
23. What does Global Workspace add computationally?
24. Is broadcast actually needed in software agents?
25. What does attention competition accomplish?
26. How do architectures distinguish active state from long-term memory?
27. How do symbolic/subsymbolic hybrids work?
28. Which mechanisms require numeric tuning that becomes maintenance debt?
29. How do architectures handle uncertainty?
30. How do architectures handle contradictory knowledge?
31. How do architectures represent context?
32. How do they represent goals?
33. How do they recover from interruption?
34. How do they select which memory enters active cognition?
35. Which ideas map naturally to Rune's Warm Neurons?
36. Which map to procedural learning?
37. Which belong to Substrate rather than Memory?
38. Which duplicate mechanisms Rune already possesses?
39. What would a minimal cognitive architecture for Rune actually contain?
40. Would Rune be better served by borrowing isolated mechanisms rather than
adopting any architecture?
## R0 claims under test (HYPOTHESES, not accepted)
H1: ACT-R base-level activation (B_i ≈ Σ t_j^-d) should inform deterministic
Warm Neuron activation.
H2: Recency + frequency should replace wash_count-style frequency-only behavior.
H3: ACT-R/Soar fan normalization supports graph/PPR anti-hub weighting.
H4: Soar chunking supports impasse → successful resolution → procedure promotion.
H5: Global Workspace / LIDA suggests selected context → broadcast → learning.
H6: Context inclusion itself might be treated as a consolidation/learning event.
H7: Activation noise should be rejected for Rune.
H8: Production-rule engines should be rejected.
H9: Codelet concurrency / strict cognitive-cycle timing should be rejected.
H10: Cognitive architectures largely validate Rune's existing separation of
memory / active context / procedural execution.
## Technical correction to verify (§8)
R0 represented ACT-R base-level activation approximately as:
B_i = Σ_j t_j^-d
Verify against original ACT-R sources: the canonical formulation commonly
includes a logarithm around the summed decayed accesses:
B_i = ln(Σ_j t_j^-d)
Verify: exact canonical formulations, historical revisions, optimized
approximations, what d represents, where noise enters, what spreading
activation adds, what retrieval threshold adds, whether Soar copied the same
formula exactly or approximately. If R0 misstated the formula, record an
explicit correction.
## Falsifiers
F1: If ACT-R activation's predictive success is confined to laboratory
response-time fitting with non-identifiable parameters, it does not
justify Rune adoption.
F2: If fan-effect → graph-normalization transfer conflates three distinct
mathematics (human semantic-network fan, graph-degree normalization,
PageRank/PPR), the analogy must be rebuilt per-domain or dropped.
F3: If Soar chunking's utility problem dominates (rule explosion outweighs
benefit), impasse-driven promotion is rejected for Rune.
F4: If Global Workspace broadcast reduces to publish/subscribe that Rune's
event/state machinery already implements, GWT adds nothing.
F5: If cognitive cycles provide no property that event-driven architecture
cannot supply more cheaply (bounded work, fairness, budgets), cycles
are rejected as biological imitation.
F6: If the scaling/failure history shows architectures fail on maintenance
burden rather than mechanism quality, the lesson is anti-architecture:
borrow mechanisms, never frameworks.
## Stopping criterion
Evidence saturation: new sources repeat known mechanisms/criticisms, add
only detail. No arbitrary paper-count target — but a few paragraphs and a
handful of citations are NOT sufficient for a foundational field.
@@ -0,0 +1,110 @@
# #378 R1 — 01_inward.md
## Current Rune mechanisms vs cognitive-architecture questions (evidence-first)
_Source: direct read-only inspection of memory.db (924 entries) + behavior.db
+ T0/T0.1 archaeology. Status: PROVEN / IMPLEMENTED_UNPROVEN / DESIGNED /
DORMANT / ABSENT / BROKEN._
### Canonical Memory and use_history
- 924 entries (729 fact, 195 neuron). wash_count>0 on 304.
- Status: PROVEN. Use-history exists; T0.1 found it unvalidated as quality
signal (superseded entries carry high wash counts).
### wash_count — what job does it do?
- Currently feeds: promotion_eligible (143 rows), retrieval ranking
(frequency term), and nothing else. It does triple duty for truth,
activation, and promotion — three unrelated jobs on one counter.
- Timestamps available: created_at, last_accessed, last_washed per entry.
Per-OCCURRENCE timestamps (ACT-R needs the full access history, not just
last-accessed): ABSENT. An access log would be NEW.
- Status: PROVEN counter; ABSENT occurrence history.
### Warm/neuron state
- 195 neuron rows; tier='warm' on ALL 924 rows = vestigial (T0.1 R4).
- No activation equation, no spreading, no threshold, no noise.
- Status: DORMANT as architecture; PROVEN as rows.
### Retrieval ranking
- Hybrid dense+BM25+RRF+floor (T0 PROVEN). Rank terms: importance,
wash_count (frequency), recency via last_accessed (coarse).
- No decay function, no fan normalization, no threshold gate.
- Status: PROVEN; activation mathematics ABSENT.
### ContextBroker
- Planned (T1 target); current: keyword routing + session/task scoping
(PROVEN per T0 production entrypoints).
- Performs PART of a workspace: bounded selection into context. No
broadcast, no competition, no learning-from-inclusion.
- Status: IMPLEMENTED (selection) / DESIGNED (workspace semantics).
### Task/session state
- auto_tasks.db (2 tasks), PendingOperation machinery, event-driven waits
(PROVEN, R13/M9/M10 PASS). Goal stacks: ABSENT as such — goals live in
task records + conversation, not a goal buffer.
- Interruption/resume: PROVEN via event-driven continuation (async
programme FROZEN_ACCEPTED).
### Success/failure learning
- behavior.db: 2 corrections, 1 habit, 0 activations. Mechanism exists;
volume is negligible — no statistical signal has ever flowed through it.
- Status: IMPLEMENTED_UNPROVEN (mechanism) / ABSENT (evidence base).
### Promotion mechanisms
- promotion_eligible flag (143 rows); governance scripts (provisional/
validated/locked lifecycle, PROVEN as code). Impasse signal: ABSENT —
no retrieval-failure vs tool-failure distinction is logged.
- Status: DESIGNED (gate semantics) / ABSENT (impasse trigger).
### Procedural-learning design
- Skill files exist; promotion/demotion lifecycle DESIGNED (child G
research), not exercised. No chunking, no compilation, no utility
tracking. Status: DESIGNED.
### Graph/PPR plans
- graph.sqlite DORMANT (last edge 2026-08-26). PPR: EXPERIMENT (child I
protocol defined, bridge-node recall + hybrid ablation). Fan
normalization: DESIGNED as requirement, not implemented.
- Status: DORMANT / EXPERIMENT.
### Scaffolding / Spine / Substrate
- Scaffolding: construction authority, PROVEN (contracts driven through
real flow). Spine: structural truth, evidence-gated maturity (per child P
research). Substrate: execution substrate, DESIGNED.
- These already solve: executive control (task authority + event-driven
continuation), architectural state representation (Spine), execution
(Substrate). Cognitive-architecture imports must not duplicate them.
### Event-driven continuation/recovery
- PROVEN (async programme frozen). This is Rune's answer to anything a
cognitive cycle might offer (bounded work, fairness, budgets) — the
burden is on cycles to show what events cannot do.
### Growth Delta mechanisms
- Outcome-learned utility: DESIGNED (child E/G research); wash_count is
the current proxy, unvalidated.
### Current learning signals (inventory)
1. wash_count (frequency of retrieval/use) — PROVEN counter, unvalidated.
2. importance (LLM-assigned scalar) — PROVEN field, calibration unknown.
3. last_accessed / last_washed (coarse recency) — PROVEN fields.
4. corrections (2 rows) — negligible volume.
5. promotion_eligible (143 rows) — gate output, not a signal.
6. Per-occurrence access history — ABSENT.
7. Retrieval-failure events — ABSENT.
8. Outcome-verified success/failure per procedure — ABSENT.
## Inward questions answered (§9)
- Reliable impasse signal? NO — ABSENT. Retrieval failure vs tool failure
is not distinguished anywhere.
- Access timestamps sufficient for ACT-R-like activation? PARTIAL —
last_accessed/last_washed exist per entry; per-occurrence history ABSENT.
- wash_count's jobs? THREE unrelated jobs (truth proxy, activation term,
promotion input) on one counter — the core finding.
- ContextBroker as workspace? PARTIAL — selection yes; competition,
broadcast, learning-from-inclusion no.
- Substrate as executive control? DESIGNED — the claim is untested.
- Spine as state representation? PROVEN (per T0/T21.5 + child P).
- Vocabulary renaming risk? HIGH — "activation," "chunk," "workspace,"
"attention" could all rename existing systems without adding mechanism.
@@ -0,0 +1,10 @@
# 02 — OUTWARD (populated by the deep-research actor; verified by controller)
Files: field_history.md, act_r.md, soar.md, clarion.md,
lida_global_workspace.md, sigma.md, opencog_hyperon.md,
other_architectures.md, declarative_memory.md, procedural_learning.md,
activation_retrieval.md, spreading_activation.md, working_memory_attention.md,
goal_impasse_control.md, symbolic_subsymbolic.md, cognitive_cycles.md,
scaling_and_failure.md, modern_agent_relevance.md, competing_models.md,
criticism_replication.md, software_transfer.md
+ sources.md (ledger) + claims.json (machine-readable).
@@ -0,0 +1,20 @@
# ACT-R deep pass
**History/versions:** 4.0 (1998, Lebiere join, perceptual-motor from EPIC), 5.0 (2004 modules+buffers, brain mapping), 6.0 (2005 rewritten, dynamic pattern matching), 7.x (2015+, typeless chunks, JSON-RPC, Python tutorial). Common Lisp; jACT-R, python_actr, pyactup are partial mirrors. Maintained at CMU, active modelling community, 700+ models, cognitive-tutor deployment — but NOT a production agent substrate.
**Mechanisms:** declarative chunks (typed slot-vectors); productions (buffer-condition → buffer-action, single firing per ~50ms cycle); buffers (goal, imaginal/problem state, retrieval, visual, aural, manual); modules (perceptual-motor + declarative + procedural).
**VERIFIED CANONICAL BASE-LEVEL EQUATION (load-bearing):** per Anderson et al. 2004; Anderson 2007; ACT-R 7 reference manual:
> **B_i = ln( Σ_j t_j^(−d) ) + β_i**
B_i = base-level activation of chunk i; t_j = lag since j-th encounter/use; d = decay rate (default ≈0.5, typically 0.4–0.6); β_i = offset/intercept (prior/familiarity constant). **The logarithm is canonical** — it converts summed recency/frequency trace into log-odds-like need probability under Anderson & Schooler (1991) rational analysis. **R0 CORRECTION: R0 wrote B_i = Σ t_j^−d, missing the ln. Without it the quantity is not activation but raw recency mass.** Historical revisions: early ACT versions used power-law strength without log; rational-analysis integration (1990–93) introduced log-sum form; later work adds β, optional optimized/approximated forms (recency-only or two-point approximations) per reference manual.
**Full activation:** A_i = B_i + Σ_j W_j·S_ji + P_i + ε, where spreading ΣW·S is context boost, P partial-match penalty, ε logistic/similar noise. Retrieval only if A_i > τ (threshold); latency T = F·e^(−A) (F latency factor); probability logistic in (A−τ). Spreading: W_j source weighting (usually 1/n sources), S_ji ≈ S − ln(fan_j) (association strength minus fan penalty). Utility learning for productions: U updated by reward minus cost with noise; production compilation collapses sequences. Noise enters twice: activation noise (transient retrieval stochasticity) and utility noise — both principled as sampling, but in practice often free parameters.
**Fitting methodology:** grid-search parameters per experiment to latency/accuracy/BOLD. Strength: genuine quantitative prediction. Weakness (contested): **parameter identifiability — admitted in Anderson 2004 itself**: "the retrieval threshold, τ, and latency factor, F, are parameters that have varied substantially from model to model," with only the empirical relation F ≈ .35·e^τ offered. d = 0.5 is community convention ("has emerged as the default value... over a large range of applications"), not derivation. Replication requires exact parameters + history traces rarely published. Transfer limits: parameters tuned to one paradigm rarely transfer; brittle chunk-type engineering.
**Anchor-verification note (post-repair):** the author preprint was read in FULL — equation verified verbatim including the logarithm. Anderson & Schooler 1991 (companion OCR'd in full) explicitly states: "We are not too concerned with whether the memory or environmental functions are truly power functions or just good approximations" — the theory itself transfers the SIGNALS, not the power-law form. This is the strongest possible grounding for the R1 conclusion "adopt signals, benchmark the form."
**Soar copy question — VERIFIED:** Laird (2012, semantic memory ch.; restated Laird 2022 arXiv:2201.09305) says Soar SMEM "implements the base-level activation scheme originally developed for ACT-R." It is **functionally the same form (log-sum power-law) but approximately, not byte-identical**: own decay/parameters, own usage-history storage, plus lazy-evaluation spreading (Jones et al. 2016 ICCM). Cite as approximate adoption, not exact port.
@@ -0,0 +1,6 @@
# Activation / retrieval compared
**What is activation FOR?** The literature conflates five functions Rune must separate: (1) retrieval ordering (rank candidates); (2) cache residency (what stays hot — ECAN/STI, warm neurons); (3) context inclusion (what enters prompt — working-memory budget); (4) forgetting (what decays — base-level); (5) procedural selection (which skill fires — utility). ACT-R uses one number for 1/3/4; Soar splits utility vs declarative activation; ECAN splits STI vs LTI. Rune should follow the split: distinct signals per function (relevance, frequency, recency, accessibility, residency, importance, utility, trust, confidence, task affinity), not one "activation."
Separate dimensions per mandate §20 — do not collapse into one scalar without evidence.
@@ -0,0 +1,6 @@
# CLARION (fair treatment)
Sun's dual-representation thesis: every subsystem has **explicit** (localist chunks/rules) and **implicit** (distributed microfeatures/Q-networks) levels, bidirectionally linked (bottom-up rule extraction RER; top-down guidance). Four subsystems: action-centered (procedural), non-action-centered (semantic/episodic), motivational (drives→goals), metacognitive (monitoring/parameter-setting). Explains skill speed-up, verbalization gains, transfer, pressure degradation (Sun et al. 2005 Psych. Rev.; Sun 2016 OUP).
**Bearing on Rune:** the explicit/implicit split is PARTIALLY but not fully captured by deterministic/LLM/local-model layering. What CLARION adds: (a) redundant encoding with principled bottom-up extraction (experience → rule) and top-down shaping (rule → habit) — Rune's procedural-promotion path lacks the second direction; (b) motivational/metacognitive subsystems as first-class (drives → goals → parameter control) — Rune has trust/authority but no drive economy; (c) synergy accounting (when to trust which level). Weaknesses: implementation fragmented (pyClarion partial), validation mostly lab tasks (serial reaction, artificial grammar, Tower of Hanoi), heavy machinery for modest engineering gain. Borrow the bidirectional learning loop and metacognitive parameter control; skip the four-box ontology as mandatory.
Loaded 100 of 776 files, more files were not shown because too many files have changed in this diff. Show more