100 Commits
Author SHA1 Message Date
Nick 7ec615a656 probe: ssh push test 2026-10-06 13:54:32 +01:00
Nick 0873b521e3 feat(scaffold): programme_continuation wired into close() (T5.15 slice 3) + same-second contract-id collision fix
Slice 3 of the completion wave: closing a contract that is a stage of a persisted Programme marks that stage COMPLETE, persists the ledger, and rides the continuation canary on the close envelope — the next eligible stage is SURFACED, never guessed (task done ≠ programme done). No programme bound → no continuation block; ledger failure degrades without failing the closure. Three contracts. Also fixed en route: contract ids were second-granularity timestamps that collided when two needs filed in the same second (red test proves distinct ids now, uuid suffix added).
2026-10-06 03:46:24 +01:00
Nick 55f268f978 feat(scaffold): construction_commands dispatch — the serving wire (T5.15 slice 2)
The command seam validated intents but nothing EXECUTED them. dispatch() binds the canonical store, runs the validator, then executes accepted intents through the Construction Interface (resume/transition/amend_scope), refusing via the lifecycle with accepted=False+success=True (a refusal is a valid protocol outcome, not an error). Idempotent replay returns the recorded intent without re-executing. Three contracts: end-to-end phase movement, refusal shape, replay-no-double-execute; seam file 12/12. Slice 1 of 5 was stage_guards (#2467 wire wave).
2026-10-06 02:40:49 +01:00
Nick 320026a4a3 feat(scaffold): stage_guards wired into the completion-facing transitions (T5.15 slice 1)
The five orphaned V1 components: slice 1 wires stage_guards for real. transition(verifying|closed) now runs §15F readiness StageChecks derived from guard: verification obligations (or inline guard_checks); a blocked guard = VERIFICATION_FAILED envelope and the phase does NOT move — builder cannot self-certify past a failing check. building/free edges unchanged; capabilities() schema documents the new arg; CLI transport carries guard_checks as JSON arg 4. Four contracts red-first (blocked/pass/inline-override/free-edge); 56 interface+guards tests green.
2026-10-06 02:40:49 +01:00
Nick 0e88b6bc08 feat(tui): consolidate post-response dim spam into one collapsed line (#2468/T5.13)
Five separate dim system messages after every task/build response (budget, claims, growth, self-improve, plus the cron/queue echoes) spammed chat. New collect_post_response_signals() is a PURE headless collector with degrade-not-crash try blocks; the worker renders ONE line or silence. 6 frozen contracts: compose order [chat,task], resize semantics re-keyed, collector all-signals/silence/never-raises/cycle-multiple. 38 TUI/layout tests green; pyright error count unchanged at baseline 8.
2026-10-06 02:40:25 +01:00
Nick 004e5b3118 feat(tui): swap panes — chat LEFT, task RIGHT (#2465/T5.14)
Nick: chat-first feels natural. Compose yield order reversed (rune_tui.py compose), resize_left/resize_right actions re-keyed to the new visual positions (left=chat shrink now grows task), focus actions and all name-keyed query_one calls untouched (position-independent by design). Static source proof: yield order [chat, task]; 45 layout/TUI tests green.
2026-10-06 02:40:25 +01:00
Nick d8ce21b76d fix(spine): the measured dichotomy decides — hints demoted to labeled fallbacks (#2461, Nick correction)
Nick caught the deviation: module verdicts were substring-guessed from names (memory→rust, gitea→go) with a silent rust default. Authority order now: the measured classification map (import-evidence) decides FIRST for every module; hint hits are labeled "(name hint)" so provenance is visible; unmeasured+unhinted modules are "unclassified" (12), never a guessed rust. Store rebuilt: 106 rust / 45 go measured, 33+7 hint-labeled, 23 test-infra, 12 honest unclassified. Battery 95 green (test updated to pin the authority contract).
2026-10-06 02:28:16 +01:00
Nick d4d43dbf67 merge: spine_language tests (the new-module henxel repair) 2026-10-06 02:07:44 +01:00
Nick 8a6c950140 test(spine_language): the carved transforms ship WITH tests (#2461 new-module henxel)
CI red at d67fc46: spine_language.py crossed the new-module henxel with zero coverage. Eight contracts: measured-map read + graceful degrade, kind-default verdicts, TUI/hints, subsystem member-majority, unqualified-discovery honesty (candidate stays DECLARED), legacy-ID normalization with edge re-pointing, and the closed-contract-only gather law. 8/8 green. Also: construction_commands dispatch WIP stashed on its own branch (slice 2, next).
2026-10-06 02:04:19 +01:00
Nick d67fc46581 chore(rebase): refresh store/rebase inventory + classification for the 6 post-W0 modules (#2461 close-out)
The W0 map had drifted (174 vs 180 files): cc_loader/sc_loader/mr_loader/mems_loader (FFI kernel membranes → RUST), spine_language (deterministic carve → RUST), __init__ (metadata reads) now carry evidence-backed side records and measured function/line counts. spine_language._classification_sides() — the runtime reader — sees 180 entries; spine battery green.
2026-10-06 01:40:56 +01:00
Nick 7f5d57236a fix(ci): 0.99.0 CI repair — silent-handler annotations + spine_language umbrella mapping (#2461)
The 0.99.0 bump ran CI against the delegation code before the annotations landed: BLE001 345->349, S110 75->81 (my new kernel-failure fallbacks), plus spine_language unmapped in the umbrella manifest (test_umbrella_impact) and the resulting spine-rebuild membership diff (rebuild-neutrality). All four new fallbacks carry intentional-silence noqa annotations per the ratchet rule (count now exactly 345/75 — baseline UNCHANGED, ledger honest); spine_language mapped into perception next to spine; store rebuilt so the membership edge and language stamps are in the committed store. 127 tests green incl. the four CI-red surfaces.
2026-10-06 01:22:05 +01:00
Nick c5be22be09 feat(cognition): witness/safety/abstraction kernel delegation + regex_lite faithful-subset rewrite (#2461 W3.4, #2465 adjacency)
The W3.4 kernels existed but the Python publics still ran Python. Now: witness extract_topic/detect_signals delegate through the _stopwords()/_tables() gather seams (PATTERN-TABLE GATHER-SEAM LAW) with _py_ oracles; abstraction extract_facts gains the deterministic kernel FALLBACK when the LLM returns nothing; tier_manager was already wired; the RUNE_COGNITION_CORE=python pin is now honored by a SHARED cc_loader.core() probe (the four module-local probes silently ignored it). The canary matrix caught a REAL kernel bug: regex_lite dropped \b anchors as literal b chars so every word-boundary row silently missed (bwrongb never appears in text); rewritten as alternatives-expansion + segment-variant DFS gap-walk; 34-row matrix judged against REAL Python re shows 0 mismatches. canary_growth_pins 27/27 x5 both engine modes; canary_unbounded 14/14; per-row fixtures carry re-truth, not hand labels (a lying fixture is worse than uncovered).
2026-10-06 00:05:54 +01:00
Nick 6eb5e06119 refactor(spine): carve the #2465 doc-level transforms into spine_language.py (#2461 keep-green)
spine.py crossed the 1200-line giant-file debt cap (1203) with the language-verdict addition — CI lint red. The three transforms (language placement, discovery-ID normalization, contract-discovery write-back + gatherer) move to spine_language.py intact, re-exported through spine for import-compat (structure unchanged: 256 entities, same verdicts; spine battery 87, canaries 19/19 + 21/21, henxels hold, spine.py back to 1034).
2026-10-05 23:53:33 +01:00
Nick 78e4750a77 feat(tier): tier_manager delegates get/promote/demote to the cognition_core kernels (#2461 W3.4 delegation owed)
The kernels and FFI landed in b0a682b but the Python publics still ran Python — the strangler breach this slice owed. Live probe caught the FFI-arg-shape defect: promote/demote take the FULL ENTRY (kernel recomputes current tier internally), not a tier string; passing a string silently returned threshold-default verdicts (promote cold went warm-to-hot WRONGLY via defaults, demote rock went cold ignoring rock protection). 12-case kernel==oracle sweep green: wash>=20, recency hot/warm/cold, naive-timestamp parity trap, rock protection. PY oracle bodies kept; RUNE_COGNITION_CORE=python pins fallback; canary_growth_pins 26/26 both engines; canary_unbounded 14/14.
2026-10-05 23:50:11 +01:00
Nick b8184a0f01 chore(spine): store rebuild carries subsystem language verdicts (#2465) 2026-10-05 23:47:58 +01:00
Nick 469b91f217 feat(spine): subsystem language verdicts from member majority (#2465 addition 3)
The five unassessed subsystems are containers: their language derives from member modules measured sides (classification.json, the W0 dichotomy map, rust and go counts carried in the verdict text). Unclassified members noted rather than guessed; unreadable classification degrades to unassessed. Spine canaries 19/19 and 21/21, spine battery 87 green.
2026-10-05 23:47:55 +01:00
Nick bb960b1656 test(gitea): canary the numeric-ID stale-label removal (#2467)
Replace the obsolete removeLabel(name) pattern assertion with the actual Gitea /labels/{id} request, check ID lookup under the 404 idempotency guard, and require real P0–P3 managed labels. Local canary 39/39; workflow JS regression passes.
2026-10-05 22:22:53 +01:00
Nick 3186566514 fix(gitea): reconcile priority labels by numeric Gitea ID (#2467)
Issue #2467 carried both P0 and P2 because name-based label DELETE returned 404 and the workflow silently ignored it. Use the numeric ID API, enforce exactly one priority, clear stale unprioritized flags, and execute the workflow JavaScript against a Gitea-compatible fake in regression tests.
2026-10-05 22:14:47 +01:00
Nick 24d14ff8e1 fix(spine): preserve candidate discoveries without inventing module IDs (#2465)
Migrate 22 malformed contract-discovery IDs to construction-surface, retain evidence/edges, keep candidates DECLARED, unify cold/warm language projection, and refresh the pinned aiohttp lock. Red regression tests precede the fix; local full suite 2301 passed, spine canaries 19/19 and 21/21.
2026-10-05 22:14:46 +01:00
Nick b0a682b61f feat(cognition): R2 W3.4 — tier/witness/safety/abstraction kernels + protocol upgrade (#2461, #2465)
Contract BUILDER-2026-10-05T12:03:34Z-cli — FIRST SLICE under the 90/100
verification law (64172d8).

Kernels (cognition_core/broker.rs):
- tier_get/promote/demote: thresholds+now injected (no-clock); wash>=20
  gate; rock immobility on demote; naive/malformed → designed fallback
- witness: extract_topic (word-run + stopwords-as-data), detect_signals
  (error/correction/completion/topic-drift/commitment/contradiction/
  preference/urgency/learning; pattern tables travel as data; the regex-
  lite subset is faithful to the tables' shapes)
- safety: get_params projection, update_pattern bump/new-row semantics
- abstraction: extract_facts sentence/content-word projection
- crate-level probe tests (parse_probe.rs: aware parse, epoch, tier recency)

Protocol upgrade (issue #2465) — three additions to the machine itself:
1. PER-CONTRACT MINI-DOC: construction_projection.mini_doc() emits the
   LLM quick-lookup page (what was built / connections / how to update)
   per closed contract; close() writes it to store/scaffold/docs/<cid>.md
2. SPINE WRITE-BACK: spine.build() now consumes closed contracts'
   discovered entities (expected_new_observed + candidate corrections) —
   the spine learns what construction actually built (256 entities now)
3. LANGUAGE VERDICTS: every spine entity carries identities.language
   (198 rust / 31 go / 6 tui / 5 unassessed); other projects get the
   fit assessment at classification

Also: one lost FFI block restored (the stash dance dropped
cc_tier_*/cc_witness_*/cc_safety_*/cc_abstraction_* — the battery
caught it: undefined symbol).

Gates: canary_growth_pins 26/26 x3, persona 18/18, cognition_core
38/38, suite 2299/0, ruff clean, type ratchet PASS, henxels all-hold.
2026-10-05 19:34:05 +01:00
Nick f489467e1b fix(ci): the priority gate's demand is now programmatically satisfied
Nick's catch (2026-10-05): the auto-label bot highlighted that issues
carry priority only in their titles — the PRIORITY GATE job demanded
P0-P3 labels but nothing ever ASSIGNED them programmatically. The title
inference even used a dead label ('priority: high', normalized away
2026-09-04).

- auto-label's priority inference re-implemented in the gate's own
  namespace: title prefix \bP([0-3])\b first, then keyword inference
  (spine/critical/urgent -> P0; broken/fix/repair/defect -> P1;
  kernel/port/refactor/improve -> P2; benchmark/measurement/deferred ->
  P3); managedLabels now carry the REAL P-labels
- paired with the custodian fix: create_issue assigns the P-label at
  FILING (no issue ever lands unprioritized)
- full open-issue set backfilled (2461-2466, 2455/2459) and the live
  probe (#2466, self-verifying) closed after verifying P1 landed
  at filing
2026-10-05 19:05:38 +01:00
Nick 64172d8675 docs(plan): the 90/100 verification law (Nick 2026-10-05)
- 100% branch coverage on the deterministic Rust kernels (achievable,
  exhaustive via parity matrices)
- ≥90% per-slice changed-lines working bar, aiming higher per slice
- floor ratchet climbs after clean waves (70->76->84->90)
- honest fixtures only — a lying-fixture branch is worse than uncovered
- assertion quality counts: value-verifying asserts only
2026-10-05 12:58:18 +01:00
Nick 7a9d823792 feat(cognition): R2 W3.3 kernels in cognition_core (broker.rs: drift_check + identity_prompt assembly + growth near_dup/profile + pins recall/projection)
Missing from the previous commit's staged set (the harness caught it):
the full W3.3 kernel block now lands. All parity walls verified:
canary_growth_pins 9/9, canary_persona 18/18, canary_cognition_core
38/38, suite 2298/0, diff-cover 72%.
2026-10-05 12:50:33 +01:00
Nick 98b5a73ed1 feat(cognition): R2 W3.3 — identity/growth/pins kernels + full coverage (72%)
- identity_anchors: check_drift delegates (pattern table stays the
  module's data authority via _pattern_triples); _py_check_drift oracle
  covers the four prefix families; drift parity proven on the full
  table (31 patterns) + the full-text multi-class case
- growth_delta: _near_dup/growth_profile delegate; oracle accepts delta
  dicts AND raw strings; near-dup kernel corrected to the REAL
  semantics: prof-key = strip-punct lowercase words >4 chars, split at
  |A∩B|/max(|A|,|B|) >= 0.25 (NOT a jaccard-min heuristic)
- pins: recall kernel projects via _project parity (details-blob parse,
  defaults, 'reason' field); empty-context abstention frozen
- probe branches exercised honestly: pinned-fallback + ImportError via
  the from-import resolution path (the from-import goes through the
  package attribute, not sys.modules — the PEP resolution law frozen in
  the battery)
- reflect malformed-JSON + [:3] cap + apply budget cut frozen
- suite 2295/0; diff-cover 72% (floor 70); canaries 9/9+18/18+38/38
  x3; henxels hold; ruff/type clean
2026-10-05 12:50:33 +01:00
Nick 538bbeb821 feat(cognition): R2 W3.2 — persona_gate decision kernels (cognition_core)
Contract BUILDER-2026-10-05T07:19:27Z-cli (Wave 3 slice 2, #2461).

- cognition_core/broker.rs gains the persona-decision kernel:
  persona_lex (distinctive content words: punct strip, light plural
  stem, acronym preservation — 55-word stoplist), persona_overlap
  (intersection over min-size), persona_decide (engagement matrix:
  amplifier set, semantic gates 0.45/0.30/0.68, user-rule 0.4 bar,
  permissive/legacy-restrictive verdicts, _cite parity '[topic:pN] text')
- persona_gate.py: _lex/_overlap/decide delegate; semantic cosines
  gathered Python-side (embedder calls are IO — the membrane's
  discipline) and passed into the kernel; _py_ oracles are the
  load-bearing fallback
- FFI: cc_persona_lex/overlap/decide; loader extended
- canary_persona.py (canary-first red on every seam): 18/18 x3 —
  lex matrix incl. acronyms/3-char exclusions, decide engagement paths,
  citation format parity
- shim battery 35/35; suite 2294/0; ruff clean; type ratchet PASS;
  henxels all-hold
2026-10-05 09:00:43 +01:00
Nick eb01156d9f Merge branch 'master' of http://127.0.0.1:3000/conductor/rune into r2-wave2-memory-retrieval 2026-10-05 08:43:19 +01:00
Nick 290d264f31 feat(cognition): R2 W3.1 — context_broker kernel + the surrogate-pair parser fix across all nine crates
Contract BUILDER-2026-10-05T07:19:27Z-cli, closed: module:context_broker
correctly_predicted; cognition_core expected_new_observed; cc_loader
surfaces honestly new (#2463 wave epic).

- cognition_core crate (zero-dep, no-clock): context_broker's four
  deterministic kernels — default_estimator (chars//4; utf16-length
  corruption caught — the canary's astral cases), default_budget,
  default_memory_budget (+cap), memory_disabled (env gate value-parsed)
- THE PARSER BUG (nine pyjson copies repaired): the surrogate-pair branch
  tested self.b[i+1..] for the second escape's backslash — but hex4 had
  already advanced i past the first escape's 'u+digits', so the correct
  guard window is [i..] not [i+1..]; and after the guard, i advanced +2
  leaving hex4 to read a shifted window ('bad \\u digits' on
  \\ud83c\\udfb8). Fixed: guard at [i..], pre-hex4 advance +1.
  Astral chars (emoji) now parse as ONE code point — char-count parity
  restored everywhere (estimator/chunk/norm)
- context_broker: four functions delegate (load-bearing _py_ oracles);
  the env gate is cross-checked Python-side (Python verdict stays
  authority)
- cc_loader: ctypes shim, CC_RUST_LIB file-form; battery-covered
- CI: crate builds in both jobs, CC_RUST_LIB envs, canary registered

Gates: canary 38/38 x3 + full seven-crate wall green, suite 2293/0,
type ratchet PASS, ruff clean, henxels all-hold, diff-cover 75%.
2026-10-05 08:43:19 +01:00
Nick 1283b0bf94 fix(memory): W2.1 coverage 62->84 + pair-list contract harmonized
- chunk gather + projection now speak the W2.1 pair-list contract
  consistently on BOTH engines (fusion['ranks'] is [[rowid, rrf], ...];
  dict-form still accepted for backward callers)
- oracle-path tests: all three modes, abstention edges, malformed
  timestamps, hybrid accumulation, chunk SQL gather through a real
  fixture (vec-table absent by design; embed stubbed — vector execution
  stays Python per the W2.0 ruling)
- battery 32->32 tests extended; suite 2291/0; canary 75/75 x3;
  diff-cover 84% (floor 70)
2026-10-05 07:51:40 +01:00
Nick 1ee35d76c9 fix(memory): W2.1 coverage + stopword parity + chunk projection kernel
- battery: delegation + projection coverage for the kernel consumers
  (29-test shim battery; CI's 45% was the pre-extension tree)
- chunk projection (chunk_recall tail) moved into the kernel:
  RRF-desc order, text[:400] chars, budget cap, page/room/default
  semantics — canary 75/75 x3
- stopword list AST-extracted exactly (51 words incl. needs/wants/likes)
- memory_store: recall/fused/association/chunk kernels delegate with
  _py_ oracles as load-bearing fallback

Gates: canary 75/75 x3, shim battery 29/29, suite 2286/0, ruff clean,
type ratchet PASS, henxels all-hold. PR 2460 updated with the
propagation evidence line.
2026-10-05 07:20:38 +01:00
Nick e8daf78eaa Merge remote-tracking branch 'gitea/master' into r2-wave2-memory-retrieval 2026-10-05 06:39:03 +01:00
Nick 19976c310c feat(memory): R2 W2.1 — deterministic Rust memory-retrieval kernel (#2458)
Contract BUILDER-2026-10-04T20:10:25Z-cli, closed: memory_store and
memory_selector correctly_predicted; kernel expected_new_observed; shim
surfaces honestly new. Stacked on W2.0 (merged de54453).

- memory_retrieval crate (zero-dep, no-clock, rlib+cdylib+bin): the
  retrieval transform family in ONE kernel surface — map_reduce,
  position_aware, fts_query_conjunctive (51-word stoplist extracted via
  AST, no transcription drift), chunk_text (byte-vs-char law honored),
  norm_key, plus the extracted kernels: rank_fusion (RRF/lexical
  normalization/mode selection), score_recall_rows (metadata blend +
  mode-specific QPP abstention), merge_association_rows (association
  projection), fuse_results (fact/research projection + per-kind
  min-max scale alignment)
- PARITY-PLUS-IMPROVEMENT proven: recall's N+1 (per-candidate entry
  reads + repeated DF probes) ELIMINATED — rows batch through the W2.0
  read boundary once and the kernel runs per retrieval stage
- Parity trap frozen: naive timestamps take Python's designed
  TypeError->recency=1.0 fallback (parse_iso now refuses naive, exactly
  like aware-vs-naive subtraction) — the 34-case matrix caught this
- UTF-8 transport fix: ensure_ascii=True surrogate pairs corrupt astral
  chars (emoji) in char-count semantics — direct UTF-8 transport, frozen
- both _py_ oracles and delegating publics; RUNE_RETRIEVAL_CORE=python
  pins the fallback
- CI: crate builds in both jobs, MR_RUST_LIB envs, canary registered

Gates: canary 72/72 x3, suite 2286/0, type ratchet PASS, ruff clean,
henxels all-hold. Store: 218 entities,
rust-crate:memory_retrieval modeled.
2026-10-05 06:38:57 +01:00
Nick e94c8e27a8 Merge remote-tracking branch 'gitea/master' into r2-wave2-memory-storage 2026-10-04 21:07:54 +01:00
Nick 0816c5997d feat(memory): R2 W2.0 — retain SQLite behind a zero-dep Rust read boundary (#2456)
Contract BUILDER-2026-10-04T15:54:17Z-cli closed: module:memory_store correctly_predicted; memory_storage crate, mems_loader, and canary honestly new.

- memory_storage crate: zero Cargo dependencies; system libsqlite3 FFI; sqlite3_open_v2(SQLITE_OPEN_READONLY) makes writes impossible at the connection level; no write-capable mems_* exports
- typed read parity: INTEGER/FLOAT/TEXT/NULL/BLOB, bound string/numeric/bool/NULL params, aggregates, empty results, unicode, and honest SQLite errors
- mutation SQL is rejected; fixture SHA-256 is identical before/after all reads and the rejected mutation
- memory_store gains an explicit backend seam: stdlib SQLite remains the default; Rust read path is opt-in via RUNE_MEMORY_STORAGE=rust; connection-based transactional callers are untouched
- stats_for_path is the proving consumer; both backends return identical result shape
- canary-first: crate-absent red proven, now 19/19 three consecutive
- CI builds the crate in both jobs, pins MEMS_RUST_LIB, and runs the crate canary; pytest shim battery covers loader/seam lines

Evidence: full suite 2283/0, diff-cover 71% >= 70, type ratchet PASS, ruff clean, henxels all-hold. SQLite is retained exactly as Nick directed; this slice exports no Rust write path.
2026-10-04 21:07:43 +01:00
Nick 0cd587dfd3 Merge branch 'master' of http://127.0.0.1:3000/conductor/rune 2026-10-04 16:52:43 +01:00
Nick 8404cddb1d feat(scaffolding): R2 Wave 1 — the scaffolding engine reborn (Go start / Rust execution)
Contract BUILDER-2026-10-04T15:25:33Z-cli, closed: scaffold,
construction_decision, go-surface:rune-entry correctly_predicted; crate +
shim + canary honestly new. The engine governed its own rebuild.

- scaffold_core crate (zero-dep, no-clock, rlib+cdylib+bin):
  lifecycle.rs (the LEGAL_TRANSITIONS state machine with exact error
  strings — the single authority, terminals derived), close.rs (the
  closure classification — all buckets incl. the dict-literal overwrite
  quirk and legacy aliases), language.rs (Nick's protocol addition: the
  placement verdict — rune dichotomy rule, other-project fit assessment)
- THE PARITY PROOF: all 43 production contracts in the ledger replay to
  IDENTICAL closure verdicts — the new engine reproduces the V1-accepted
  system's real history byte-for-byte
- Go surface: rune scaffold subcommand — pure ops direct to the Rust
  binary over stdio NDJSON (the tranche's first contracted membrane
  junction); store-backed ops proxy to the engine (strangler membrane);
  4 new Go unit tests (stub-binary junction + failure surfacing)
- scaffold.py: bucket math factored to _py_close_quality, consumed by
  close_contract and the replay battery (one computation, two engines)
- construction_decision.py: language_placement in the classification path
- Canary-first: canary_scaffold_core.py red-proven, now 152/152 x3
  (legality matrix 81 pairs, ledger replay, determinism, Go membrane,
  placement matrix incl. delegation agreement)
- CI: crate builds in both jobs, SC_RUST_LIB envs, canary registered

Gates: pytest green (one bridge-flake rerun), canary 152/152 x3, type
ratchet PASS, ruff clean, henxels all-hold (shim battery extended).
Store: 214 entities — rust-crate:scaffold_core modeled.
2026-10-04 16:52:13 +01:00
Nick 6b712a9b75 feat(rebase): R2 Wave 0 — measured inventory + classification + straggler closure
Wave 0.1/0.2: 174 modules, 2,191 functions AST-measured
(store/rebase/inventory.json) and evidence-classified per the dichotomy
law (store/rebase/classification.json — every module carries its import/
content evidence string): GO 43 modules/19,495 lines (reactive,
initiating, network, turn-time), RUST 93/36,215 (deterministic, state,
storage, cognition), TUI-LAST 7/5,438, TEST-INFRA 29/5,395, RETIRES 2
(bootstrap glue). plans/total-rebase-inventory.md is the human-readable
table.

Wave 0.3: the five R1 stragglers (#2171, #2119, #1844, #1755, #1738)
dispositioned with placement evidence and closed — superseded-into-R2,
each folded into its owning wave.
2026-10-04 16:23:55 +01:00
Nick 31f49671ec docs(plan): total-rebase tranche R2 v2 — Nick's six critiques folded in
- parity-plus-improvement rule (parity is the floor, measured improvement
  is in scope, functionality is the gate)
- hybridized Go<->Rust membrane (the no-socket wall withdrawn; junctions
  are contracted, recorded exceptions to the default dichotomy)
- continuous TUI wiring per unit (the TUI wave stays last but integrates
  a system already aimed at it)
- language-placement intelligence in the scaffolding protocol itself
  (rune: the dichotomy rule; other projects: language-fit assessment)
- SQLite RETAINED and wired via system-library FFI (zero-dep legal);
  the bespoke memory redesign deferred to its own later program
- provenance lock: Wave 1 rebuilds the V1-ACCEPTED scaffolding (Nick's
  design, SCAFFOLDING_V1_DEFINITION.md + North Star verbatim), proven by
  production-ledger parity replay
2026-10-04 16:17:32 +01:00
Nick 103a42103b docs(plan): total-rebase tranche R2 — Go initiates and reacts, Rust determines and stores
Designed on the measured inventory (161 modules, 64,482 lines, from the
spine store) per the TRANCHE-DEPTH TEMPLATE. Scaffolding engine first
(Go start / Rust execution, Wave 1) so every later wave is driven by the
new protocol itself; zero-dep law holds with the split doing the work
(Go owns network + reactivity, Rust owns deterministic compute, bespoke
storage engine replaces SQLite in Wave 2); TUI last over the transport
seam; 5 R1 stragglers folded into Wave 0; approval gate before execution.
2026-10-04 16:02:42 +01:00
Nick ee653c6a4c Merge remote-tracking branch 'gitea/master' into phase-g-strangler-evidence-provenance
# Conflicts:
#	requirements-ci.txt
2026-10-04 13:18:54 +01:00
Nick 171f3fb250 fix(tests): close the diff-cover hole — 63% -> 76% on the changed-lines floor
Runs 18367/18369 failed unit-tests on diff-cover (63% < 70%, 338
missing lines) with pytest itself green — the changed-lines floor counts
PYTEST-traced lines only, and three slice surfaces had canary-only
coverage. Battery extension (the shim-battery law applied to my own
slices):
- warm_router: gate branches, finish stack, public score_neuron wrapper
  (designed-fallback determinism), base-level math + gather (hermetic
  via monkeypatched table ensure — STORE_DB resolution is suite-order
  dependent, the order-dependent failure the coverage run exposed)
- tui_transport: InProcess four-method drive, V1 against an in-process
  core, factory modes incl. the bogus-mode ValueError
- token_optimizer: optimize_prompt/get_status/get_cache_stats/flush

CI-exact verification: full coverage suite 2278/0, diff-cover 76%
(floor 70). ruff clean.
2026-10-04 13:09:53 +01:00
Nick 9731181a6b fix(tests): respawn the bridge daemon on mid-test death (root-caused)
The hardening's own diagnostic nailed it (run 18359): the daemon answers
/health at fixture setup, then dies SILENTLY mid-test (alive=False,
out='') on the saturated runner — host shows 20GB swap in use, and a
silent kill with zero output is the memory-pressure signature, not a
race. A retry can never survive a dead process.

Fix: registrations are file-backed under WR_ROOT, so a respawned daemon
resumes the same state — post_event now ensures liveness before each
attempt (respawn on death) and _spawn is the single spawn path (init's
T21.5 fresh-port retry preserved). Bridge suites 19/19, ruff clean.
2026-10-04 12:30:37 +01:00
Nick 544c19719e fix(tests): harden the bridge daemon post_event against load-dependent refusal
Observed 2026-10-04 (runs 18340/18342/18346/18347): the fixture's daemon
answers /health at setup, then a POST lands ECONNREFUSED under runner
load — the twin-failure pattern across two commits while sibling runs
passed. Harness-side hardening per the intermittent-defect law:
post_event retries twice with a beat, and on final failure dumps the
daemon's captured output (alive state + log tail) so the next diagnosis
starts from evidence. Bridge suite 11/11 locally, ruff clean.
2026-10-04 12:18:28 +01:00
Nick d571658b5a fix(ci): register tui_transport in the TUI registry
The tui_panels_are_governed henxel held on the H4 slice-1 surface
(runs 18346/18347): new TUI surfaces ship with a registry entry in the
same PR. Entry added (not-a-surface seam, contract ref, coverage ref).
Local henxels: all hold.
2026-10-04 12:16:23 +01:00
Nick 50c997beab feat(phase-h): H4 slice 1 — TUI transport seam (the migration wave's strangler path)
Contract BUILDER-2026-10-04T10:32:00Z-cli, closed: rune_tui,
go-surface:rune-entry, canary_rune_serve correctly_predicted;
tui_transport + the core_server extension honestly new.

The TUI's operator surface is exactly 4 public calls — this slice puts
them behind one seam so the wave migrates surface-by-surface instead of
rewriting 4k lines of Textual in one go:
- tui_transport.py (new): InProcessTransport (today's behavior,
  DEFAULT via RUNE_TUI_TRANSPORT=inprocess — zero behavior change on
  merge) and V1Transport (stdlib HTTP against the Go front door)
- core_server.py: /v1/conversation + /v1/approvals/resolve — the two
  endpoints the TUI needed beyond H2's set; the Go front passes them
  through (proxy law), H2 battery extended to 28/28 with parity
- rune_tui.py: the 4 call sites route through the seam; the one
  private _task_state peek stays in-process by design (annotated)
- canary_tui_transport.py (new, canary-first red-proven): 9/9 x3 —
  four-method equivalence against the stub core, approval boolean
  round-trips both ways, dead core raises (never a silent empty answer)

Gates: pytest 2270/0, canaries 9/9 + 28/28 x3, type ratchet PASS,
ruff clean. Store rebuilt: 212 entities.
2026-10-04 11:52:38 +01:00
Nick 9e6215e605 fix(ci): henxels holds — intentional mirrors registered + shim-layer pytest battery
Contract BUILDER-2026-10-04T10:29:39Z-cli (successor to 10:20:24Z-cli,
same red evidence run 18322 lint job 51891).

- henxels.yaml: the deliberate-duplicate registry — shared/** (deployed-
  vintage mirror tree), the named src/rune strangler shims, per-crate
  pyjson copies (self-contained zero-dep design), tiny zero-dep
  lockfiles, store/scaffold data, issue-template + completion_file
  mirrors, the interop/rebase-proof fixture
- tests/test_rust_core_shims.py (new, 11/11): the thin pytest battery
  the diff-cover law owed the shim layer — drives the DELEGATION lines
  (loader resolves, envelope unpack, public-vs-fallback agreement) for
  spine_loader, ms_loader, cs_loader, tc_loader, and core_server's
  in-process shapes; skips cleanly on unbuilt crates

Local: henxels all-hold green, battery 11/11.
2026-10-04 11:30:19 +01:00
Nick 6429c5bb49 fix(ci): canary environment repair — runner-HOME rustup path + per-run go binary
Contract BUILDER-2026-10-04T10:20:24Z-cli, closed: all four surfaces
correctly_predicted. Red evidence: run 18322 (4 canary failures).

Two defect classes, both canary-side environment assumptions:
- the Rust-parity canaries resolved the rustup toolchain via
  Path.home() — on the runner that is /var/lib/gitea-desktop-runner,
  which has no toolchain, so cargo fell through to the BROKEN system
  rustc (LLVM_23.1 symbol error). Now the absolute /home/nick path
  (x-ACL covers the runner user) wins, with the home path as fallback
  for other hosts. token_counting gets the same fix preemptively.
- canary_rune_serve built its Go binary to the fixed path
  /tmp/rune-serve-canary — nick owns the local file; the runner cannot
  overwrite it (EACCES). Now a per-run path (-PID).

Verified: all five canaries green locally; runner-HOME simulated
(HOME=/var/lib/gitea-desktop-runner) green for the crate build;
ruff + type ratchet clean.
2026-10-04 11:22:49 +01:00
Nick ea34f2d5ab feat(inference): H3 slice 5 — token counting/compression into the token_counting crate
Contract BUILDER-2026-10-04T09:57:23Z-cli, closed: module:token_optimizer
correctly_predicted; crate + shim + canary honestly new. FINAL H3 domain —
the Phase H plan's back-end port list is now fully delivered.

- token_counting crate (zero-dep, rlib+cdylib+bin): estimate_tokens
  (code points, floor division), compress_context (hand-rolled run
  collapse for 3+ newlines and 2+ spaces — no regex crate; literal
  case-sensitive prefix shortening; unicode strip)
- tc_loader.py: ctypes shim (TC_RUST_LIB file-form)
- token_optimizer.py: estimate_tokens/_compress_context delegate;
  class keeps cache I/O, persona loading, debounce clock
- Repair en route (caught by test_token_optimizer_cache.py): the first
  helper-block placement sat mid-class and swallowed four methods
  (optimize_prompt/get_status/get_cache_stats/flush) into a nested def —
  moved after the class, suite green again
- Canary-first: canary_token_counting.py red-proven, now 26/26 three
  consecutive (unicode code points, emoji, run boundaries, tab-vs-space,
  mid-word prefix non-match, delegation)
- CI: crate builds in both jobs, TC_RUST_LIB envs, canary registered

Gates: pytest 2259/0, canary 26/26 x3, type ratchet PASS, ruff clean.
Store rebuilt through the Rust spine: 211 entities,
rust-crate:token_counting modeled.
2026-10-04 11:18:19 +01:00
Nick 0eff96a335 feat(capability): H3 slice 4 — capability scoring ported to the capability_scoring crate
Contract BUILDER-2026-10-04T09:43:55Z-cli, closed: capability_fit and
capability_broker correctly_predicted; crate + shim + canary honestly new.

- capability_scoring crate (zero-dep, rlib+cdylib+bin): evaluate_fit
  (EXACT/PARTIAL/INCOMPATIBLE/UNKNOWN with exact reason strings,
  unhealthy status join incl. truthy superseded_by, set-math missing
  list), score_card (weights 4.0 name / 3.0 capability / 2.0 examples /
  0.8 description / 0.3 generic penalty / priority bonus)
- wordlists.rs GENERATED from the capability_broker.py literals via AST
  extraction (12 generic caps, 94 stopwords — no transcription drift)
- hand-rolled ASCII word-run scanner replaces re.findall(r'\w+') —
  no regex crate (zero-dep law holds)
- cs_loader.py: ctypes shim (CS_RUST_LIB file-form)
- capability_fit.py / capability_broker.py: _py_ variants as fallback +
  parity oracle, thin delegating publics, RUNE_CAPABILITY_CORE pin
- Canary-first: canary_capability_scoring.py red-proven, now 24/24
  three consecutive (every fit class, every weight branch, stopword
  and generic penalty, delegation)
- CI: crate builds in both jobs, CS_RUST_LIB envs, canary registered

Gates: pytest 2259/0, canary 24/24 x3, type ratchet PASS, ruff clean.
Store rebuilt through the Rust spine: 209 entities,
rust-crate:capability_scoring modeled.
2026-10-04 10:56:10 +01:00
Nick de68444e50 feat(memory): H3 slice 3 — warm_router scoring math into memory_scoring
Contract BUILDER-2026-10-04T09:28:47Z-cli, closed: warm_router and
rust-crate:memory_scoring correctly_predicted.

- warm.rs: score gate (keyword primary gate, semantic secondary gate
  0.55, boost shape, context cap), score finish (importance, b
  contribution, wash boost, cache boost, body-knowledge overlap, fan
  penalty MULTIPLYING before length bonus and protected boost ADD —
  order is load-bearing), ACT-R base-level decay (power-law sum, ln,
  clamp [-2,2], cold -2.0, non-string row -> -0.2 whole call faithful
  to the original's AttributeError-through-outer-catch)
- warm_router.py restructured gather-then-combine: embeddings, SQLite
  use-history, and the cache file are gathered in the wrapper in the
  original's exact reach order — NO base-level or cache I/O on the
  no-fire path (the original early-returns before touching them)
- base_level_activation keeps its SQLite scan; the decay math
  delegates; the outer exception contract (anything -> -2.0) preserved
- Battery extended: 108/108 three consecutive (7 gate branches,
  11 finish stacks, 7 ACT-R cases incl. clamp-high and cold starts)

Gates: pytest 2259/0, canary 108/108 x3, type ratchet PASS, ruff clean.
2026-10-04 10:42:41 +01:00
Nick d58e88da5c feat(memory): H3 slice 2 — drift_compression + drift_cache pure surfaces into memory_scoring
Contract BUILDER-2026-10-04T09:15:51Z-cli, closed: drift_compression,
drift_cache AND rust-crate:memory_scoring correctly_predicted (the
resolver + existing entity made the crate predictable this time);
canary/loader honestly predated the contract.

- compression.rs: ratio table, compress_text (int() truncation,
  Unicode char counts, post-clamp ellipsis compare), entry/warn
  surfaces with exact recommendation strings (em-dashes included)
- cache.rs: compute_priority (raw product, no rounding — faithful),
  qualifies_for_cache admission decision; DriftCache file I/O and
  clock stay Python (zero-dep split law)
- drift_compression.py / drift_cache.py: _py_ variants as fallback +
  parity oracle, thin delegating publics, shared _ms_core seam
- ms_loader.py: 7 new FFI symbols, same segfault-law discipline
- Canary battery extended: 83/83 three consecutive (ratio boundaries,
  text edges incl. unicode, every warn branch, priority grid,
  qualification boundaries)

Gates: pytest 2259/0, canary 83/83 x3, type ratchet PASS, ruff clean.
2026-10-04 10:27:15 +01:00
Nick c730196dba feat(memory): H3 slice 1 — drift_core scoring trio ported to the memory_scoring crate
Contract BUILDER-2026-10-04T08:57:33Z-cli, closed: module:drift_core
correctly_predicted; crate + shim + canary honestly new.

- memory_scoring crate (zero-dep, rlib+cdylib+bin): compute_value with
  now injected (no-clock law — the original reads the wall clock),
  check_promotion_eligibility, pre_commit_gate_entry. Hand-rolled
  ISO-8601 parser (no chrono), banker's rounding via round_ties_even,
  Unicode-aware char counts, Python falsy-coercion semantics preserved
  (0.0 importance -> 0.5)
- Vintage quirk preserved, not fixed: the fourth harmful pattern carries
  uppercase but matches against text.lower() — it can never fire in the
  original, and the parity battery caught my intent-faithful port
  diverging. Behavior fixes belong to their own contract
- ms_loader.py: ctypes shim (FFI segfault law, MS_RUST_LIB file-form)
- drift_core.py: pure trio delegates when the crate is built
  (load-bearing Python fallback; RUNE_MEMORY_CORE=python pins it);
  DB-backed functions stay Python (zero-dep split law);
  signatures made honestly Optional (implicit-Optional ratchet repair)
- Canary-first: canary_memory_scoring.py red-proven crate-absent,
  now 32/32 three consecutive — factor battery, threshold boundaries,
  every critic branch, edge inputs, public-API delegation
- CI: crate builds in both jobs, MS_RUST_LIB envs, canary registered

Gates: pytest 2259/0, canary 32/32 x3, type ratchet PASS, ruff clean.
Store rebuilt through the Rust spine: 207 entities,
rust-crate:memory_scoring + module:canary_memory_scoring modeled.
2026-10-04 10:14:36 +01:00
Nick c750513fab feat(phase-h): H2 Go front door — /v1 surface with NDJSON streaming + parity battery
Contract BUILDER-2026-10-04T08:32:43Z-cli, closed: go-surface:rune-entry
and workflow:ci.yml correctly_predicted; core_server + canary honestly
new (unresolvable at submit time).

- core_server.py (new): stdlib sidecar over the operator surface —
  GET /v1/models, GET /v1/status, POST /v1/chat/completions with NDJSON
  streaming; one error envelope shape across every failure path;
  injectable operator (the canary drives a deterministic stub via the
  established _execute_on_model seam — no live model calls)
- serve.go (new): rune serve subcommand — Go owns the front door
  (stdlib net/http only), byte-pass-through proxy to the core,
  locally-generated error envelopes byte-matching the core's shape,
  core-down 502 core_unavailable
- canary-first: canary_rune_serve.py fired red (module absent), now
  22/22 three consecutive — Python shape freeze, cross-language parity
  modulo volatile (id/created), NDJSON line-sequence equality,
  core-down honesty on both sides
- Go unit tests 6 → 11 (help/flag exits, 404 + 502 envelopes,
  byte-for-byte proxy pass-through); vet clean
- CI: canary registered; go-surface job covers serve.go module-wide

Gates: pytest 2259/0, canary 22/22 x3, type ratchet PASS
(cast-narrowed stdlib override, zero ignores), ruff clean.
2026-10-04 09:55:16 +01:00
Nick 27c4bf8d78 feat(spine): H3-spine — spine projection machinery ported to a zero-dep Rust crate
Contract BUILDER-2026-10-04T07:19:36Z-cli, closed: module:spine
correctly_predicted; crate + loader + canary + CI wiring honestly new
(unresolvable at submit time — they are the delivery).
Nick directives: 'rebuild the spine in rust' + 'add scaffolding to the
rust conversion' — this is both, through the full pipeline.

Rust core (src/rust/rune_spine/, zero-dep, rlib+cdylib+bin):
- pyjson.rs: Python-parity JSON (reused from evidence_provenance)
- store.rs: doc semantics — high-water add_entity, dedup add_relationship
  with CANDIDATE guard, authority observation + reconcile, resolve_status,
  impact_frontier with the obligation semantics tables
- project.rs: full build() projection — carry-forward, manifest ingest
  with generated-view refusal, module re-derivation, deployed observation,
  meta-surface projection (rust-crate/go-surface/config/workflow)
- drift.rs + query.rs: drift classification, query, export_umbrellas
- FFI: single-arg JSON envelopes, sp_free_string; no-clock law (now is
  always an argument)

Zero-dep split law: every filesystem scan stays in spine.py
(_gather_build_inputs/_gather_drift_inputs); both cores consume the same
gathered dict, so parity divergence is logic, never environment.
spine_loader.py: ctypes shim (argtypes+restype per the FFI segfault law,
SP_RUST_LIB file-form override, load-bearing Python fallback).
The unseeded Phase A path stays on the Python core — the public
ingest_umbrellas seam is monkeypatched by isolation tests.

Parity battery (canary-first, red-proven crate-absent):
canary_spine_rust.py 21/21 — drift, 10 query entities, export, seeded
build, unseeded ingest, plus a carry-forward mask guard (asserts the
Rust projection models declared surfaces directly — caught the
config_manifest wiring bug the structural diff could not).

Gates: pytest 2259/0, canary_spine_meta 19/19 x2 through the Rust path,
type ratchet PASS, ruff clean, diff-cover 84% >= 70.
CI: crate builds in both jobs, SP_RUST_LIB pinned, canary registered.
Store rebuilt through the Rust core itself: 204 entities,
rust-crate:rune_spine modeled (self-hosting meta-scaffold).
2026-10-04 09:26:01 +01:00
Nick 5b8023ca2a docs(scaffolding): T4.7 reassessment matrix — all tranche rows correctly_predicted
Successor closures against the H-meta-modeled spine with the repaired
resolver (57eaa8f):
- row 1 v2 slice-1 query_memory: 3/3 (BUILDER-2026-10-04T07:17:13Z-cli)
- row 2 slice-2 evidence_provenance six ports: 9/9 (07:17:15Z-cli)
- row 3 H1 Go first-call shim: 4/4 (07:17:17Z-cli)

Every delivered tranche surface now audits clean against the spine it
lives in. Matrix complete; T4.7 done.
2026-10-04 08:17:40 +01:00
Nick 57eaa8f383 fix(scaffolding): contract scope resolver recognizes H-meta entity kinds
Contract BUILDER-2026-10-04T07:14:03Z-cli, closed: module:construction_decision
correctly_predicted, zero genuinely_unexpected_new.

T4.7 row-1 closure flagged rust-crate:query_memory resolving as
kind=unresolved — classify_surface's prefix set predated the H-meta
entity classes (rust-crate:/go-surface:/config:/workflow:), so
spine-modeled surfaces could never close correctly_predicted.

Red-first: test_hmeta_kind_prefixes_classify_as_structural_entity
failed pre-fix; identity-resolution path needed no change (works for
any id present in an authority). Regression frozen in
test_construction_decision.py (2 new tests, 21/21 file green,
decision neighborhood 107/107).
2026-10-04 08:16:38 +01:00
Nick 567fd39937 feat(spine): H-meta meta-scaffold — every part of rune modeled as a spine entity
Contract BUILDER-2026-10-04T06:24:56Z-cli, closed: module:spine
correctly_predicted; six new entity surfaces honestly unmodelable at
submit time (they are the delivery).

- spine.py: project_meta_surfaces() in the seeded derivation path
  (build step 4) — rust-crate, go-surface, config, and workflow entity
  classes with belongs_to edges; crate-resident canary scan projects
  obligated_canary edges from the owning crate
- config/umbrellas.json: declared rust_crates, go_surfaces, configs;
  canary registrations for audit_ledger, rune_entry, spine_meta
- canary_spine_meta.py (new, canary-first: 14 red proven): entity
  existence/kind checks, canary modeling + edges, determinism, and
  open-world carry-forward — 19/19 five consecutive runs
- determinism contract made honest: structural equality (deep
  timestamp strip incl. last_success + observation set-dedup), not
  clock equality — the per-build deployed_identity observation ticks
  by design
- test_structural_store: schema gate admits the new entity kinds
- ci.yml: canary_spine_meta registered in the canary loop

Gates: umbrella/henxels/structural 32/32, full pytest 2257/0.
2026-10-04 08:09:40 +01:00
Nick 817a97abd9 feat(phase-h): H1 Go first-call shim — delivered under construction contract BUILDER-2026-10-04T05:25:57Z-cli
Scaffolding-first rebuild of the reverted ad-hoc attempt (1e6cb4d), per
Nick's 2026-10-04 directive that all coding replacements run through the
construction pipeline:

- Need submitted with acceptance criteria + constraints (zero-dep Go,
  pinned toolchain, canaries-first); resolution REUSE, approval covered
  by Nick's Go-frontend directive; contract generated and approved.
- CANARY LANDED FIRST (canary_rune_entry.py restored; module absent ->
  canary red proves ordering), then the module restored from the reverted
  reference and the canary went 12/12 green.
- Contract lifecycle driven to close: observe -> verifying -> close.
  Closure verdict (honest): all four delivered surfaces land in
  genuinely_unexpected_new — the spine/structural registry does not model
  the new Go surface, the canary, the pin file, or the workflow yet. That
  IS the coverage signal the closure exists to emit; the spine-modeling
  gap is now a recorded follow-up across H-wave deliveries.

Retrofit closures also completed under the same directive:
- Slice 2 (evidence-provenance): BUILDER-2026-10-04T05:23:17Z-cli — all
  six ported modules correctly_predicted; crate + canaries + shim battery
  honestly unmodeled.
- Slice 1 (query-memory): BUILDER-2026-10-04T05:24:11Z-cli —
  module:query_memory correctly_predicted; crate + canaries unmodeled.
- BUILDER-2026-10-04T05:14:20Z-cli (v1) and ...:18:52Z (v2) stand as
  labeled learning artifacts (entity-vocabulary mismatch).

go test 6/6, go vet clean, canary 12/12 (desktop + bare-HOME CI sim),
henxels exit 0, pin check PASS.
2026-10-04 06:28:51 +01:00
Nick 1e6cb4d1ba revert(phase-h): withdraw ad-hoc H1 shim + enablement — will be rebuilt through the scaffolding construction pipeline
Nick directive 2026-10-04: all coding replacements must be done via the
scaffolding construction pipeline (construction_decision -> normalization
-> discovery/fit/resolution -> toolchain -> layout obligations -> approval
gate -> durable trace -> generated contract -> canaries-first ->
implementation -> verification -> delivery record). The H1 Go shim was
built ad-hoc; this reverts it (and the H0 CI surface) for a proper
rebuild. The scaffolding run that replaces it follows as its own
construction contract.
2026-10-04 06:11:20 +01:00
Nick 4e11aa4268 fix(ci): go pin check strips the distro build-experiment suffix
CachyOS ships go 1.27.1-X:nodwarf5 (an LLVM build experiment flag). The
pin compares the RELEASE (1.27.1), not the suffix — same pin law, honest
comparison. Verified locally before push this time.
2026-10-04 05:59:05 +01:00
Nick 1703c25367 feat(phase-h): H0+H1 — Go toolchain enablement and the first-call shim
H0 (enablement, per plan 2026-10-04-phase-h-go-frontend-rust-backend.md):
- Go 1.27.1 installed (pacman, world-readable — runner user verified).
- go-version.txt pins the toolchain; the go-surface CI job fails loud on
  drift instead of letting a distro upgrade change behavior downstream.
- go-surface job: vet + test + build, runs on the rune-ci-desktop label.

H1 (first-call shim, Go owns the front end per Nick's USER-LOCKED directive):
- src/go/rune-entry: the 'rune' binary replicates the DEPLOYED bash
  launcher's exact contract — cd /mnt/workdrive/rune-code/current/src,
  RUNE_HOME/RUNE_MEMORY_DIR/MIMO_PROBE_ENABLED env (explicit ambient
  overrides win), exec handoff to the memory-venv python -m rune with
  args/signals/exit codes passing through 1:1. Falls back to the dev
  checkout when the deployed revision is absent, and to PATH python3 when
  the venv is absent (CI sandboxes).
- Flags: --version (deployed pyproject), --python-only (resolved handoff),
  --help (exit 0), unknown flag (usage on stderr, exit 2).
- canary_rune_entry.py: 12 checks — builds the module in a temp dir
  (zero-dep, system Go), verifies the version surface, the handoff shape,
  flag discipline, the Go unit battery (6 tests), and go vet. Green on the
  desktop AND under a bare-HOME CI simulation (the fallback expectation is
  asserted honestly, not fudged).
- Registered in the canary suite loop (henxels exit 0).

Observed-not-invented: the launcher contract comes from ~/.local/bin/rune;
the version from the deployed pyproject (0.89.0 at this commit).
2026-10-04 05:52:43 +01:00
Nick e93315d156 fix(ci): same label correction on the branch (rune-desktop -> rune-ci-desktop) 2026-10-04 05:09:54 +01:00
Nick be49fb32d1 fix(ci): retargeted jobs must use the runner LABEL rune-ci-desktop, not the runner name
Correction to 1462262: act_runner matches jobs by runner LABELS. The only
registered runner (rune-desktop on gitea-desktop-runner) carries the label
'rune-ci-desktop:host' — 'rune-desktop' is the runner's NAME, which matches
nothing. All 8 retargeted jobs queued forever (runs 18197/18203/18211
stuck exactly this way) while ci.yml jobs (which use the correct label)
drained normally. rune-desktop -> rune-ci-desktop in all 8 spots.
2026-10-04 05:09:53 +01:00
Nick c41ed97373 docs(plan): phase H — Go front end / Rust back end (Nick's USER-LOCKED directive)
Directive supersedes KEEP-PYTHON rubric verdicts. Plan scopes:
- Go: runtime entry (rune binary), CLI/IPC first-call dispatch, /v1
  endpoint surface (the rubric's one capability-proven Go fit: stdlib
  net/http + NDJSON streaming). TUI deferred to its own wave (H4).
- Rust: remaining pure-logic back-end modules (drift_*, warm_router
  scoring, memory_store helpers, capability scoring, token counting)
  into zero-dep crates, each port running the full slice-2 pipeline.
- Honest constraints carried: network code never in crates; SQLite/regex/
  IO stay at language edges; every surface gets observed-byte-parity proof.

Sequenced H0 (enablement: install Go, CI Go job) -> H1 (first-call shim)
-> H2 (dispatch + /v1) -> H3 (back-end ports) -> H4 (TUI wave).
2026-10-04 04:47:40 +01:00
Nick 558401844e fix(release): TUI footer version + drift gate now covers the footer pattern
Master CI unit-tests failure (run 18195): rune_tui.py:1888's footer said
'Rune v0.88.4' while __version__ is 0.89.0. Root cause in the auto-version
push-to-master bump: its replace pairs cover the footer, but the drift
GATE's regex checks only covered the Version: header. When RELEASE_VERSION
was stale, both replaces no-opped; the gate's RECOVER regex force-fixed
the header (first-match re.sub) and the footer passed through unchecked —
the exact half-bump shape seen in 396ae12.

- rune_tui.py footer -> Rune v0.89.0 (fixes test_tui_banner_uses_the_reviewed_release_version)
- auto-version.yml: gate checks add the footer regex ('Rune v({VER}) \|'),
  so future footer drift triggers the same RECOVER path as the header.
2026-10-04 04:34:05 +01:00
Nick 26e4929b10 chore(deps): re-resolve ci lock — markupsafe 3.0.4, platformdirs 4.12.3, websockets 17.2 (master catches up to the strangler branch's regen) 2026-10-04 03:16:27 +01:00
Nick 1462262476 fix(ci): retarget 8 jobs from dead rune-infra-pi label to rune-desktop (master)
Same fix as 0bf4726 on the strangler branch, applied directly to master:
queued workflow runs resolve their workflow definition from the DEFAULT
branch, so the strangler-branch commit alone could not drain stuck runs
18178 (auto-label on a PR) and 18183 (auto-label on an issue). This is
the landing spot. 8 occurrences across 5 workflows retargeted.
2026-10-04 03:01:40 +01:00
Nick 0bf47265c8 fix(ci): retarget 8 jobs from dead rune-infra-pi label to live rune-desktop runner
New submissions (issues/PRs) were stuck queued forever: auto-label.yml's
priority-gate + demand-comment jobs declared runs-on: rune-infra-pi, a
runner that no longer exists anywhere (registration list shows only
rune-desktop on gitea-desktop-runner). Every issue or PR filed since the
label went dark sat unprocessed — which is exactly the 'new submissions
not working' symptom.

Retargeted (sed, 8 occurrences across 4 workflows):
- auto-label.yml (2): priority gate, demand comment
- auto-backup.yml (1), auto-update-gitea.yml (1), auto-version.yml (1)
- maintenance.yml (5)

Verified live: probe issue + probe PR + probe branch all created AND
processed successfully through the API (submissions themselves work; it
was the responder workflows that were orphaned). Probe artifacts cleaned
up. The stuck queued runs 18178/18183 will drain once this lands.
2026-10-04 02:49:13 +01:00
Nick 02a9dc4a31 fix(ci): rust toolchain law — healthy rustup toolchain, runner-owned target, EP_RUST_LIB wiring
CI cargo build failed twice (runs 18169/18170): the SYSTEM rustc is broken
on this host at the packaging level — pacman rust 1:1.99.0-1's
librustc_driver.so has 638 undefined symbols versioned LLVM_23.1, and
/usr/lib/libLLVM.so.23.1 does not define narrow-char std::string::_M_mutate
under that node (it exports _M_create/_M_assign there; only the wide-char
_M_mutate carries the version). Every compile dies with a symbol-lookup
error while cargo --version prints fine — a silent-broken build host.

Fix (all local, no system changes):
- PATH points at /home/nick/.rustup/toolchains/stable.../bin FIRST — that
  toolchain is healthy and ships its own libLLVM. The ordering matters: via
  RUSTUP_TOOLCHAIN (shim-based), rustup would exec the broken system rustc.
  /home/nick already carries the x-ACL for gitea-desktop-runner (proven:
  runner-user build succeeds, 0.95s, zero-dep crate).
- CARGO_TARGET_DIR is a runner-owned /tmp dir (the repo's target/ is
  nick-owned; publish-by-copy into it failed with EACCES). No copy step at
  all now: ep_loader + the canary resolve artifacts via EP_RUST_LIB (file
  path form — the loader's override takes a FILE; set in both jobs' env).
- unit-tests job gains the same env block as canary (RUNE_HOME/
  RUNE_MEMORY_DIR/EP_RUST_LIB) so the shim battery's cdylib load and the
  isolation law hold in CI exactly as locally.
- Python canary resolves _BIN next to the EP_RUST_LIB file (binary and
  cdylib are siblings in the release dir; desktop keeps the repo-relative
  default).

Verified locally: runner-user build + EP_RUST_LIB file-form through BOTH
canaries (74/74, 66/66) and the shim battery (7/7); desktop default path
re-verified after artifact restoration (deps/ hardlinks were never lost —
an earlier publish test's rm removed the top-level copies; restored from
deps/).
2026-10-04 02:17:44 +01:00
Nick 0f3aeff58b fix(ci): diff-cover ratchet + canary artifact coupling — shim battery, crate build in CI
diff-cover 70% floor (run 18164's unit-tests failure):
- The floor counts CHANGED lines covered by pytest only. The strangler's
  verification moved the six ported shims to canaries/parities (outside
  pytest), so 46% of slice-2's changed lines were pytest-covered and the
  gate red-lined the port itself.
- tests/test_evidence_provenance_shims.py: a six-test shim battery driving
  the delegation surfaces the port changed (verification_layer dispatch +
  seven wrappers, evidence_probe schema/budget, behaviour_ledger state
  machine incl. accept_limitation + reload round-trip, behavior decision
  math on an isolated db, claim_audit scan->verify->degrade->journal->
  report pipeline, audit_ledger append->verify->read on the isolated
  ledger). Isolation law documented in the module docstring: RUNE_HOME/
  RUNE_MEMORY_DIR pinned before import (both resolve paths at import);
  behavior/claim_audit are imported by no other test file.
- save() finding: mutators never auto-persist in EITHER vintage (verified
  against the pre-port module) — the round-trip test calls save().
- .coveragerc omits ffi_query_memory_smoke.py (= the canary precedent:
  standalone evidence script, never suite-imported).
- Result replicated locally against gitea/master: 116 diff lines, 87%
  (floor 70), exit 0.

Canary job now builds the crate (run 18164's canary failure):
- Until 18164 the job silently relied on the host executor seeing the
  desktop's prebuilt target/ — my checkout-relative BIN made that visible
  as an uncaught Popen FileNotFoundError (§5 crash before finishing).
- ci.yml gains cargo build --release for the zero-dep crate (system cargo,
  world-readable on the runner; no registry fetch).
- §5 fails loud-but-counted (FAIL test, not a crash) when the artifact is
  missing, with the regression meaning spelled out.

Local wall: pytest 2257/0; canaries 74+66 both modes; lint 345/75 PASS;
type ratchet PASS under the pinned instrument; henxels exit 0; umbrella
gate exit 0; dep-lock in sync.
2026-10-04 02:08:29 +01:00
Nick ff2abcd502 fix(ci): run-18161 follow-through — mode detection, plan kebab-case, smoke coverage, deterministic type instrument
Canary mode detection (the real 18161 defect):
- isfile() is not a valid LIVE/ISOLATED discriminator: run 18141's shim
  writes left a zombie 1-entry ledger in the runner's persistent HOME, which
  flipped the naive gate to LIVE with wrong data. The discriminator is now
  the repo's own CI-sandbox convention (RUNE_HOME=/tmp/rune-ci-<id> — the
  workflow's own cleanup guard matches exactly that).
- The isolated battery seeds a PER-RUN temp ledger (module-attr override on
  the shim's LEDGER_FILE) instead of writing the runner's persistent home;
  binary §5 gets HOME=<temp> so binary and shim resolve the same file.
  Both modes: 74/74 locally and under simulated runner topology (zombie
  ledger present, RUNE_HOME set). Rust canary §4 gets the same dual-mode
  treatment.

Henxels holds cleared:
- plans/: three phase-g files renamed to kebab-case; references updated in
  lib.rs, ep_loader.py, canary docstring, Cargo.toml, supersession ledger.
- ffi_query_memory_smoke coverage: smoke repaired (was stranded — imported
  the deleted src/rune vintage; now drives shared/ shim, 41/41 green) and
  tests/test_ffi_query_memory_smoke.py runs it, skipping honestly when the
  cdylib isn't built (CI has no cargo step).

Type ratchet — instrument repair (§16V), not reading-management:
- scripts/type_check_ratchet.py now pins pyright --pythonpath to the
  INVOKING interpreter. Ambient-interpreter dependency resolution was the
  residual non-determinism: runner (py311, no rich/Pillow) vs desktop (3.14
  system site) produced 460 vs 454 on the identical tree, and any import
  ignore flipped to unnecessary-ignore in the other environment.
- pyrightconfig extraPaths now covers src/rune + shared + both crate dirs
  (bare intra-repo imports resolve under the pinned environment).
- Pillow declared in pyproject (genuine lazy dep of the diamond-frames
  surface; was undeclared) — lock regenerated, dep-lock checker green.
- Measured under the pinned instrument: 115 errors / 439 warnings
  (CI-equivalent locked 3.11 venv) and 115/436 (local 3.14 venv) — both
  below the 117/454 baseline; baseline unchanged. My canary's 4
  reportOptionalSubscript errors fixed by real narrowing, not suppression.

Lint baseline: BLE001 346 -> 345 (bulk_issue_guard.py's retry catch gains a
reasoned noqa; the file stays untracked per checkpoint hygiene, but the
honest-ledger test counts disk state — the noqa keeps local == CI).

Local wall: full pytest 2251/0 (incl. the new smoke test); canaries 74+66
both modes; parities 33/24/13/16/17; henxels exit 0; umbrella gate exit 0;
dep-lock green.
2026-10-04 01:08:20 +01:00
Nick b61af7a526 fix(ci): slice-2 canary completeness + gate repair — dual-mode canary law, ports 3-6 sections
Canary completeness (contract §5/§10 — owed at slice end):
- canary_audit_ledger.py 34 -> 74 checks: port-3 (evidence_probe schema gate
  + budget count + ProbeBudgetExceeded), port-4 (behaviour_ledger state
  machine: define/record/invalidate/outstanding/summary/history + byte-exact
  error envelopes), port-5 (behavior decision math through the shim on an
  isolated RUNE_HOME db: correction/habit math, promotion, not-found shapes),
  port-6 (claim_audit full pipeline on an isolated journal: scan/scan_text/
  audit/report + verify + stoplist wiring).
- canary_evidence_provenance_rust.py 28 -> 66 checks: the same four ports
  driven through the cdylib FFI (ep_validate_probe, ep_bl_*, ep_habit_/
  ep_correction_reinforce, ep_ca_* batteries).

Dual-mode canary law (repairs run 18141's red):
- Live-ledger pins (entries floor, live read/list shapes) fire only when the
  live promotion ledger exists in this process's HOME; under CI's sandboxed
  HOME the same sections run an isolated battery (shim-seeded entries,
  FFI-built chain) — identical check count, honest MODE print. The law and
  the artifact coupling are documented in both canary docstrings.
- Ghost-divergence repair: the Rust binary honors RUNE_MEMORY_DIR/RUNE_HOME
  first (main.rs ledger_path) while the deployed shim resolves expanduser
  (HOME); §5 binary envs now strip RUNE_* so both surfaces resolve the same
  ledger in every environment.
- §10 pins RUNE_MEMORY_DIR alongside RUNE_HOME (memory_dir() honors the
  former first).

Gate debt exposed by 18141's failure profile (pre-existing, now closed):
- config/umbrellas.json: ffi_query_memory_smoke mapped to the memory
  umbrella (owed since 43e7f5f; umbrella gate green in push mode).
- requirements-ci.txt regenerated: markupsafe 3.0.3 -> 3.0.4,
  websockets 17.1 -> 17.2 (checker green).
- lint-baseline.json BLE001 347 -> 346: claim_audit silent handlers
  repaired with exc_info logging + reasoned noqa (deliberate-silence sites
  only); canary battery handlers carry the canary-law reason. S110 holds.
- type ratchet green at 107/454 (local pyright pinned to CI's 1.1.414;
  isinstance runtime-shape checks carry scoped ignores; ep_loader imports
  annotated as runtime-by-design).
- store/scaffold + spine snapshots travel with the change (as at 2ac2d0a);
  supersession ledger canary rows updated to the true final counts.

Full local wall: 5 parity harnesses 33+24+13+16+17 all green; both canaries
green in LIVE and ISOLATED modes; consumer import chains (iteration,
testing_mode, rune_operator, contracts, curator + deployed shims) green;
live chain intact through the deployed shim; pytest suite 2250 passed/0.
2026-10-04 00:32:28 +01:00
Nick 497d14a449 ci: register canary_audit_ledger in the canary suite loop
The henxels contract requires every src/rune/canary_*.py on disk to be
registered in the CI canary loop (gap #138's rule is per-canary). The
slice-2 canary (port 1, canary pair carrier, 34 checks) was added with
the port but its registration was missed — the contract test caught it
live. Registered in the slice-1 position (after canary_query_memory,
the strangler-adjacent grouping).
2026-10-03 16:25:52 +01:00
Nick 2e68b6b054 phase-g slice 2: supersession ledger + registry remap + shared deletion
- plans/2026-10-03-phaseG-evidence-provenance-supersession.md: the
  slice-level ledger — port table (6/6, commits + parity + consumer
  proof), 12-step doctrine discharge, vintage-merge disclosures
  (symmetry guard, scan_text repair, port-1 sequence break), consumer
  map, live-data rules honored.
- shared/audit_ledger.py DELETED (superseded; zero importers verified
  by sweep; deployed shim + Rust core proven live before removal —
  language-governance rule ⑥).
- coverage registry: audit_ledger removed from SHARED_D.
- regression gate: exit 0 pre- and post-deletion.
2026-10-03 16:20:08 +01:00
Nick 969e39f6a3 phase-g slice 2 port 6: claim_audit decision skeleton -> rust core (parity 17/17)
- claims.rs: the verify() verdict tree (comparative-no-anchor gate,
  ledger-hits PASS, DEGRADE tails), report aggregation (total/by_verdict/
  by_type with '?' defaults), the clean fold, evidence-term stoplist.
  Regex engine + I/O stay Python (zero-dep crate law); timestamps Python.
- ep_ca_verify_gate / ep_ca_audit_clean / ep_ca_report_aggregate /
  ep_ca_evidence_terms FFI + ep_loader wrappers (restype law).
- claim_audit.py is now a shim, BOTH copies (src/rune + deployed):
  verify() delegates the tree + term filtering; report() / clean fold
  delegate; regex machinery (scan/reframe/degrade/EVIDENCE_TAG) + journal
  I/O + runner stay Python.
- VINTAGE MERGE (disclosed): the deployed scripts vintage carried the
  SYMMETRY GUARD (research_lens.symmetry_check, 2026-08-15) which src/rune
  lacked — preserved (load-bearing behavior, feature-preserving merge).
- REPAIRED a dead consumer: rune_tui.py:3752 calls claim_audit.scan_text()
  expecting {degraded, claims, clean} — NO implementation existed in either
  vintage (silent try/except death since the call landed). scan_text() is
  now a first-class surface; verified live (returns the exact dict shape).
- parity_claim.py: 17-case battery — verify tree 12 (flags derived the
  same way the original derives them: original verify() vs gate FFI),
  report aggregate over a real-shaped journal (incl. '?' fallback rows),
  clean fold 3, stoplist filter — 17/17 GREEN pre-switch vs original.
- deployed shim live: real journal (1127 rows, 851 DEGRADE / 276 PASS)
  aggregates through the Rust core; TUI backend trio imports clean.
2026-10-03 16:19:12 +01:00
Nick 273267763e phase-g slice 2 port 5: behavior decision math -> rust core (parity 16/16)
- habitmath.rs: the reinforce decision math — habit (activation/success/
  failure counting, confidence min(1.0, 0.5 + rate*0.5), candidate→active
  promotion at min_activations, neutral still counts activation) and
  correction (success +0.1 / failure −0.3 with ceilings/floors, evidence
  counting, active/archived at 0.3). STORAGE STAYS PYTHON — SQLite I/O
  and regex matching remain in the module (the crate is zero-dep by
  design; hand-rolling SQLite/regex would be hubris, not hardening).
  No clock in the core — timestamps pinned by the shim.
- ep_habit_reinforce / ep_correction_reinforce FFI + ep_loader wrappers.
- behavior.py is now a shim: reinforce() fetches the row, delegates the
  math, writes the update back; add/match/list/stats/CLI unchanged.
- parity_behavior.py: 12 decision-math cases (outcome × state × boundary:
  promotion-at-min, floors, ceilings, neutral, archive-threshold) with
  SEMANTIC comparison (parse-then-compare — the 1.0-vs-1 render delta is
  serialization, not semantics) + full-stack live-db scenarios both sides
  (promotion observed, activations logged) — 16/16 GREEN.
- deployed ~/.config/opencode/scripts/behavior.py upgraded to the same
  shim shape (vintage upgrade per contract §2) pointing at the LIVE db
  (~/.config/opencode/memory/behavior.db, 2 corrections / 1 habit,
  untouched); read paths verified against the live db (stats + match).
  Pre-deploy backup: /tmp/behavior_deployed_pre_port5.bak.
2026-10-03 16:01:52 +01:00
Nick 8973caae77 phase-g slice 2 port 4: behaviour_ledger -> rust core (parity 13/13)
- behaviour.rs: the full state machine — define (normalize/dup-check),
  transitions with history append (at/from/to/kind/detail[:200]/gen),
  record_auto_verification (ceiling AUTO_VERIFIED), record_real_world
  (USER_CONFIRMED iff passed && confirmed_by==user), accept_limitation,
  invalidate_for_change (CONFIRMED_STATES-only, deps ∩ closure + owner
  hit, default reason 'structural change touched: [...]' Python list
  repr sorted, reasons override, unrelated preserved), retest_history,
  outstanding (TEST_FAILED-first sort), summary. Timestamps passed IN
  (now) — no clock in the core, parity deterministic.
- FFI: doc-in/doc-out convention with {ok, err} envelope — err raises
  ValueError with the exact Python message (duplicate/unknown-behaviour/
  unknown-state all byte-equal). Read paths: ep_bl_get/retest_history/
  outstanding/summary.
- behaviour_ledger.py is now a shim: file glue (load/save) + constants
  stay Python; every state-machine op delegates via the doc envelope.
- parity_behaviour.py: full-scenario battery (3 behaviours, auto+real-
  world+other-confirm, selective invalidation with reasons override +
  owner hit, filters, error messages, save render indent=1 sort_keys)
  — byte-equal docs, 13/13 GREEN pre-switch (vs original) and
  post-switch (round-trip).
- consumers verified: iteration.py:23, testing_mode.py:19 (constants at
  import), rune_tui.py:3152 (lazy) — import chains green.
2026-10-03 15:59:14 +01:00
Nick 3450a1cb83 phase-g slice 2 port 3: evidence_probe -> rust core (parity 24/24)
- probe.rs: validate_probe schema gate + count_probes budget count,
  byte-parity on every error string incl. Python repr rendering:
  {status!r} single-quote escaping, sorted-list ['a', 'b'] shapes,
  non-string-status double-error (field error + membership error —
  Python runs the membership check on the RAW value), GROUNDED source
  >= 8, extra-fields sorted, field-order iteration.
- ep_validate_probe + ep_count_probes FFI; ep_loader wrappers with
  restype declarations (the segfault law holds: every new ep_* symbol
  gets argtypes+restype).
- evidence_probe.py is now a shim: validate_probe + count_probes
  delegate to the Rust core; run_probe orchestration (runner subprocess,
  exception semantics, budget enforcement, record_probe) stays Python.
- parity_probe.py: 24-case battery (17 schema-gate shapes incl. the
  non-string status trap, 3 non-dict top levels, 4 count_probes file
  shapes) byte-equal through FFI; GREEN pre-switch (vs original) and
  post-switch (round-trip).
- consumers verified: rune_operator.py:581/603 (run_probe), failure_
  recovery.py (budget map), research_stage_executor.py:312 (run_probe +
  MAX_PROBES_PER_TASK + ProbeBudgetExceeded) — all 23 sibling tests
  green through the shim.
2026-10-03 15:54:38 +01:00
Nick 9cb93e6573 phase-g slice 2 port 2: verification_layer -> rust core (parity 33/33)
- verification.rs: all seven verifiers + dispatch, to_dict shape
  byte-parity (key order passed/verifier_type/evidence_refs/failures/
  retryable/escalation_reason), Python str() rendering rules (bool ->
  True/False in evidence_refs — exit_code=False renders False not 0),
  Python == 0 semantics (bool/int cross-compare), default-value guards.
- ep_verify FFI + ep_loader.verify wrapper; verification_layer.py is now
  a shim (dataclass stays Python — rune_operator:323 constructs it
  directly; verify_* delegate to the Rust core and reconstruct).
- parity_verification.py: 33-case battery (7 verifiers, pass/fail/edge/
  default/unknown) byte-equal through the FFI, incl. CLI indent=2 render;
  GREEN pre-switch (vs original) and post-switch (round-trip).
- canaries extended: python 34/34 (deployed shim + port-2 sections),
  rust 28/28 (ep_verify battery + key-order parity).
- consumers: contracts.py dynamic __import__, canary_native MODULES list,
  full_audit file list — all resolve the shim; import surface unchanged.
2026-10-03 15:51:48 +01:00
Nick 4b0d1d24d2 phase-g slice 2 port 1: audit_ledger canary pair (deployed-shim 28/28, rust 23/23)
- Python canary pins the deployed shim surface to the frozen contract:
  live-path LEDGER_FILE, drift-key default, 3-key dict verify_chain,
  ascending serving order (observed), canary append through the shim
  (live entry 4242, chain intact post-append), rust CLI parity shapes.
- Rust canary drives the compiled surfaces: binary CLI shapes (verify/
  list/log-promotion + argparse error shapes incl. --limit=N form), FFI
  contract via ep_loader (5 fns), fresh-ledger append+verify+get, and the
  live-chain drift-key rule (23+ entries, chain intact).
- Sequence-break disclosure: the shim was deployed before these canaries
  existed; both now green against the deployed state — recorded on #2449.
2026-10-03 15:46:15 +01:00
Nick 114c394741 phase-g slice 2: evidence_provenance rust crate + ctypes loader (audit_ledger parity-complete, shadow 18/18) 2026-10-03 02:41:21 +01:00
Nick 7c68e41a63 phase-g slice 2: freeze evidence-provenance contract (drift-key live-ledger resolution, authority = src/rune vintage, port order set) 2026-10-02 23:12:22 +01:00
Nick 2ac2d0aefd refactor(query-memory): supersede old Python implementation with Rust cdylib (strangler steps 9-12)
Old src/rune/query_memory.py deleted (zero importers verified by sweep).
Coverage-audit registry remapped: shared/query_memory.py (ctypes shim) is
canonical; query_memory out of SRC_A/SHARED_D, into SHARED_B. Supersession
ledger written to plans/. Steps 1-11 evidence in ledger + issue #2448.
2026-10-02 20:52:40 +01:00
Nick 6f44a87894 feat(phase-g): authority-switch shim — deployed query_memory.py is now a ctypes shim over the Rust cdylib
Step 8 of the 12-step strangler doctrine: the deployed in-process consumers
(memory_store.py, growth_simulator.py) now run the Rust classification core
in-process via qm_loader.py. Full historical Python class API preserved,
including the query-history snapshot attribute (loaded at construction,
appended on record — canary check 2 reads it).

Post-switch verification wall ALL GREEN: FFI smoke 41/41, parity harness
ALL GREEN (stdout + history.jsonl + topic_stats.json byte-parity), Python
canary 12/12, Rust canary 27/27, both consumers verified live against the
deployed shim.
2026-10-02 20:24:26 +01:00
Nick 485623dbc4 feat(query-memory): add qm_topic_stats + qm_dead_weight FFI exports and loader bindings
Closes the FFI surface gap: Python get_topic_stats/get_dead_weight_topics
now have FFI exports wrapping the existing Rust topic_stats/dead_weight
impls via TopicStats::to_json. Loader extended with the two bindings
returning the pinned Python shapes (ordered dict / filtered name list).
FFI-gap parity probe: exact-equal vs deployed Python. Verification wall
green: smoke 41/41, parity ALL GREEN, canaries 12/12 + 27/27.
2026-10-02 19:49:19 +01:00
Nick 43e7f5f7d2 feat(query-memory): FFI exports for in-process Python consumption of the Rust core
Seven #[no_mangle] extern "C" exports on lib.rs (qm_new, qm_with_dir, qm_rate,
qm_record, qm_stats, qm_history, qm_health) so the deployed in-process consumer
(~/.config/opencode/scripts/memory_store.py adaptive_exploration_rate) can load
the compiled Rust core via cdylib instead of the Python implementation.

- ctypes loader qm_loader.py mirrors the deployed consumer's exact call shape
- FFI smoke src/rune/ffi_query_memory_smoke.py: 41/41 PASS against an isolated
  store — construction-ordering fixes: seed-then-construct (both implementations
  snapshot the store at construction), post-record health parity
- verification post-FFI: parity harness ALL GREEN, Python canary 12/12,
  Rust canary 27/27 (src/rust/query_memory/canary_rust.py)

Phase G strangler slice 1, step toward shadow comparison + authority switch.
2026-10-02 17:59:50 +01:00
Nick 54d2db97b0 refactor(query-memory): split core into lib.rs — rlib + cdylib for in-process Python loading
Phase G slice 1 (retrieval-index) strangler: the whole implementation lived
in main.rs (prior checkpoint's lib.rs claim was wrong — disk wins). Core
(QueryMemory, classification, serialization) now in src/lib.rs; main.rs is
a thin CLI shell over it. crate-type = [rlib, cdylib] so the deployed mimo
scripts (memory_store.py, growth_simulator.py) can load the compiled core
in-process instead of paying interpreter-subprocess costs.

Verified post-refactor: parity harness ALL GREEN (stdout + history.jsonl +
topic_stats.json byte-parity), Python canary 12/12 exit 0, Rust canary
27/27 exit 0 against rebuilt release binary.
2026-10-02 17:25:10 +01:00
Nick 523a859656 test(query-memory): add Rust canary proving C1-C8 against compiled binary
C9 canary for the Phase G strangler slice 1 (retrieval-index): 27 checks
in the same PASS/FAIL counter discipline as the Python canary, driving
target/release/query_memory with isolated HOME per section. Covers CLI
surface (C8), storage layout + cross-compat (C1), classification
tie-break (C2), adaptive rate clamp + threshold (C3), dead weight (C4),
corruption tolerance (C5), timestamp shape (C6), truncation (C7).

Fixes one probe defect found live: the C5 history-corruption probe
expected stats to rebuild from history.jsonl, but get_topic_stats reads
ONLY topic_stats.json in BOTH implementations (verified byte-identical
side-by-side) — probe corrected to assert the shared real behaviour.

Observed: 27/27 PASS, exit 0.
2026-10-02 16:11:54 +01:00
Nick 9b765852b8 feat(retrieval-index): Rust strangler candidate — Phase G slice 1
Zero-dependency Rust port of src/rune/query_memory.py (retrieval-index,
RUST-candidate per Phase E admission gate):

- src/rust/query_memory/ — first Rust workspace in the repo
- json_min.rs: hand-rolled JSON parser/serializer mirroring json.dumps
  (preserve-order objects, ensure_ascii escaping, surrogate pairs,
  indent-2 stats shape, f64 shortest-repr parity)
- main.rs: classification core + CLI (record/stats/rate/health),
  TOPIC_KEYWORDS in source insertion order, first-max tie-break,
  adaptive exploration rate (+-0.05 at >=10 queries), UTC isoformat
  parity incl. microsecond-omission law
- parity_test.py: cross-language conformance harness — identical
  command sequence through both implementations in isolated HOMEs,
  byte-parity on history.jsonl (timestamps masked) + topic_stats.json

Observed: cargo build clean; parity harness ALL GREEN (stdout +
both store files) across 24-command sequence covering unicode,
first-max tie-breaks, special chars, adaptive-threshold crossing.

Refs: /tmp/phaseG_retrieval_index_contract.md (C1-C10)
2026-10-02 15:40:12 +01:00
Nick f1e63b703e fix(token_optimizer): include content in CacheEntry.to_dict — closes #770 cache-loss defect
Pre-fix to_dict omitted the required field content, so _load's
CacheEntry(**entry_data) raised TypeError on every reload and the
blanket except silently discarded the whole cache on every restart.

Frozen regression contract tests/test_token_optimizer_cache.py
(3 tests: save_persists_content, roundtrip_restores_content,
corrupt_storage_degrades_to_empty_cache). Full suite 2250/0.
2026-09-30 12:18:35 +01:00
Nick 6d40f94f18 fix(test): hermetic group-liveness probe in TTY no-accumulation test
The test measured 'group-kill leaves nothing behind' via a global
'pgrep -x -c sleep' before/after delta — any unrelated system sleep
starting mid-loop on the runner (mount helpers, cron helpers) landed
in the delta and false-failed. CI run 13255 failed with exactly
'1 NEW sleep survivor' from an ambient sleep, reproduced locally
(/tmp/ambient_proof.mjs: measured_delta 1 from one spawned ambient
sleep).

Fix: probe OUR OWN process groups with kill(-pgid, 0) after the kill
sequence — a live group answers, a fully-reaped group throws ESRCH.
Hermetic to ambient load; negative control (/tmp/hermetic_catch.mjs)
confirms the probe still reports a survivor when the kill is skipped,
so the test's protective intent is preserved.

Verified: test green x3 locally, whole TTY contract file 8/8, fixed
test green under deliberate ambient-sleep bombardment.
2026-09-30 02:07:30 +01:00
Nick 7a869476be fix(forge_client): terminate _request with explicit raise — clears 5 pyright Optional warnings at call sites
_request never returns None (every attempt returns or raises), but the
implicit exhausted-loop path made pyright infer Optional at all 5 call
sites' .json() accesses, pushing the warning ratchet 454→459. The
terminal AssertionError documents exhaustiveness at the source instead
of 5 duplicated guards. Local pyright: errors 109, warnings 447 (≤454).
2026-09-30 01:41:30 +01:00
Nick e5292cce7b feat(forge): add httpx retry/timeout wrapper for transient-failure resilience
- _request() helper in forge_client.py: retry on connect-phase transport
  errors and idempotent-method 5xx/429, exponential backoff, 30s timeout
  default preserved per attempt; create_issue (POST) and list-style GETs
  route through it per retry-where-noise semantics
- frozen contract tests/test_forge_client_resilience.py (10 tests,
  written red-first per the bug-fix contract)
- legacy FakeResponse fixtures updated with status_code=200 (wrapper
  reads status_code for the GET-5xx retry gate)
- httpx wrapper spec: docs/rebase-language-rubric.md W4 named improvement
- model_routing.py:99 probe deliberately EXCLUDED (failure is the
  signal, not noise — one-shot design is the contract)
2026-09-30 01:10:22 +01:00
Nick 9425ccc1f4 docs(rebase): record executed kill-test dispositions for orjson + inventory items
orjson: microbench on live 3.5MB knowledge.json — load 1.68x (bar 2x FAIL),
dump+decode 1.71x (bar 5x FAIL) => KEEP-PYTHON, no dependency declared.
Inventory correction: DONE via regen (5bc837c); W2 drift claim verified false.
2026-09-30 00:00:57 +01:00
Nick 3ed547f86f chore(deps): re-resolve ci lock after upstream platformdirs 4.12.2 release
Dep-lock drift ratchet red on CI run 13207. Documented regen path:
uv pip compile --upgrade. Only the pin moved.
2026-09-29 23:55:18 +01:00
Nick 5bc837c232 fix(rebase): regenerate inventory — drop deleted complexity_scorer + 12 stale files, add 49 current (rubric named correction) 2026-09-29 23:23:58 +01:00
Nick 08bc1a6b62 feat(native): add JSONL streaming reader for native units (W7 contract gap)
stream_native(): per-line json.loads over subprocess stdout, progress
events yielded live, terminal envelope validated as the FINAL line,
watchdog timeout with adapter-kill vs unit-death distinction, concurrent
stderr drain. Generator yields event dicts then one terminal NativeResult
(gaining an events field). Malformed interior lines skipped and counted;
a malformed final line invalidates the envelope, so ok=False while partial
progress stays available. Tests use a Python subprocess as the fake
native unit — no Rust build dependency in the test path (house style
from tests/test_native_interop_proof.py).
2026-09-29 23:08:32 +01:00
Nick 201ca05b56 docs(rebase): land FINAL Wave 1 language-fit rubric (40 clusters, 0 recodes) 2026-09-29 23:08:32 +01:00
Nick 5cd90f2104 fix(ci): exempt docs/rebase/** from top-level-docs henxel
The top-level docs henxel (in: ./docs/*) reaches subdirectories —
run 13170 held docs/rebase/rebase-inventory.json and
docs/rebase-wave-coverage.json after the c8bc454 relocation. The
./docs/v1/** precedent in the same except list shows the rule's
recursive reach; the Wave 0 JSON artifacts are machine-generated
data, not docs, and follow the same precedent shape.
2026-09-29 15:09:23 +01:00
Nick c8bc454e33 fix(lint): relocate Wave 0 JSON artifacts to docs/rebase/
The henxels allowed_filetypes rule polices top-level ./docs/* for
markdown/yaml only; machine-generated JSON artifacts are not docs.
Moving rebase-inventory.json and rebase-wave-coverage.json under
docs/rebase/ (outside the single-segment glob) rather than widening
the gate's except list to fit new files. All consumer references
updated (rebase_inventory.py, rebase_issue_factory.py, wave0 report).
2026-09-29 14:47:38 +01:00
Nick b81edb2029 fix(tests): pin event-bus journal into tmp in terminalization helper test
test_terminalization_helper_single_path scanned the ambient
event_bus.JOURNAL_DIR — an import-time-frozen constant resolved via
memory_env.memory_dir(), whose RUNE_HOME defaults to the hardcoded
/mnt/workdrive/rune. On this machine that path coincidentally IS the
repo, so the test passed locally; on the CI runner the default path is
unwritable, emit()'s deliberate degradation swallowed the write, and the
scan found no task.outcome — the sole unit red of 2,219 on run 13155.

Fix pins JOURNAL_DIR/EVENT_LOG to the test's TemporaryDirectory with
addCleanup restore — same isolation-seam family as the hot-store law
(ambient state must never be read by tests). Red-first repro'd with a
hostile RUNE_HOME locally: exact CI signature ([] is not true) before
the pin, green after.
2026-09-29 14:11:30 +01:00