Compare commits

...
58 Commits
Author SHA1 Message Date
conductor 01b57297b8 chore(release): auto-bump version to 0.88.4 — earned by #2269 (Wave 0: rebase tranche inventory, issue factory, Rust interop proof)
Auto-version and Release / release (push) Successful in 18s
deploy / deploy (push) Failing after 11m59s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 3s
CI Pipeline / lint (push) Successful in 1m5s
CI Pipeline / unit-tests (push) Failing after 4m45s
CI Pipeline / canary (push) Successful in 29s
CI Pipeline / best-practices (push) Successful in 2s
CI Pipeline / documentation (push) Successful in 1s
CI Pipeline / type-check (push) Successful in 26s
CI Pipeline / gitea-offline (push) Successful in 13s
CI Pipeline / required-checks (push) Failing after 1s
Promotion record: http://192.168.1.156:3000/conductor/rune/pulls/2269
2026-09-30 00:10:04 +01:00
conductor 497db5a144 Merge pull request 'Wave 0: rebase tranche inventory, issue factory, Rust interop proof' (#2269) from tranche-r1-wave-0 into master
CI Pipeline / best-practices (push) Successful in 11s
CI Pipeline / documentation (push) Successful in 3s
CI Pipeline / canary (push) Successful in 1m21s
CI Pipeline / type-check (push) Successful in 1m10s
CI Pipeline / lint (push) Successful in 1m30s
CI Pipeline / gitea-offline (push) Successful in 19s
Auto-version and Release / release (push) Successful in 46s
CI Pipeline / unit-tests (push) Successful in 6m24s
deploy / deploy (push) Failing after 15m7s
CI Pipeline / required-checks (push) Successful in 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 2s
2026-09-30 00:09:13 +01:00
Nick 9425ccc1f4 docs(rebase): record executed kill-test dispositions for orjson + inventory items
CI Pipeline / lint (push) Successful in 1m26s
CI Pipeline / best-practices (push) Successful in 3s
CI Pipeline / documentation (push) Successful in 3s
CI Pipeline / canary (push) Successful in 58s
CI Pipeline / gitea-offline (push) Successful in 14s
CI Pipeline / type-check (push) Successful in 1m0s
CI Pipeline / lint (pull_request) Successful in 1m15s
CI Pipeline / best-practices (pull_request) Successful in 8s
CI Pipeline / documentation (pull_request) Successful in 5s
CI Pipeline / canary (pull_request) Successful in 1m4s
CI Pipeline / gitea-offline (pull_request) Successful in 14s
deploy / deploy (push) Skipped
Spec gate (headless) / spec-gate (pull_request) Successful in 6s
CI Pipeline / type-check (pull_request) Successful in 1m6s
CI Pipeline / unit-tests (push) Successful in 5m50s
CI Pipeline / required-checks (push) Successful in 4s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 3s
CI Pipeline / unit-tests (pull_request) Successful in 5m42s
CI Pipeline / required-checks (pull_request) Successful in 3s
CI Pipeline / CI Pipeline / notify-event-bridge (pull_request) Successful in 2s
Auto-version and Release / release (pull_request) Successful in 54s
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
CI Pipeline / best-practices (push) Successful in 37s
CI Pipeline / documentation (push) Successful in 5s
CI Pipeline / type-check (push) Successful in 1m36s
CI Pipeline / canary (push) Successful in 2m20s
CI Pipeline / lint (push) Successful in 2m25s
CI Pipeline / gitea-offline (push) Successful in 16s
CI Pipeline / lint (pull_request) Successful in 1m0s
CI Pipeline / best-practices (pull_request) Successful in 5s
CI Pipeline / canary (pull_request) Successful in 52s
CI Pipeline / documentation (pull_request) Successful in 4s
CI Pipeline / gitea-offline (pull_request) Successful in 15s
deploy / deploy (push) Skipped
Spec gate (headless) / spec-gate (pull_request) Successful in 5s
CI Pipeline / type-check (pull_request) Successful in 58s
CI Pipeline / unit-tests (push) Failing after 6m36s
CI Pipeline / unit-tests (pull_request) Successful in 5m11s
CI Pipeline / required-checks (push) Failing after 2s
CI Pipeline / required-checks (pull_request) Successful in 2s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 3s
CI Pipeline / CI Pipeline / notify-event-bridge (pull_request) Successful in 4s
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)
CI Pipeline / best-practices (push) Successful in 5s
CI Pipeline / documentation (push) Successful in 2s
CI Pipeline / lint (push) Failing after 23s
CI Pipeline / canary (push) Successful in 31s
CI Pipeline / type-check (push) Successful in 27s
CI Pipeline / gitea-offline (push) Successful in 13s
CI Pipeline / lint (pull_request) Failing after 20s
CI Pipeline / best-practices (pull_request) Successful in 1s
CI Pipeline / documentation (pull_request) Successful in 1s
CI Pipeline / canary (pull_request) Successful in 26s
CI Pipeline / gitea-offline (pull_request) Successful in 13s
deploy / deploy (push) Skipped
Spec gate (headless) / spec-gate (pull_request) Successful in 4s
CI Pipeline / type-check (pull_request) Successful in 26s
CI Pipeline / unit-tests (push) Successful in 4m48s
CI Pipeline / required-checks (push) Failing after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 2s
CI Pipeline / unit-tests (pull_request) Successful in 4m48s
CI Pipeline / required-checks (pull_request) Failing after 1s
CI Pipeline / CI Pipeline / notify-event-bridge (pull_request) Successful in 2s
2026-09-29 23:23:58 +01:00
Nick 08bc1a6b62 feat(native): add JSONL streaming reader for native units (W7 contract gap)
CI Pipeline / best-practices (push) Successful in 4s
CI Pipeline / documentation (push) Successful in 1s
CI Pipeline / lint (push) Failing after 24s
CI Pipeline / canary (push) Successful in 31s
CI Pipeline / type-check (push) Successful in 27s
CI Pipeline / gitea-offline (push) Successful in 14s
CI Pipeline / lint (pull_request) Failing after 21s
CI Pipeline / best-practices (pull_request) Successful in 2s
CI Pipeline / documentation (pull_request) Successful in 2s
CI Pipeline / canary (pull_request) Successful in 26s
CI Pipeline / gitea-offline (pull_request) Successful in 13s
deploy / deploy (push) Skipped
Spec gate (headless) / spec-gate (pull_request) Successful in 3s
CI Pipeline / type-check (pull_request) Successful in 27s
CI Pipeline / unit-tests (push) Failing after 4m49s
CI Pipeline / required-checks (push) Failing after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 2s
CI Pipeline / unit-tests (pull_request) Successful in 4m48s
CI Pipeline / required-checks (pull_request) Failing after 1s
CI Pipeline / CI Pipeline / notify-event-bridge (pull_request) Successful in 2s
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
CI Pipeline / best-practices (push) Successful in 4s
CI Pipeline / documentation (push) Successful in 2s
CI Pipeline / canary (push) Successful in 30s
CI Pipeline / type-check (push) Successful in 26s
CI Pipeline / lint (push) Successful in 36s
CI Pipeline / gitea-offline (push) Successful in 13s
CI Pipeline / lint (pull_request) Successful in 33s
CI Pipeline / best-practices (pull_request) Successful in 2s
CI Pipeline / documentation (pull_request) Successful in 1s
CI Pipeline / canary (pull_request) Successful in 27s
CI Pipeline / gitea-offline (pull_request) Successful in 14s
deploy / deploy (push) Skipped
Spec gate (headless) / spec-gate (pull_request) Successful in 4s
CI Pipeline / type-check (pull_request) Successful in 27s
CI Pipeline / unit-tests (push) Successful in 4m50s
CI Pipeline / required-checks (push) Successful in 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 2s
CI Pipeline / unit-tests (pull_request) Failing after 4m38s
CI Pipeline / required-checks (pull_request) Failing after 1s
CI Pipeline / CI Pipeline / notify-event-bridge (pull_request) Successful in 2s
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/
CI Pipeline / best-practices (push) Successful in 5s
CI Pipeline / documentation (push) Successful in 1s
CI Pipeline / canary (push) Successful in 31s
Auto-label / priority-gate (pull_request) Skipped
Auto-label / auto-label (pull_request) Successful in 1s
CI Pipeline / type-check (push) Successful in 26s
CI Pipeline / lint (push) Failing after 37s
CI Pipeline / gitea-offline (push) Successful in 13s
CI Pipeline / lint (pull_request) Failing after 34s
CI Pipeline / best-practices (pull_request) Successful in 2s
CI Pipeline / documentation (pull_request) Successful in 1s
CI Pipeline / canary (pull_request) Successful in 28s
CI Pipeline / gitea-offline (pull_request) Successful in 13s
deploy / deploy (push) Skipped
Spec gate (headless) / spec-gate (pull_request) Successful in 4s
CI Pipeline / type-check (pull_request) Successful in 26s
CI Pipeline / unit-tests (push) Successful in 4m52s
CI Pipeline / required-checks (push) Failing after 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 1s
CI Pipeline / unit-tests (pull_request) Failing after 4m39s
CI Pipeline / required-checks (pull_request) Failing after 1s
CI Pipeline / CI Pipeline / notify-event-bridge (pull_request) Successful in 2s
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
CI Pipeline / best-practices (push) Successful in 4s
CI Pipeline / documentation (push) Successful in 2s
CI Pipeline / type-check (push) Successful in 27s
CI Pipeline / lint (push) Failing after 36s
CI Pipeline / canary (push) Successful in 36s
CI Pipeline / gitea-offline (push) Successful in 13s
CI Pipeline / unit-tests (pull_request) Failing after 21s
CI Pipeline / best-practices (pull_request) Successful in 2s
CI Pipeline / documentation (pull_request) Successful in 2s
CI Pipeline / lint (pull_request) Failing after 34s
CI Pipeline / canary (pull_request) Successful in 28s
Spec gate (headless) / spec-gate (pull_request) Successful in 4s
deploy / deploy (push) Skipped
CI Pipeline / gitea-offline (pull_request) Successful in 14s
CI Pipeline / type-check (pull_request) Successful in 27s
CI Pipeline / required-checks (pull_request) Failing after 1s
CI Pipeline / CI Pipeline / notify-event-bridge (pull_request) Successful in 1s
CI Pipeline / unit-tests (push) Successful in 4m52s
CI Pipeline / required-checks (push) Failing after 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 2s
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
Nick 87a890dce3 fix(ci): regenerate requirements-ci.txt — dep-lock drift from 0.88.3 pyproject bump
Master's auto-bump to 0.88.3 changed pyproject.toml without regenerating
the CI dep lock; the merge carried both sides in (coverage 7.16.1 ->
7.16.2, nodeenv, platformdirs). Canonical regen per
scripts/check_dep_lock.py's documented command, plus --upgrade: uv pip
compile to an EXISTING output file preserves its stale pins as resolver
preferences, so a plain in-place regen silently keeps the old pins.
Measured: same uv, same invocation, -o fresh-path resolves 7.16.2 while
-o requirements-ci.txt kept 7.16.1 until --upgrade was added.
2026-09-29 14:11:30 +01:00
Nick a0821be8a5 fix(rebase): narrow inventory signature-unparse handlers to explicit exception types
CI Pipeline / lint (push) Failing after 22s
CI Pipeline / best-practices (push) Successful in 2s
CI Pipeline / documentation (push) Successful in 1s
CI Pipeline / canary (push) Successful in 26s
CI Pipeline / gitea-offline (push) Successful in 12s
CI Pipeline / type-check (push) Successful in 25s
CI Pipeline / lint (pull_request) Failing after 19s
CI Pipeline / unit-tests (pull_request) Failing after 18s
CI Pipeline / best-practices (pull_request) Successful in 1s
CI Pipeline / documentation (pull_request) Successful in 1s
CI Pipeline / canary (pull_request) Successful in 25s
CI Pipeline / type-check (pull_request) Successful in 26s
deploy / deploy (push) Skipped
Spec gate (headless) / spec-gate (pull_request) Successful in 3s
CI Pipeline / gitea-offline (pull_request) Successful in 12s
CI Pipeline / required-checks (pull_request) Failing after 1s
CI Pipeline / CI Pipeline / notify-event-bridge (pull_request) Successful in 1s
CI Pipeline / unit-tests (push) Failing after 4m42s
CI Pipeline / required-checks (push) Failing after 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 2s
Replaces two blind except-Exception-pass handlers in _arg_str/_signature
with (AttributeError, RecursionError, ValueError) and documents the
degraded-metadata contract: a pathological annotation node must never
abort the whole inventory walk.
2026-09-29 13:29:53 +01:00
Nick cb137bd37a Merge remote-tracking branch 'gitea/master' into tranche-r1-wave-0
CI Pipeline / best-practices (pull_request) Successful in 3s
CI Pipeline / documentation (pull_request) Successful in 1s
CI Pipeline / unit-tests (pull_request) Failing after 22s
CI Pipeline / lint (pull_request) Failing after 24s
Spec gate (headless) / spec-gate (pull_request) Successful in 3s
CI Pipeline / canary (pull_request) Successful in 28s
CI Pipeline / type-check (pull_request) Successful in 26s
CI Pipeline / gitea-offline (pull_request) Successful in 13s
CI Pipeline / best-practices (push) Successful in 2s
CI Pipeline / documentation (push) Successful in 2s
CI Pipeline / lint (push) Failing after 20s
CI Pipeline / canary (push) Successful in 27s
deploy / deploy (push) Skipped
CI Pipeline / required-checks (pull_request) Failing after 0s
CI Pipeline / gitea-offline (push) Successful in 13s
CI Pipeline / type-check (push) Successful in 27s
CI Pipeline / CI Pipeline / notify-event-bridge (pull_request) Successful in 2s
CI Pipeline / unit-tests (push) Failing after 4m43s
CI Pipeline / required-checks (push) Failing after 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 2s
# Conflicts:
#	.gitignore
#	config/umbrellas.json
2026-09-29 13:26:54 +01:00
Nick 72afb1a55a feat(rebase): wave 0 — whole-project inventory, per-function issue factory, Rust interop proof unit
CI Pipeline / best-practices (push) Successful in 4s
CI Pipeline / documentation (push) Successful in 1s
CI Pipeline / lint (push) Failing after 24s
CI Pipeline / type-check (push) Successful in 23s
CI Pipeline / canary (push) Successful in 32s
CI Pipeline / gitea-offline (push) Successful in 13s
CI Pipeline / unit-tests (push) Failing after 44s
CI Pipeline / required-checks (push) Successful in 1s
Auto-label / priority-gate (pull_request) Skipped
Auto-label / auto-label (pull_request) Successful in 2s
CI Pipeline / best-practices (pull_request) Successful in 3s
CI Pipeline / documentation (pull_request) Successful in 1s
CI Pipeline / lint (pull_request) Failing after 23s
CI Pipeline / canary (pull_request) Successful in 30s
CI Pipeline / type-check (pull_request) Successful in 24s
Spec gate (headless) / spec-gate (pull_request) Successful in 4s
CI Pipeline / gitea-offline (pull_request) Successful in 13s
CI Pipeline / unit-tests (pull_request) Failing after 44s
CI Pipeline / required-checks (pull_request) Successful in 0s
Wave 0 of the approved language-rebasing tranche (R1):

- scripts/rebase_inventory.py: AST-based whole-project inventory →
  docs/rebase-inventory.json (1,852 true units = 1,030 top-level fns
  + 822 methods; module-level walk skips defs; class-method leak fixed)
- docs/rebase-wave-coverage.json: waves 2–7 coverage {239,251,129,544,415,274}
- scripts/rebase_issue_factory.py: one-issue-per-unit Gitea factory,
  dry-run default, deterministic titles + dedup, --limit defaults to
  unlimited for create; 1,852 issues created across waves 2–7
- interop/rebase-proof + shared/native_units.py + tests: std-only Rust
  proof unit for the §5 native-interop contract (argv→JSON, --version,
  exit 2 on failure); thin typed Python adapter; 8/8 tests pass with
  corrected ok-semantics (ok = exit 0 AND not timed out)
- config/umbrellas.json: native_units registered in capability umbrella
  (manifest law — the map travels with the change)
- docs/rebase-wave0-report.md: Wave 0 close-out report
2026-09-29 12:47:34 +01:00
conductor c9095f5af5 chore(release): auto-bump version to 0.88.3 — earned by # (patch: converged release (push-to-master bump))
Auto-version and Release / release (push) Successful in 5s
CI Pipeline / lint (push) Successful in 31s
CI Pipeline / canary (push) Successful in 24s
CI Pipeline / best-practices (push) Successful in 2s
CI Pipeline / documentation (push) Successful in 1s
CI Pipeline / type-check (push) Successful in 25s
CI Pipeline / gitea-offline (push) Successful in 12s
CI Pipeline / unit-tests (push) Successful in 4m39s
CI Pipeline / required-checks (push) Successful in 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 1s
deploy / deploy (push) Successful in 3m3s
Promotion record: (unknown)
2026-09-23 18:16:50 +01:00
conductor b5422f0772 chore(release): auto-bump version to 0.88.3 — earned by #412 (fix(scaffolding): T22 — connect the MiMo edge + apply the meaning gate on the na)
Auto-version and Release / release (push) Successful in 5s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 1s
CI Pipeline / lint (push) Successful in 31s
CI Pipeline / unit-tests (push) Successful in 4m39s
CI Pipeline / canary (push) Successful in 25s
CI Pipeline / best-practices (push) Successful in 2s
CI Pipeline / documentation (push) Successful in 1s
CI Pipeline / type-check (push) Successful in 25s
CI Pipeline / gitea-offline (push) Successful in 13s
CI Pipeline / required-checks (push) Successful in 0s
deploy / deploy (push) Failing after 5m53s
Promotion record: http://192.168.1.156:3000/conductor/rune/pulls/412
2026-09-23 18:16:42 +01:00
conductor da36b99184 Merge pull request 'fix(scaffolding): T22 — connect the MiMo edge + apply the meaning gate on the native path' (#412) from t22-scaffolding-default-path into master
CI Pipeline / best-practices (push) Successful in 4s
CI Pipeline / documentation (push) Successful in 2s
Auto-version and Release / release (push) Successful in 7s
CI Pipeline / canary (push) Successful in 29s
CI Pipeline / type-check (push) Successful in 27s
CI Pipeline / lint (push) Successful in 35s
CI Pipeline / gitea-offline (push) Successful in 13s
CI Pipeline / unit-tests (push) Successful in 4m46s
CI Pipeline / required-checks (push) Successful in 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 2s
deploy / deploy (push) Successful in 10m43s
2026-09-23 18:16:35 +01:00
conductor 873d0025ad fix(scaffolding): T22 — cover the new paths; two defects the coverage tests found
CI Pipeline / best-practices (push) Successful in 3s
CI Pipeline / documentation (push) Successful in 2s
Auto-label / priority-gate (pull_request) Skipped
Auto-label / auto-label (pull_request) Successful in 1s
CI Pipeline / canary (push) Successful in 29s
CI Pipeline / type-check (push) Successful in 27s
CI Pipeline / lint (push) Successful in 35s
CI Pipeline / gitea-offline (push) Successful in 13s
CI Pipeline / lint (pull_request) Successful in 32s
CI Pipeline / best-practices (pull_request) Successful in 1s
CI Pipeline / documentation (pull_request) Successful in 1s
CI Pipeline / canary (pull_request) Successful in 26s
CI Pipeline / gitea-offline (pull_request) Successful in 13s
Spec gate (headless) / spec-gate (pull_request) Successful in 3s
deploy / deploy (push) Skipped
CI Pipeline / type-check (pull_request) Successful in 26s
CI Pipeline / unit-tests (push) Successful in 4m44s
CI Pipeline / required-checks (push) Successful in 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 1s
CI Pipeline / unit-tests (pull_request) Successful in 4m40s
CI Pipeline / required-checks (pull_request) Successful in 1s
CI Pipeline / CI Pipeline / notify-event-bridge (pull_request) Successful in 2s
Auto-version and Release / release (pull_request) Successful in 8s
Self-review against the CI gates surfaced two genuine defects in the first
commit. Changed-lines coverage is now 85% (floor 70):

1. The bridge projection read the WRONG STORE. `_active_construction_lines`
   built `ConstructionInterface` without `project_store`, so it fell back to
   the interface default instead of the configured construction store — the
   `RUNE_CONSTRUCTION_STORE` override was ignored, so a redirected
   deployment would have projected another project's construction state.
   Fixed: pass `_construction_store()` + the project id.

2. LOST UPDATE between the intent-layer note and the main activation path.
   The degrade path called `_construction_note()`, which does its own
   load/save; the normal path then saved its own stale `doc`, silently
   clobbering the note. Fixed: append the note to the SAME in-memory doc
   (one doc, one save), so the failure is recorded and survives.

New coverage: active-contract projection + capsule rendering + read-only
guarantee; store-resolution override; intent-layer-unavailable degrade path.

Note: the stale TUI banner (`Rune v0.87.6` vs `__version__` 0.88.0) that
this commit also fixed on the old base was fixed independently on master by
the 0.88.2 release bump, so the rebase takes master's banner — nothing to
carry here.
2026-09-23 18:10:07 +01:00
conductor a9ce967557 chore(ci): refresh dependency lock — upstream patch bumps unblock #150 gate
`scripts/check_dep_lock.py` (CI step "#150: deps come ONLY from the pinned
lock") regenerates the lock into a temp path and compares. Three transitive
deps released upstream since the lock was generated, so the check fails for
ANY branch today, independent of the T22 change:

  diff-cover  10.5.1  -> 10.6.0
  multidict   6.9.0   -> 6.9.1
  platformdirs 4.11.11 -> 4.11.12

Regenerated with the exact command the gate instructs. Note: compiling with
`-o requirements-ci.txt` is a NO-OP for the pins (uv prefers the existing
output file's versions); the fresh resolution must be written to a new path
and moved into place, which is what the checker itself does.

No dependency declarations changed (pyproject.toml untouched) — pins only.
2026-09-23 18:09:26 +01:00
conductor eb3a2c681c fix(scaffolding): T22 — connect the MiMo edge and apply the meaning gate on the native path
Reality-wins audit of the accepted Scaffolding V1 system against the live
repo/runtime found three genuine wiring defects (no architecture invented):

1. The MiMo edge was DEAD. `~/.mimocode/hooks/builder-bridge.ts` hardcoded
   the ephemeral interpreter `/tmp/ci-venv/bin/python`, which no longer
   exists, so every bridge call failed and the hook silently degraded —
   MiMo received NO Rune Core preflight at all (zero fire-log lines). The
   hook was also UNVERSIONED (no canonical copy), which is how it rotted.
   Repair: canonical source `config/mimo-hooks/builder-bridge.ts` with
   durable interpreter resolution (env override > repo venv > user venv >
   /usr/bin/python3), installed + hash-verified + drift-checked by
   `install_mimo_hook.py`, which now manages a hook SET rather than one file.

2. The native path skipped the canonical meaning layer. `construction_intent`
   (the §17J/§17L/§17M intent resolver: interrogative structure, negation,
   request modals, referent/proposal resolution) existed but was imported
   ONLY by tests. `rune_operator._construction_activation` went straight to
   `classify_mode`, so a pure question carrying a target reference
   ("explain how this module works") classified EXISTING_PROJECT_CHANGE and
   recorded a construction activation for a discussion turn. Repair: the
   intent layer now resolves MEANING before the ONE classifier decides mode
   (the boundary the intent module documents). DISCUSSION maps to
   NOT_CONSTRUCTION — the canonical vocabulary is unchanged, an explicit
   user override (/scaffold-mode) outranks the gate, and an unavailable
   intent layer preserves the previous behaviour exactly rather than
   silently changing governance.

3. The shared Construction Context reported a TERMINAL contract as active.
   `construction_context()` selected on `status == "open"` alone, so 8
   contracts with phase `abandoned` (terminal) were reported as the active
   construction. Repair: terminal phases are now DERIVED once from the
   canonical transition table (`scaffold.TERMINAL_PHASES`), and a contract
   is active only when its phase is non-terminal.

Also: the bridge capsule now surfaces the active Scaffolding construction
(contract/phase/scope/obligations/next-action) to the builder as a
read-only projection of the shared Construction Context — the MiMo edge of
state Scaffolding already owns. Inject-nothing is preserved when no
contract is active; the projection never mutates and degrades to [].

Spine projection refreshed (import graph legitimately gained importers).

Honest boundary: no byte-level enforcement point exists. `tool_executor.py`
never consults construction state, so the 19A invariant gates only the
/build-start route. Establishing MiMo-surface enforcement is NEW
architecture (a tool.execute.before governance hook) and was NOT built
here — it is recorded as the exact remaining blocker.

Verification: 511 passed across the construction/operator/bridge/hook/
structural/parity suites; native-default matrix 12/12; real operator-path
proof with fresh-process readback (EXISTING_PROJECT_CHANGE activated,
question -> NOT_CONSTRUCTION, PROJECT_BUILD bootstraps scaffold + registry);
installed hook invoked directly -> capsule injected + fire log written.
LOCAL_MODEL_COMPUTE_EXECUTED = NO.
2026-09-23 18:09:26 +01:00
conductor 1bc1cdeaf0 chore(release): auto-bump version to 0.88.2 — earned by #408 (auto-label: stop re-adding managed labels to closed issues (#407))
Auto-version and Release / release (push) Successful in 11s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 2s
CI Pipeline / lint (push) Successful in 31s
CI Pipeline / unit-tests (push) Successful in 4m48s
CI Pipeline / canary (push) Successful in 27s
CI Pipeline / best-practices (push) Successful in 1s
CI Pipeline / documentation (push) Successful in 2s
CI Pipeline / type-check (push) Successful in 25s
CI Pipeline / gitea-offline (push) Successful in 12s
CI Pipeline / required-checks (push) Successful in 1s
deploy / deploy (push) Successful in 3m18s
Promotion record: http://192.168.1.156:3000/conductor/rune/pulls/408
2026-09-20 11:17:13 +01:00
conductor 31565844d7 Merge pull request 'auto-label: stop re-adding managed labels to closed issues (#407)' (#408) from fix-407-autolabel into master
CI Pipeline / best-practices (push) Successful in 3s
CI Pipeline / documentation (push) Successful in 2s
Auto-version and Release / release (push) Successful in 9s
CI Pipeline / type-check (push) Successful in 27s
CI Pipeline / canary (push) Successful in 34s
CI Pipeline / lint (push) Successful in 35s
CI Pipeline / gitea-offline (push) Successful in 13s
CI Pipeline / unit-tests (push) Successful in 4m48s
CI Pipeline / required-checks (push) Successful in 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 1s
deploy / deploy (push) Successful in 8m23s
2026-09-20 11:17:04 +01:00
conductor c08b211f0e auto-label: stop re-adding managed labels to closed issues; keyword fallback filing-time only
CI Pipeline / best-practices (push) Successful in 3s
CI Pipeline / documentation (push) Successful in 1s
Auto-label / priority-gate (pull_request) Skipped
Auto-label / auto-label (pull_request) Successful in 1s
CI Pipeline / canary (push) Successful in 29s
CI Pipeline / type-check (push) Successful in 26s
deploy / deploy (push) Skipped
CI Pipeline / lint (push) Successful in 34s
CI Pipeline / gitea-offline (push) Successful in 13s
CI Pipeline / lint (pull_request) Successful in 33s
CI Pipeline / best-practices (pull_request) Successful in 1s
CI Pipeline / documentation (pull_request) Successful in 1s
CI Pipeline / canary (pull_request) Successful in 29s
CI Pipeline / gitea-offline (pull_request) Successful in 12s
Spec gate (headless) / spec-gate (pull_request) Successful in 3s
CI Pipeline / type-check (pull_request) Successful in 26s
CI Pipeline / unit-tests (push) Successful in 4m43s
CI Pipeline / required-checks (push) Successful in 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 2s
CI Pipeline / unit-tests (pull_request) Successful in 4m40s
CI Pipeline / required-checks (pull_request) Successful in 0s
CI Pipeline / CI Pipeline / notify-event-bridge (pull_request) Successful in 1s
Auto-version and Release / release (pull_request) Successful in 7s
Root cause of #407: the labels job re-ran its full inference on every
issues event, including 'labeled' events on closed issues. Any label
mutation (human cleanup, bot churn) re-triggered inference, and the
spine-authoritative mapping re-added the type label to the closed issue
(#324: kind bug, closed FIXED_VERIFIED, bug label re-added within
seconds of every removal — making the reconciliation checker
permanently red for that issue).

Fix:
- Closed issues are skipped entirely; post-close label curation
  belongs to humans and the conductor. Labels are filing-time
  metadata.
- The pre-template keyword fallback now runs only on the 'opened'
  action, per its documented scope; edits and label events on
  spine-less issues no longer override human curation.
- Priority gate also skips closed issues (hygiene, same class).

Version intent: patch (workflow behavior fix, no API change).
Verification after merge: remove 'bug' from closed #324, wait >60s
across any label event, confirm no re-add; reconciliation checker
green for #324.
2026-09-20 11:11:30 +01:00
conductor 46c5032208 chore(release): auto-bump version to 0.88.1 — earned by # (patch: converged release (push-to-master bump))
Auto-version and Release / release (push) Successful in 5s
CI Pipeline / lint (push) Successful in 30s
CI Pipeline / canary (push) Successful in 30s
CI Pipeline / best-practices (push) Successful in 1s
CI Pipeline / documentation (push) Successful in 1s
CI Pipeline / type-check (push) Successful in 24s
CI Pipeline / gitea-offline (push) Successful in 12s
CI Pipeline / unit-tests (push) Successful in 4m39s
CI Pipeline / required-checks (push) Successful in 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 1s
deploy / deploy (push) Successful in 2m52s
Promotion record: (unknown)
2026-09-19 19:21:40 +01:00
conductor 92584daeef chore(release): auto-bump version to 0.88.1 — earned by #355 (fix(tui): sync banner version surface to 0.88.0)
Auto-version and Release / release (push) Successful in 5s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 2s
CI Pipeline / lint (push) Successful in 31s
CI Pipeline / unit-tests (push) Successful in 4m39s
CI Pipeline / canary (push) Successful in 24s
CI Pipeline / best-practices (push) Successful in 2s
CI Pipeline / documentation (push) Successful in 1s
CI Pipeline / type-check (push) Successful in 26s
CI Pipeline / gitea-offline (push) Successful in 13s
CI Pipeline / required-checks (push) Successful in 0s
deploy / deploy (push) Successful in 5m45s
Promotion record: http://192.168.1.156:3000/conductor/rune/pulls/355
2026-09-19 19:21:33 +01:00
conductor bb5e243c88 Merge pull request 'fix(tui): sync banner version surface to 0.88.0' (#355) from fix-tui-banner-surface into master
CI Pipeline / best-practices (push) Successful in 3s
CI Pipeline / documentation (push) Successful in 2s
Auto-version and Release / release (push) Successful in 6s
CI Pipeline / canary (push) Successful in 29s
CI Pipeline / type-check (push) Successful in 27s
CI Pipeline / lint (push) Successful in 34s
CI Pipeline / gitea-offline (push) Successful in 13s
CI Pipeline / unit-tests (push) Successful in 4m45s
CI Pipeline / required-checks (push) Successful in 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 2s
deploy / deploy (push) Successful in 10m44s
2026-09-19 19:21:28 +01:00
conductor ac936a8ba9 fix(tui): sync banner version surface to 0.88.0
Auto-label / priority-gate (pull_request) Skipped
Auto-label / auto-label (pull_request) Successful in 2s
CI Pipeline / lint (push) Successful in 31s
CI Pipeline / canary (push) Successful in 24s
CI Pipeline / best-practices (push) Successful in 1s
CI Pipeline / documentation (push) Successful in 1s
CI Pipeline / type-check (push) Successful in 24s
CI Pipeline / gitea-offline (push) Successful in 12s
deploy / deploy (push) Skipped
Spec gate (headless) / spec-gate (pull_request) Successful in 3s
CI Pipeline / unit-tests (push) Successful in 4m45s
CI Pipeline / required-checks (push) Successful in 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 1s
CI Pipeline / unit-tests (pull_request) Successful in 4m45s
CI Pipeline / lint (pull_request) Successful in 31s
CI Pipeline / canary (pull_request) Successful in 25s
CI Pipeline / best-practices (pull_request) Successful in 2s
CI Pipeline / documentation (pull_request) Successful in 1s
CI Pipeline / type-check (pull_request) Successful in 26s
CI Pipeline / gitea-offline (pull_request) Successful in 12s
CI Pipeline / required-checks (pull_request) Successful in 0s
CI Pipeline / CI Pipeline / notify-event-bridge (pull_request) Successful in 2s
Auto-version and Release / release (pull_request) Successful in 5s
The converged-release bump updated __init__/header but missed the TUI
banner string at rune_tui.py:1888; the banner-surface test correctly
failed master CI. The version-surfaces checker watches the header
comment only — banner added to the gap list for the bump workflow.
2026-09-19 19:13:16 +01:00
conductor e6c8c5444d chore(release): auto-bump version to 0.88.0 — earned by # (minor: converged release (push-to-master bump))
Auto-version and Release / release (push) Successful in 5s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 2s
CI Pipeline / lint (push) Successful in 31s
CI Pipeline / unit-tests (push) Failing after 4m35s
CI Pipeline / canary (push) Successful in 29s
CI Pipeline / best-practices (push) Successful in 1s
CI Pipeline / documentation (push) Successful in 2s
deploy / deploy (push) Failing after 2m8s
CI Pipeline / type-check (push) Successful in 25s
CI Pipeline / gitea-offline (push) Successful in 13s
CI Pipeline / required-checks (push) Failing after 0s
Promotion record: (unknown)
2026-09-19 18:34:33 +01:00
conductor 11270cb06a chore(release): auto-bump version to 0.87.6 — earned by #354 (await-intent: refresh refs before op-type inference (M10 correction))
Auto-version and Release / release (push) Successful in 5s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 1s
CI Pipeline / lint (push) Successful in 31s
CI Pipeline / unit-tests (push) Successful in 4m44s
CI Pipeline / canary (push) Successful in 30s
CI Pipeline / best-practices (push) Successful in 1s
CI Pipeline / documentation (push) Successful in 1s
CI Pipeline / type-check (push) Successful in 26s
CI Pipeline / gitea-offline (push) Successful in 13s
CI Pipeline / required-checks (push) Successful in 0s
deploy / deploy (push) Successful in 8m29s
Promotion record: http://192.168.1.156:3000/conductor/rune/pulls/354
2026-09-19 18:34:25 +01:00
conductor f8a568714b Merge pull request 'await-intent: refresh refs before op-type inference (M10 correction)' (#354) from m10-derive-refresh into master
CI Pipeline / best-practices (push) Successful in 4s
CI Pipeline / documentation (push) Successful in 1s
Auto-version and Release / release (push) Successful in 6s
CI Pipeline / canary (push) Successful in 28s
CI Pipeline / type-check (push) Successful in 27s
CI Pipeline / lint (push) Successful in 35s
CI Pipeline / gitea-offline (push) Successful in 13s
CI Pipeline / unit-tests (push) Successful in 4m48s
CI Pipeline / required-checks (push) Successful in 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 2s
deploy / deploy (push) Successful in 13m37s
2026-09-19 18:34:19 +01:00
conductor c3f81e60ec Merge branch 'master' into m10-derive-refresh
CI Pipeline / best-practices (push) Successful in 4s
CI Pipeline / documentation (push) Successful in 2s
CI Pipeline / canary (push) Successful in 32s
CI Pipeline / type-check (push) Successful in 28s
CI Pipeline / lint (push) Successful in 36s
CI Pipeline / gitea-offline (push) Successful in 13s
CI Pipeline / lint (pull_request) Successful in 32s
CI Pipeline / best-practices (pull_request) Successful in 2s
CI Pipeline / documentation (pull_request) Successful in 2s
CI Pipeline / canary (pull_request) Successful in 25s
CI Pipeline / gitea-offline (pull_request) Successful in 13s
Spec gate (headless) / spec-gate (pull_request) Successful in 2s
deploy / deploy (push) Skipped
CI Pipeline / type-check (pull_request) Successful in 26s
CI Pipeline / unit-tests (push) Successful in 4m48s
CI Pipeline / required-checks (push) Successful in 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 1s
CI Pipeline / unit-tests (pull_request) Successful in 4m42s
CI Pipeline / required-checks (pull_request) Successful in 0s
CI Pipeline / CI Pipeline / notify-event-bridge (pull_request) Successful in 2s
Auto-version and Release / release (pull_request) Successful in 6s
2026-09-19 18:28:51 +01:00
conductor efb99d4682 await-intent: refresh remote refs before op-type inference (M10 correction)
CI Pipeline / best-practices (push) Successful in 3s
CI Pipeline / documentation (push) Successful in 1s
Auto-label / priority-gate (pull_request) Skipped
Auto-label / auto-label (pull_request) Successful in 1s
CI Pipeline / type-check (push) Successful in 28s
CI Pipeline / canary (push) Successful in 35s
deploy / deploy (push) Skipped
CI Pipeline / lint (push) Successful in 36s
CI Pipeline / gitea-offline (push) Successful in 13s
CI Pipeline / lint (pull_request) Successful in 33s
CI Pipeline / best-practices (pull_request) Successful in 1s
CI Pipeline / documentation (pull_request) Successful in 1s
CI Pipeline / canary (pull_request) Successful in 32s
CI Pipeline / gitea-offline (pull_request) Successful in 13s
Spec gate (headless) / spec-gate (pull_request) Successful in 3s
CI Pipeline / type-check (pull_request) Successful in 26s
CI Pipeline / unit-tests (push) Successful in 4m52s
CI Pipeline / required-checks (push) Successful in 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 2s
CI Pipeline / unit-tests (pull_request) Successful in 4m44s
CI Pipeline / required-checks (pull_request) Successful in 1s
CI Pipeline / CI Pipeline / notify-event-bridge (pull_request) Successful in 2s
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))
Auto-version and Release / release (push) Successful in 5s
CI Pipeline / unit-tests (push) Successful in 4m22s
CI Pipeline / lint (push) Successful in 32s
CI Pipeline / canary (push) Successful in 25s
CI Pipeline / best-practices (push) Successful in 2s
CI Pipeline / documentation (push) Successful in 1s
CI Pipeline / type-check (push) Successful in 26s
CI Pipeline / gitea-offline (push) Successful in 12s
CI Pipeline / required-checks (push) Successful in 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 1s
deploy / deploy (push) Successful in 1m58s
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
CI Pipeline / best-practices (push) Successful in 3s
CI Pipeline / documentation (push) Successful in 1s
Auto-version and Release / release (push) Successful in 6s
CI Pipeline / canary (push) Successful in 29s
CI Pipeline / type-check (push) Successful in 27s
CI Pipeline / lint (push) Successful in 35s
CI Pipeline / gitea-offline (push) Successful in 13s
CI Pipeline / unit-tests (push) Successful in 4m31s
CI Pipeline / required-checks (push) Successful in 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 2s
deploy / deploy (push) Successful in 5m10s
2026-09-19 18:02:46 +01:00
conductor 80ed978fbf docs: R13/M9 PR-flow live proof marker (harmless, no code change)
Auto-label / priority-gate (pull_request) Skipped
Auto-label / auto-label (pull_request) Successful in 1s
CI Pipeline / best-practices (pull_request) Successful in 3s
CI Pipeline / documentation (pull_request) Successful in 1s
CI Pipeline / canary (pull_request) Successful in 28s
CI Pipeline / type-check (pull_request) Successful in 26s
CI Pipeline / lint (pull_request) Successful in 34s
Spec gate (headless) / spec-gate (pull_request) Successful in 3s
CI Pipeline / gitea-offline (pull_request) Successful in 13s
CI Pipeline / lint (push) Successful in 32s
CI Pipeline / best-practices (push) Successful in 2s
CI Pipeline / canary (push) Successful in 28s
CI Pipeline / documentation (push) Successful in 1s
CI Pipeline / gitea-offline (push) Successful in 13s
deploy / deploy (push) Skipped
CI Pipeline / type-check (push) Successful in 26s
CI Pipeline / unit-tests (pull_request) Successful in 4m24s
CI Pipeline / required-checks (pull_request) Successful in 1s
CI Pipeline / CI Pipeline / notify-event-bridge (pull_request) Successful in 2s
CI Pipeline / unit-tests (push) Successful in 4m22s
CI Pipeline / required-checks (push) Successful in 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 2s
Auto-version and Release / release (pull_request) Successful in 6s
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)
Auto-version and Release / release (push) Successful in 6s
CI Pipeline / unit-tests (push) Successful in 4m24s
CI Pipeline / lint (push) Successful in 31s
CI Pipeline / canary (push) Successful in 29s
CI Pipeline / best-practices (push) Successful in 1s
CI Pipeline / documentation (push) Successful in 1s
CI Pipeline / type-check (push) Successful in 26s
CI Pipeline / gitea-offline (push) Successful in 13s
CI Pipeline / required-checks (push) Successful in 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 1s
deploy / deploy (push) Successful in 2m2s
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
CI Pipeline / best-practices (push) Successful in 3s
CI Pipeline / documentation (push) Successful in 1s
Auto-version and Release / release (push) Successful in 5s
CI Pipeline / canary (push) Successful in 28s
CI Pipeline / type-check (push) Successful in 27s
CI Pipeline / lint (push) Successful in 34s
CI Pipeline / gitea-offline (push) Successful in 13s
CI Pipeline / unit-tests (push) Successful in 4m24s
CI Pipeline / required-checks (push) Successful in 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 1s
deploy / deploy (push) Successful in 5m6s
2026-09-19 17:46:42 +01:00
conductor 643f9aa9d1 custodian: default Gitea endpoint = PC-internal (127.0.0.1:3000)
CI Pipeline / best-practices (push) Successful in 3s
CI Pipeline / documentation (push) Successful in 2s
Auto-label / priority-gate (pull_request) Skipped
Auto-label / auto-label (pull_request) Successful in 2s
CI Pipeline / canary (push) Successful in 27s
CI Pipeline / type-check (push) Successful in 26s
deploy / deploy (push) Skipped
CI Pipeline / lint (push) Successful in 34s
CI Pipeline / gitea-offline (push) Successful in 13s
CI Pipeline / lint (pull_request) Successful in 31s
CI Pipeline / best-practices (pull_request) Successful in 1s
CI Pipeline / documentation (pull_request) Successful in 1s
CI Pipeline / canary (pull_request) Successful in 27s
CI Pipeline / gitea-offline (pull_request) Successful in 13s
Spec gate (headless) / spec-gate (pull_request) Successful in 3s
CI Pipeline / type-check (pull_request) Successful in 25s
CI Pipeline / unit-tests (push) Successful in 4m24s
CI Pipeline / required-checks (push) Successful in 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 2s
CI Pipeline / unit-tests (pull_request) Successful in 4m29s
CI Pipeline / required-checks (pull_request) Successful in 0s
CI Pipeline / CI Pipeline / notify-event-bridge (pull_request) Successful in 2s
Auto-version and Release / release (pull_request) Successful in 7s
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)
Auto-version and Release / release (push) Successful in 12s
deploy / deploy (push) Skipped
CI Pipeline / best-practices (push) Successful in 3s
CI Pipeline / documentation (push) Successful in 8s
CI Pipeline / lint (push) Failing after 50s
CI Pipeline / canary (push) Failing after 44s
CI Pipeline / gitea-offline (push) Successful in 21s
CI Pipeline / type-check (push) Successful in 40s
CI Pipeline / unit-tests (push) Failing after 5m36s
CI Pipeline / required-checks (push) Failing after 7s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 10s
Promotion record: #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
CI Pipeline / best-practices (push) Successful in 6s
Auto-version and Release / release (push) Successful in 15s
CI Pipeline / documentation (push) Successful in 7s
CI Pipeline / canary (push) Successful in 33s
CI Pipeline / lint (push) Successful in 42s
CI Pipeline / gitea-offline (push) Successful in 20s
CI Pipeline / type-check (push) Successful in 55s
CI Pipeline / unit-tests (push) Successful in 4m36s
CI Pipeline / required-checks (push) Successful in 4s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 11s
deploy / deploy (push) Failing after 12m12s
2026-09-19 16:49:48 +01:00
conductor cba9045982 auto-label: any declared kind is authoritative; absorption is the filing standard
CI Pipeline / best-practices (push) Successful in 5s
CI Pipeline / documentation (push) Successful in 5s
CI Pipeline / lint (push) Successful in 40s
CI Pipeline / canary (push) Successful in 35s
Auto-label / auto-label (pull_request) Successful in 8s
CI Pipeline / type-check (push) Successful in 29s
Auto-label / priority-gate (pull_request) Skipped
CI Pipeline / gitea-offline (push) Successful in 14s
CI Pipeline / canary (pull_request) Successful in 34s
CI Pipeline / lint (pull_request) Successful in 44s
CI Pipeline / documentation (pull_request) Successful in 10s
Spec gate (headless) / spec-gate (pull_request) Successful in 12s
CI Pipeline / gitea-offline (pull_request) Successful in 17s
deploy / deploy (push) Skipped
CI Pipeline / best-practices (pull_request) Successful in 5s
CI Pipeline / type-check (pull_request) Successful in 29s
CI Pipeline / unit-tests (push) Successful in 4m33s
CI Pipeline / required-checks (push) Successful in 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 4s
CI Pipeline / unit-tests (pull_request) Successful in 4m50s
CI Pipeline / required-checks (pull_request) Successful in 9s
CI Pipeline / CI Pipeline / notify-event-bridge (pull_request) Successful in 3s
Auto-version and Release / release (pull_request) Successful in 34s
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)
Auto-version and Release / release (push) Successful in 38s
CI Pipeline / unit-tests (push) Successful in 4m32s
CI Pipeline / lint (push) Successful in 38s
CI Pipeline / canary (push) Successful in 33s
CI Pipeline / best-practices (push) Successful in 4s
CI Pipeline / documentation (push) Successful in 6s
CI Pipeline / type-check (push) Successful in 31s
CI Pipeline / gitea-offline (push) Successful in 16s
CI Pipeline / required-checks (push) Successful in 2s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 4s
deploy / deploy (push) Successful in 4m26s
Promotion record: #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
CI Pipeline / best-practices (push) Successful in 8s
CI Pipeline / documentation (push) Successful in 6s
CI Pipeline / canary (push) Successful in 35s
CI Pipeline / type-check (push) Successful in 32s
CI Pipeline / gitea-offline (push) Successful in 17s
CI Pipeline / lint (push) Successful in 48s
Auto-version and Release / release (push) Successful in 15s
CI Pipeline / unit-tests (push) Successful in 4m37s
CI Pipeline / required-checks (push) Successful in 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 11s
deploy / deploy (push) Successful in 9m38s
2026-09-19 16:08:34 +01:00
conductor ea3c20e205 templates: heading IS the summary — drop the meta-label
CI Pipeline / best-practices (push) Successful in 11s
CI Pipeline / gitea-offline (push) Successful in 16s
CI Pipeline / canary (push) Successful in 37s
CI Pipeline / type-check (push) Successful in 29s
CI Pipeline / lint (pull_request) Successful in 37s
CI Pipeline / canary (pull_request) Successful in 38s
CI Pipeline / best-practices (pull_request) Successful in 6s
CI Pipeline / documentation (pull_request) Successful in 6s
CI Pipeline / gitea-offline (pull_request) Successful in 25s
CI Pipeline / documentation (push) Successful in 5s
deploy / deploy (push) Skipped
CI Pipeline / type-check (pull_request) Successful in 32s
CI Pipeline / lint (push) Successful in 39s
Spec gate (headless) / spec-gate (pull_request) Successful in 26s
CI Pipeline / unit-tests (push) Successful in 4m33s
CI Pipeline / required-checks (push) Successful in 2s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 7s
CI Pipeline / unit-tests (pull_request) Successful in 4m43s
CI Pipeline / required-checks (pull_request) Successful in 2s
CI Pipeline / CI Pipeline / notify-event-bridge (pull_request) Successful in 5s
Auto-version and Release / release (pull_request) Successful in 40s
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
Auto-label / priority-gate (pull_request) Skipped
Auto-label / auto-label (pull_request) Successful in 2s
CI Pipeline / lint (push) Successful in 40s
CI Pipeline / canary (push) Successful in 34s
CI Pipeline / best-practices (push) Successful in 3s
CI Pipeline / documentation (push) Successful in 4s
CI Pipeline / type-check (push) Successful in 31s
CI Pipeline / gitea-offline (push) Successful in 15s
CI Pipeline / lint (pull_request) Successful in 38s
CI Pipeline / canary (pull_request) Successful in 32s
CI Pipeline / best-practices (pull_request) Successful in 8s
CI Pipeline / documentation (pull_request) Successful in 4s
CI Pipeline / type-check (pull_request) Successful in 29s
CI Pipeline / unit-tests (push) Successful in 4m37s
CI Pipeline / gitea-offline (pull_request) Successful in 30s
Spec gate (headless) / spec-gate (pull_request) Successful in 18s
CI Pipeline / unit-tests (pull_request) Successful in 4m33s
CI Pipeline / required-checks (push) Successful in 2s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 7s
CI Pipeline / required-checks (pull_request) Successful in 3s
CI Pipeline / CI Pipeline / notify-event-bridge (pull_request) Failing after 21s
deploy / deploy (push) Failing after 13m5s
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)
Auto-version and Release / release (push) Successful in 15s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 8s
CI Pipeline / lint (push) Successful in 35s
CI Pipeline / unit-tests (push) Successful in 4m32s
CI Pipeline / canary (push) Successful in 33s
CI Pipeline / best-practices (push) Successful in 3s
CI Pipeline / documentation (push) Successful in 5s
CI Pipeline / type-check (push) Successful in 29s
CI Pipeline / gitea-offline (push) Successful in 15s
CI Pipeline / required-checks (push) Successful in 3s
deploy / deploy (push) Successful in 18m42s
Promotion record: #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
CI Pipeline / best-practices (push) Successful in 7s
CI Pipeline / documentation (push) Successful in 7s
CI Pipeline / canary (push) Successful in 35s
CI Pipeline / lint (push) Successful in 51s
CI Pipeline / gitea-offline (push) Successful in 18s
CI Pipeline / type-check (push) Successful in 32s
Auto-version and Release / release (push) Successful in 11s
CI Pipeline / unit-tests (push) Successful in 4m38s
CI Pipeline / required-checks (push) Successful in 2s
deploy / deploy (push) Failing after 15m18s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 9s
2026-09-19 15:31:49 +01:00
conductor 3788875410 test: pin live-defect record to empty — #324 verified non-reproducing 2026-09-19
CI Pipeline / best-practices (push) Successful in 5s
CI Pipeline / documentation (push) Successful in 3s
CI Pipeline / canary (push) Successful in 33s
CI Pipeline / lint (push) Successful in 38s
CI Pipeline / type-check (push) Successful in 32s
CI Pipeline / gitea-offline (push) Successful in 19s
CI Pipeline / lint (pull_request) Successful in 37s
CI Pipeline / canary (pull_request) Successful in 36s
CI Pipeline / best-practices (pull_request) Successful in 4s
CI Pipeline / documentation (pull_request) Successful in 7s
CI Pipeline / gitea-offline (pull_request) Successful in 14s
deploy / deploy (push) Skipped
CI Pipeline / type-check (pull_request) Successful in 32s
Spec gate (headless) / spec-gate (pull_request) Successful in 24s
CI Pipeline / unit-tests (push) Successful in 4m35s
CI Pipeline / required-checks (push) Successful in 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 13s
CI Pipeline / unit-tests (pull_request) Successful in 4m29s
CI Pipeline / required-checks (pull_request) Successful in 3s
CI Pipeline / CI Pipeline / notify-event-bridge (pull_request) Successful in 7s
Auto-version and Release / release (pull_request) Successful in 28s
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
CI Pipeline / best-practices (push) Successful in 6s
CI Pipeline / documentation (push) Successful in 4s
Auto-label / priority-gate (pull_request) Skipped
Auto-label / auto-label (pull_request) Successful in 3s
CI Pipeline / canary (push) Successful in 35s
CI Pipeline / lint (push) Successful in 42s
CI Pipeline / type-check (push) Successful in 29s
deploy / deploy (push) Skipped
CI Pipeline / gitea-offline (push) Successful in 15s
CI Pipeline / best-practices (pull_request) Successful in 4s
CI Pipeline / documentation (pull_request) Successful in 4s
CI Pipeline / canary (pull_request) Successful in 29s
CI Pipeline / gitea-offline (pull_request) Successful in 20s
CI Pipeline / type-check (pull_request) Successful in 43s
Spec gate (headless) / spec-gate (pull_request) Successful in 16s
CI Pipeline / lint (pull_request) Successful in 45s
CI Pipeline / unit-tests (push) Failing after 4m31s
CI Pipeline / required-checks (push) Failing after 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 3s
CI Pipeline / unit-tests (pull_request) Failing after 4m27s
CI Pipeline / required-checks (pull_request) Failing after 2s
CI Pipeline / CI Pipeline / notify-event-bridge (pull_request) Successful in 4s
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)
CI Pipeline / best-practices (push) Successful in 6s
CI Pipeline / canary (push) Successful in 32s
CI Pipeline / gitea-offline (push) Successful in 16s
CI Pipeline / type-check (push) Successful in 32s
CI Pipeline / lint (push) Successful in 37s
CI Pipeline / documentation (push) Successful in 13s
deploy / deploy (push) Skipped
CI Pipeline / unit-tests (push) Successful in 4m48s
CI Pipeline / required-checks (push) Successful in 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 3s
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
CI Pipeline / documentation (push) Successful in 12s
CI Pipeline / canary (push) Successful in 36s
CI Pipeline / type-check (push) Successful in 34s
CI Pipeline / lint (push) Successful in 35s
CI Pipeline / best-practices (push) Successful in 14s
deploy / deploy (push) Skipped
CI Pipeline / gitea-offline (push) Successful in 31s
CI Pipeline / unit-tests (push) Failing after 4m47s
CI Pipeline / required-checks (push) Failing after 2s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 5s
2026-09-19 07:18:07 +01:00
conductor d9bcebb730 feat(tty): MiMo harness process-ownership contract — group-killed bash execution + explicit detachment
CI Pipeline / best-practices (push) Successful in 5s
CI Pipeline / documentation (push) Successful in 5s
CI Pipeline / canary (push) Successful in 29s
CI Pipeline / lint (push) Successful in 37s
deploy / deploy (push) Skipped
CI Pipeline / type-check (push) Successful in 30s
CI Pipeline / gitea-offline (push) Successful in 15s
CI Pipeline / unit-tests (push) Successful in 4m46s
CI Pipeline / required-checks (push) Successful in 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 4s
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)
CI Pipeline / documentation (push) Successful in 4s
CI Pipeline / best-practices (push) Successful in 6s
CI Pipeline / gitea-offline (push) Successful in 17s
CI Pipeline / canary (push) Successful in 31s
deploy / deploy (push) Skipped
CI Pipeline / type-check (push) Successful in 32s
CI Pipeline / lint (push) Successful in 38s
CI Pipeline / unit-tests (push) Successful in 4m27s
CI Pipeline / required-checks (push) Successful in 2s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 4s
2026-09-19 06:39:11 +01:00
conductor 634821efd4 chore(r8): LOST_EVENT_RECOVERY PASS — live lost-event proof + canonical evidence
CI Pipeline / best-practices (push) Successful in 4s
CI Pipeline / documentation (push) Successful in 4s
CI Pipeline / lint (push) Successful in 52s
CI Pipeline / canary (push) Successful in 50s
CI Pipeline / type-check (push) Successful in 39s
deploy / deploy (push) Skipped
CI Pipeline / gitea-offline (push) Successful in 15s
CI Pipeline / unit-tests (push) Successful in 4m43s
CI Pipeline / required-checks (push) Successful in 2s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 4s
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
CI Pipeline / best-practices (push) Successful in 5s
CI Pipeline / documentation (push) Successful in 3s
CI Pipeline / canary (push) Successful in 31s
CI Pipeline / lint (push) Successful in 38s
deploy / deploy (push) Skipped
CI Pipeline / type-check (push) Successful in 27s
CI Pipeline / gitea-offline (push) Successful in 16s
CI Pipeline / unit-tests (push) Successful in 4m27s
CI Pipeline / required-checks (push) Successful in 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 3s
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
CI Pipeline / best-practices (push) Successful in 7s
CI Pipeline / lint (push) Failing after 28s
CI Pipeline / documentation (push) Successful in 4s
CI Pipeline / canary (push) Successful in 33s
deploy / deploy (push) Skipped
CI Pipeline / gitea-offline (push) Successful in 16s
CI Pipeline / type-check (push) Successful in 32s
CI Pipeline / unit-tests (push) Failing after 4m38s
CI Pipeline / required-checks (push) Failing after 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 4s
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
CI Pipeline / best-practices (push) Successful in 6s
CI Pipeline / documentation (push) Successful in 4s
CI Pipeline / lint (push) Failing after 30s
CI Pipeline / canary (push) Successful in 34s
deploy / deploy (push) Skipped
CI Pipeline / gitea-offline (push) Successful in 16s
CI Pipeline / unit-tests (push) Failing after 4m33s
CI Pipeline / type-check (push) Failing after 12m29s
CI Pipeline / required-checks (push) Failing after 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 9s
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
57 changed files with 177660 additions and 376 deletions

No files matched your search

+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
+50 -12
View File
@@ -11,7 +11,7 @@ jobs:
# P0/P1/P2/P3. An issue that lands without one gets 'unprioritized' +
# a demand comment — filing is not complete until prioritized.
priority-gate:
if: github.event_name == 'issues' && github.event.action != 'labeled'
if: github.event_name == 'issues' && github.event.action != 'labeled' && github.event.issue.state == 'open'
runs-on: rune-infra-pi
steps:
- name: Enforce priority label
@@ -50,6 +50,20 @@ jobs:
uses: actions/github-script@v7
with:
script: |
// CLOSED-ISSUE GUARD (#407): labels are filing-time metadata.
// A closed issue's lifecycle has ended; re-running label
// inference on it re-adds stale type labels (bug = currently
// incorrect behavior — a closed fixed issue must not carry
// it) and makes any human label cleanup self-defeating,
// because every PUT fires a 'labeled' event that re-triggers
// this job. Post-close label curation belongs to humans and
// the conductor, not this workflow.
const issueState = context.payload.issue?.state;
if (issueState === 'closed') {
console.log(`Issue #${context.payload.issue?.number} is closed — auto-label skips (labels are curated post-close).`);
return;
}
const action = context.payload.action;
const title = context.payload.issue?.title || context.payload.pull_request?.title || '';
const body = context.payload.issue?.body || context.payload.pull_request?.body || '';
const text = (title + ' ' + body).toLowerCase();
@@ -58,9 +72,43 @@ 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 if (action === 'opened') {
// KEYWORD FALLBACK (#407): pre-template issues only, and
// ONLY at filing time. Re-running keyword guesses on every
// edit/label event overrides human curation of spine-less
// issues (documented rule: keyword heuristics are the
// pre-template fallback, not a standing authority).
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 +140,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,
+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.87.0**
**Current release: v0.88.4**
**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.**
+124
View File
@@ -0,0 +1,124 @@
import { execFile } from "node:child_process"
import { existsSync, appendFileSync } from "node:fs"
// builder-bridge — Rune Core preflight for the MiMo builder (handoff
// 2026-09-10 §3–§7, Option C bridge tranche). For each user turn, the hook
// extracts the user's message from the outgoing LLM request, runs the Rune
// Core builder-bridge preflight (deterministic: route classification +
// memory selection + active-Scaffolding projection, ZERO model calls), and
// appends a compact capsule to the final user message. Same Rune Core the
// TUI/operator path uses — this file is a thin adapter with no cognition.
//
// CANONICAL SOURCE: config/mimo-hooks/builder-bridge.ts
// Installed to ~/.mimocode/hooks/builder-bridge.ts by
// `scripts/install_mimo_hook.py` (hash-verified, drift-detecting — the same
// contract as event-wait-guard.ts). T22: this file was previously
// UNVERSIONED and hardcoded an ephemeral interpreter path (/tmp/ci-venv),
// which silently killed the whole edge; both defects are repaired here.
//
// Overhead contract (§7/§8): capsule ≤ ~300 tokens; a repeat/empty task
// costs ~0ms (TTL cache); a fresh task ~150ms (bounded retrieval). The hook
// degrades silently to no-injection on any failure — it must never block
// the builder.
//
// Injection policy: only append when the capsule is non-empty. A plain
// "hello" gets nothing (§5: if nothing relevant exists, inject nothing).
const BRIDGE = "/mnt/workdrive/issue161-harness/src/rune/builder_bridge_cli.py"
const MARKER_PREFIX = "/tmp/rune-bridge-"
// Interpreter resolution (T22 repair): the previous hardcoded
// "/tmp/ci-venv/bin/python" is an EPHEMERAL path that no longer exists, so
// every bridge call failed and the hook silently degraded — the MiMo edge
// received no Rune Core preflight at all (zero fire-log lines). Resolve
// against durable candidates, first existing wins; env override wins over
// all of them. If nothing exists the hook degrades as before.
const PY_CANDIDATES = [
process.env.MIMO_BRIDGE_PY,
"/mnt/workdrive/issue161-harness/.test-venv/bin/python",
"/home/nick/.venvs/memory/bin/python3",
"/usr/bin/python3",
].filter((p) => typeof p === "string" && p.length > 0)
function resolvePy() {
for (const p of PY_CANDIDATES) {
try {
if (existsSync(p)) return p
} catch {}
}
return null
}
// Per-process dedupe: identical task text within the cache TTL does not need
// a second bridge call — the CLI has its own TTL cache, but skipping the
// process spawn entirely for the same message text within 10 minutes keeps
// repeats at ~0ms.
const lastText = new Map() // text -> timestamp
const TTL = 600_000
function extractUserText(messages) {
// messages: Array<{ info: Message, parts: Part[] }> — newest last.
for (let i = messages.length - 1; i >= 0; i--) {
const m = messages[i]
if (m?.info?.role !== "user") continue
const texts = []
for (const p of m.parts ?? []) {
if (p?.type === "text" && typeof p.text === "string") texts.push(p.text)
}
if (texts.length) return texts.join("\n").slice(0, 4000)
}
return ""
}
export default {
"experimental.chat.messages.transform": async (input, output) => {
try {
if (!Array.isArray(output.messages) || output.messages.length === 0) return
const userText = extractUserText(output.messages)
if (!userText || userText.length < 12) return // trivial/noise guard
// Harness-internal steps (checkpoint writer, compaction, system
// reminders) are not builder tasks — no capsule (measured: the fire
// log showed checkpoint-writer steps receiving capsules 2026-09-10).
if (/^(<system-reminder>|EXTRACTION REQUIRED)/.test(userText.trim())) return
const now = Date.now()
const prev = lastText.get(userText)
if (prev !== undefined && now - prev < TTL) return // dedupe repeats
lastText.set(userText, now)
if (lastText.size > 64) {
// evict oldest
let oldestKey = null, oldestVal = Infinity
for (const [k, v] of lastText) if (v < oldestVal) { oldestVal = v; oldestKey = k }
if (oldestKey) lastText.delete(oldestKey)
}
const py = resolvePy()
if (!py) return // no durable interpreter — degrade (never block)
const capsule = await new Promise((resolve) => {
execFile(py, [BRIDGE, userText], { timeout: 15_000 }, (err, stdout) => {
resolve(err ? "" : (stdout?.toString() ?? ""))
})
})
if (!capsule.trim()) return
// Durable fire-trace: one line per ACTUAL injection into an outgoing
// model request (handoff §1 proof requirement). Not a canary — this is
// standing observability for the bridge's consumer edge.
try {
appendFileSync("/tmp/rune-bridge-fire.log",
JSON.stringify({ ts: new Date().toISOString(), task: userText.slice(0, 80), capsule_tokens: Math.round(capsule.length / 4), py }) + "\n")
} catch {}
// Append the capsule to the LAST user message (the one being answered).
const last = output.messages[output.messages.length - 1]
if (last?.parts && Array.isArray(last.parts)) {
last.parts.push({
type: "text",
text: "\n\n<rune-preflight>\n" + capsule.trim() + "\n</rune-preflight>\n(Injected by Rune Core builder bridge — deterministic preflight, zero model calls. Relevant state above; ignore if not applicable to this task.)",
})
}
} catch {
// never block the builder on bridge failure
}
},
}
+78 -40
View File
@@ -1,54 +1,92 @@
import { tool } from "@mimo-ai/plugin"
import { execSync } from "child_process"
// await_operation — T21.3 §21.3C: FIRST-CLASS async wait tool.
// Uses the plugin tool() API with args (not parameters).
export const AwaitOperation = tool({
description: [
"Wait for an asynchronous external operation (CI, deploy, release) to complete.",
"Registers on the event bridge, yields until the completion event arrives, then returns the verified result.",
"USE THIS instead of `sleep N; curl status` — it is the canonical event-driven wait.",
].join(" "),
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: {
sha: tool.schema.string().describe(
"The exact commit SHA the operation is running against"),
deadline_secs: tool.schema.number().optional().describe(
"Maximum wait in seconds (default 900)"),
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, ctx) {
const repoRoot = "/mnt/workdrive/issue161-harness"
const deadline = args.deadline_secs || 900
const cmd = [
"python3", `${repoRoot}/scripts/ci_event_wait.py`,
"--sha", args.sha,
"--deadline", String(deadline),
].join(" ")
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: repoRoot,
timeout: (deadline + 60) * 1000,
cwd: "/mnt/workdrive/issue161-harness",
timeout: (norm.deadline_secs + 60) * 1000,
encoding: "utf-8" as const,
env: {
...process.env,
DEPLOY_SHA: args.sha,
RUNE_WR_ROOT: "/mnt/workdrive/wr-bridge",
RUNE_WR_CODE: "/home/nick/.local/share/mimo-wait-resume",
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",
},
})
const lines = result.trim().split("\n")
const jsonLine = lines.find((l: string) => l.startsWith("{"))
if (jsonLine) return jsonLine
return "await_operation: no JSON output"
} catch (e: any) {
const stdout = e.stdout || ""
const lines = stdout.trim().split("\n")
const jsonLine = lines.find((l: string) => l.startsWith("{"))
if (jsonLine) return jsonLine
return JSON.stringify({
ok: false,
error: `await_operation failed: ${(e.stderr || e.message || "?").slice(0, 200)}`,
})
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)"
},
})
+1
View File
@@ -17,6 +17,7 @@
"intent_continuity",
"local_tool_runtime",
"message_queue",
"native_units",
"openai_compat_transport",
"provider_context",
"recall_uplift",
+58 -60
View File
@@ -11,24 +11,22 @@
"NEEDS_REVALIDATION",
"DEFERRED_FUTURE"
],
"live_defects": [
324
],
"live_defects": [],
"records": [
{
"number": 324,
"title": "Engine defect: checkpoint writer fails deterministically on aborted worker sessions (MessageAbortedError -> empty checkpoint shells)",
"tracker_state": "open",
"reconciliation_state": "VALID_OPEN",
"tracker_state": "closed",
"reconciliation_state": "FIXED_VERIFIED",
"labels": [
"bug",
"custodian",
"life",
"memory"
],
"live_defect": true,
"last_revalidated": "2026-09-11",
"next_action": ""
"live_defect": false,
"last_revalidated": "2026-09-19",
"next_action": "none \u2014 defect no longer reproduces: zero MessageAbortedError in current logs (incl. active worker), six most recent session checkpoints full documents (111-396 lines); verified by present-absence 2026-09-19"
},
{
"number": 316,
@@ -237,8 +235,8 @@
{
"number": 183,
"title": "Future: typed temporal semantics for facts, relationships, beliefs, and preferences",
"tracker_state": "open",
"reconciliation_state": "DEFERRED_FUTURE",
"tracker_state": "closed",
"reconciliation_state": "HISTORICAL_EVIDENCE",
"labels": [
"P3 \u2014 low",
"governance",
@@ -250,14 +248,14 @@
"ready"
],
"live_defect": false,
"last_revalidated": "2026-09-11",
"next_action": ""
"last_revalidated": "2026-09-19",
"next_action": "none \u2014 idea absorbed into parent epic #181 as tracked checklist item; full detail preserved in this closed issue; re-mint when live"
},
{
"number": 182,
"title": "Future: GitHub code-search prior-art audit for graph and vector memory",
"tracker_state": "open",
"reconciliation_state": "DEFERRED_FUTURE",
"tracker_state": "closed",
"reconciliation_state": "HISTORICAL_EVIDENCE",
"labels": [
"P3 \u2014 low",
"governance",
@@ -266,8 +264,8 @@
"ready"
],
"live_defect": false,
"last_revalidated": "2026-09-11",
"next_action": ""
"last_revalidated": "2026-09-19",
"next_action": "none \u2014 idea absorbed into parent epic #181 as tracked checklist item; full detail preserved in this closed issue; re-mint when live"
},
{
"number": 181,
@@ -287,13 +285,13 @@
],
"live_defect": false,
"last_revalidated": "2026-09-11",
"next_action": ""
"next_action": "epic holds absorbed children #182 #183 + research watchlist #164 #165 #166; closes when prerequisites land or ideas dropped"
},
{
"number": 179,
"title": "Future: succession/privacy semantics and lineage evaluation",
"tracker_state": "open",
"reconciliation_state": "DEFERRED_FUTURE",
"tracker_state": "closed",
"reconciliation_state": "HISTORICAL_EVIDENCE",
"labels": [
"P3 \u2014 low",
"governance",
@@ -305,14 +303,14 @@
"ready"
],
"live_defect": false,
"last_revalidated": "2026-09-11",
"next_action": ""
"last_revalidated": "2026-09-19",
"next_action": "none \u2014 idea absorbed into parent epic #175 as tracked checklist item; full detail preserved in this closed issue; re-mint when live"
},
{
"number": 178,
"title": "Future: evidence-grounded ancestral perspective with explicit uncertainty",
"tracker_state": "open",
"reconciliation_state": "DEFERRED_FUTURE",
"tracker_state": "closed",
"reconciliation_state": "HISTORICAL_EVIDENCE",
"labels": [
"P3 \u2014 low",
"governance",
@@ -322,14 +320,14 @@
"perception"
],
"live_defect": false,
"last_revalidated": "2026-09-11",
"next_action": ""
"last_revalidated": "2026-09-19",
"next_action": "none \u2014 idea absorbed into parent epic #175 as tracked checklist item; full detail preserved in this closed issue; re-mint when live"
},
{
"number": 177,
"title": "Future: temporal autobiographical model with provenance and reinterpretation lineage",
"tracker_state": "open",
"reconciliation_state": "DEFERRED_FUTURE",
"tracker_state": "closed",
"reconciliation_state": "HISTORICAL_EVIDENCE",
"labels": [
"P3 \u2014 low",
"governance",
@@ -340,14 +338,14 @@
"ready"
],
"live_defect": false,
"last_revalidated": "2026-09-11",
"next_action": ""
"last_revalidated": "2026-09-19",
"next_action": "none \u2014 idea absorbed into parent epic #175 as tracked checklist item; full detail preserved in this closed issue; re-mint when live"
},
{
"number": 176,
"title": "Future: lineage-aware situated curiosity for meaningful autobiographical gaps",
"tracker_state": "open",
"reconciliation_state": "DEFERRED_FUTURE",
"tracker_state": "closed",
"reconciliation_state": "HISTORICAL_EVIDENCE",
"labels": [
"P3 \u2014 low",
"feature",
@@ -358,8 +356,8 @@
"ready"
],
"live_defect": false,
"last_revalidated": "2026-09-11",
"next_action": ""
"last_revalidated": "2026-09-19",
"next_action": "none \u2014 idea absorbed into parent epic #175 as tracked checklist item; full detail preserved in this closed issue; re-mint when live"
},
{
"number": 175,
@@ -379,13 +377,13 @@
],
"live_defect": false,
"last_revalidated": "2026-09-11",
"next_action": ""
"next_action": "epic holds absorbed children #176-#179 as checklist items; closes when prerequisites land or ideas dropped"
},
{
"number": 166,
"title": "RESEARCH WATCHLIST: Memory-R1 (RL memory ops), Titans (test-time memory), Vespa/Weaviate/Milvus (retrieval competitors)",
"tracker_state": "open",
"reconciliation_state": "DEFERRED_FUTURE",
"tracker_state": "closed",
"reconciliation_state": "HISTORICAL_EVIDENCE",
"labels": [
"P3 \u2014 low",
"growth",
@@ -394,14 +392,14 @@
"ready"
],
"live_defect": false,
"last_revalidated": "2026-09-11",
"next_action": ""
"last_revalidated": "2026-09-19",
"next_action": "none \u2014 idea absorbed into parent epic #181 as tracked checklist item; full detail preserved in this closed issue; re-mint when live"
},
{
"number": 165,
"title": "RESEARCH: SimpleMem semantic compression + A-MEM dynamic linking + Letta sleep-time compute",
"tracker_state": "open",
"reconciliation_state": "DEFERRED_FUTURE",
"tracker_state": "closed",
"reconciliation_state": "HISTORICAL_EVIDENCE",
"labels": [
"P3 \u2014 low",
"infrastructure",
@@ -410,14 +408,14 @@
"ready"
],
"live_defect": false,
"last_revalidated": "2026-09-11",
"next_action": ""
"last_revalidated": "2026-09-19",
"next_action": "none \u2014 idea absorbed into parent epic #181 as tracked checklist item; full detail preserved in this closed issue; re-mint when live"
},
{
"number": 164,
"title": "RESEARCH: HippoRAG 2 \u2014 PPR-style associative propagation as warm-neuron activation candidate",
"tracker_state": "open",
"reconciliation_state": "DEFERRED_FUTURE",
"tracker_state": "closed",
"reconciliation_state": "HISTORICAL_EVIDENCE",
"labels": [
"P3 \u2014 low",
"growth",
@@ -426,27 +424,27 @@
"ready"
],
"live_defect": false,
"last_revalidated": "2026-09-11",
"next_action": ""
"last_revalidated": "2026-09-19",
"next_action": "none \u2014 idea absorbed into parent epic #181 as tracked checklist item; full detail preserved in this closed issue; re-mint when live"
},
{
"number": 163,
"title": "Temporal graph backend spike: Neo4j vs FalkorDB (LadybugDB experimental; Graphiti as reference)",
"tracker_state": "open",
"reconciliation_state": "NEEDS_REVALIDATION",
"reconciliation_state": "VALID_OPEN",
"labels": [
"P1 \u2014 high",
"ready"
],
"live_defect": false,
"last_revalidated": "2026-09-11",
"next_action": ""
"last_revalidated": "2026-09-19",
"next_action": "run the backend spike; compare on same corpus/query set; record evidence-backed recommendation"
},
{
"number": 162,
"title": "Qdrant associative-memory projection spike (dense/sparse/multivector + ColBERT late-interaction reranking)",
"tracker_state": "open",
"reconciliation_state": "NEEDS_REVALIDATION",
"tracker_state": "closed",
"reconciliation_state": "SUPERSEDED",
"labels": [
"P1 \u2014 high",
"custodian",
@@ -454,8 +452,8 @@
"ready"
],
"live_defect": false,
"last_revalidated": "2026-09-11",
"next_action": ""
"last_revalidated": "2026-09-19",
"next_action": "none \u2014 scope carried verbatim by #316 (ADAPT-1 B3-v2); single-tracker rule"
},
{
"number": 159,
@@ -478,8 +476,8 @@
{
"number": 158,
"title": "Generated wiring-status / architecture-truth report",
"tracker_state": "open",
"reconciliation_state": "VALID_OPEN",
"tracker_state": "closed",
"reconciliation_state": "SUPERSEDED",
"labels": [
"P2 \u2014 medium",
"growth",
@@ -489,8 +487,8 @@
"ready"
],
"live_defect": false,
"last_revalidated": "2026-09-11",
"next_action": ""
"last_revalidated": "2026-09-19",
"next_action": "none \u2014 scope carried verbatim by #315 (ADAPT-1 B2-v2); single-tracker rule"
},
{
"number": 156,
@@ -1151,6 +1149,6 @@
"next_action": ""
}
],
"last_reconciled": "2026-09-12",
"reconciled_by": "PL1 held-out era reconciliation (fresh session 2026-09-12)"
}
"last_reconciled": "2026-09-19",
"reconciled_by": "fresh-session tranche 2026-09-19: template retrofit (spine+plain-English on all open issues), closures #158/#162 (SUPERSEDED) and #324 (FIXED_VERIFIED), research labels applied to #163/#164/#165/#166/#182/#316, stale bug labels removed from #163-#166; 2026-09-19 absorption pass: parked children absorbed into parents (#175<-#176..#179; #181<-#182,#183,#164..#166) per one-open-note-per-idea standard"
}
+382
View File
@@ -0,0 +1,382 @@
# Language-Fit Rubric — Wave 1 (Language-Rebasing Tranche R1)
> STATUS: FINAL — self-verified 2026-09-29 per tranche §12 (all 6 rounds completed,
> evidence-sufficiency statements recorded, kill tests frozen; execution proceeds on the
> evidence, every RECODE still passes its benchmark gate — no win, no recode).
> Per-subsystem sections filled from live research rounds (≥2 live-verified external sources per claim,
> per-source lessons, evidence→decision mapping, kill test per candidate). No code changes in Wave 1.
> Governing law from §11: **KEEP-PYTHON honesty determines how much of the rebase volume is real.**
> Toolchain baseline: Rust 1.98.1 + GCC 16.2.1 present; Go NOT installed — Go earns installation only
> through rubric evidence here.
## Verdict (all rounds, one paragraph)
**KEEP-PYTHON across the board: 40 clusters scored, 0 recode units awarded.** Six research
rounds (W2 leaf utilities, W3 memory, W4 provider-layer, W5 orchestration, W6 runtime-core,
W7 TUI) each characterized their subsystem's actual workload inward (file:line-anchored) and
tested Python/Rust/Go/C against it with live-verified sources and frozen kill tests. The
pattern is consistent: the compute-shaped work already executes in C (hashlib, sqlite3/FTS5/vec0,
json, regex), the dominant latency is network or LLM-bound, and no cluster contains a hot loop
that pays for a process-boundary recode through the 658 µs–0.63 ms interop crossing. **Go:
REJECTED — does not earn installation this tranche** (D5=0 everywhere; nothing measured or
fetch-confirmed earns it; orchestration additionally rejects its design fit; K-GO kill tests
frozen per round should the case be revived). **Rust: toolchain-ready, justified nowhere this
tranche** — keep as the standing option behind the CI-proven std-only adapter for any future
measured hot loop. **C: rejected everywhere scored** (duplicates C already inside SQLite/hashlib;
adds an unsafe-memory surface). The rebase volume the tranche hypothesized is real only as a
small set of named improvements — see "Wave-plan consequence" below.
## Rubric dimensions (applied to every candidate language per subsystem)
| Dimension | Question | Evidence required |
|---|---|---|
| D1 Workload fit | Does the subsystem's dominant workload (I/O-bound, CPU-bound, FFI, protocol, UI) actually favour this language? | Benchmarks or authoritative docs, live-verified |
| D2 Measured gain | What wins, concretely — latency, memory, startup, binary distribution? | Named hot paths from the Wave 0 inventory + numbers |
| D3 Interop cost | What does the interop contract (§5) cost to carry for this boundary? | Adapter surface size, ABI/build complexity |
| D4 Ecosystem | Do the needed libraries exist and are they maintained? | Live-verified crate/package/module listings |
| D5 Toolchain reality | Is the toolchain present (or installable and justified) on this machine and the CI runner? | Runner + local `--version` evidence |
| D6 Maintenance continuity | Can the Rune ecosystem's single-maintainer loop sustain code in this language here? | Honest judgement, stated plainly |
| D7 Kill test | What is the CHEAPEST disproof of this candidate? | One falsifiable early test, frozen before any recode |
Scoring: each candidate gets D1–D6 scored 0–2 with one-line evidence each, D7 written regardless.
Decision per subsystem: **KEEP-PYTHON** / **RECODE→<language>** — KEEP-PYTHON is the expected default;
a RECODE that cannot pass its own kill test reverts to KEEP-PYTHON before implementation.
---
## W3 — Memory & persistence (units: memory_store 56 fns, curator 43, warm_router 32, memory_consolidation 20, sleep_time 25, + graph_memory, night_mode, identity_anchors)
- **Research round actor:** general-2 (COMPLETED 2026-09-29 — artifacts at
`research/wave1/memory/`: inward.md, outward/ ×6, outward-sources.md, synthesis.md)
- **Intention profile:** JSONL-heavy appends, BM25/FTS ranking, consolidation passes, long-running
scheduled jobs, file-backed state.
- **Decision:** **KEEP-PYTHON (all 7 clusters, zero RECODE).** Cluster verdicts:
(1) hot-store JSON persistence — KEEP with upgrade path: orjson in-process wheel
(~10× dumps / 2× loads); a bespoke Rust CLI unit is dead on spawn cost (the
`shared/native_units.py` crossing ~1–5 ms ≈ orjson's entire 3.4 MB `knowledge.json` decode);
(2) SQLite store + FTS5/vec0 recall — KEEP, the compute is already C inside SQLite
(`memory_store.py:646` vec0 MATCH, `:693` bm25); (3) neuron scoring/routing — KEEP,
network-bound `_embed` (Ollama subprocess curl) dominates; (4) graph BFS — KEEP,
hops=1 default, per-node SQL, tiny N; the future fix is a SQL CTE, not a language;
(5) batch consolidation/curator — KEEP, LLM/I-O-bound and latency-insensitive,
asyncio sweet spot; (6) orchestration/glue — KEEP, pure glue pinned by the Python-TUI
interop contract; (7) embedding transport — KEEP, network-bound.
- **Candidate matrix summary:** Python 7/7 · Go 0/7 (not installed, nothing measured or
fetch-confirmed earns installation; Go's JSON stack mid-rewrite upstream) · hand-written C
0/7 (C already battle-tested inside SQLite — hand-writing would duplicate it) · Rust 0/7
as CLI units (spawn cost kills the one credible vector; in-process wheels excluded by
Wave 0 policy).
- **Kill tests (frozen in synthesis.md):** Rust-JSON — orjson microbench on live 3.4 MB
`knowledge.json` (if drop-in and ≥2× load / ≥5× dump, the CLI unit is disproven on spawn
cost); Rust-general — kill unless a profile shows ≥50% wall time in pure Python compute
(none exists; reopen only on materially changed workload); Go — instrument one
`consolidate_all` run, kill if Python-compute share <50% (it will be — LLM/I-O bound);
C — kill unless a hot kernel absent from the SQLite extension ecosystem is identified
(none).
- **Sources + lessons:** 6 live-fetched 2026-09-29 (orjson, sled, sqlite-vec, SQLite FTS5
docs, Go json/v2 rewrite issue, pydantic-core) — full annotations in
`research/wave1/memory/outward-sources.md`.
- **Evidence sufficiency (honest):** static analysis only, no runtime profiling;
memory.store SQLite DB not materialized locally — kill tests specify *measured*
thresholds rather than assertions. Verdicts rest on "Python is glue around C/network,"
which profiling would only strengthen.
## W4 — Provider/model layer (units: provider_registry 28, model_connect 10, model_routing 15, model_profiles 15, provider_budget 21, + standardized_providers, model_registry, connection_pool)
- **Research round actor:** general-5 (COMPLETED 2026-09-29 — artifacts at
`research/wave1/provider-layer/`: inward.md, outward-sources.md, outward/ (8 evidence
JSONs), synthesis.md)
- **Intention profile:** HTTP/SSE streaming, connection pooling, retries/backoff, protocol parsing,
tool-call reliability.
- **Intention profile correction (inward-verified):** the layer has **NO retry/backoff and NO
SSE stub at all** (grep-verified) — `stream: False` everywhere, ~900 lines, remote-LLM-latency-
bound. Rewrite pitches are therefore feature-adds, not ports.
- **Candidate matrix:** 5 clusters, all KEEP-PYTHON. Scores (1–5 = fit for the cluster's actual
workload): (C1) HTTP wire + transport (provider_registry, openai_compat_transport, model_connect
discovery) Python 5 / Go 2 / Rust 1; (C2) connection pool (connection_pool.py, 144 lines —
in-process object guards under threading.Lock, NOT a TCP pool) Python 5 / Go 2 / Rust 2;
(C3) routing decisions (model_routing.py, 432 lines, pure decision logic, one httpx call)
Python 5 / Go 1 / Rust 1; (C4) budget accounting (provider_budget.py, 354 lines, pure
arithmetic + lock, no I/O) Python 5 / Go 1 / Rust 1; (C5) config/registry/normalization
(model_profiles, model_registry, standardized_providers, model_connect tables — dataclasses +
JSON, editable by non-systems programmers) Python 5 / Go 1 / Rust 1.
- **Decision:** **KEEP-PYTHON (all 5 clusters).**
- **Kill tests:** C1 Go — KILLED: toolchain absent (`which go` → not found); 28 call-site
behaviors incl. the tool-call envelope contract (openai_compat_transport.py:67-107, 160-207)
would be re-implemented with zero incumbent test port and NO performance signal (remote-LLM-
latency-bound, kilobyte payloads). Re-earn path if Go is ever installed: std-only proof via
`interop/rebase-proof/` + a benchmark harness on C1 only. C1 Rust — KILLED BY CONSTRUCTION:
SSE parsing requires reqwest+tokio+eventsource-stream+nom (outward O3/O4/O5 — even mistral.rs
takes the tokio stack), violating the std-only interop contract. C2–C5 Go/Rust — KILLED:
burden of proof sits on the rewrite candidates; kill tests need contention/throughput/
counter-evidence that does not exist; routing runs once per request at millisecond scale
against multi-second LLM calls (5 orders of magnitude below any measurable threshold).
- **Sources + lessons:** 8 live-fetched (O1–O8), ≥2 per major claim, coverage map in
`outward-sources.md`. Lessons: (1) stdlib-only Rust has no realistic precedent for HTTP/SSE
workloads — the interop contract's zero-crate standard effectively decides Rust out of all
network-wire clusters; (2) Go's stdlib HTTP+NDJSON streaming is capability-proven
(pkg.go.dev/net/http, ollama api/client.go, ollama's Go API server) — Go's losses here are
evidence-absence, not capability-absence; (3) the honest reliability upgrade for this layer
is a small Python-level httpx retry/timeout wrapper — a feature-add, not a language change.
## W5 — Orchestration, authority, plugins, skills (units: orchestration/ 44 files 244 fns, contracts, build_mode 34, construction_authority*, verification_construction, spine, + governance surfaces: drift_*, persona_gate, safety_override, witness, behavior, growth_delta, claim_audit)
- **Research round actor:** general-1 (COMPLETED 2026-09-29 — artifacts at
`research/wave1/orchestration/`: inward.md, outward-sources.md, outward/ (4 search
JSONs), synthesis.md)
- **Intention profile:** contract/lifecycle state machines, authority gating, fail-closed validation,
HMAC-chained ledgers, policy dispatch.
- **Intention profile correction (inward-verified):** the subsystem is durable-ledger I/O,
authority wiring, deterministic policy gates, and TUI-facing coordination — NOT hot loops
(2 RLocks, 0 sockets, 0 thread pools across 43 files). **Scope gap: `construction_authority.py`
and `verification_construction.py` do not exist in the tree** — the construction cluster is
covered by build_mode.py; no evidence invented for the missing files.
- **Candidate matrix:** 6 clusters, all KEEP-PYTHON. Scores (1–5 = fit for the cluster's actual
workload): (C1) durable state & ledger stores (event_store.py:56-101, atomic.py, evidence_store.py
— fsync-bound; hashing already C via hashlib) Python 5; (C2) composition roots & authority wiring
(composition.py, authority.py, cognitive.py — pure glue, runtime cost ≈ 0) Python 5; (C3)
policy/state machines/gates (lifecycle.py, scheduler.py, broker.py, no_change.py, reflex.py —
deterministic dict/enum decisions, sub-ms; testability is the requirement) Python 5; (C4)
structural self-model & schema tooling (spine.py:24-25, microkernel.py, contracts.py, records.py
— introspection + canonical JSON; only candidate for a future Rust spine-diff if snapshots grow
1000×) Python 4; (C5) TUI-facing orchestration & build pipeline (build_mode.py 11-stage pipeline,
gateway.py, transport.py — the consumer IS the Python TUI; latency dominated by LLM/subprocess
waits) Python 5; (C6) benchmark/migration harnesses (retrieval_benchmark.py, migrate.py,
benchmark.py — offline tooling, recode buys nothing, loses iteration speed) Python 4.
- **Decision:** **KEEP-PYTHON (all 6 clusters). This subsystem contributes 0 recode units to
the wave plan.** Go: REJECTED, do not install — differentiator (goroutine-dense servers)
targets a workload absent here; cost is exception→error-value rewrite of ~260 functions.
Rust: FEASIBLE (toolchain proven) but UNJUSTIFIED anywhere — no cluster has the hot loop
that pays for a process-boundary recode; keep as toolchain-ready for other subsystems.
C: REJECTED — the only compute-shaped work (sha256) already executes C via stdlib hashlib.
- **Kill tests:** K1 (frozen, ALREADY RUN): 100 round-trips through the rebase-proof adapter —
mean 0.63ms, p95 0.74ms, cold 0.87ms, 100% exit-0 + ok:true → adapter overhead does NOT block
recodes on cost; recodes die on value grounds. Re-open any cluster if profiling shows a
function consuming >10% of a real interactive session. K-GO (frozen, ~30 min): Go prototype
of event_store.py's batched append+fsync vs Python at 1000 events; if Python's p95 is within
2× of Go's, Go is dead here permanently. K-RUST (frozen, ~20 min): measure spine diff on a
10k-entity snapshot; <50ms kills any Rust spine recode by absence of pain.
- **Sources + lessons:** 4 live-fetched web sources (pydantic-core, ruff blog, go.dev FAQ,
Python 3.14 hashlib docs) + 1 LOCAL EXPERIMENT (n=100 adapter benchmark). Lessons: (1) the
rebase-proof adapter round-trips at 0.63ms/op — subprocess-per-op is viable for coarse ops,
never per-event; (2) Python's "slowness" argument dissolves where the actual compute already
runs in C via stdlib (hashlib, sqlite) — the language question is really "where is the hot
loop", and here the answer is nowhere; (3) assumed limits flagged honestly: human-scale event
cadence (batch_size=8) and Linux spawn cost — both would need revisit at 10⁴+ events/sec or
cross-platform targets.
## W6 — Runtime core & tooling (units: tool_executor 46, tool_protocol 27, local_tool_runtime 32, capability_broker 19, context_broker 21, work_manager 25, cron_engine 28, + failure_auto_filer 28, hook_engine, elastic_cognition, auto_tasks, goal)
- **Research round actor:** general-4 (COMPLETED 2026-09-29 on disk despite cancellation
notification — artifacts at `research/wave1/runtime-core/`: inward.md, outward/,
outward-sources.md, synthesis.md)
- **Intention profile:** subprocess/process supervision, native execution boundary (native_units
adapter already exists), event loops, cron scheduling, hook dispatch.
- **Decision:** **STAY-PYTHON (all 6 clusters).** Round scores (1–5 = fit for the cluster's
actual inward-characterized workload): (A) subprocess lifecycle (tool_executor, cron_engine,
auto_tasks) 4.7 — `subprocess.run(timeout=, capture_output=)` is a one-call expression of the
pattern; Rust std::process has NO built-in child timeout (outward-verified), strictly more
code under zero-crate; (B) protocol/JSON parsing (tool_protocol, brokers) 4.5 — inputs are
KB-scale model fragments; Python json/regex is already C-backed, so a rewrite swaps C for
compiled code at the same asymptotic cost; serde's typed-struct model actively mismatches
fence-wrapped schema-flexible output; (C) model→tool control loop + HTTP
(local_tool_runtime, elastic_cognition, goal) 4.8 — wall time is LLM HTTP latency in seconds;
Python overhead is µs–ms noise; the loop's content is policy (circuit breaker, escalation
ladders, routing tables); (D) context assembly (context_broker) 4.7 — correctness lives in
admission policy and degrade-not-crash semantics, not speed; compaction is itself an LLM call;
(E) reliability/queueing (failure_auto_filer) 4.2 — honest lowest: on paper the best Rust
candidate (queue + worker + crash-safe JSONL spool), but perf requirement ≈ nil and the
correctness burden is threading semantics a rewrite would re-risk for no win ("nothing
breaks today"); (F) declarative config/brokers (work_manager, hook_engine, capability_broker)
4.9 — literal data, no-op runtime, portable to anything valuable in nothing.
- **Candidate matrix summary:** Python 6/6 · Go 0/6 (paper verdicts only — evidence-starved,
not installed, kill tests unrunnable locally) · Rust 0/6 (kill tests runnable via the
existing std-only interop harness) · C unscored (no FFI-adjacent cluster surfaced).
Best-language moment found anywhere: robfig/cron replacing ~37 hand-rolled cron-parsing
lines (cron_engine.py:199-236) — ergonomics nicety, not a fit verdict.
- **Kill tests (frozen in synthesis.md):** Rust-A — re-express `_run_command`
(tool_executor.py:1064) with std::process + manual timeout; kill if >2× the ~40-line
Python wrapper (Q4 predicts it is); Go-A — port `cron_engine._run_loop` with os/exec,
measure task-fire latency delta (prediction: zero — 60 s sleep and child runtime dominate);
B — parse the largest observed tool-protocol stream 1000× in Python; kill if total <1 s
(no rewrite yields an observable win); C — instrument `_run_loop`
(local_tool_runtime.py:417), log non-HTTP CPU per iteration (prediction <1% of wall);
D — time `assemble`+`_admit` on the largest stored context, kill if <10 ms; E — fault-inject
kill -9 during spool append; if recovery semantics already hold, the rewrite has no
correctness win to buy; F — none needed: absence of any win condition IS the disproof.
- **Sources + lessons:** live-fetched 2026-09-29 — annotations in
`research/wave1/runtime-core/outward-sources.md`; headline lessons: Rust std::process lacks
child timeout (Q4); Go os/exec reaches parity but changes only syntax (Q1); Python
json/regex C-backed (Q5b); serde typed structs mismatch dynamic model output (Q5a);
concurrency features irrelevant at ≤2 threads (Q6).
- **Evidence sufficiency:** Python verdicts fully evidenced inward+outward; Go execution-side
evidence honestly starved (paper kill tests carried forward); E's JSONL-spool crash-safety
claim rests on inward semantics only — flagged in synthesis.md.
## W7 — Operator + TUI (units: rune_operator 61 fns, rune_tui 161 fns — largest module, tui_validator)
- **Research round actor:** general-3 (COMPLETED 2026-09-29 — artifacts at
`research/wave1/tui/`: inward.md, outward/ ×8, outward-sources.md, synthesis.md)
- **Intention profile:** terminal rendering, input handling, rich layout, hot store state, supervisory
command surface. Design decision 4 holds: TUI consumes the interop contract, never rewritten first.
- **Decision:** **KEEP-PYTHON (TUI shell; all 4 clusters, zero RECODE, no carve-out found).**
Cluster scores (1 = recode, 5 = keep): (A) rendering/widgets 4 — no hot loop exists; render is
plain Rich `Text` concatenation (rune_tui.py:1331, chat_bubble.py:157), only animation a 0.12 s
spinner (:263), no markdown/Syntax parsing anywhere in src/rune; (B) event glue (~50 `_cmd_*`
handlers, reactives, tool-widget maps) 5 — this is Textual's core competency (workers,
`exclusive=True`, `call_from_thread`); vendor docs (ratatui) admit "little to no help in organizing
large applications"; (C) model send path + envelope 5 — synchronous `send_task` in async worker;
the envelope shape (`success/response/thinking/tool_events/degraded`, rune_tui.py:3624ff) is
ALREADY the de-facto interop contract; (D) subprocess/streaming 5 — JSONL streaming precedent
already in-tree (`_cmd_pull` :3443-3517): the pattern for consuming recoded units, not a recode
target. Whole-TUI native recode 1/5 REJECTED — 80+ first-party module coupling, framework-provided
concurrency re-implemented by hand; Go additionally toolchain-blocked. Countervailing evidence
(Bubble Tea/tview/Codex TUI maturity) recorded honestly in outward-sources.md — it does not
outweigh the coupling.
- **⚠ CONTRACT GAP FLAGGED (binds Waves 2–7):** `shared/native_units.py` parses only the LAST
stdout line — it must gain a JSONL streaming reader (per-line `json.loads` + terminal-envelope
validation) before any recoded long-running unit can stream progress to the TUI. Small, testable,
non-breaking; candidate for the first Wave 2 implementation issue.
- **Adapter surface (TUI as consumer — adopted as the rubric's interop-contract restatement):**
(1) single-invocation stateless CLI (`native_unit <op> [args]`, no daemon); (2) success = final
stdout line `{"ok":true, …}` generalizing the model-send envelope — recoded units emitting
`response`/`tool_events`/`degraded` plug in with zero TUI changes; (3) failure = `ok:false` +
nonzero exit, stderr human-only, success = exit 0 AND not timed out; (4) mandatory `--version`
on every unit (status bar + `canary_tui_drift.py` detect live units vs Python fallback);
(5) JSONL streaming mode for long ops with terminal sentinel envelope; (6) per-call timeout
budget, `timed_out` surfaced in `NativeResult` for graceful degradation; (7) streamed events
referencing UI objects carry the TUI's stable keys — `(channel, call_id)` for tool widgets
(:3676), WorkPane `_entries` object ids (:1239) — preserved verbatim; (8) std-only for
proof-phase units.
- **Candidate matrix summary:** Python 4/4 clusters · Rust/Go whole-TUI 1/5 rejected · carve-out
candidates: none found (future markdown parsing would carve as a Rust native unit behind the
adapter, not now).
- **Kill tests (frozen in synthesis.md):** stay-Python — killed if >16 ms UI-thread stalls under
heavy event bursts OR IPC latency dominates message round-trip (Textual pilot measurement);
Rust recode — killed if the adapter must expose >~15 first-party modules (count today ≈80:
killed NOW); Go recode — additionally killed by toolchain absence (`command -v go` empty).
- **Sources + lessons:** 8 live-fetched 2026-09-29 (Textual workers guide, ratatui vendor docs,
Bubble Tea/tview/Codex countervailing evidence, JSON Lines spec, push-granular-work guidance) —
annotations in `research/wave1/tui/outward-sources.md`.
- **Evidence sufficiency (honest):** full inward read of all 5 TUI files with line refs; ≥2 sources
per major claim; gap = no runtime profiling (stall kill test unmeasured — but no mechanism exists
for the stall to occur; the 120 ms 21-step pipeline was already removed, `_run_warm_router`
:3575 is a no-op).
## W2 — Leaf utilities & canaries (~40 modules, low coupling: pins, time_awareness, message_queue, event_envelope, attention_capsule, complexity_scorer, token_optimizer, cache 501/17, prompt_sync, chat_bubble, ~15 canary_* modules)
- **Research round actor:** general-6 (COMPLETED 2026-09-29 — full report in actor notification)
- **Intention profile:** small pure helpers, envelopes, scoring, cache; smallest blast radius; the
factory + interop proving ground at real scale.
- **Ground-truth measurements (local, this session):** Python fn call ~46 ns (100k timed
iterations in-process) · native CLI roundtrip ~658 µs (subprocess to
`interop/rebase-proof/target/release/rebase-proof --version`) · Python startup floor ~18 ms ·
overhead ratio ≈ **14,000×**. The only CI-proven interop contract is the subprocess CLI boundary
(`shared/native_units.py`: argv in → JSON stdout, `--version`, timeout, typed `NativeResult`).
PyO3/in-process bindings excluded by Wave 0 policy. Therefore every per-call crossing costs
≥658 µs — a per-turn helper would need to run >14,000× faster in Rust to break even.
- **Candidate matrix (representative — full per-cluster 0–2 scoring in round report):**
Python 12/12 in every cluster · Rust 5–6/12 · Go 1–3/12 (D5=0, not installed) · C 1–2/12.
No module contains a hot loop (heaviest: 2 `re.sub` per turn in token_optimizer).
- **Decision:** **KEEP-PYTHON (all ~40, zero RECODE).** Cluster verdicts: (a) pure CRUD helpers
pins/time_awareness/token_optimizer — KEEP, CPython 3.11+ already 10–60% faster on this shape
(PEP 659); (b) message/envelope/capsule structures — KEEP, recode would insert a boundary
between the chattiest neighbors; (c) cache.py (501 L, largest in wave) — KEEP, the fast part is
already C (sqlite3 DB-API 2.0 over SQLite's C library), Python is thin orchestration, batching
(threshold 50 / 30 s) already amortizes writes; (d) chat_bubble.py — KEEP, **hard-pinned** to
Python by the Textual framework (recode = full framework abandonment, bottleneck is human
typing speed); (e) prompt_sync.py glue — KEEP, glue into Python siblings (memory_env,
voice_sync, build_pipeline_policy); (f) ~19 canary_* — KEEP **categorically**, a canary that
verifies Python importability cannot exist in another language.
- **Kill tests (reopening criteria, all fail today on first cheap measurement):** Rust — microbench
one per-turn helper behind the native_units CLI, must beat the Python in-process call >10×
end-to-end including the 658 µs crossing (whole call <~46 µs; a trivial `--version` already
costs 658 µs); Go — identical benchmark post-install, uninstall if roundtrip >100 µs with no
named hot path; C — identical benchmark + required fuzz-clean JSON roundtrip, plus a
demonstrated GC-free allocation-hot loop first; cache.py — recode only if Python-side
orchestration (excl. sqlite3 waits) exceeds 5% of end-to-end latency; capsule/envelope/queue —
recode only if one turn's Python total exceeds ~5 ms AND a candidate's CLI path is >10× cheaper.
- **Sources + lessons:** (1) https://docs.python.org/3/whatsnew/3.11.html — 10–60% faster,
PEP 659 specializing interpreter: CPython already optimized for helper-shaped code, the D2
baseline is a moving improving target; (2) https://docs.python.org/3/whatsnew/3.13.html —
free-threading/JIT experimental, KEEP-PYTHON ≠ frozen but no bets on experimental paths;
(3) https://www.maturin.rs/ — in-process Rust↔Python needs a whole binding/packaging toolchain
atop the CLI boundary, D3 worse than measured 658 µs (Wave 0 policy excludes it anyway);
(4) https://go.dev/doc/install — Go is a pre-install prerequisite, D5=0 everywhere, never earned
installation; (5) https://textual.textualize.io/ — Textual is a Python TUI framework,
chat_bubble.py framework-pinned; (6) https://docs.python.org/3/library/sqlite3.html — sqlite3 is
DB-API 2.0 over C, cache.py's perf layer already native. All fetched live 2026-09-29.
- **⚠ Inventory drift (VERIFIED 2026-09-29):** complexity_scorer.py listed in
rebase-inventory.json (2 mentions) but absent on disk — deleted in commit 867321e
("governed retirement — complexity_scorer deleted (602 lines)"). Wave 0 inventory needs a
correction pass; the module was scored nowhere (no source to characterize).
---
## Wave-plan consequence (T5 scope, from the verdict above)
With **0 recode units awarded**, the tranche's hypothesized rebase volume is real only as the
work below. Waves 2–9 are **disposition + named improvements, NOT mass recoding**:
**Waves 2–7 — per-issue disposition (the 1,852 `[rebase w{wave}]` issues):**
Each issue receives its tranche §7 disposition — improve / fix / missing-connectors answered
with evidence — plus a language verdict of **KEEP-PYTHON with its rubric evidence line**
(the round section for that subsystem names the claim). Disposition runs leaf-first
(Wave 2 → 7), the canonical suite stays green throughout, and no issue closes without its
evidence line. A recode is off the table unless a frozen kill test is reopened — and then
tranche §6 still governs: **no benchmark win, no recode.** Go is not installed and earned no
installation; Rust stays toolchain-ready but unjustified (standing option behind the
CI-proven adapter).
**Named improvements — the actual rebase volume (ship alongside disposition):**
1. **JSONL streaming reader for `shared/native_units.py`** (W7 contract gap): the adapter
parses only the LAST stdout line; it must gain per-line `json.loads` + terminal-envelope
validation before any recoded long-running unit could stream progress. Small, testable,
non-breaking — first implementation issue of Wave 2.
2. **httpx retry/timeout wrapper for the provider layer** (W4): the honest reliability
upgrade is a feature-add, not a language change.
3. **orjson upgrade path** (W3 cluster 1): the only credible Python-side JSON win —
in-process, no boundary crossing. **DISPOSITION (2026-09-29, kill test EXECUTED and
FAILED — KEEP-PYTHON stands, no dependency declared):** microbench on the live
`~/.rune/consolidation/knowledge.json` (3,540,959 bytes, n=30 best-of): load 13.15 ms
std vs 7.85 ms orjson = **1.68× (bar ≥2×: FAIL)**; dump 9.58 ms std vs 5.61 ms
orjson-with-decode = **1.71× (bar ≥5×: FAIL)**; raw-bytes dump 1.39 ms = 6.91× but is
not drop-in (every `write_text`/`json.dump`-to-file site would need a bytes→str or
binary-write conversion). Roundtrip equality verified. Bench: `/tmp/orjson_bench.py`
shape (uvx --with orjson). The bytes trap measured real: decode() eats ~60% of the
dump win.
4. **complexity_scorer.py inventory correction**: listed in `rebase-inventory.json` but
deleted on disk (commit `867321e`, 602 lines) — Wave 0 inventory needs the correction
pass. **DISPOSITION (2026-09-29, DONE):** inventory regenerated per the script's own
header (never hand-edit) — 177→213 files, 1,852→2,314 functions, 13 dead files
dropped; committed + pushed `5bc837c`. The W2 round's "2 mentions" drift claim
verified FALSE against the live inventory (zero hits).
5. **robfig/cron** (W6): recorded as a best-language footnote only; no action.
**Wave 8 — TUI integration proof:** demonstrate the TUI reading/utilising the mixed-language
surfaces that exist (the `interop/rebase-proof` unit through the upgraded adapter), per the
8-point adapter surface adopted above.
**Wave 9 — close-out audit:** 100% of the 1,852 issues dispositioned, debt-table revision,
version bump.
## Cross-cutting candidates (evaluated once, referenced by every subsystem)
- **Rust (present, 1.98.1):** interop proof unit already CI-proven (std-only, zero crates, `interop/rebase-proof/`, adapter in `shared/native_units.py`, ok = exit 0 AND not timed out).
- **Go (absent):** must earn installation through D1–D5 evidence here before any recode targets it.
- **C (present, GCC 16.2.1):** expected to lose D6 in most subsystems; scored where FFI-adjacent work exists.
- **Python (KEEP baseline):** the default. Every subsystem begins here; evidence must move it.
## Evidence ledger (per-source lessons, all rounds)
Index of per-source evidence. Full annotations live in each round's
`research/wave1/<subsystem>/outward-sources.md`; this ledger records the headline lesson
each source contributed and the rubric claims it supports.
| Round | Sources (live-fetched 2026-09-29) | Headline lessons | Supports |
|---|---|---|---|
| W2 leaf utilities | 6: python.org 3.11 + 3.13 whatsnew, maturin.rs, go.dev/doc/install, textual.textualize.io, docs.python.org sqlite3 | CPython 3.11+ already 10–60% faster on helper-shaped code (PEP 659) — D2 baseline is a moving target; free-threading/JIT experimental, no bets; in-process bindings need a whole toolchain atop the CLI boundary (excluded by Wave 0 policy anyway); Go is pre-install prerequisite, D5=0; Textual framework-pins chat_bubble.py; sqlite3 perf layer already C | W2 KEEP-PYTHON ×~40; the 14,000× crossing-overhead law |
| W3 memory | 6: orjson, sled, sqlite-vec, SQLite FTS5 docs, Go json/v2 rewrite issue, pydantic-core | orjson is the only credible Python-side JSON win (in-process, no boundary); SQLite FTS5/vec0 compute is already C; Go's JSON stack mid-rewrite upstream (versioning risk); pydantic-core shows the Rust-as-wheel pattern, excluded by policy | W3 KEEP-PYTHON 7/7; orjson upgrade path on cluster 1 |
| W4 provider-layer | 8: live-fetched O1–O8 (HTTP/SSE ecosystem, tokio-stack precedents incl. mistral.rs, pkg.go.dev/net/http, ollama Go client/server) | stdlib-only Rust has no realistic HTTP/SSE precedent — the zero-crate contract decides Rust out of all network-wire clusters by construction; Go's stdlib HTTP+NDJSON streaming is capability-proven (its losses here are evidence-absence, not capability-absence); the honest reliability upgrade is a Python httpx retry/timeout wrapper — feature-add, not language change | W4 KEEP-PYTHON 5/5; SSE-cluster Rust kill-by-construction |
| W5 orchestration | 4: pydantic-core, ruff blog, go.dev FAQ, Python 3.14 hashlib docs + 1 LOCAL EXPERIMENT (n=100 adapter benchmark) | adapter round-trips at 0.63ms/op — subprocess-per-op viable for coarse ops, never per-event; Python "slowness" dissolves where compute already runs in C via stdlib; the language question is really "where is the hot loop" (here: nowhere) | W5 KEEP-PYTHON 6/6; K1 kill test already run |
| W6 runtime-core | headline lessons (full set in round outward-sources.md) | Rust std::process lacks built-in child timeout — strictly more code under zero-crate; Go os/exec reaches parity but changes only syntax; Python json/regex C-backed so rewrite swaps C for compiled code at equal asymptotic cost; serde typed structs mismatch schema-flexible model output; concurrency features irrelevant at ≤2 threads | W6 STAY-PYTHON 6/6; robfig/cron as best-language footnote |
| W7 TUI | 8: Textual workers guide, ratatui vendor docs, Bubble Tea/tview/Codex TUI (countervailing), JSON Lines spec, push-granular-work guidance | Textual workers/`call_from_thread` are the core competency for event glue; ratatui admits "little to no help in organizing large applications"; countervailing native-TUI frameworks recorded honestly — do not outweigh 80+ module coupling; JSONL per-line parse + terminal sentinel is the streaming contract; vendor guidance: push granular speed-sensitive work to subcomponents only when measured | W7 KEEP-PYTHON 4/4; the 8-point adapter surface (adopted as the rubric's interop-contract restatement) |
+50
View File
@@ -0,0 +1,50 @@
# Wave 0 close-out report — language-rebasing tranche R1
Branch: `tranche-r1-wave-0` · Date: 2026-09-29
## 1. Inventory (docs/rebase/rebase-inventory.json)
- 177 Python modules, ~52,750 lines, 227 classes
- TRUE unit count: **1,852 = 1,030 top-level functions + 822 class methods**
- Zero duplicate call edges, zero method leaks (generator double-walk defect
root-caused and fixed in scripts/rebase_inventory.py)
- Cross-verified against an independent fresh AST walk: zero missing units;
six inventory-"extras" are real nested/if-try-block classes the naive walk
misses (inventory is MORE complete, not less)
## 2. Issue factory (scripts/rebase_issue_factory.py)
- One issue per unit following R1 §7; wave-batched (2–7); dedup-safe via
deterministic title `[rebase w{wave}] {relpath}::{unit}` + existing-titles
scan per run (retries never duplicate — preserve-first)
- `plan` → {2: 239, 3: 251, 4: 129, 5: 544, 6: 415, 7: 274} = 1,852,
zero unassigned
- `sample --wave 5` → full §7 template holds; `_compute_hash` exactly once as
labelled callee with line number
- Contract fix during Wave 0: `--limit` default changed 5 → 0 (unlimited) for
`create`; `sample` keeps its 5. A full-wave create with the old default
would have silently truncated each wave to five issues.
## 3. Interop proof unit (R1 §5)
- Rust unit at interop/rebase-proof/ (std-only, zero crates): argv in → JSON
on stdout, non-zero exit on failure, mandatory `--version`
- Shell-proven: version flag, JSON out, exit 2 on failure, stderr diagnostic
- Python thin adapter shared/native_units.py: typed NativeResult, timeout +
stderr capture, unit failures as data (never exceptions)
- Adapter contract fix during Wave 0: `ok` no longer requires a JSON
`ok:true` field — plain-text output (`--version`) succeeds on exit code
- tests/test_native_interop_proof.py: **8 passed** — version contract, sum
happy path, hash determinism, failure paths, timeout, stderr capture
## 4. Per-wave issue creation
<!-- FILLED BY THE COMPLETION LOOP — do not hand-edit -->
- Wave 4 (129 units): created=127 skipped(dedup)=2 (includes smoke #417–418)
- Wave 2 (239 units): created=239 skipped(dedup)=0
- Wave 3 (251 units): created=251 skipped(dedup)=0
- Wave 5 (544 units): created=544 skipped(dedup)=0
- Wave 6 (415 units): created=415 skipped(dedup)=0
- Wave 7 (274 units): created=274 skipped(dedup)=0
- TOTAL: 1,850 created + 2 dedup = 1,852 / 1,852 ✅ full coverage
File diff suppressed because it is too large. Load diff
+12
View File
@@ -0,0 +1,12 @@
{
"units_per_wave": {
"2": 239,
"3": 251,
"4": 129,
"5": 544,
"6": 415,
"7": 274
},
"unassigned_modules": {},
"unassigned_module_count": 0
}
+1 -1
View File
@@ -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/**", "./docs/gitea_issue_reconciliation.json"]
except: ["./docs/v1/**", "./docs/wiki/**", "./docs/gitea_issue_reconciliation.json", "./docs/rebase/**"]
- henxel: "The known giant stays visible — file-size debt is tracked, not silent"
in: ./src/rune/*
+7
View File
@@ -0,0 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "rebase-proof"
version = "0.1.0"
+15
View File
@@ -0,0 +1,15 @@
[package]
name = "rebase-proof"
version = "0.1.0"
edition = "2021"
# Wave 0 interop proof unit (R1 §5). Std-only by design: no crates, no network,
# deterministic build. The pattern under proof is the CLI boundary itself, not the
# computation inside it.
[[bin]]
name = "rebase-proof"
path = "src/main.rs"
[profile.release]
strip = true
+117
View File
@@ -0,0 +1,117 @@
//! Wave 0 interop proof unit (R1 §5 of the language-rebasing tranche).
//!
//! Contract under proof:
//! - standalone binary; argv in, JSON on stdout
//! - non-zero exit on failure (JSON error object still printed to stdout)
//! - `--version` flag mandatory
//! - Python wraps it in a thin adapter (`shared/native_units.py`); tests call
//! it the same way.
//!
//! Ops: sum / echo / hash (fnv1a64) / sleep / fail. All std-only.
use std::env;
use std::process::exit;
use std::thread;
use std::time::Duration;
const VERSION: &str = env!("CARGO_PKG_VERSION");
/// FNV-1a 64-bit — dependency-free deterministic hash for the proof unit.
fn fnv1a64(data: &[u8]) -> u64 {
let mut hash: u64 = 0xcbf29ce484222325;
for byte in data {
hash ^= u64::from(*byte);
hash = hash.wrapping_mul(0x100000001b3);
}
hash
}
fn print_json(line: &str) {
println!("{line}");
}
fn emit_ok(body: &str) {
print_json(&format!("{{\"ok\":true,{body}}}"));
exit(0);
}
fn emit_err(message: &str) -> ! {
// Escape the minimal set so the JSON stays parseable for arbitrary op names.
let escaped: String = message
.chars()
.map(|c| match c {
'"' => "\\\"".to_string(),
'\\' => "\\\\".to_string(),
'\n' => "\\n".to_string(),
'\r' => "\\r".to_string(),
'\t' => "\\t".to_string(),
other => other.to_string(),
})
.collect();
print_json(&format!("{{\"ok\":false,\"error\":\"{escaped}\"}}"));
exit(2);
}
fn main() {
let args: Vec<String> = env::args().skip(1).collect();
if args.as_slice() == ["--version"] || args.as_slice() == ["-V"] {
println!("rebase-proof {VERSION}");
exit(0);
}
if args.is_empty() {
eprintln!("usage: rebase-proof <op> [args...] | --version");
emit_err("no op given");
}
let op = args[0].as_str();
let rest = &args[1..];
match op {
"sum" => {
let mut total: i128 = 0;
for a in rest {
match a.parse::<i128>() {
Ok(v) => total += v,
Err(_) => emit_err(&format!("sum: not an integer: {a}")),
}
}
emit_ok(&format!("\"op\":\"sum\",\"result\":{total}"));
}
"echo" => {
let joined = rest.join(" ");
let escaped: String = joined
.chars()
.map(|c| match c {
'"' => "\\\"".to_string(),
'\\' => "\\\\".to_string(),
'\n' => "\\n".to_string(),
'\r' => "\\r".to_string(),
'\t' => "\\t".to_string(),
other => other.to_string(),
})
.collect();
emit_ok(&format!("\"op\":\"echo\",\"text\":\"{escaped}\""));
}
"hash" => {
let joined = rest.join(" ");
let h = fnv1a64(joined.as_bytes());
emit_ok(&format!("\"op\":\"hash\",\"fnv1a64\":\"{h:016x}\""));
}
"sleep" => {
let ms: u64 = match rest.first().map(|s| s.parse::<u64>()) {
Some(Ok(v)) => v,
_ => emit_err("sleep: expected milliseconds"),
};
thread::sleep(Duration::from_millis(ms));
emit_ok(&format!("\"op\":\"sleep\",\"slept_ms\":{ms}"));
}
"fail" => {
// Deliberate failure: stderr diagnostic + JSON error + exit 2.
// Proves stderr capture and non-zero exit in the adapter.
eprintln!("rebase-proof: deliberate failure for adapter proof");
emit_err("deliberate failure");
}
other => emit_err(&format!("unknown op: {other}")),
}
}
+401 -1
View File
@@ -1 +1,401 @@
[]
[
{
"name": "read_file",
"description": "Read a file with optional windowed viewing (offset/limit). Returns numbered lines. Use offset/limit for large files (100 lines at a time).",
"capabilities": [
"read_file"
],
"file": "tool_executor.py",
"full_path": "",
"priority": 100,
"semantic_examples": [],
"risk": "read-only",
"preconditions": [
"path exists and is a readable file"
],
"side_effects": [],
"auto_invoked": false,
"hooks": [],
"native_tool": true,
"searchable_text": "read_file read a file with optional windowed viewing (offset/limit). returns numbered lines. use offset/limit for large files (100 lines at a time). native tool"
},
{
"name": "edit_file",
"description": "Surgical search/replace edit. More reliable than full file rewrites. The search string must match exactly.",
"capabilities": [
"edit_file"
],
"file": "tool_executor.py",
"full_path": "",
"priority": 100,
"semantic_examples": [],
"risk": "write",
"preconditions": [
"path is inside an allowed write directory",
"search string matches exactly once"
],
"side_effects": [
"rewrites the target file atomically after approval",
"creates a .bak backup under ~/.rune/undo"
],
"auto_invoked": false,
"hooks": [],
"native_tool": true,
"searchable_text": "edit_file surgical search/replace edit. more reliable than full file rewrites. the search string must match exactly. native tool"
},
{
"name": "write_file",
"description": "Write content to a file. Creates parent directories if needed. Shows diff before writing. Use for new files or full rewrites.",
"capabilities": [
"write_file"
],
"file": "tool_executor.py",
"full_path": "",
"priority": 100,
"semantic_examples": [],
"risk": "write",
"preconditions": [
"path is inside an allowed write directory"
],
"side_effects": [
"writes the full file content atomically after approval",
"creates a .bak backup under ~/.rune/undo"
],
"auto_invoked": false,
"hooks": [],
"native_tool": true,
"searchable_text": "write_file write content to a file. creates parent directories if needed. shows diff before writing. use for new files or full rewrites. native tool"
},
{
"name": "glob_files",
"description": "Find files matching a glob pattern. Returns file paths sorted by modification time.",
"capabilities": [
"glob_files"
],
"file": "tool_executor.py",
"full_path": "",
"priority": 100,
"semantic_examples": [],
"risk": "read-only",
"preconditions": [
"search directory is readable"
],
"side_effects": [],
"auto_invoked": false,
"hooks": [],
"native_tool": true,
"searchable_text": "glob_files find files matching a glob pattern. returns file paths sorted by modification time. native tool"
},
{
"name": "grep_files",
"description": "Search for a pattern in files. Returns file paths and line numbers. Use include to filter by file type.",
"capabilities": [
"grep_files"
],
"file": "tool_executor.py",
"full_path": "",
"priority": 100,
"semantic_examples": [],
"risk": "read-only",
"preconditions": [
"search directory is readable"
],
"side_effects": [],
"auto_invoked": false,
"hooks": [],
"native_tool": true,
"searchable_text": "grep_files search for a pattern in files. returns file paths and line numbers. use include to filter by file type. native tool"
},
{
"name": "list_directory",
"description": "List files and directories at a path. Returns names with / suffix for directories.",
"capabilities": [
"list_directory"
],
"file": "tool_executor.py",
"full_path": "",
"priority": 100,
"semantic_examples": [],
"risk": "read-only",
"preconditions": [
"path is a readable directory"
],
"side_effects": [],
"auto_invoked": false,
"hooks": [],
"native_tool": true,
"searchable_text": "list_directory list files and directories at a path. returns names with / suffix for directories. native tool"
},
{
"name": "lint_file",
"description": "Lint a file for syntax errors and style issues. Blocks bad edits. Supports Python (ruff), JS/TS (eslint), Go (golangci-lint), and more.",
"capabilities": [
"lint_file"
],
"file": "tool_executor.py",
"full_path": "",
"priority": 100,
"semantic_examples": [],
"risk": "read-only",
"preconditions": [
"file exists",
"a linter is configured for the language"
],
"side_effects": [],
"auto_invoked": false,
"hooks": [],
"native_tool": true,
"searchable_text": "lint_file lint a file for syntax errors and style issues. blocks bad edits. supports python (ruff), js/ts (eslint), go (golangci-lint), and more. native tool"
},
{
"name": "run_tests",
"description": "Run tests for a file or project. Auto-detects test runner from language.",
"capabilities": [
"run_tests"
],
"file": "tool_executor.py",
"full_path": "",
"priority": 100,
"semantic_examples": [],
"risk": "write",
"preconditions": [
"a test runner is configured for the project"
],
"side_effects": [
"runs project test commands which may create or delete files"
],
"auto_invoked": false,
"hooks": [],
"native_tool": true,
"searchable_text": "run_tests run tests for a file or project. auto-detects test runner from language. native tool"
},
{
"name": "format_code",
"description": "Auto-format code files. Supports Python (black/ruff), JS/TS (prettier), Go (gofmt), and more.",
"capabilities": [
"format_code"
],
"file": "tool_executor.py",
"full_path": "",
"priority": 100,
"semantic_examples": [],
"risk": "write",
"preconditions": [
"path is inside an allowed write directory",
"a formatter is configured for the language"
],
"side_effects": [
"rewrites files in place to the formatter's style"
],
"auto_invoked": false,
"hooks": [],
"native_tool": true,
"searchable_text": "format_code auto-format code files. supports python (black/ruff), js/ts (prettier), go (gofmt), and more. native tool"
},
{
"name": "git_diff",
"description": "Show git diff for staged or unstaged changes.",
"capabilities": [
"git_diff"
],
"file": "tool_executor.py",
"full_path": "",
"priority": 100,
"semantic_examples": [],
"risk": "read-only",
"preconditions": [
"working directory is a git repository"
],
"side_effects": [],
"auto_invoked": false,
"hooks": [],
"native_tool": true,
"searchable_text": "git_diff show git diff for staged or unstaged changes. native tool"
},
{
"name": "git_log",
"description": "Show recent git commits.",
"capabilities": [
"git_log"
],
"file": "tool_executor.py",
"full_path": "",
"priority": 100,
"semantic_examples": [],
"risk": "read-only",
"preconditions": [
"working directory is a git repository"
],
"side_effects": [],
"auto_invoked": false,
"hooks": [],
"native_tool": true,
"searchable_text": "git_log show recent git commits. native tool"
},
{
"name": "git_commit",
"description": "Commit changes with a message. Auto-stages modified files.",
"capabilities": [
"git_commit"
],
"file": "tool_executor.py",
"full_path": "",
"priority": 100,
"semantic_examples": [],
"risk": "irreversible",
"preconditions": [
"working directory is a git repository",
"there are changes to commit"
],
"side_effects": [
"creates a commit on the current branch"
],
"auto_invoked": false,
"hooks": [],
"native_tool": true,
"searchable_text": "git_commit commit changes with a message. auto-stages modified files. native tool"
},
{
"name": "repo_map",
"description": "Generate an AST-based codebase map showing key symbols (classes, functions, imports). Uses tree-sitter for 100+ languages.",
"capabilities": [
"repo_map"
],
"file": "tool_executor.py",
"full_path": "",
"priority": 100,
"semantic_examples": [],
"risk": "read-only",
"preconditions": [
"target directory is readable"
],
"side_effects": [],
"auto_invoked": false,
"hooks": [],
"native_tool": true,
"searchable_text": "repo_map generate an ast-based codebase map showing key symbols (classes, functions, imports). uses tree-sitter for 100+ languages. native tool"
},
{
"name": "run_command",
"description": "Run an approved command. Prefer argv (shell=False); shell syntax requires shell=true and explicit user approval.",
"capabilities": [
"run_command"
],
"file": "tool_executor.py",
"full_path": "",
"priority": 100,
"semantic_examples": [],
"risk": "irreversible",
"preconditions": [
"operator approves the command",
"required binaries are on PATH"
],
"side_effects": [
"executes arbitrary commands with their full side effects"
],
"auto_invoked": false,
"hooks": [],
"native_tool": true,
"searchable_text": "run_command run an approved command. prefer argv (shell=false); shell syntax requires shell=true and explicit user approval. native tool"
},
{
"name": "read_persona",
"description": "Read Rune's persona definition. Returns the full persona block with voice, identity, and rules.",
"capabilities": [
"read_persona"
],
"file": "tool_executor.py",
"full_path": "",
"priority": 100,
"semantic_examples": [],
"risk": "read-only",
"preconditions": [
"persona MEMORY.md exists"
],
"side_effects": [],
"auto_invoked": false,
"hooks": [],
"native_tool": true,
"searchable_text": "read_persona read rune's persona definition. returns the full persona block with voice, identity, and rules. native tool"
},
{
"name": "query_memory",
"description": "Query Rune's memory store. Returns relevant memories for a query.",
"capabilities": [
"query_memory"
],
"file": "tool_executor.py",
"full_path": "",
"priority": 100,
"semantic_examples": [],
"risk": "read-only",
"preconditions": [
"memory store database is available"
],
"side_effects": [],
"auto_invoked": false,
"hooks": [],
"native_tool": true,
"searchable_text": "query_memory query rune's memory store. returns relevant memories for a query. native tool"
},
{
"name": "check_growth",
"description": "Check Rune's growth log. Returns recent growth entries and patterns.",
"capabilities": [
"check_growth"
],
"file": "tool_executor.py",
"full_path": "",
"priority": 100,
"semantic_examples": [],
"risk": "read-only",
"preconditions": [
"growth log file exists"
],
"side_effects": [],
"auto_invoked": false,
"hooks": [],
"native_tool": true,
"searchable_text": "check_growth check rune's growth log. returns recent growth entries and patterns. native tool"
},
{
"name": "diagnose_behavior",
"description": "Diagnose Rune's current behavior. Returns analysis of persona adherence, voice consistency, and drift.",
"capabilities": [
"diagnose_behavior"
],
"file": "tool_executor.py",
"full_path": "",
"priority": 100,
"semantic_examples": [],
"risk": "read-only",
"preconditions": [
"recent response text provided"
],
"side_effects": [],
"auto_invoked": false,
"hooks": [],
"native_tool": true,
"searchable_text": "diagnose_behavior diagnose rune's current behavior. returns analysis of persona adherence, voice consistency, and drift. native tool"
},
{
"name": "find_capability",
"description": "Search all installed capabilities for what you need. Returns matching tool names with descriptions and argument schemas. Use this when a capability you need is not in your current tool set; the matched tool becomes callable in the same session.",
"capabilities": [
"find_capability"
],
"file": "tool_executor.py",
"full_path": "",
"priority": 100,
"semantic_examples": [],
"risk": "read-only",
"preconditions": [
"a capability query describing the needed outcome"
],
"side_effects": [],
"auto_invoked": false,
"hooks": [],
"native_tool": true,
"searchable_text": "find_capability search all installed capabilities for what you need. returns matching tool names with descriptions and argument schemas. use this when a capability you need is not in your current tool set; the matched tool becomes callable in the same session. native tool"
}
]
+38287 -15
View File
File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "rune"
version = "0.87.0"
version = "0.88.4"
description = "Rune — a stateful coding assistant with persistent memory, orchestration, and TUI"
requires-python = ">=3.10"
+6 -6
View File
@@ -1,5 +1,5 @@
# This file was autogenerated by uv via the following command:
# uv pip compile pyproject.toml -o /tmp/req_new.txt --extra dev --extra memory --python-version 3.11
# uv pip compile pyproject.toml -o requirements-ci.txt --extra dev --extra memory --python-version 3.11
aiohappyeyeballs==2.7.1
# via aiohttp
aiohttp==3.14.3
@@ -18,9 +18,9 @@ certifi==2026.7.22
# httpx
chardet==7.6.0
# via diff-cover
coverage==7.16.1
coverage==7.16.2
# via rune (pyproject.toml)
diff-cover==10.5.1
diff-cover==10.6.0
# via rune (pyproject.toml)
frozenlist==1.8.0
# via
@@ -56,15 +56,15 @@ mdit-py-plugins==0.6.1
# via textual
mdurl==0.1.2
# via markdown-it-py
multidict==6.9.0
multidict==6.9.1
# via
# aiohttp
# yarl
nodeenv==1.10.0
nodeenv==1.11.0
# via pyright
packaging==26.3
# via pytest
platformdirs==4.11.11
platformdirs==4.12.2
# via textual
pluggy==1.6.0
# via
+17 -3
View File
@@ -148,9 +148,18 @@ def sha_branch(sha: str) -> str:
def sha_on_master(sha: str) -> bool:
out = _git("branch", "--contains", sha)
return any(l.strip().endswith("master") or l.strip() == "master"
for l in out.splitlines())
"""SHA is an ancestor of master (local or remote-tracking refs).
M10 correction (2026-09-19): --all so a freshly fetched master
(refs/remotes/gitea/master) counts; local branches alone go stale
between fetches. derive_op_type refreshes refs before calling this.
"""
out = _git("branch", "--all", "--contains", sha)
for l in out.splitlines():
s = l.strip().removeprefix("remotes/").removesuffix(" *")
if s == "master" or s.endswith("/master"):
return True
return False
def open_pr_for_sha(sha: str) -> int | None:
@@ -184,6 +193,11 @@ def derive_op_type(sha: str) -> tuple[str, str]:
were created from model-supplied defaults and cannot be trusted.
Never trusts model input.
"""
# 0. M10 correction (2026-09-19): refresh remote-tracking refs before
# inference. A just-merged master commit is invisible to
# branch --contains until refs are fetched; stale local git state
# must never outrank repo truth. Bounded by GIT_TIMEOUT, fail-open.
_git("fetch", "--quiet", "gitea", "+refs/heads/*:refs/remotes/gitea/*")
for rec in _load_wait_records():
if _rec_sha(rec) != sha:
continue
+5 -2
View File
@@ -86,9 +86,12 @@ def main() -> int:
if live_state == "open" and rec["tracker_state"] == "closed" and rec["reconciliation_state"] in TERMINAL_STATES:
drift.append(f"#{num}: live state open but artifact says closed/{rec['reconciliation_state']}")
live_bug = "bug" in [l["name"] for l in li.get("labels", [])]
if live_bug and not rec.get("live_defect"):
# Same open-only exemption as the artifact-records block above: a
# closed issue's labels are historical record; FIXED_VERIFIED issues
# legitimately keep the bug label after closure.
if live_bug and rec.get("tracker_state") == "open" and not rec.get("live_defect"):
drift.append(f"#{num}: live bug label present but artifact records no live defect")
if not live_bug and rec.get("live_defect"):
if not live_bug and rec.get("live_defect") and rec.get("tracker_state") == "open":
drift.append(f"#{num}: artifact records live defect but live bug label absent")
# Live defects in the artifact must all be OPEN in the tracker
+54 -26
View File
@@ -1,43 +1,71 @@
#!/usr/bin/env python3
"""install_mimo_hook.py — T21.2 §21.2D: canonical MiMo hook installer.
"""install_mimo_hook.py — T21.2 §21.2D (T22: multi-hook): canonical MiMo
hook installer.
Canonical source: config/mimo-hooks/event-wait-guard.ts
Target: ~/.mimocode/hooks/event-wait-guard.ts
Verifies hash after install. Detects drift in both directions."""
Canonical sources: config/mimo-hooks/*.ts
Targets: ~/.mimocode/hooks/<same-name>.ts
Every hook is hash-verified after install; drift is detected in both
directions. T22 added builder-bridge.ts to the managed set — it was
previously installed by hand, unversioned, which is how it silently rotted
(hardcoded ephemeral interpreter). A hook that reaches the builder must be
version-controlled and drift-checked like any other authority.
Usage:
python3 scripts/install_mimo_hook.py # sync all managed hooks
python3 scripts/install_mimo_hook.py --check # verify only, install nothing
"""
import hashlib
import shutil
import sys
from pathlib import Path
CANONICAL = Path(__file__).resolve().parent.parent / "config" / "mimo-hooks" / "event-wait-guard.ts"
TARGET = Path.home() / ".mimocode" / "hooks" / "event-wait-guard.ts"
REPO = Path(__file__).resolve().parent.parent
CANONICAL_DIR = REPO / "config" / "mimo-hooks"
TARGET_DIR = Path.home() / ".mimocode" / "hooks"
# The managed set. Adding a file here is what makes a hook version-controlled.
MANAGED = ["event-wait-guard.ts", "builder-bridge.ts"]
def sha256(p: Path) -> str:
return hashlib.sha256(p.read_bytes()).hexdigest()
def main() -> int:
if not CANONICAL.is_file():
print(f"canonical source missing: {CANONICAL}")
return 1
canon_hash = sha256(CANONICAL)
if TARGET.is_file():
target_hash = sha256(TARGET)
if target_hash == canon_hash:
print(f"in-sync: {target_hash[:12]}")
return 0
print(f"DRIFT: canonical={canon_hash[:12]} installed={target_hash[:12]}")
def sync_one(name: str, check_only: bool) -> bool:
canonical = CANONICAL_DIR / name
target = TARGET_DIR / name
if not canonical.is_file():
print(f"canonical source missing: {canonical}")
return False
canon_hash = sha256(canonical)
if target.is_file() and sha256(target) == canon_hash:
print(f"in-sync: {name} {canon_hash[:12]}")
return True
if check_only:
state = "DRIFT" if target.is_file() else "MISSING"
inst = sha256(target)[:12] if target.is_file() else "-"
print(f"{state}: {name} canonical={canon_hash[:12]} installed={inst}")
return False
if target.is_file():
print(f"DRIFT: {name} canonical={canon_hash[:12]} installed={sha256(target)[:12]}")
else:
print(f"hook missing at {TARGET}")
TARGET.parent.mkdir(parents=True, exist_ok=True)
shutil.copy2(CANONICAL, TARGET)
installed_hash = sha256(TARGET)
if installed_hash != canon_hash:
print(f"INSTALL FAILED: hash mismatch after copy")
return 1
print(f"installed: {installed_hash[:12]}")
return 0
print(f"hook missing at {target}")
TARGET_DIR.mkdir(parents=True, exist_ok=True)
shutil.copy2(canonical, target)
if sha256(target) != canon_hash:
print(f"INSTALL FAILED: {name} hash mismatch after copy")
return False
print(f"installed: {name} {canon_hash[:12]}")
return True
def main() -> int:
check_only = "--check" in sys.argv
ok = True
for name in MANAGED:
ok = sync_one(name, check_only) and ok
return 0 if ok else 1
if __name__ == "__main__":
+52
View File
@@ -0,0 +1,52 @@
#!/usr/bin/env python3
"""install_mimo_tools.py — canonical MiMo tool installer (TTY-repair tranche).
Canonical sources: config/mimo-tools/{bash.ts,await-operation.ts}
Targets: ~/.mimocode/tools/{bash.ts,await-operation.ts}
Verifies hashes after install; detects drift in both directions
(the parity test reads these hashes).
"""
import hashlib
import shutil
import sys
from pathlib import Path
REPO = Path(__file__).resolve().parent.parent
TOOLS = ["bash.ts", "await-operation.ts"]
def sha256(p: Path) -> str:
return hashlib.sha256(p.read_bytes()).hexdigest()
def main() -> int:
rc = 0
for name in TOOLS:
canon = REPO / "config" / "mimo-tools" / name
target = Path.home() / ".mimocode" / "tools" / name
if not canon.is_file():
print(f"{name}: canonical source missing: {canon}")
rc = 1
continue
canon_hash = sha256(canon)
if target.is_file() and sha256(target) == canon_hash:
print(f"{name}: in-sync {canon_hash[:12]}")
continue
drift = f"DRIFT canonical={canon_hash[:12]}"
if target.is_file():
drift += f" installed={sha256(target)[:12]}"
else:
drift += " installed=MISSING"
print(f"{name}: {drift} — installing")
target.parent.mkdir(parents=True, exist_ok=True)
shutil.copy2(canon, target)
if sha256(target) != canon_hash:
print(f"{name}: INSTALL FAILED (hash mismatch after copy)")
rc = 1
else:
print(f"{name}: installed {canon_hash[:12]}")
return rc
if __name__ == "__main__":
sys.exit(main())
+23
View File
@@ -42,6 +42,29 @@ def main() -> int:
"exit_code": 0 if result == "success" else 1,
"completed_at": time.time(),
}
# R8 lost-event failure-recovery: operation-scoped fault injection.
# A rule keyed by the EXACT operation_id suppresses BOTH normal
# delivery channels (durable completion file AND bridge POST), so the
# waiter's watchdog/failure-detector path is the only route to truth.
# Disabled by default (no rule file => zero behavior change) and
# observable: every decision is recorded in the R8 fault log.
try:
import r8_fault # noqa: E402 — sibling module
if r8_fault.should_suppress(payload["operation_id"]):
r8_fault.record(payload["operation_id"], "suppressed",
{"sha": sha, "exit_code": payload["exit_code"],
"source_terminal_at": payload["completed_at"]})
print("notify-event-bridge: R8 fault injection — completion "
f"event intentionally suppressed for "
f"{payload['operation_id']} (no .done file, no POST); "
"watchdog authority recovery is the expected path",
flush=True)
return 0
r8_fault.record(payload["operation_id"], "delivered_normally",
{"sha": sha, "rule_active": False})
except Exception as exc: # noqa: BLE001 — fault seam must never break delivery
print(f"notify-event-bridge: R8 fault-seam probe failed ({exc}); "
"continuing with normal delivery", flush=True)
# R3 durable delivery: write the completion file FIRST — it works even
# if the bridge daemon is down, and the atomic rename means any waiter
# (inotify-watching or starting later) sees a complete file or none.
+83
View File
@@ -0,0 +1,83 @@
#!/usr/bin/env python3
"""r8_fault.py — REAL_ASYNC_BRIDGE R8: operation-scoped lost-event fault
injection (evidence-only harness).
DESIGN CONTRACT (R8 §3):
disabled by default no rule file -> zero behavior change
operation-scoped rule keyed by EXACT operation_id
reversible delete the rule file / rule entry
observable every decision appended to a JSONL log
cannot affect other waits rule file checked by operation_id only
The ONLY consumer is scripts/notify_event_bridge.py: before normal
delivery it consults should_suppress(operation_id). Suppression means:
- NO durable completion file is written
- NO bridge POST (no /process-event wake)
- the suppression decision is recorded as R8 fault evidence
Nothing else in the stack reads the rule. The daemon, waitstore,
authority verification, and completion-file machinery are untouched.
"""
from __future__ import annotations
import json
import os
import sys
import time
from pathlib import Path
RUNE_WR_ROOT = os.environ.get("RUNE_WR_ROOT") or os.environ.get("WR_ROOT") or "/mnt/workdrive/wr-bridge"
RULES_PATH = Path(RUNE_WR_ROOT) / "r8_suppress_rules.json"
FAULT_LOG = Path(RUNE_WR_ROOT) / "r8_fault_log.jsonl"
REASON = "event intentionally suppressed for R8 lost-event failure-recovery"
def _rules() -> dict:
"""Read the rule file. Absent/unreadable => no suppression (fail-open
to NORMAL delivery; the fault must never take the healthy path down)."""
try:
return json.loads(RULES_PATH.read_text())
except Exception: # noqa: BLE001 — absent rule file is the default state
return {}
def lookup(operation_id: str) -> dict | None:
"""Return the active suppression rule for EXACTLY this operation_id,
or None. Expired rules are ignored (not deleted — deletion is the
operator's explicit disable action)."""
spec = _rules()
if not spec.get("enabled"):
return None
rule = spec.get("operations", {}).get(operation_id)
if not rule:
return None
expires = rule.get("expires_at")
if expires:
try:
if time.time() > time.mktime(time.strptime(expires, "%Y-%m-%dT%H:%M:%SZ")) - time.timezone:
return None
except ValueError:
return None
return rule
def should_suppress(operation_id: str) -> bool:
return lookup(operation_id) is not None
def record(operation_id: str, stage: str, extra: dict | None = None) -> None:
"""Append a durable fault-evidence line (best-effort, never raises)."""
try:
entry = {
"at": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
"operation_id": operation_id,
"reason": REASON,
"stage": stage,
**(extra or {}),
}
FAULT_LOG.parent.mkdir(parents=True, exist_ok=True)
with FAULT_LOG.open("a") as f:
f.write(json.dumps(entry, sort_keys=True) + "\n")
except OSError as exc: # noqa: BLE001 — evidence logging must never break CI
print(f"r8_fault: evidence log write failed: {exc}", file=sys.stderr)
+214
View File
@@ -0,0 +1,214 @@
#!/usr/bin/env python3
"""Tranche R1 Wave 0 — whole-project inventory generator.
Parses every .py file under src/rune/ with the stdlib AST and emits
docs/rebase/rebase-inventory.json: files, classes, functions (with signatures and
line ranges), imports, and best-effort caller/callee edges (intra-module call
graph + cross-module edges resolved through import tables).
Deterministic and idempotent: same tree in, same JSON out (sorted keys,
sorted files). The issue-factory reads this file; nothing else may edit it.
"""
from __future__ import annotations
import ast
import json
import sys
from collections import defaultdict
from pathlib import Path
REPO = Path(__file__).resolve().parent.parent
SRC = REPO / "src" / "rune"
OUT = REPO / "docs" / "rebase" / "rebase-inventory.json"
def _arg_str(a: ast.arg) -> str:
s = a.arg
if a.annotation is not None:
# Degraded signature (no annotation) is deterministic metadata — never
# let one pathological annotation node abort the whole inventory walk.
try:
s += f": {ast.unparse(a.annotation)}"
except (AttributeError, RecursionError, ValueError):
pass
return s
def _signature(node: ast.FunctionDef | ast.AsyncFunctionDef) -> str:
parts = [_arg_str(a) for a in node.args.args]
if node.args.vararg:
parts.append(f"*{node.args.vararg.arg}")
elif node.args.kwonlyargs:
parts.append("*")
parts += [_arg_str(a) for a in node.args.kwonlyargs]
if node.args.kwarg:
parts.append(f"**{node.args.kwarg.arg}")
ret = ""
if node.returns is not None:
# Same degraded-metadata contract as _arg_str.
try:
ret = f" -> {ast.unparse(node.returns)}"
except (AttributeError, RecursionError, ValueError):
pass
return f"({', '.join(parts)}){ret}"
class FileVisitor(ast.NodeVisitor):
def __init__(self) -> None:
self.functions: list[dict] = []
self.classes: list[dict] = []
self.imports: list[dict] = []
self.calls: list[tuple[int, str]] = [] # (lineno, dotted call name)
def _fn(self, node, parents: list[str]) -> dict:
return {
"name": ".".join([*parents, node.name]),
"signature": _signature(node),
"line_start": node.lineno,
"line_end": node.end_lineno or node.lineno,
"decorators": [ast.unparse(d) for d in node.decorator_list
if isinstance(d, (ast.Name, ast.Attribute, ast.Call))],
"async": isinstance(node, ast.AsyncFunctionDef),
}
def visit_ClassDef(self, node: ast.ClassDef) -> None:
methods = []
for child in node.body:
if isinstance(child, (ast.FunctionDef, ast.AsyncFunctionDef)):
methods.append(self._fn(child, [node.name]))
self.calls.extend(
(n.lineno, ast.unparse(n.func))
for n in ast.walk(child)
if isinstance(n, ast.Call) and not isinstance(n.func, ast.Name if False else type(None))
and isinstance(n.func, (ast.Name, ast.Attribute))
)
self.classes.append({
"name": node.name,
"bases": [ast.unparse(b) for b in node.bases],
"line_start": node.lineno,
"line_end": node.end_lineno or node.lineno,
"methods": methods,
})
# visit only non-function children: methods are already captured above,
# and a generic_visit would re-fire visit_FunctionDef on them (duplicate
# units + duplicate call edges). Nested classes are still visited.
for child in node.body:
if not isinstance(child, (ast.FunctionDef, ast.AsyncFunctionDef)):
self.visit(child)
def visit_FunctionDef(self, node) -> None:
# top-level only reached here (methods captured in ClassDef)
self.functions.append(self._fn(node, []))
self.calls.extend(
(n.lineno, ast.unparse(n.func))
for n in ast.walk(node)
if isinstance(n, ast.Call) and isinstance(n.func, (ast.Name, ast.Attribute))
)
# do not descend into nested defs separately; they are folded into parents
# (their calls are already captured by the ast.walk above). No generic_visit:
# it would re-collect nested defs as top-level functions and duplicate edges.
visit_AsyncFunctionDef = visit_FunctionDef
def visit_Import(self, node: ast.Import) -> None:
for a in node.names:
self.imports.append({"module": a.name, "as": a.asname, "line": node.lineno})
def visit_ImportFrom(self, node: ast.ImportFrom) -> None:
mod = node.module or ""
for a in node.names:
self.imports.append({"module": f"{mod}.{a.name}" if a.name != "*" else mod,
"as": a.asname or a.name, "line": node.lineno,
"from": True})
def collect_file(path: Path) -> dict:
src_text = path.read_text(encoding="utf-8", errors="replace")
tree = ast.parse(src_text)
v = FileVisitor()
v.visit(tree)
# module-level calls (outside defs/classes) — walk tree body directly.
# SKIP def/class statements: their bodies are walked by the visit_ methods;
# walking them here duplicated every call edge inside every top-level function.
for stmt in tree.body:
if isinstance(stmt, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef)):
continue
for n in ast.walk(stmt):
if isinstance(n, ast.Call) and isinstance(n.func, (ast.Name, ast.Attribute)):
v.calls.append((n.lineno, ast.unparse(n.func)))
defined = {f["name"].split(".")[-1] for f in v.functions}
defined |= {m["name"].split(".")[-1] for c in v.classes for m in c["methods"]}
defined |= {c["name"] for c in v.classes}
callees = []
for lineno, call in v.calls:
root = call.split(".")[0].split("(")[0].strip()
callees.append({"line": lineno, "call": call,
"internal": root in defined or root == "self"})
return {
"path": str(path.relative_to(REPO)),
"lines": len(src_text.splitlines()),
"imports": sorted({i["module"] for i in v.imports}),
"import_lines": v.imports,
"functions": sorted(v.functions, key=lambda f: (f["line_start"], f["name"])),
"classes": sorted(v.classes, key=lambda c: c["line_start"]),
"calls": callees,
}
def cross_module_edges(files: dict[str, dict]) -> dict[str, set[str]]:
"""Resolve import tables: module-stem -> set of imported module stems
(rune-internal only), so the factory can attribute cross-module edges."""
graph = defaultdict(set)
for rel, info in files.items():
stem = Path(rel).stem
for imp in info["imports"]:
top = imp.split(".")[0]
second = ".".join(imp.split(".")[:2])
if top == "rune":
graph[stem].add(imp.replace("rune.", "", 1).split(".")[0])
elif not imp.startswith("_") and top not in sys.stdlib_module_names:
graph[stem].add(f"ext:{top}")
return graph
def main() -> None:
py_files = sorted(SRC.rglob("*.py"))
files: dict[str, dict] = {}
for p in py_files:
try:
info = collect_file(p)
except SyntaxError as e: # a file that cannot parse is a finding, not a skip
info = {"path": str(p.relative_to(REPO)), "lines": 0, "imports": [],
"import_lines": [], "functions": [], "classes": [], "calls": [],
"parse_error": f"{type(e).__name__}: {e}"}
files[info["path"]] = info
graph = cross_module_edges(files)
total_fns = sum(len(f["functions"]) + sum(len(c["methods"]) for c in f["classes"])
for f in files.values())
doc = {
"_meta": {
"generator": "scripts/rebase_inventory.py",
"tranche": "R1 language rebase, Wave 0",
"note": "Machine-generated. Regenerate with the script; never hand-edit.",
"files": len(files),
"functions_total": total_fns,
"classes_total": sum(len(f["classes"]) for f in files.values()),
"lines_total": sum(f["lines"] for f in files.values()),
},
"import_graph": {k: sorted(v) for k, v in sorted(graph.items())},
"files": dict(sorted(files.items())),
}
OUT.write_text(json.dumps(doc, indent=1, sort_keys=False) + "\n", encoding="utf-8")
m = doc["_meta"]
print(f"inventory written: {OUT}")
print(f"files={m['files']} functions={m['functions_total']} "
f"classes={m['classes_total']} lines={m['lines_total']}")
if __name__ == "__main__":
main()
+356
View File
@@ -0,0 +1,356 @@
#!/usr/bin/env python3
"""Tranche R1 Wave 0 — per-function issue factory.
Reads docs/rebase/rebase-inventory.json and emits one issue per unit (top-level
function or class method) following tranche R1 §7. Wave-batched, dedup-safe
(deterministic title + existing-issue scan before create), rate-limited.
Modes:
plan — coverage report: units per wave, unassigned modules (no silent drops)
sample — emit N rendered issues to a file for review (no Gitea call)
create — create issues in Gitea for one wave
Dedup contract: issue titles are deterministic —
[rebase w{wave}] {relpath}::{unit}
The factory fetches existing issue titles once per run and skips any that
already exist, so retries never duplicate (preserve-first Gitea addendum).
The factory NEVER writes behaviour prose. Current-behaviour paragraphs and
the three evidence answers (IMPROVE / FIX / MISSING CONNECTORS) are filled at
disposition time by the working agent — the issue carries the mandatory
fields and line ranges, not fabricated content.
"""
import argparse
import json
import os
import sys
import time
import urllib.request
import urllib.error
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parent.parent
INVENTORY = REPO_ROOT / "docs" / "rebase" / "rebase-inventory.json"
COVERAGE_OUT = REPO_ROOT / "docs" / "rebase" / "rebase-wave-coverage.json"
GITEA_URL = os.environ.get("GITEA_URL", "https://gitea.thingscouldgetdicey.online")
REPO = "conductor/rune"
sys.path.insert(0, str(Path(__file__).resolve().parent.parent / "shared"))
from gitea_auth import load_gitea_token # noqa: E402
TRANCHE_REF = "tranche R1 language rebase (2026-09-29), ~/.config/opencode/tranches/2026-09-29-language-rebase-tranche-R1.md"
# Wave membership from R1 §4 (initial, measured). Directory entries match by
# path prefix; bare stems match the file stem. Modules matching no entry are
# reported UNASSIGNED by `plan` — never silently dropped (R1 §9 risk 7).
WAVE_PLAN = {
2: [ # leaf utilities & canaries
"pins", "time_awareness", "message_queue", "event_envelope",
"attention_capsule", "complexity_scorer", "token_optimizer", "cache",
"prompt_sync", "chat_bubble", "canary_*",
],
3: [ # memory & persistence
"memory_store", "curator", "warm_router", "memory_consolidation",
"graph_memory", "sleep_time", "night_mode", "identity_anchors",
"query_memory", "memory_env", "warm_neuron_store", "subconscious_pass",
"task_persist",
],
4: [ # provider/model layer
"provider_registry", "model_connect", "model_routing", "model_profiles",
"provider_budget", "standardized_providers", "model_registry",
"connection_pool", "forge_client",
],
5: [ # orchestration, authority, plugins, skills, governance
"orchestration/", "microkernel", "contracts", "build_mode", "plugins/",
"skills/", "construction_authority", "construction_authority_cli",
"construction_decision", "construction_mode", "verification_construction",
"authority_recovery", "spine", "drift_core", "drift_ledger",
"drift_observability", "persona_gate", "safety_override", "witness",
"behavior", "growth_delta", "claim_audit", "verification_layer",
"drift_compression", "drift_cache", "self_improve", "persona_definition",
"outcome_ledger", "audit_ledger", "subsystem_health",
],
6: [ # runtime core & tooling
"tool_executor", "tool_protocol", "local_tool_runtime",
"capability_broker", "context_broker", "work_manager", "cron_engine",
"auto_tasks", "goal", "failure_auto_filer", "hook_engine",
"elastic_cognition", "event_bus", "system_registry", "abstraction",
"tiered_executor", "progressive_escalation", "tier_manager",
"parallel_processor", "shard_manager", "response_adapter",
"context_pressure", "auto_context", "cognitive_budgeter",
"recall_router", "inference_trace", "task_gate", "salience_gate",
"dependency_tracker", "rune_profiler",
],
7: [ # operator + TUI, last by design
"rune_operator", "rune_tui", "tui_validator", "voice_hybrid",
"voice_sync", "voicebox", "voice_injector", "message_widgets",
"rune_graphic", "rune_spinner", "__main__",
],
}
WAVE_NAMES = {
2: "leaf utilities & canaries",
3: "memory & persistence",
4: "provider/model layer",
5: "orchestration, authority, plugins, skills, governance",
6: "runtime core & tooling",
7: "operator + TUI",
}
def match_module(relpath: str):
"""Return the wave number for a module path, or None if unassigned."""
stem = Path(relpath).stem
for wave, patterns in WAVE_PLAN.items():
for pat in patterns:
if pat.endswith("/"):
if pat in relpath:
return wave
elif pat.endswith("*"):
if stem.startswith(pat[:-1]):
return wave
elif stem == pat:
return wave
return None
def iter_units(inv):
"""Yield (relpath, unit_name, entry) for every function and method."""
for relpath, mod in sorted(inv["files"].items()):
for fn in mod["functions"]:
yield relpath, fn["name"], fn
for cls in mod["classes"]:
for m in cls.get("methods", []):
yield relpath, f"{cls['name']}.{m['name']}", m
def internal_edges(relpath: str, entry: dict):
"""Collect internal (in-repo) call names and line numbers for a unit."""
lines = (entry["line_start"], entry["line_end"])
mod = inv_cache["files"][relpath]
calls = [c for c in mod.get("calls", [])
if lines[0] <= c["line"] <= lines[1] and c.get("internal")]
return calls
inv_cache = {}
def issue_title(wave: int, relpath: str, unit: str) -> str:
return f"[rebase w{wave}] {relpath}::{unit}"
def render_issue(wave: int, relpath: str, unit: str, entry: dict) -> dict:
calls = internal_edges(relpath, entry)
call_lines = "\n".join(
f" - `{c['call']}` (line {c['line']})" for c in calls[:20]
) or " - (no internal call edges in range)"
sig = entry.get("signature", "()")
body = f"""\
## Identity (from the Wave 0 inventory — machine-generated)
- **File**: `{relpath}`
- **Unit**: `{unit}`
- **Signature**: `def {unit}{sig}` (async: {entry.get('async', False)})
- **Line range**: {entry['line_start']}–{entry['line_end']}
- **Decorators**: {entry.get('decorators', []) or 'none'}
- **Internal call edges** (callers/callees inside the repo, from inventory):
{call_lines}
## Current behaviour
One honest paragraph from READING THE CODE at the line range above — what it
actually does, not what the docstring promises. Write this at disposition
time; the factory does not fabricate it.
## The three questions — each answered WITH EVIDENCE
1. **IMPROVE?** Can the unit be improved within its scope? Evidence or "no — because …".
(Bounded to unit scope; larger findings spawn NEW issues, never expand this one.)
2. **FIX?** Is it broken, buggy, or failing its expected outcome? Evidence: a failing
test, a reproduced fault, or a code-level defect citation. A "no" needs evidence too.
3. **MISSING CONNECTORS?** Are there expected outcomes this unit should connect to but
doesn't (unwired events, dead parameters, promised-but-absent calls)? Evidence required.
A silent skip on any question is a factory bug — answer all three.
## Language verdict (per tranche R1 §6 rubric — evidence beats instinct)
Choose exactly one, with the evidence line:
- **KEEP-PYTHON** — one sentence of justification.
- **RECODE-<lang>** — rubric scores (all 7 dimensions) + benchmark-gate plan: the compiled
replacement must beat the Python original on the MEASURED hot path, or the recode is
rejected and recorded. No win, no recode.
- **MERGE-into:<module>** — name the target and why.
- **DEPRECATE** — name the caller that no longer needs it.
Go is NOT pre-decided. Python is not pre-decided. The rubric decides.
## Constraint context
- henxels structural contract: this unit's module ≤ 1,200 lines (or on the debt table's
exception list — check before adding lines).
- Spine: any module-surface change requires `store/spine/current.json` regen with the code
change (`test_manifest_maps_every_module` is the arbiter for new top-level modules).
- Debt table: docs/structural-contract.md.
## Pipeline plan
1. Branch `issue-<N>` from current master (existing issue-N convention).
2. Scaffolding activation for any construction (construction_mode/decision per unit change).
3. Research rounds are MANDATORY for any RECODE verdict (research-stage-headless; ≥2
live-verified external sources per claim; per-source lessons; kill test per candidate).
4. Implementation behind the interop contract (R1 §5): compiled units are standalone
binaries — argv in, JSON on stdout, non-zero exit on failure, `--version` mandatory;
Python wraps in a thin adapter; store stays the shared truth.
5. Local gates: pytest + ruff + spine-store regen (if surface changed) + henxels.
6. PR → pipeline-gate + ci + required checks → merge-robot → auto-version.
## Verification
- The specific test proving this unit's change: (write at disposition).
- The keep-green set it must not break: full suite must stay green; named
keep-green tests for this unit's callers.
## Provenance
- Tranche: {TRANCHE_REF}
- Wave: {wave} ({WAVE_NAMES.get(wave, 'unassigned')})
- Inventory: docs/rebase/rebase-inventory.json (regenerate with scripts/rebase_inventory.py — never hand-edit)
- Factory: scripts/rebase_issue_factory.py
"""
return {
"title": issue_title(wave, relpath, unit),
"body": body,
"labels": ["rebase", f"wave-{wave}"],
"meta": {
"wave": wave,
"file": relpath,
"unit": unit,
"line_start": entry["line_start"],
"line_end": entry["line_end"],
"async": entry.get("async", False),
},
}
def fetch_existing_titles() -> set:
"""Fetch all issue titles in the repo (paginated) for dedup."""
token = load_gitea_token()
titles = set()
page = 1
while True:
url = (f"{GITEA_URL}/api/v1/repos/{REPO}/issues"
f"?state=all&type=issues&limit=50&page={page}")
req = urllib.request.Request(url, headers={"Authorization": f"token {token}"})
with urllib.request.urlopen(req, timeout=30) as resp:
batch = json.loads(resp.read())
if not batch:
break
titles.update(i["title"] for i in batch)
if len(batch) < 50:
break
page += 1
return titles
def create_issue(entry: dict) -> dict:
token = load_gitea_token()
url = f"{GITEA_URL}/api/v1/repos/{REPO}/issues"
payload = json.dumps({
"title": entry["title"],
"body": entry["body"],
"labels": [], # label NAMES are set via the labels endpoint by auto-label; keep create minimal
}).encode()
req = urllib.request.Request(url, data=payload, method="POST",
headers={"Authorization": f"token {token}",
"Content-Type": "application/json"})
with urllib.request.urlopen(req, timeout=30) as resp:
return json.loads(resp.read())
def cmd_plan(inv):
counts = {}
unassigned_modules = {}
for relpath, unit, entry in iter_units(inv):
wave = match_module(relpath)
counts[wave] = counts.get(wave, 0) + 1
if wave is None:
unassigned_modules.setdefault(relpath, inv["files"][relpath]["lines"])
report = {
"units_per_wave": {str(k if k is not None else "UNASSIGNED"): v
for k, v in sorted(counts.items(), key=lambda kv: str(kv[0]))},
"unassigned_modules": dict(sorted(unassigned_modules.items(), key=lambda kv: -kv[1])),
"unassigned_module_count": len(unassigned_modules),
}
print(json.dumps(report, indent=1))
COVERAGE_OUT.write_text(json.dumps(report, indent=1) + "\n")
print(f"\ncoverage written to {COVERAGE_OUT.relative_to(REPO_ROOT)}", file=sys.stderr)
return 0 if not unassigned_modules else 1
def cmd_sample(inv, wave, limit, out):
emitted = 0
records = []
for relpath, unit, entry in iter_units(inv):
if match_module(relpath) != wave:
continue
records.append(render_issue(wave, relpath, unit, entry))
emitted += 1
if emitted >= limit:
break
Path(out).write_text("\n".join(json.dumps(r) for r in records) + "\n")
print(f"sampled {emitted} issues for wave {wave} -> {out}", file=sys.stderr)
return 0
def cmd_create(inv, wave, limit, dry_gap):
existing = fetch_existing_titles()
created, skipped = 0, 0
for relpath, unit, entry in iter_units(inv):
if match_module(relpath) != wave:
continue
title = issue_title(wave, relpath, unit)
if title in existing:
skipped += 1
continue
issue = create_issue(render_issue(wave, relpath, unit, entry))
created += 1
print(f"created #{issue.get('number')}: {title}", file=sys.stderr)
if limit and created >= limit:
break
time.sleep(dry_gap)
print(f"\nwave {wave}: created={created} skipped(dedup)={skipped}", file=sys.stderr)
return 0
def main():
ap = argparse.ArgumentParser(description=__doc__)
ap.add_argument("command", choices=["plan", "sample", "create"])
ap.add_argument("--wave", type=int, help="wave number (2-7)")
ap.add_argument("--limit", type=int, default=0, help="max issues for sample/create (0 = unlimited; sample defaults to 5)")
ap.add_argument("--out", default=None, help="sample output file")
ap.add_argument("--gap", type=float, default=0.5, help="seconds between creates")
args = ap.parse_args()
inv_cache.update(json.loads(INVENTORY.read_text()))
inv = inv_cache
if args.command == "plan":
return cmd_plan(inv)
if args.command == "sample":
if not args.wave:
ap.error("--wave required")
out = args.out or f"docs/rebase-factory-sample-w{args.wave}.json"
return cmd_sample(inv, args.wave, args.limit or 5, out)
if args.command == "create":
if not args.wave:
ap.error("--wave required")
return cmd_create(inv, args.wave, args.limit, args.gap)
return 2
if __name__ == "__main__":
sys.exit(main())
+88 -12
View File
@@ -33,7 +33,7 @@ SCRIPTS_DIR = os.path.expanduser("~/.config/opencode/scripts")
SHARED_DIR = os.path.expanduser("~/.config/opencode/shared")
CUSTODIAN_STATE_FILE = os.path.expanduser("~/.config/opencode/memory/custodian_state.json")
GITEA_URL = os.environ.get("GITEA_URL", "https://gitea.thingscouldgetdicey.online")
GITEA_URL = os.environ.get("GITEA_URL", "http://127.0.0.1:3000") # gitea.internal (PC); external = https://gitea.thingscouldgetdicey.online via Pi Caddy
GITEA_TOKEN = load_gitea_token()
REPO = "conductor/rune"
TUI_DIR = "/mnt/workdrive/rune"
@@ -54,6 +54,15 @@ UMBRELLA_TAGS = {
}
# Issue template directory — canonical copies live beside this script
# (mirrored to .gitea/ISSUE_TEMPLATE/ for the web-UI submission path).
ISSUE_TEMPLATE_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "issue_templates")
# kind -> Gitea label that MUST be present on the issue
KIND_LABEL = {"feature": "feature", "bug": "bug", "research": "research"}
VERSION_INTENTS = ("major", "minor", "patch", "none")
class Custodian:
"""The Custodian agent for Gitea-based self-improvement."""
@@ -105,23 +114,90 @@ class Custodian:
except Exception as e:
return {"error": str(e)[:200]}
def create_issue(self, title: str, body: str, labels: List[str] = None) -> dict:
"""Create a Gitea issue with plain-language description.
def _ensure_label(self, name: str, description: str = "", color: str = "#6f42c1") -> bool:
"""Make sure a label exists on the repo; return its id or None."""
labels = self._gitea_api("labels")
if isinstance(labels, list):
for l in labels:
if l["name"] == name:
return l["id"]
data = {"name": name, "description": description or name, "color": color}
created = self._gitea_api("labels", method="POST", data=data)
return created.get("id") if isinstance(created, dict) else None
Labels should be umbrella names (memory, governance, etc).
They get converted to IDs automatically.
def _load_issue_template(self, kind: str) -> str:
"""Load the canonical issue template for a kind, WITHOUT the web-UI
frontmatter (name/about/title/labels — that metadata belongs to the
submission form, not the issue body). Empty string if absent."""
path = os.path.join(ISSUE_TEMPLATE_DIR, f"{kind}.md")
try:
with open(path) as f:
text = f.read()
except FileNotFoundError:
return ""
if text.startswith("---"):
end = text.find("\n---", 3)
if end != -1:
text = text[end + 4:]
return text.lstrip("\n")
def create_issue(
self,
title: str,
body: str,
labels: List[str] = None,
kind: str = "feature",
version_intent: Optional[str] = None,
) -> dict:
"""Create a Gitea issue assembled from the canonical template.
kind: feature | bug | research — selects the template and forces the
matching label (the research label is auto-created if missing).
version_intent: major | minor | patch | none — pre-ticks the matching
box in the template's Version impact section. The pipeline
verifies the real bump at merge and flags mismatches.
labels: umbrella names (memory, governance, ...); converted to IDs.
The caller's body replaces the SUBMITTED_BODY marker inside the
template's Plain English section — plain terms first, always.
ORGANISATION STANDARD (one open note per idea, 2026-09-19): before
minting a standalone issue, check whether the work belongs inside an
existing parent. Ideas parked under a blocked/future epic are filed
as checklist items in the parent's "Absorbed children" section, NOT
as standalone issues — the board stays uncluttered and every idea
has exactly one home. Mint a standalone issue only when the work is
live, dependency-tracked, or about to start. Absorbed ideas are
reversible: re-mint standalone when they become live.
"""
# Convert label names to IDs
# 1. assemble body from template (graceful: unformatted if template missing)
template = self._load_issue_template(kind)
text = body.strip()
if template and "<!-- SUBMITTED_BODY -->" in template:
text = template.replace("<!-- SUBMITTED_BODY -->", text, 1)
if version_intent in VERSION_INTENTS:
text = text.replace(f"- [ ] {version_intent} ", f"- [x] {version_intent} ", 1)
# 2. labels: umbrella names + mandatory kind label
labels = list(labels or [])
kind_label = KIND_LABEL.get(kind)
if kind_label and kind_label not in labels:
labels.append(kind_label)
all_labels = self._gitea_api("labels")
label_map = {l["name"]: l["id"] for l in all_labels} if isinstance(all_labels, list) else {}
label_ids = []
if labels:
all_labels = self._gitea_api("labels")
if isinstance(all_labels, list):
label_map = {l["name"]: l["id"] for l in all_labels}
label_ids = [label_map[l] for l in labels if l in label_map]
for l in labels:
if l in label_map:
label_ids.append(label_map[l])
else:
lid = self._ensure_label(l)
if lid:
label_ids.append(lid)
data = {
"title": title,
"body": body,
"body": text,
"labels": label_ids,
}
result = self._gitea_api("issues", method="POST", data=data)
+91
View File
@@ -0,0 +1,91 @@
---
name: Bug Fix
about: Demonstrate currently incorrect behaviour — plain English first, proof required
title: "[BUG] "
labels: bug
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 -->
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). -->
**WHAT (bug):**
**WHERE:**
**EVIDENCE:**
## Pipeline requirements
<!-- Every fix must clear these before the issue closes. -->
- [ ] TDD: regression test written first, red → green
- [ ] `ruff check` and `ruff format --check` clean
- [ ] Spec-compliance review gate: PASS
- [ ] Code-quality review gate: Approved
- [ ] Full orchestration suite regression green (suite total)
- [ ] Canary passes (name)
- [ ] Closed with a properly formatted closing comment + commit 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)
- [ ] **Trigger** — what event activates it
- [ ] **Read/write authority** — which canonical state it reads/changes
- [ ] **Provenance** — derived state traceable to evidence
- [ ] **Verification** — how we know the change helped
- [ ] **Failure visibility** — how failure surfaces
- [ ] **Reversibility** — bad learned state can be superseded/replayed/rolled back
- [ ] **Dormant cost** — what it costs when irrelevant
- [ ] **Benchmark + ablation** — what measurable behaviour improves; what happens when disabled
- [ ] **No duplicate authority** — why extend vs create
Hard invariants: derived cognition preserves evidentiary ancestry · epistemic confidence ≠ attentional utility ≠ current applicability · retrieval never increases utility · self-model-induced behaviour is not independent evidence · historical truth survives present-state change · raw evidence is never destroyed by promotion.
## Related umbrella
- [ ] Memory
- [ ] Governance
- [ ] Identity
- [ ] Growth
- [ ] Perception
- [ ] Infrastructure
- [ ] Orchestration
## Priority (REQUIRED — the priority gate)
<!-- Pick exactly one. An issue without a priority is not filed. -->
- [ ] **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
+97
View File
@@ -0,0 +1,97 @@
---
name: Feature Request
about: New feature or improvement — plain English first, verifiable close conditions, version intent
title: "[FEATURE] "
labels: feature
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. 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 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.
WHY — design-spec reference (S#) or reason.
FILES — affected components.
ACCEPTANCE — frozen-test file + test count + canary name.
DEPENDENCIES — parent epic + preceding stage/plan refs. -->
**WHAT:**
**WHY:**
**FILES:**
**ACCEPTANCE:**
**DEPENDENCIES:**
## Pipeline requirements
<!-- Every stage must clear these before the issue closes. -->
- [ ] TDD: frozen tests written first, red → green (N passed)
- [ ] `ruff check` and `ruff format --check` clean
- [ ] Spec-compliance review gate: PASS
- [ ] Code-quality review gate: Approved
- [ ] Full orchestration suite regression green (suite total)
- [ ] 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)
- [ ] **Trigger** — what event activates it
- [ ] **Read/write authority** — which canonical state it reads/changes
- [ ] **Provenance** — derived state traceable to evidence
- [ ] **Verification** — how we know the change helped
- [ ] **Failure visibility** — how failure surfaces
- [ ] **Reversibility** — bad learned state can be superseded/replayed/rolled back
- [ ] **Dormant cost** — what it costs when irrelevant
- [ ] **Benchmark + ablation** — what measurable behaviour improves; what happens when disabled
- [ ] **No duplicate authority** — why extend vs create
Hard invariants: derived cognition preserves evidentiary ancestry · epistemic confidence ≠ attentional utility ≠ current applicability · retrieval never increases utility · self-model-induced behaviour is not independent evidence · historical truth survives present-state change · 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** — 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
+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
+216
View File
@@ -0,0 +1,216 @@
"""Thin adapter for native (compiled) units — R1 §5 interop contract, Wave 0.
The contract under proof: compiled units are standalone binaries exposing a
CLI boundary — argv in, JSON on stdout, non-zero exit on failure, a mandatory
``--version`` flag. This module is the Python side: run a unit, enforce a
timeout, capture stderr, and return a TYPED result. It never raises for unit
failures (those are data in the result); it raises only for adapter misuse
(missing binary, bad timeout).
No IPC daemon, no PyO3 — the file-based store stays the shared truth. If
research later surfaces a materially better pattern it competes through the
research pipeline; the CLI boundary is the default, not a cage.
"""
from __future__ import annotations
import json
import subprocess
import threading
import time
from dataclasses import dataclass, field
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parent.parent
PROOF_UNIT = REPO_ROOT / "interop" / "rebase-proof" / "target" / "release" / "rebase-proof"
@dataclass
class NativeResult:
"""Typed result of one native-unit invocation.
ok — the invocation succeeded (exit 0 AND not timed out); when
the unit emitted JSON with an ``ok`` field, that field must
not be False (plain-text output like ``--version`` has none)
exit_code — raw process exit code
data — parsed JSON object from stdout, or None if unparseable
stderr — captured stderr text (may be non-empty even on success)
duration_ms — wall-clock cost of the invocation
timed_out — True when the unit exceeded the timeout and was killed
events — in streaming mode: every parsed JSON object line, in
arrival order (empty for non-streaming :func:`run_native`)
"""
ok: bool
exit_code: int
data: dict | None
stderr: str
duration_ms: int
timed_out: bool = False
raw_stdout: str = field(default="", repr=False)
events: list[dict] = field(default_factory=list)
def run_native(binary: Path, args: list[str], timeout_s: float = 10.0) -> NativeResult:
"""Invoke a native unit and return a typed result.
Raises FileNotFoundError only when *binary* itself is absent (adapter
misuse) — every unit-level failure is reported via the result, never an
exception, so callers can branch on ``result.ok`` without try/except.
"""
if not binary.is_file():
raise FileNotFoundError(f"native unit not built: {binary}")
started = time.monotonic()
timed_out = False
try:
proc = subprocess.run(
[str(binary), *args],
capture_output=True,
text=True,
timeout=timeout_s,
check=False, # exit codes are data, never exceptions
)
exit_code, stdout, stderr = proc.returncode, proc.stdout, proc.stderr
except subprocess.TimeoutExpired as exc:
timed_out = True
exit_code = -1
stdout = exc.stdout or "" if isinstance(exc.stdout, str) else (exc.stdout or b"").decode(errors="replace")
stderr = exc.stderr or "" if isinstance(exc.stderr, str) else (exc.stderr or b"").decode(errors="replace")
duration_ms = int((time.monotonic() - started) * 1000)
data: dict | None = None
stripped = stdout.strip()
if stripped:
try:
parsed = json.loads(stripped.splitlines()[-1])
if isinstance(parsed, dict):
data = parsed
except json.JSONDecodeError:
data = None
ok = (not timed_out) and exit_code == 0 and (data is None or data.get("ok") is not False)
return NativeResult(
ok=ok,
exit_code=exit_code,
data=data,
stderr=stderr,
duration_ms=duration_ms,
timed_out=timed_out,
raw_stdout=stdout,
)
def run_proof(args: list[str], timeout_s: float = 10.0) -> NativeResult:
"""Run the Wave 0 proof unit with the standard contract defaults."""
return run_native(PROOF_UNIT, args, timeout_s=timeout_s)
def stream_native(
binary: Path,
args: list[str],
timeout_s: float = 10.0,
on_event=None,
):
"""Run a native unit in JSONL streaming mode, yielding events as they arrive.
The JSONL streaming contract (rubric §W7): one JSON object per stdout
line — ``{"ok": true, "event": ...}`` progress objects along the way, and
a terminal envelope as the FINAL line. This generator yields each parsed
event dict the moment it arrives (so a long op surfaces partial progress
instead of blocking until exit), then yields exactly one terminal
:class:`NativeResult`. *on_event*, when given, is called with each parsed
event as it arrives (the TUI wraps this in ``call_from_thread``).
Stream-mode ok-semantics are stricter than :func:`run_native`: ``ok``
requires exit 0, no timeout, AND a valid terminal envelope (the final
stdout line parsed as a JSON object whose ``ok`` is not False). Malformed
interior lines are skipped and counted in ``malformed_lines``; malformed
FINAL line means no valid terminal envelope, so ``ok`` is False — partial
progress stays available in ``events``. That is the point of streaming.
Same failure discipline as :func:`run_native`: raises FileNotFoundError
when *binary* is absent; every unit-level failure (bad envelope, timeout,
non-zero exit) is data on the terminal result, never an exception.
"""
if on_event is not None and not callable(on_event):
raise TypeError("on_event must be callable")
if not binary.is_file():
raise FileNotFoundError(f"native unit not built: {binary}")
started = time.monotonic()
proc = subprocess.Popen(
[str(binary), *args],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
)
# stderr must drain concurrently — reading it after the stdout loop
# deadlocks when a unit floods stderr past the pipe buffer mid-stream.
stderr_parts: list[str] = []
stderr_drain = threading.Thread(
target=lambda: stderr_parts.append(proc.stderr.read()), daemon=True
)
stderr_drain.start()
killed = threading.Event()
# The watchdog's kill and the flag are one step so an adapter-side
# timeout is never mistaken for a unit dying by its own signal.
watchdog = threading.Timer(timeout_s, lambda: (killed.set(), proc.kill()))
watchdog.start()
events: list[dict] = []
malformed_lines = 0
# True only while the most recent non-empty stdout line parsed as a JSON
# object — a malformed final line invalidates the terminal envelope.
final_line_is_json = False
try:
for line in proc.stdout:
line = line.strip()
if not line:
continue
try:
parsed = json.loads(line)
except json.JSONDecodeError:
malformed_lines += 1
final_line_is_json = False
continue
if not isinstance(parsed, dict):
malformed_lines += 1
final_line_is_json = False
continue
events.append(parsed)
final_line_is_json = True
if on_event is not None:
on_event(parsed)
yield parsed
proc.wait()
finally:
watchdog.cancel()
stderr_drain.join(timeout=5.0)
timed_out = killed.is_set()
duration_ms = int((time.monotonic() - started) * 1000)
exit_code = proc.returncode if proc.returncode is not None else -1
if timed_out:
exit_code = -1 # adapter-side kill, never a unit's own exit
terminal = events[-1] if (events and final_line_is_json) else None
ok = (
not timed_out
and exit_code == 0
and terminal is not None
and terminal.get("ok") is not False
)
yield NativeResult(
ok=ok,
exit_code=exit_code,
data=terminal,
stderr=stderr_parts[0] if stderr_parts else "",
duration_ms=duration_ms,
timed_out=timed_out,
events=events,
)
+1 -1
View File
@@ -6,7 +6,7 @@ This is the main entry point for the Rune program.
import json
from pathlib import Path
__version__ = "0.87.0"
__version__ = "0.88.4"
# One build identity (handoff 2026-09-10 §4): the semantic version above is
# the repo-level truth (auto-bumped at merge); the DEPLOYED revision (exact
+61
View File
@@ -64,6 +64,7 @@ class BuilderCapsule:
memory_lines: list = field(default_factory=list)
lesson_lines: list = field(default_factory=list)
constraints: list = field(default_factory=list)
construction_lines: list = field(default_factory=list)
generated_at: str = ""
core_version: str = "rune-core/operator-path"
@@ -75,6 +76,7 @@ class BuilderCapsule:
"memory_lines": self.memory_lines[:MAX_MEMORY_LINES],
"lesson_lines": self.lesson_lines[:MAX_LESSON_LINES],
"constraints": self.constraints,
"construction_lines": self.construction_lines,
"generated_at": self.generated_at,
"core_version": self.core_version,
}
@@ -87,10 +89,14 @@ class BuilderCapsule:
and not d["lesson_lines"]
and not d["unknowns"]
and not d["constraints"]
and not d["construction_lines"]
and d["task_route"] in ("LOCAL_FIX", "STANDARD_CHANGE")
):
return "" # nothing useful — inject nothing (handoff §5)
lines = [f"### Rune Core preflight ({d['task_route']})"]
if d["construction_lines"]:
lines.append("**Active Scaffolding construction (read-only projection):**")
lines += [f"- {c}" for c in d["construction_lines"]]
if d["memory_lines"]:
lines.append("**Relevant Rune memory:**")
lines += [f"- {m}" for m in d["memory_lines"]]
@@ -107,6 +113,56 @@ class BuilderCapsule:
return "\n".join(lines)
def _construction_store() -> str:
"""The SAME construction store the operator path uses (env override
honoured; default derives from the repo root, never a bare relative
path). Kept identical to rune_operator._construction_store."""
import os as _os
env = _os.environ.get("RUNE_CONSTRUCTION_STORE")
if env:
return env
from pathlib import Path as _P
return str(_P(__file__).resolve().parent.parent.parent / "store" / "scaffold")
def _active_construction_lines() -> list:
"""Read-only projection of the ACTIVE Scaffolding construction into
builder-consumable lines. This is the MiMo edge of the shared
Construction Context (§15) — it surfaces canonical state; it is NOT a
second construction authority and never mutates. Degrade-safe: any
failure returns [] (the bridge must never block the builder)."""
try:
from .construction_interface import ConstructionInterface
env = ConstructionInterface(builder="mimo-bridge",
project_store=_construction_store(),
project_id="issue161-harness"
).construction_context()
st = env.get("state") or {}
if not st.get("active"):
return []
out = [f"contract {st.get('contract_id')} · phase {st.get('phase')}"
f" · status {st.get('status')}"
f" · mode {st.get('construction_mode')}"]
if st.get("project"):
out.append(f"project: {st['project']}")
if st.get("need"):
out.append(f"need: {st['need']}")
scope = st.get("scope") or []
if scope:
out.append("scope: " + ", ".join(str(x) for x in scope[:8]))
obl = st.get("obligations") or []
if obl:
out.append(f"outstanding obligations: {len(obl)}")
for o in obl[:3]:
txt = o.get("obligation") or o.get("kind") or o
out.append(f" - {str(txt)[:120]}")
if st.get("next_action"):
out.append(f"next action: {st['next_action']}")
return out
except Exception: # noqa: BLE001 — projection only; never block the builder
return []
def _default_selector():
"""The SAME MemorySelector the operator path uses (lazy, degrade-safe)."""
try:
@@ -166,6 +222,11 @@ def preflight(task_text: str, memory_selector=None) -> BuilderCapsule:
# design (handoff §9: raw SEED records are outcome telemetry, not lessons).
capsule.lesson_lines = _validated_lessons_for(task_text or "")
# Active Scaffolding construction state (read-only projection of the
# shared Construction Context). Empty when no contract is active, so
# the inject-nothing policy is preserved for ordinary turns.
capsule.construction_lines = _active_construction_lines()
return capsule
+1 -1
View File
@@ -231,7 +231,7 @@ def main() -> int:
)
check(
"Rune minor version advertises provisioning and restore verification",
'__version__ = "0.87.0"' in rune_version,
'__version__ = "0.88.4"' in rune_version,
failures,
)
# #169 policy update: auto-bump on merge is sanctioned (Nick directive:
+9 -2
View File
@@ -181,9 +181,16 @@ class ConstructionInterface:
if contract_id:
target = self.scaffold.contract(doc, contract_id)
else:
# most recent non-closed contract = the active construction
# Most recent ACTIVE contract = status open AND phase non-terminal.
# T22 repair: a contract whose phase is terminal (abandoned/closed
# — see scaffold.TERMINAL_PHASES) is NOT active construction, even
# if its status field was left "open". Without the phase test the
# projection reported stale abandoned contracts as the active
# construction (8 such records observed in the live store).
from .scaffold import TERMINAL_PHASES
open_contracts = [e for e in contracts
if e.get("status") == "open"]
if e.get("status") == "open"
and e.get("phase") not in TERMINAL_PHASES]
target = (sorted(open_contracts,
key=lambda e: e.get("observed_at", ""))[-1]
if open_contracts else None)
+63 -3
View File
@@ -805,13 +805,22 @@ class RuneOperator:
except Exception: # noqa: S110 — notes are best-effort by design
pass
def _construction_activation(self, description: str, task_id: str) -> None:
def _construction_activation(self, description: str, task_id: str,
channel: str = OPERATOR_CHANNEL) -> None:
"""SCAFFOLD-TRANCHE-0011/0012 §11: contextual construction
classification + activation on the NORMAL input path. Deterministic;
the mode lands in the durable scaffold store where the shared
Construction Context (and the future TUI) reads it. Delegates all
lifecycle decisions to construction_mode/construction_activation —
NO duplicate intelligence here."""
NO duplicate intelligence here.
§17J criterion 1 (T22 wiring): the canonical intent layer
(construction_intent) resolves MEANING before the ONE
classifier decides mode — the boundary the intent module
documents ("the intent layer resolves MEANING; classify_mode
decides mode"). A turn the intent layer resolves as
DISCUSSION is not a construction demand, so no construction
state is recorded for it."""
from .construction_mode import classify_mode, _STANDALONE_WORDS
from .construction_activation import activate
# §15J case F: manual override feeds the SAME decision path — a
@@ -849,6 +858,56 @@ class RuneOperator:
from .scaffold import Scaffold
s = Scaffold(self._construction_store(), "issue161-harness")
doc = s.load()
# §17J criterion 1: meaning gate BEFORE the classifier.
# Context = the operator's own canonical conversation window
# (no new state store); the current message is excluded so it
# is not double-recorded as its own referent.
try:
from .construction_intent import (
ConversationContext, resolve_construction_intent)
ctx = ConversationContext()
for _m in self.conversation_window(channel, n=8):
_txt = str(_m.get("content", ""))
if _txt and _txt != description:
ctx.record_turn(str(_m.get("role", "user")), _txt)
_intent = resolve_construction_intent(description, ctx)
except Exception as exc: # noqa: BLE001 — intent layer
# unavailable: PRESERVE the pre-existing behaviour exactly
# (classify+activate) rather than silently changing
# governance in an unproven direction. The note is appended to
# THIS doc (not via _construction_note, which does its own
# load/save) because the normal path saves `doc` afterwards —
# a separate write would be clobbered (lost update).
_intent = None
doc.setdefault("observations", []).append({
"kind": "construction_note",
"text": (f"intent layer unavailable ({exc}); "
f"classifier path unchanged")[:300],
"observed_at": __import__("datetime").datetime.utcnow()
.strftime("%Y-%m-%dT%H:%M:%SZ")})
# An explicit user override is USER AUTHORITY and outranks the
# meaning gate (§15J case F: the override is already carried with
# user provenance into the SAME classify_mode call).
if (override is None and _intent is not None
and _intent.action_intent == "DISCUSSION"):
# The intent layer resolved this turn as DISCUSSION: it is not a
# construction demand, so no construction state is created. The
# record keeps the SAME canonical observation kind/shape every
# other input produces (mode vocabulary unchanged — DISCUSSION
# maps to NOT_CONSTRUCTION, "no construction state"), with the
# intent evidence retained so the verdict is auditable.
doc.setdefault("observations", []).append({
"kind": "construction_activated",
"task": task_id,
"mode": "NOT_CONSTRUCTION",
"activated": False,
"lifecycle": "",
"classification_evidence": _intent.classification_evidence[:3],
"intent_layer": "DISCUSSION",
"observed_at": __import__("datetime").datetime.utcnow()
.strftime("%Y-%m-%dT%H:%M:%SZ")})
s.save(doc)
return
rec = activate(mode_decision, need=type("N", (), {
"objective": description,
"project": "rune",
@@ -929,7 +988,8 @@ class RuneOperator:
# failure NEVER blocks the ordinary task path (same lifecycle
# guarantee as the route above).
try:
self._construction_activation(description, state_task.task_id)
self._construction_activation(description, state_task.task_id,
channel=channel)
except Exception as exc: # noqa: BLE001 — construction must not break tasks
try:
self._task_state.transition(
+2 -2
View File
@@ -8,7 +8,7 @@ mode system, subject header, shared memory and identity.
This is not an interface. This is how I see, speak, and interact with the world.
Version: v0.87.0
Version: v0.88.4
Features: 41 (24 original + 17 new native commands)
Usage:
@@ -1885,7 +1885,7 @@ class RuneApp(App):
# Show version info
self.chat_channel.add_message(
"system",
f"[dim]Rune v0.87.0 | Textual TUI | {len(loaded)} native modules[/dim]",
f"[dim]Rune v0.88.4 | Textual TUI | {len(loaded)} native modules[/dim]",
)
# Auto-show night mode suggestion if evening/night hours
+5 -1
View File
@@ -57,7 +57,7 @@ from rune.structural_store import ( # shared generic core — no Rune constants
task_entities,
)
__all__ = ["Scaffold", "PHASES", "LEGAL_TRANSITIONS", "REPO_PLACEMENTS", "REPO_SECRET_FIELDS"]
__all__ = ["Scaffold", "PHASES", "LEGAL_TRANSITIONS", "TERMINAL_PHASES", "REPO_PLACEMENTS", "REPO_SECRET_FIELDS"]
# ── constants ─────────────────────────────────────────────────────────────
@@ -73,6 +73,10 @@ LEGAL_TRANSITIONS = {
"failed": {"building", "abandoned"}, # retry path
"abandoned": set(),
}
# Terminal phases are DERIVED from the canonical transition table: a
# phase with no legal successor ends the contract. One authority —
# consumers must not re-declare their own terminal list.
TERMINAL_PHASES = frozenset(p for p, nxt in LEGAL_TRANSITIONS.items() if not nxt)
STATUSES = {"open", "closed", "failed", "abandoned"}
REPO_PLACEMENTS = {"RUNE_REPO", "EXISTING_PROJECT_REPO", "NEW_MANAGED_REPO"}
REPO_SECRET_FIELDS = {"token", "api_key", "password", "secret", "auth_header", "credential", "api_token"}
+12
View File
@@ -7,3 +7,15 @@
{"action": "ContinuePendingOperation", "at": "2026-09-18T10:30:10Z", "authority": "ci_runs", "deadline_provenance": "GOVERNED_OPERATION_POLICY", "deadline_secs": 1800, "evidence": "commit_on_feature_branch", "model_deadline_ignored": true, "model_op_type_ignored": true, "normalized": true, "op_type": "branch_ci", "operation_id": "ci-427c3ac6bb3fd67492d3596a33919d1e5aa4a8d1"}
{"action": "ContinuePendingOperation", "at": "2026-09-18T10:30:40Z", "authority": "ci_runs", "deadline_provenance": "GOVERNED_OPERATION_POLICY", "deadline_secs": 1800, "evidence": "commit_on_feature_branch", "model_deadline_ignored": true, "model_op_type_ignored": false, "normalized": true, "op_type": "branch_ci", "operation_id": "ci-427c3ac6bb3fd67492d3596a33919d1e5aa4a8d1", "raw_command_kind": "sleep_poll", "raw_sleep_seconds_suppressed": 240}
{"at": "2026-09-18T20:23:58Z", "candidates": ["", "", "", "", "", "", "", "", "", "", "", "", "", "op-latency-proof", "dbg-op", "dbg3", "t15-BUILDER-2026-09-15T02:18:49Z-Verboo Code/glm-5.3-flash", "t15-resume-BUILDER-2026-09-15T02:18:49Z-Verboo Code/glm-5.3-flash", "t15-BUILDER-2026-09-15T03:11:05Z-Verboo Code/glm-5.3-flash", "t15-release-196cf19", "", "", "ci-c707a81933f7f90eaaae4000282674b6a2e3cb4c", "ci-4a06d9f11a722b7aa32fc38ab92b3ba8130414af", "ci-b51afea0cbfe00b5493647ed61d071fe104b306a", "", "ci-986b450bc22e969cbd2f09fdcfbc24e4337740ba", "ci-2a4f9c8367d06acbda4b39c1cee388796b25cc85", "ci-fe9d154778c117e8b0f1fbae4e5e7d9121546839", "ci-c9dee14c626b853cab625b431af3b23866b84314", "ci-c9dee14c626b853cab625b431af3b23866b84314", "ci-repro-test-sha", "", "", "", "", "", "", "", "", "", "", "ci-3c54782634993361bbab3c66f948fc59121865a5", "ci-3c54782634993361bbab3c66f948fc59121865a5", "", "", "", "ci-dcead3feccb57b6dfb30effd96fcac6b563f8099", "ci-ab2dfe7b09c154a329c5145da4d32639a83579b6", "ci-95946b6efd883e56797134617d42daed1acf798a", "ci-45869a77cdea1c2ce9e5c1f54c9840c3acef1487", "ci-98cb3a98a5f2e245cd0fd6003ffd02a238120ddc", "ci-98cb3a98a5f2e245cd0fd6003ffd02a238120ddc", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-5d20dc7f513b740a165952ca00f758660d328c43", "ci-0a470d86b80baefeb71c795626a901fac19bf731", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-40b3731928f499a77653613cb6c3e6db93cb64a1", "ci-be6bc17e93d8ffbc2679d913e55dd848dc8fa82e", "ci-be6bc17e93d8ffbc2679d913e55dd848dc8fa82e", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-6b5d8ad02308f24422b1efd7c0d343ebb5c7a19d", "ci-6b5d8ad02308f24422b1efd7c0d343ebb5c7a19d", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-00013f8c0b174011bcea12351facf7f1f382e8a3", "ci-756ebe6f45ad83a919738539a1565c17ed8572ac", "ci-df8262bd58122e33d4c447dc863e39ddde684963", "ci-4944f9e79d0a9c4df1d76a0d8c119e33e1f9a55", "ci-4944f9e79d0a9c4df1d76a0d8c119e33e1f9a55", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed8d5cf2ae99554eb02b95771082e449c8", "ci-7cf7c8d0a9c4aa7c6c1a7c2e0a2e7c3b4c5d6e7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7008743a1a7f8c1b9e4b0b8e4c4f4f4f4f4f4f4", "ci-70087436203f8e44181b94676a05418730b8de5d", "ci-70087436203f8e44181b94676a05418730b8de5d", "ci-26e37653e3f8c1b9e4b0b8e4c4f4f4f4f4f4f4f", "ci-26e3765319bc29064f7d42f092bc86dcc7b2ecc0", "ci-2b6a5a6b95629d3cf48fd171cbf6a2544f771817", "ci-2b6a5a6b95629d3cf48fd171cbf6a2544f771817", "ci-5db8b202d97e4721369aa507e2bea7b1cf66af5c", "ci-04a277f7668e99d56c1b7c05e2e40a1da93dca55", "ci-5718a3ea85c397434595e79b7a63700617c1de21", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-f714120", "ci-65001196d831a7f51b2bbc2b6bbcfe34c70442ff", "ci-65001196d831a7f51b2bbc2b6bbcfe34c70442ff", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-853cf3e0ae10ad3d45cd879527093368ccad8251", "ci-599c3ab1c23f7eaec323c67b3523fdb9e1acea74", "ci-599c3ab1c23f7eaec323c67b3523fdb9e1acea74", "ci-a54ab559cbd50e77ac55db4056951bd6655a0632", "ci-a54ab559cbd50e77ac55db4056951bd6655a0632", "ci-a54ab559cbd59bb9696d329c998cd58a221edd72", "ci-1c5dc557a69a368aad267d1871f4eda646a822fb", "ci-1c5dc557a69a368aad267d1871f4eda646a822fb", "ci-05f2a74c6fa086ddec55d146b780859df34d31a5", "ci-05f2a74c6fa086ddec55d146b780859df34d31a5", "ci-2e05ea6", "ci-d53bb9a", "ci-d53bb9a53Line truncated
{"at": "2026-09-19T04:42:44Z", "candidates": ["", "", "", "", "", "", "", "", "", "", "", "", "", "op-latency-proof", "dbg-op", "dbg3", "t15-BUILDER-2026-09-15T02:18:49Z-Verboo Code/glm-5.3-flash", "t15-resume-BUILDER-2026-09-15T02:18:49Z-Verboo Code/glm-5.3-flash", "t15-BUILDER-2026-09-15T03:11:05Z-Verboo Code/glm-5.3-flash", "t15-release-196cf19", "", "", "ci-c707a81933f7f90eaaae4000282674b6a2e3cb4c", "ci-4a06d9f11a722b7aa32fc38ab92b3ba8130414af", "ci-b51afea0cbfe00b5493647ed61d071fe104b306a", "", "ci-986b450bc22e969cbd2f09fdcfbc24e4337740ba", "ci-2a4f9c8367d06acbda4b39c1cee388796b25cc85", "ci-fe9d154778c117e8b0f1fbae4e5e7d9121546839", "ci-c9dee14c626b853cab625b431af3b23866b84314", "ci-c9dee14c626b853cab625b431af3b23866b84314", "ci-repro-test-sha", "", "", "", "", "", "", "", "", "", "", "ci-3c54782634993361bbab3c66f948fc59121865a5", "ci-3c54782634993361bbab3c66f948fc59121865a5", "", "", "", "ci-dcead3feccb57b6dfb30effd96fcac6b563f8099", "ci-ab2dfe7b09c154a329c5145da4d32639a83579b6", "ci-95946b6efd883e56797134617d42daed1acf798a", "ci-45869a77cdea1c2ce9e5c1f54c9840c3acef1487", "ci-98cb3a98a5f2e245cd0fd6003ffd02a238120ddc", "ci-98cb3a98a5f2e245cd0fd6003ffd02a238120ddc", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-5d20dc7f513b740a165952ca00f758660d328c43", "ci-0a470d86b80baefeb71c795626a901fac19bf731", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-40b3731928f499a77653613cb6c3e6db93cb64a1", "ci-be6bc17e93d8ffbc2679d913e55dd848dc8fa82e", "ci-be6bc17e93d8ffbc2679d913e55dd848dc8fa82e", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-6b5d8ad02308f24422b1efd7c0d343ebb5c7a19d", "ci-6b5d8ad02308f24422b1efd7c0d343ebb5c7a19d", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-00013f8c0b174011bcea12351facf7f1f382e8a3", "ci-756ebe6f45ad83a919738539a1565c17ed8572ac", "ci-df8262bd58122e33d4c447dc863e39ddde684963", "ci-4944f9e79d0a9c4df1d76a0d8c119e33e1f9a55", "ci-4944f9e79d0a9c4df1d76a0d8c119e33e1f9a55", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed8d5cf2ae99554eb02b95771082e449c8", "ci-7cf7c8d0a9c4aa7c6c1a7c2e0a2e7c3b4c5d6e7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7008743a1a7f8c1b9e4b0b8e4c4f4f4f4f4f4f4", "ci-70087436203f8e44181b94676a05418730b8de5d", "ci-70087436203f8e44181b94676a05418730b8de5d", "ci-26e37653e3f8c1b9e4b0b8e4c4f4f4f4f4f4f4f", "ci-26e3765319bc29064f7d42f092bc86dcc7b2ecc0", "ci-2b6a5a6b95629d3cf48fd171cbf6a2544f771817", "ci-2b6a5a6b95629d3cf48fd171cbf6a2544f771817", "ci-5db8b202d97e4721369aa507e2bea7b1cf66af5c", "ci-04a277f7668e99d56c1b7c05e2e40a1da93dca55", "ci-5718a3ea85c397434595e79b7a63700617c1de21", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-f714120", "ci-65001196d831a7f51b2bbc2b6bbcfe34c70442ff", "ci-65001196d831a7f51b2bbc2b6bbcfe34c70442ff", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-853cf3e0ae10ad3d45cd879527093368ccad8251", "ci-599c3ab1c23f7eaec323c67b3523fdb9e1acea74", "ci-599c3ab1c23f7eaec323c67b3523fdb9e1acea74", "ci-a54ab559cbd50e77ac55db4056951bd6655a0632", "ci-a54ab559cbd50e77ac55db4056951bd6655a0632", "ci-a54ab559cbd59bb9696d329c998cd58a221edd72", "ci-1c5dc557a69a368aad267d1871f4eda646a822fb", "ci-1c5dc557a69a368aad267d1871f4eda646a822fb", "ci-05f2a74c6fa086ddec55d146b780859df34d31a5", "ci-05f2a74c6fa086ddec55d146b780859df34d31a5", "ci-2e05ea6", "ci-d53bb9a", "ci-d53bb9a53Line truncated
{"at": "2026-09-19T04:44:06Z", "candidates": ["", "", "", "", "", "", "", "", "", "", "", "", "", "op-latency-proof", "dbg-op", "dbg3", "t15-BUILDER-2026-09-15T02:18:49Z-Verboo Code/glm-5.3-flash", "t15-resume-BUILDER-2026-09-15T02:18:49Z-Verboo Code/glm-5.3-flash", "t15-BUILDER-2026-09-15T03:11:05Z-Verboo Code/glm-5.3-flash", "t15-release-196cf19", "", "", "ci-c707a81933f7f90eaaae4000282674b6a2e3cb4c", "ci-4a06d9f11a722b7aa32fc38ab92b3ba8130414af", "ci-b51afea0cbfe00b5493647ed61d071fe104b306a", "", "ci-986b450bc22e969cbd2f09fdcfbc24e4337740ba", "ci-2a4f9c8367d06acbda4b39c1cee388796b25cc85", "ci-fe9d154778c117e8b0f1fbae4e5e7d9121546839", "ci-c9dee14c626b853cab625b431af3b23866b84314", "ci-c9dee14c626b853cab625b431af3b23866b84314", "ci-repro-test-sha", "", "", "", "", "", "", "", "", "", "", "ci-3c54782634993361bbab3c66f948fc59121865a5", "ci-3c54782634993361bbab3c66f948fc59121865a5", "", "", "", "ci-dcead3feccb57b6dfb30effd96fcac6b563f8099", "ci-ab2dfe7b09c154a329c5145da4d32639a83579b6", "ci-95946b6efd883e56797134617d42daed1acf798a", "ci-45869a77cdea1c2ce9e5c1f54c9840c3acef1487", "ci-98cb3a98a5f2e245cd0fd6003ffd02a238120ddc", "ci-98cb3a98a5f2e245cd0fd6003ffd02a238120ddc", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-5d20dc7f513b740a165952ca00f758660d328c43", "ci-0a470d86b80baefeb71c795626a901fac19bf731", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-40b3731928f499a77653613cb6c3e6db93cb64a1", "ci-be6bc17e93d8ffbc2679d913e55dd848dc8fa82e", "ci-be6bc17e93d8ffbc2679d913e55dd848dc8fa82e", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-6b5d8ad02308f24422b1efd7c0d343ebb5c7a19d", "ci-6b5d8ad02308f24422b1efd7c0d343ebb5c7a19d", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-00013f8c0b174011bcea12351facf7f1f382e8a3", "ci-756ebe6f45ad83a919738539a1565c17ed8572ac", "ci-df8262bd58122e33d4c447dc863e39ddde684963", "ci-4944f9e79d0a9c4df1d76a0d8c119e33e1f9a55", "ci-4944f9e79d0a9c4df1d76a0d8c119e33e1f9a55", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed8d5cf2ae99554eb02b95771082e449c8", "ci-7cf7c8d0a9c4aa7c6c1a7c2e0a2e7c3b4c5d6e7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7008743a1a7f8c1b9e4b0b8e4c4f4f4f4f4f4f4", "ci-70087436203f8e44181b94676a05418730b8de5d", "ci-70087436203f8e44181b94676a05418730b8de5d", "ci-26e37653e3f8c1b9e4b0b8e4c4f4f4f4f4f4f4f", "ci-26e3765319bc29064f7d42f092bc86dcc7b2ecc0", "ci-2b6a5a6b95629d3cf48fd171cbf6a2544f771817", "ci-2b6a5a6b95629d3cf48fd171cbf6a2544f771817", "ci-5db8b202d97e4721369aa507e2bea7b1cf66af5c", "ci-04a277f7668e99d56c1b7c05e2e40a1da93dca55", "ci-5718a3ea85c397434595e79b7a63700617c1de21", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-f714120", "ci-65001196d831a7f51b2bbc2b6bbcfe34c70442ff", "ci-65001196d831a7f51b2bbc2b6bbcfe34c70442ff", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-853cf3e0ae10ad3d45cd879527093368ccad8251", "ci-599c3ab1c23f7eaec323c67b3523fdb9e1acea74", "ci-599c3ab1c23f7eaec323c67b3523fdb9e1acea74", "ci-a54ab559cbd50e77ac55db4056951bd6655a0632", "ci-a54ab559cbd50e77ac55db4056951bd6655a0632", "ci-a54ab559cbd59bb9696d329c998cd58a221edd72", "ci-1c5dc557a69a368aad267d1871f4eda646a822fb", "ci-1c5dc557a69a368aad267d1871f4eda646a822fb", "ci-05f2a74c6fa086ddec55d146b780859df34d31a5", "ci-05f2a74c6fa086ddec55d146b780859df34d31a5", "ci-2e05ea6", "ci-d53bb9a", "ci-d53bb9a53Line truncated
{"at": "2026-09-19T04:46:33Z", "candidates": ["", "", "", "", "", "", "", "", "", "", "", "", "", "op-latency-proof", "dbg-op", "dbg3", "t15-BUILDER-2026-09-15T02:18:49Z-Verboo Code/glm-5.3-flash", "t15-resume-BUILDER-2026-09-15T02:18:49Z-Verboo Code/glm-5.3-flash", "t15-BUILDER-2026-09-15T03:11:05Z-Verboo Code/glm-5.3-flash", "t15-release-196cf19", "", "", "ci-c707a81933f7f90eaaae4000282674b6a2e3cb4c", "ci-4a06d9f11a722b7aa32fc38ab92b3ba8130414af", "ci-b51afea0cbfe00b5493647ed61d071fe104b306a", "", "ci-986b450bc22e969cbd2f09fdcfbc24e4337740ba", "ci-2a4f9c8367d06acbda4b39c1cee388796b25cc85", "ci-fe9d154778c117e8b0f1fbae4e5e7d9121546839", "ci-c9dee14c626b853cab625b431af3b23866b84314", "ci-c9dee14c626b853cab625b431af3b23866b84314", "ci-repro-test-sha", "", "", "", "", "", "", "", "", "", "", "ci-3c54782634993361bbab3c66f948fc59121865a5", "ci-3c54782634993361bbab3c66f948fc59121865a5", "", "", "", "ci-dcead3feccb57b6dfb30effd96fcac6b563f8099", "ci-ab2dfe7b09c154a329c5145da4d32639a83579b6", "ci-95946b6efd883e56797134617d42daed1acf798a", "ci-45869a77cdea1c2ce9e5c1f54c9840c3acef1487", "ci-98cb3a98a5f2e245cd0fd6003ffd02a238120ddc", "ci-98cb3a98a5f2e245cd0fd6003ffd02a238120ddc", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-5d20dc7f513b740a165952ca00f758660d328c43", "ci-0a470d86b80baefeb71c795626a901fac19bf731", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-40b3731928f499a77653613cb6c3e6db93cb64a1", "ci-be6bc17e93d8ffbc2679d913e55dd848dc8fa82e", "ci-be6bc17e93d8ffbc2679d913e55dd848dc8fa82e", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-6b5d8ad02308f24422b1efd7c0d343ebb5c7a19d", "ci-6b5d8ad02308f24422b1efd7c0d343ebb5c7a19d", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-00013f8c0b174011bcea12351facf7f1f382e8a3", "ci-756ebe6f45ad83a919738539a1565c17ed8572ac", "ci-df8262bd58122e33d4c447dc863e39ddde684963", "ci-4944f9e79d0a9c4df1d76a0d8c119e33e1f9a55", "ci-4944f9e79d0a9c4df1d76a0d8c119e33e1f9a55", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed8d5cf2ae99554eb02b95771082e449c8", "ci-7cf7c8d0a9c4aa7c6c1a7c2e0a2e7c3b4c5d6e7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7008743a1a7f8c1b9e4b0b8e4c4f4f4f4f4f4f4", "ci-70087436203f8e44181b94676a05418730b8de5d", "ci-70087436203f8e44181b94676a05418730b8de5d", "ci-26e37653e3f8c1b9e4b0b8e4c4f4f4f4f4f4f4f", "ci-26e3765319bc29064f7d42f092bc86dcc7b2ecc0", "ci-2b6a5a6b95629d3cf48fd171cbf6a2544f771817", "ci-2b6a5a6b95629d3cf48fd171cbf6a2544f771817", "ci-5db8b202d97e4721369aa507e2bea7b1cf66af5c", "ci-04a277f7668e99d56c1b7c05e2e40a1da93dca55", "ci-5718a3ea85c397434595e79b7a63700617c1de21", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-f714120", "ci-65001196d831a7f51b2bbc2b6bbcfe34c70442ff", "ci-65001196d831a7f51b2bbc2b6bbcfe34c70442ff", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-853cf3e0ae10ad3d45cd879527093368ccad8251", "ci-599c3ab1c23f7eaec323c67b3523fdb9e1acea74", "ci-599c3ab1c23f7eaec323c67b3523fdb9e1acea74", "ci-a54ab559cbd50e77ac55db4056951bd6655a0632", "ci-a54ab559cbd50e77ac55db4056951bd6655a0632", "ci-a54ab559cbd59bb9696d329c998cd58a221edd72", "ci-1c5dc557a69a368aad267d1871f4eda646a822fb", "ci-1c5dc557a69a368aad267d1871f4eda646a822fb", "ci-05f2a74c6fa086ddec55d146b780859df34d31a5", "ci-05f2a74c6fa086ddec55d146b780859df34d31a5", "ci-2e05ea6", "ci-d53bb9a", "ci-d53bb9a53Line truncated
{"at": "2026-09-19T04:49:08Z", "candidates": ["", "", "", "", "", "", "", "", "", "", "", "", "", "op-latency-proof", "dbg-op", "dbg3", "t15-BUILDER-2026-09-15T02:18:49Z-Verboo Code/glm-5.3-flash", "t15-resume-BUILDER-2026-09-15T02:18:49Z-Verboo Code/glm-5.3-flash", "t15-BUILDER-2026-09-15T03:11:05Z-Verboo Code/glm-5.3-flash", "t15-release-196cf19", "", "", "ci-c707a81933f7f90eaaae4000282674b6a2e3cb4c", "ci-4a06d9f11a722b7aa32fc38ab92b3ba8130414af", "ci-b51afea0cbfe00b5493647ed61d071fe104b306a", "", "ci-986b450bc22e969cbd2f09fdcfbc24e4337740ba", "ci-2a4f9c8367d06acbda4b39c1cee388796b25cc85", "ci-fe9d154778c117e8b0f1fbae4e5e7d9121546839", "ci-c9dee14c626b853cab625b431af3b23866b84314", "ci-c9dee14c626b853cab625b431af3b23866b84314", "ci-repro-test-sha", "", "", "", "", "", "", "", "", "", "", "ci-3c54782634993361bbab3c66f948fc59121865a5", "ci-3c54782634993361bbab3c66f948fc59121865a5", "", "", "", "ci-dcead3feccb57b6dfb30effd96fcac6b563f8099", "ci-ab2dfe7b09c154a329c5145da4d32639a83579b6", "ci-95946b6efd883e56797134617d42daed1acf798a", "ci-45869a77cdea1c2ce9e5c1f54c9840c3acef1487", "ci-98cb3a98a5f2e245cd0fd6003ffd02a238120ddc", "ci-98cb3a98a5f2e245cd0fd6003ffd02a238120ddc", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-5d20dc7f513b740a165952ca00f758660d328c43", "ci-0a470d86b80baefeb71c795626a901fac19bf731", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-40b3731928f499a77653613cb6c3e6db93cb64a1", "ci-be6bc17e93d8ffbc2679d913e55dd848dc8fa82e", "ci-be6bc17e93d8ffbc2679d913e55dd848dc8fa82e", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-6b5d8ad02308f24422b1efd7c0d343ebb5c7a19d", "ci-6b5d8ad02308f24422b1efd7c0d343ebb5c7a19d", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-00013f8c0b174011bcea12351facf7f1f382e8a3", "ci-756ebe6f45ad83a919738539a1565c17ed8572ac", "ci-df8262bd58122e33d4c447dc863e39ddde684963", "ci-4944f9e79d0a9c4df1d76a0d8c119e33e1f9a55", "ci-4944f9e79d0a9c4df1d76a0d8c119e33e1f9a55", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed8d5cf2ae99554eb02b95771082e449c8", "ci-7cf7c8d0a9c4aa7c6c1a7c2e0a2e7c3b4c5d6e7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7008743a1a7f8c1b9e4b0b8e4c4f4f4f4f4f4f4", "ci-70087436203f8e44181b94676a05418730b8de5d", "ci-70087436203f8e44181b94676a05418730b8de5d", "ci-26e37653e3f8c1b9e4b0b8e4c4f4f4f4f4f4f4f", "ci-26e3765319bc29064f7d42f092bc86dcc7b2ecc0", "ci-2b6a5a6b95629d3cf48fd171cbf6a2544f771817", "ci-2b6a5a6b95629d3cf48fd171cbf6a2544f771817", "ci-5db8b202d97e4721369aa507e2bea7b1cf66af5c", "ci-04a277f7668e99d56c1b7c05e2e40a1da93dca55", "ci-5718a3ea85c397434595e79b7a63700617c1de21", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-f714120", "ci-65001196d831a7f51b2bbc2b6bbcfe34c70442ff", "ci-65001196d831a7f51b2bbc2b6bbcfe34c70442ff", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-853cf3e0ae10ad3d45cd879527093368ccad8251", "ci-599c3ab1c23f7eaec323c67b3523fdb9e1acea74", "ci-599c3ab1c23f7eaec323c67b3523fdb9e1acea74", "ci-a54ab559cbd50e77ac55db4056951bd6655a0632", "ci-a54ab559cbd50e77ac55db4056951bd6655a0632", "ci-a54ab559cbd59bb9696d329c998cd58a221edd72", "ci-1c5dc557a69a368aad267d1871f4eda646a822fb", "ci-1c5dc557a69a368aad267d1871f4eda646a822fb", "ci-05f2a74c6fa086ddec55d146b780859df34d31a5", "ci-05f2a74c6fa086ddec55d146b780859df34d31a5", "ci-2e05ea6", "ci-d53bb9a", "ci-d53bb9a53Line truncated
{"at": "2026-09-19T04:52:18Z", "candidates": ["", "", "", "", "", "", "", "", "", "", "", "", "", "op-latency-proof", "dbg-op", "dbg3", "t15-BUILDER-2026-09-15T02:18:49Z-Verboo Code/glm-5.3-flash", "t15-resume-BUILDER-2026-09-15T02:18:49Z-Verboo Code/glm-5.3-flash", "t15-BUILDER-2026-09-15T03:11:05Z-Verboo Code/glm-5.3-flash", "t15-release-196cf19", "", "", "ci-c707a81933f7f90eaaae4000282674b6a2e3cb4c", "ci-4a06d9f11a722b7aa32fc38ab92b3ba8130414af", "ci-b51afea0cbfe00b5493647ed61d071fe104b306a", "", "ci-986b450bc22e969cbd2f09fdcfbc24e4337740ba", "ci-2a4f9c8367d06acbda4b39c1cee388796b25cc85", "ci-fe9d154778c117e8b0f1fbae4e5e7d9121546839", "ci-c9dee14c626b853cab625b431af3b23866b84314", "ci-c9dee14c626b853cab625b431af3b23866b84314", "ci-repro-test-sha", "", "", "", "", "", "", "", "", "", "", "ci-3c54782634993361bbab3c66f948fc59121865a5", "ci-3c54782634993361bbab3c66f948fc59121865a5", "", "", "", "ci-dcead3feccb57b6dfb30effd96fcac6b563f8099", "ci-ab2dfe7b09c154a329c5145da4d32639a83579b6", "ci-95946b6efd883e56797134617d42daed1acf798a", "ci-45869a77cdea1c2ce9e5c1f54c9840c3acef1487", "ci-98cb3a98a5f2e245cd0fd6003ffd02a238120ddc", "ci-98cb3a98a5f2e245cd0fd6003ffd02a238120ddc", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-5d20dc7f513b740a165952ca00f758660d328c43", "ci-0a470d86b80baefeb71c795626a901fac19bf731", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-40b3731928f499a77653613cb6c3e6db93cb64a1", "ci-be6bc17e93d8ffbc2679d913e55dd848dc8fa82e", "ci-be6bc17e93d8ffbc2679d913e55dd848dc8fa82e", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-6b5d8ad02308f24422b1efd7c0d343ebb5c7a19d", "ci-6b5d8ad02308f24422b1efd7c0d343ebb5c7a19d", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-00013f8c0b174011bcea12351facf7f1f382e8a3", "ci-756ebe6f45ad83a919738539a1565c17ed8572ac", "ci-df8262bd58122e33d4c447dc863e39ddde684963", "ci-4944f9e79d0a9c4df1d76a0d8c119e33e1f9a55", "ci-4944f9e79d0a9c4df1d76a0d8c119e33e1f9a55", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed8d5cf2ae99554eb02b95771082e449c8", "ci-7cf7c8d0a9c4aa7c6c1a7c2e0a2e7c3b4c5d6e7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7008743a1a7f8c1b9e4b0b8e4c4f4f4f4f4f4f4", "ci-70087436203f8e44181b94676a05418730b8de5d", "ci-70087436203f8e44181b94676a05418730b8de5d", "ci-26e37653e3f8c1b9e4b0b8e4c4f4f4f4f4f4f4f", "ci-26e3765319bc29064f7d42f092bc86dcc7b2ecc0", "ci-2b6a5a6b95629d3cf48fd171cbf6a2544f771817", "ci-2b6a5a6b95629d3cf48fd171cbf6a2544f771817", "ci-5db8b202d97e4721369aa507e2bea7b1cf66af5c", "ci-04a277f7668e99d56c1b7c05e2e40a1da93dca55", "ci-5718a3ea85c397434595e79b7a63700617c1de21", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-f714120", "ci-65001196d831a7f51b2bbc2b6bbcfe34c70442ff", "ci-65001196d831a7f51b2bbc2b6bbcfe34c70442ff", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-853cf3e0ae10ad3d45cd879527093368ccad8251", "ci-599c3ab1c23f7eaec323c67b3523fdb9e1acea74", "ci-599c3ab1c23f7eaec323c67b3523fdb9e1acea74", "ci-a54ab559cbd50e77ac55db4056951bd6655a0632", "ci-a54ab559cbd50e77ac55db4056951bd6655a0632", "ci-a54ab559cbd59bb9696d329c998cd58a221edd72", "ci-1c5dc557a69a368aad267d1871f4eda646a822fb", "ci-1c5dc557a69a368aad267d1871f4eda646a822fb", "ci-05f2a74c6fa086ddec55d146b780859df34d31a5", "ci-05f2a74c6fa086ddec55d146b780859df34d31a5", "ci-2e05ea6", "ci-d53bb9a", "ci-d53bb9a53Line truncated
{"at": "2026-09-19T04:54:51Z", "candidates": ["", "", "", "", "", "", "", "", "", "", "", "", "", "op-latency-proof", "dbg-op", "dbg3", "t15-BUILDER-2026-09-15T02:18:49Z-Verboo Code/glm-5.3-flash", "t15-resume-BUILDER-2026-09-15T02:18:49Z-Verboo Code/glm-5.3-flash", "t15-BUILDER-2026-09-15T03:11:05Z-Verboo Code/glm-5.3-flash", "t15-release-196cf19", "", "", "ci-c707a81933f7f90eaaae4000282674b6a2e3cb4c", "ci-4a06d9f11a722b7aa32fc38ab92b3ba8130414af", "ci-b51afea0cbfe00b5493647ed61d071fe104b306a", "", "ci-986b450bc22e969cbd2f09fdcfbc24e4337740ba", "ci-2a4f9c8367d06acbda4b39c1cee388796b25cc85", "ci-fe9d154778c117e8b0f1fbae4e5e7d9121546839", "ci-c9dee14c626b853cab625b431af3b23866b84314", "ci-c9dee14c626b853cab625b431af3b23866b84314", "ci-repro-test-sha", "", "", "", "", "", "", "", "", "", "", "ci-3c54782634993361bbab3c66f948fc59121865a5", "ci-3c54782634993361bbab3c66f948fc59121865a5", "", "", "", "ci-dcead3feccb57b6dfb30effd96fcac6b563f8099", "ci-ab2dfe7b09c154a329c5145da4d32639a83579b6", "ci-95946b6efd883e56797134617d42daed1acf798a", "ci-45869a77cdea1c2ce9e5c1f54c9840c3acef1487", "ci-98cb3a98a5f2e245cd0fd6003ffd02a238120ddc", "ci-98cb3a98a5f2e245cd0fd6003ffd02a238120ddc", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-5d20dc7f513b740a165952ca00f758660d328c43", "ci-0a470d86b80baefeb71c795626a901fac19bf731", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-40b3731928f499a77653613cb6c3e6db93cb64a1", "ci-be6bc17e93d8ffbc2679d913e55dd848dc8fa82e", "ci-be6bc17e93d8ffbc2679d913e55dd848dc8fa82e", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-6b5d8ad02308f24422b1efd7c0d343ebb5c7a19d", "ci-6b5d8ad02308f24422b1efd7c0d343ebb5c7a19d", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-00013f8c0b174011bcea12351facf7f1f382e8a3", "ci-756ebe6f45ad83a919738539a1565c17ed8572ac", "ci-df8262bd58122e33d4c447dc863e39ddde684963", "ci-4944f9e79d0a9c4df1d76a0d8c119e33e1f9a55", "ci-4944f9e79d0a9c4df1d76a0d8c119e33e1f9a55", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed8d5cf2ae99554eb02b95771082e449c8", "ci-7cf7c8d0a9c4aa7c6c1a7c2e0a2e7c3b4c5d6e7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7008743a1a7f8c1b9e4b0b8e4c4f4f4f4f4f4f4", "ci-70087436203f8e44181b94676a05418730b8de5d", "ci-70087436203f8e44181b94676a05418730b8de5d", "ci-26e37653e3f8c1b9e4b0b8e4c4f4f4f4f4f4f4f", "ci-26e3765319bc29064f7d42f092bc86dcc7b2ecc0", "ci-2b6a5a6b95629d3cf48fd171cbf6a2544f771817", "ci-2b6a5a6b95629d3cf48fd171cbf6a2544f771817", "ci-5db8b202d97e4721369aa507e2bea7b1cf66af5c", "ci-04a277f7668e99d56c1b7c05e2e40a1da93dca55", "ci-5718a3ea85c397434595e79b7a63700617c1de21", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-f714120", "ci-65001196d831a7f51b2bbc2b6bbcfe34c70442ff", "ci-65001196d831a7f51b2bbc2b6bbcfe34c70442ff", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-853cf3e0ae10ad3d45cd879527093368ccad8251", "ci-599c3ab1c23f7eaec323c67b3523fdb9e1acea74", "ci-599c3ab1c23f7eaec323c67b3523fdb9e1acea74", "ci-a54ab559cbd50e77ac55db4056951bd6655a0632", "ci-a54ab559cbd50e77ac55db4056951bd6655a0632", "ci-a54ab559cbd59bb9696d329c998cd58a221edd72", "ci-1c5dc557a69a368aad267d1871f4eda646a822fb", "ci-1c5dc557a69a368aad267d1871f4eda646a822fb", "ci-05f2a74c6fa086ddec55d146b780859df34d31a5", "ci-05f2a74c6fa086ddec55d146b780859df34d31a5", "ci-2e05ea6", "ci-d53bb9a", "ci-d53bb9a53Line truncated
{"at": "2026-09-19T04:57:26Z", "candidates": ["", "", "", "", "", "", "", "", "", "", "", "", "", "op-latency-proof", "dbg-op", "dbg3", "t15-BUILDER-2026-09-15T02:18:49Z-Verboo Code/glm-5.3-flash", "t15-resume-BUILDER-2026-09-15T02:18:49Z-Verboo Code/glm-5.3-flash", "t15-BUILDER-2026-09-15T03:11:05Z-Verboo Code/glm-5.3-flash", "t15-release-196cf19", "", "", "ci-c707a81933f7f90eaaae4000282674b6a2e3cb4c", "ci-4a06d9f11a722b7aa32fc38ab92b3ba8130414af", "ci-b51afea0cbfe00b5493647ed61d071fe104b306a", "", "ci-986b450bc22e969cbd2f09fdcfbc24e4337740ba", "ci-2a4f9c8367d06acbda4b39c1cee388796b25cc85", "ci-fe9d154778c117e8b0f1fbae4e5e7d9121546839", "ci-c9dee14c626b853cab625b431af3b23866b84314", "ci-c9dee14c626b853cab625b431af3b23866b84314", "ci-repro-test-sha", "", "", "", "", "", "", "", "", "", "", "ci-3c54782634993361bbab3c66f948fc59121865a5", "ci-3c54782634993361bbab3c66f948fc59121865a5", "", "", "", "ci-dcead3feccb57b6dfb30effd96fcac6b563f8099", "ci-ab2dfe7b09c154a329c5145da4d32639a83579b6", "ci-95946b6efd883e56797134617d42daed1acf798a", "ci-45869a77cdea1c2ce9e5c1f54c9840c3acef1487", "ci-98cb3a98a5f2e245cd0fd6003ffd02a238120ddc", "ci-98cb3a98a5f2e245cd0fd6003ffd02a238120ddc", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-5d20dc7f513b740a165952ca00f758660d328c43", "ci-0a470d86b80baefeb71c795626a901fac19bf731", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-40b3731928f499a77653613cb6c3e6db93cb64a1", "ci-be6bc17e93d8ffbc2679d913e55dd848dc8fa82e", "ci-be6bc17e93d8ffbc2679d913e55dd848dc8fa82e", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-6b5d8ad02308f24422b1efd7c0d343ebb5c7a19d", "ci-6b5d8ad02308f24422b1efd7c0d343ebb5c7a19d", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-00013f8c0b174011bcea12351facf7f1f382e8a3", "ci-756ebe6f45ad83a919738539a1565c17ed8572ac", "ci-df8262bd58122e33d4c447dc863e39ddde684963", "ci-4944f9e79d0a9c4df1d76a0d8c119e33e1f9a55", "ci-4944f9e79d0a9c4df1d76a0d8c119e33e1f9a55", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed8d5cf2ae99554eb02b95771082e449c8", "ci-7cf7c8d0a9c4aa7c6c1a7c2e0a2e7c3b4c5d6e7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7008743a1a7f8c1b9e4b0b8e4c4f4f4f4f4f4f4", "ci-70087436203f8e44181b94676a05418730b8de5d", "ci-70087436203f8e44181b94676a05418730b8de5d", "ci-26e37653e3f8c1b9e4b0b8e4c4f4f4f4f4f4f4f", "ci-26e3765319bc29064f7d42f092bc86dcc7b2ecc0", "ci-2b6a5a6b95629d3cf48fd171cbf6a2544f771817", "ci-2b6a5a6b95629d3cf48fd171cbf6a2544f771817", "ci-5db8b202d97e4721369aa507e2bea7b1cf66af5c", "ci-04a277f7668e99d56c1b7c05e2e40a1da93dca55", "ci-5718a3ea85c397434595e79b7a63700617c1de21", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-f714120", "ci-65001196d831a7f51b2bbc2b6bbcfe34c70442ff", "ci-65001196d831a7f51b2bbc2b6bbcfe34c70442ff", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-853cf3e0ae10ad3d45cd879527093368ccad8251", "ci-599c3ab1c23f7eaec323c67b3523fdb9e1acea74", "ci-599c3ab1c23f7eaec323c67b3523fdb9e1acea74", "ci-a54ab559cbd50e77ac55db4056951bd6655a0632", "ci-a54ab559cbd50e77ac55db4056951bd6655a0632", "ci-a54ab559cbd59bb9696d329c998cd58a221edd72", "ci-1c5dc557a69a368aad267d1871f4eda646a822fb", "ci-1c5dc557a69a368aad267d1871f4eda646a822fb", "ci-05f2a74c6fa086ddec55d146b780859df34d31a5", "ci-05f2a74c6fa086ddec55d146b780859df34d31a5", "ci-2e05ea6", "ci-d53bb9a", "ci-d53bb9a53Line truncated
{"at": "2026-09-19T04:59:46Z", "candidates": ["", "", "", "", "", "", "", "", "", "", "", "", "", "op-latency-proof", "dbg-op", "dbg3", "t15-BUILDER-2026-09-15T02:18:49Z-Verboo Code/glm-5.3-flash", "t15-resume-BUILDER-2026-09-15T02:18:49Z-Verboo Code/glm-5.3-flash", "t15-BUILDER-2026-09-15T03:11:05Z-Verboo Code/glm-5.3-flash", "t15-release-196cf19", "", "", "ci-c707a81933f7f90eaaae4000282674b6a2e3cb4c", "ci-4a06d9f11a722b7aa32fc38ab92b3ba8130414af", "ci-b51afea0cbfe00b5493647ed61d071fe104b306a", "", "ci-986b450bc22e969cbd2f09fdcfbc24e4337740ba", "ci-2a4f9c8367d06acbda4b39c1cee388796b25cc85", "ci-fe9d154778c117e8b0f1fbae4e5e7d9121546839", "ci-c9dee14c626b853cab625b431af3b23866b84314", "ci-c9dee14c626b853cab625b431af3b23866b84314", "ci-repro-test-sha", "", "", "", "", "", "", "", "", "", "", "ci-3c54782634993361bbab3c66f948fc59121865a5", "ci-3c54782634993361bbab3c66f948fc59121865a5", "", "", "", "ci-dcead3feccb57b6dfb30effd96fcac6b563f8099", "ci-ab2dfe7b09c154a329c5145da4d32639a83579b6", "ci-95946b6efd883e56797134617d42daed1acf798a", "ci-45869a77cdea1c2ce9e5c1f54c9840c3acef1487", "ci-98cb3a98a5f2e245cd0fd6003ffd02a238120ddc", "ci-98cb3a98a5f2e245cd0fd6003ffd02a238120ddc", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-5d20dc7f513b740a165952ca00f758660d328c43", "ci-0a470d86b80baefeb71c795626a901fac19bf731", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-40b3731928f499a77653613cb6c3e6db93cb64a1", "ci-be6bc17e93d8ffbc2679d913e55dd848dc8fa82e", "ci-be6bc17e93d8ffbc2679d913e55dd848dc8fa82e", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-6b5d8ad02308f24422b1efd7c0d343ebb5c7a19d", "ci-6b5d8ad02308f24422b1efd7c0d343ebb5c7a19d", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-00013f8c0b174011bcea12351facf7f1f382e8a3", "ci-756ebe6f45ad83a919738539a1565c17ed8572ac", "ci-df8262bd58122e33d4c447dc863e39ddde684963", "ci-4944f9e79d0a9c4df1d76a0d8c119e33e1f9a55", "ci-4944f9e79d0a9c4df1d76a0d8c119e33e1f9a55", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed8d5cf2ae99554eb02b95771082e449c8", "ci-7cf7c8d0a9c4aa7c6c1a7c2e0a2e7c3b4c5d6e7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7008743a1a7f8c1b9e4b0b8e4c4f4f4f4f4f4f4", "ci-70087436203f8e44181b94676a05418730b8de5d", "ci-70087436203f8e44181b94676a05418730b8de5d", "ci-26e37653e3f8c1b9e4b0b8e4c4f4f4f4f4f4f4f", "ci-26e3765319bc29064f7d42f092bc86dcc7b2ecc0", "ci-2b6a5a6b95629d3cf48fd171cbf6a2544f771817", "ci-2b6a5a6b95629d3cf48fd171cbf6a2544f771817", "ci-5db8b202d97e4721369aa507e2bea7b1cf66af5c", "ci-04a277f7668e99d56c1b7c05e2e40a1da93dca55", "ci-5718a3ea85c397434595e79b7a63700617c1de21", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-f714120", "ci-65001196d831a7f51b2bbc2b6bbcfe34c70442ff", "ci-65001196d831a7f51b2bbc2b6bbcfe34c70442ff", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-853cf3e0ae10ad3d45cd879527093368ccad8251", "ci-599c3ab1c23f7eaec323c67b3523fdb9e1acea74", "ci-599c3ab1c23f7eaec323c67b3523fdb9e1acea74", "ci-a54ab559cbd50e77ac55db4056951bd6655a0632", "ci-a54ab559cbd50e77ac55db4056951bd6655a0632", "ci-a54ab559cbd59bb9696d329c998cd58a221edd72", "ci-1c5dc557a69a368aad267d1871f4eda646a822fb", "ci-1c5dc557a69a368aad267d1871f4eda646a822fb", "ci-05f2a74c6fa086ddec55d146b780859df34d31a5", "ci-05f2a74c6fa086ddec55d146b780859df34d31a5", "ci-2e05ea6", "ci-d53bb9a", "ci-d53bb9a53Line truncated
{"at": "2026-09-19T05:02:08Z", "candidates": ["", "", "", "", "", "", "", "", "", "", "", "", "", "op-latency-proof", "dbg-op", "dbg3", "t15-BUILDER-2026-09-15T02:18:49Z-Verboo Code/glm-5.3-flash", "t15-resume-BUILDER-2026-09-15T02:18:49Z-Verboo Code/glm-5.3-flash", "t15-BUILDER-2026-09-15T03:11:05Z-Verboo Code/glm-5.3-flash", "t15-release-196cf19", "", "", "ci-c707a81933f7f90eaaae4000282674b6a2e3cb4c", "ci-4a06d9f11a722b7aa32fc38ab92b3ba8130414af", "ci-b51afea0cbfe00b5493647ed61d071fe104b306a", "", "ci-986b450bc22e969cbd2f09fdcfbc24e4337740ba", "ci-2a4f9c8367d06acbda4b39c1cee388796b25cc85", "ci-fe9d154778c117e8b0f1fbae4e5e7d9121546839", "ci-c9dee14c626b853cab625b431af3b23866b84314", "ci-c9dee14c626b853cab625b431af3b23866b84314", "ci-repro-test-sha", "", "", "", "", "", "", "", "", "", "", "ci-3c54782634993361bbab3c66f948fc59121865a5", "ci-3c54782634993361bbab3c66f948fc59121865a5", "", "", "", "ci-dcead3feccb57b6dfb30effd96fcac6b563f8099", "ci-ab2dfe7b09c154a329c5145da4d32639a83579b6", "ci-95946b6efd883e56797134617d42daed1acf798a", "ci-45869a77cdea1c2ce9e5c1f54c9840c3acef1487", "ci-98cb3a98a5f2e245cd0fd6003ffd02a238120ddc", "ci-98cb3a98a5f2e245cd0fd6003ffd02a238120ddc", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-5d20dc7f513b740a165952ca00f758660d328c43", "ci-0a470d86b80baefeb71c795626a901fac19bf731", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-40b3731928f499a77653613cb6c3e6db93cb64a1", "ci-be6bc17e93d8ffbc2679d913e55dd848dc8fa82e", "ci-be6bc17e93d8ffbc2679d913e55dd848dc8fa82e", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-6b5d8ad02308f24422b1efd7c0d343ebb5c7a19d", "ci-6b5d8ad02308f24422b1efd7c0d343ebb5c7a19d", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-00013f8c0b174011bcea12351facf7f1f382e8a3", "ci-756ebe6f45ad83a919738539a1565c17ed8572ac", "ci-df8262bd58122e33d4c447dc863e39ddde684963", "ci-4944f9e79d0a9c4df1d76a0d8c119e33e1f9a55", "ci-4944f9e79d0a9c4df1d76a0d8c119e33e1f9a55", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed8d5cf2ae99554eb02b95771082e449c8", "ci-7cf7c8d0a9c4aa7c6c1a7c2e0a2e7c3b4c5d6e7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7008743a1a7f8c1b9e4b0b8e4c4f4f4f4f4f4f4", "ci-70087436203f8e44181b94676a05418730b8de5d", "ci-70087436203f8e44181b94676a05418730b8de5d", "ci-26e37653e3f8c1b9e4b0b8e4c4f4f4f4f4f4f4f", "ci-26e3765319bc29064f7d42f092bc86dcc7b2ecc0", "ci-2b6a5a6b95629d3cf48fd171cbf6a2544f771817", "ci-2b6a5a6b95629d3cf48fd171cbf6a2544f771817", "ci-5db8b202d97e4721369aa507e2bea7b1cf66af5c", "ci-04a277f7668e99d56c1b7c05e2e40a1da93dca55", "ci-5718a3ea85c397434595e79b7a63700617c1de21", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-f714120", "ci-65001196d831a7f51b2bbc2b6bbcfe34c70442ff", "ci-65001196d831a7f51b2bbc2b6bbcfe34c70442ff", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-853cf3e0ae10ad3d45cd879527093368ccad8251", "ci-599c3ab1c23f7eaec323c67b3523fdb9e1acea74", "ci-599c3ab1c23f7eaec323c67b3523fdb9e1acea74", "ci-a54ab559cbd50e77ac55db4056951bd6655a0632", "ci-a54ab559cbd50e77ac55db4056951bd6655a0632", "ci-a54ab559cbd59bb9696d329c998cd58a221edd72", "ci-1c5dc557a69a368aad267d1871f4eda646a822fb", "ci-1c5dc557a69a368aad267d1871f4eda646a822fb", "ci-05f2a74c6fa086ddec55d146b780859df34d31a5", "ci-05f2a74c6fa086ddec55d146b780859df34d31a5", "ci-2e05ea6", "ci-d53bb9a", "ci-d53bb9a53Line truncated
{"action": "ContinuePendingOperation", "at": "2026-09-19T05:16:37Z", "authority": "ci_runs", "deadline_provenance": "GOVERNED_OPERATION_POLICY", "deadline_secs": 1800, "evidence": "explicit_id_fresh_registration", "model_deadline_ignored": false, "model_op_type_ignored": false, "normalized": true, "op_type": "branch_ci", "operation_id": "ci-c6c18ae041ddac41e714af14ca0ce8c2e918078c"}
{"at": "2026-09-19T05:18:31Z", "candidates": ["", "", "", "", "", "", "", "", "", "", "", "", "", "op-latency-proof", "dbg-op", "dbg3", "t15-BUILDER-2026-09-15T02:18:49Z-Verboo Code/glm-5.3-flash", "t15-resume-BUILDER-2026-09-15T02:18:49Z-Verboo Code/glm-5.3-flash", "t15-BUILDER-2026-09-15T03:11:05Z-Verboo Code/glm-5.3-flash", "t15-release-196cf19", "", "", "ci-c707a81933f7f90eaaae4000282674b6a2e3cb4c", "ci-4a06d9f11a722b7aa32fc38ab92b3ba8130414af", "ci-b51afea0cbfe00b5493647ed61d071fe104b306a", "", "ci-986b450bc22e969cbd2f09fdcfbc24e4337740ba", "ci-2a4f9c8367d06acbda4b39c1cee388796b25cc85", "ci-fe9d154778c117e8b0f1fbae4e5e7d9121546839", "ci-c9dee14c626b853cab625b431af3b23866b84314", "ci-c9dee14c626b853cab625b431af3b23866b84314", "ci-repro-test-sha", "", "", "", "", "", "", "", "", "", "", "ci-3c54782634993361bbab3c66f948fc59121865a5", "ci-3c54782634993361bbab3c66f948fc59121865a5", "", "", "", "ci-dcead3feccb57b6dfb30effd96fcac6b563f8099", "ci-ab2dfe7b09c154a329c5145da4d32639a83579b6", "ci-95946b6efd883e56797134617d42daed1acf798a", "ci-45869a77cdea1c2ce9e5c1f54c9840c3acef1487", "ci-98cb3a98a5f2e245cd0fd6003ffd02a238120ddc", "ci-98cb3a98a5f2e245cd0fd6003ffd02a238120ddc", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-5d20dc7f513b740a165952ca00f758660d328c43", "ci-0a470d86b80baefeb71c795626a901fac19bf731", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-40b3731928f499a77653613cb6c3e6db93cb64a1", "ci-be6bc17e93d8ffbc2679d913e55dd848dc8fa82e", "ci-be6bc17e93d8ffbc2679d913e55dd848dc8fa82e", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-6b5d8ad02308f24422b1efd7c0d343ebb5c7a19d", "ci-6b5d8ad02308f24422b1efd7c0d343ebb5c7a19d", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-00013f8c0b174011bcea12351facf7f1f382e8a3", "ci-756ebe6f45ad83a919738539a1565c17ed8572ac", "ci-df8262bd58122e33d4c447dc863e39ddde684963", "ci-4944f9e79d0a9c4df1d76a0d8c119e33e1f9a55", "ci-4944f9e79d0a9c4df1d76a0d8c119e33e1f9a55", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed8d5cf2ae99554eb02b95771082e449c8", "ci-7cf7c8d0a9c4aa7c6c1a7c2e0a2e7c3b4c5d6e7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7008743a1a7f8c1b9e4b0b8e4c4f4f4f4f4f4f4", "ci-70087436203f8e44181b94676a05418730b8de5d", "ci-70087436203f8e44181b94676a05418730b8de5d", "ci-26e37653e3f8c1b9e4b0b8e4c4f4f4f4f4f4f4f", "ci-26e3765319bc29064f7d42f092bc86dcc7b2ecc0", "ci-2b6a5a6b95629d3cf48fd171cbf6a2544f771817", "ci-2b6a5a6b95629d3cf48fd171cbf6a2544f771817", "ci-5db8b202d97e4721369aa507e2bea7b1cf66af5c", "ci-04a277f7668e99d56c1b7c05e2e40a1da93dca55", "ci-5718a3ea85c397434595e79b7a63700617c1de21", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-f714120", "ci-65001196d831a7f51b2bbc2b6bbcfe34c70442ff", "ci-65001196d831a7f51b2bbc2b6bbcfe34c70442ff", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-853cf3e0ae10ad3d45cd879527093368ccad8251", "ci-599c3ab1c23f7eaec323c67b3523fdb9e1acea74", "ci-599c3ab1c23f7eaec323c67b3523fdb9e1acea74", "ci-a54ab559cbd50e77ac55db4056951bd6655a0632", "ci-a54ab559cbd50e77ac55db4056951bd6655a0632", "ci-a54ab559cbd59bb9696d329c998cd58a221edd72", "ci-1c5dc557a69a368aad267d1871f4eda646a822fb", "ci-1c5dc557a69a368aad267d1871f4eda646a822fb", "ci-05f2a74c6fa086ddec55d146b780859df34d31a5", "ci-05f2a74c6fa086ddec55d146b780859df34d31a5", "ci-2e05ea6", "ci-d53bb9a", "ci-d53bb9a53Line truncated
{"at": "2026-09-19T05:20:46Z", "candidates": ["", "", "", "", "", "", "", "", "", "", "", "", "", "op-latency-proof", "dbg-op", "dbg3", "t15-BUILDER-2026-09-15T02:18:49Z-Verboo Code/glm-5.3-flash", "t15-resume-BUILDER-2026-09-15T02:18:49Z-Verboo Code/glm-5.3-flash", "t15-BUILDER-2026-09-15T03:11:05Z-Verboo Code/glm-5.3-flash", "t15-release-196cf19", "", "", "ci-c707a81933f7f90eaaae4000282674b6a2e3cb4c", "ci-4a06d9f11a722b7aa32fc38ab92b3ba8130414af", "ci-b51afea0cbfe00b5493647ed61d071fe104b306a", "", "ci-986b450bc22e969cbd2f09fdcfbc24e4337740ba", "ci-2a4f9c8367d06acbda4b39c1cee388796b25cc85", "ci-fe9d154778c117e8b0f1fbae4e5e7d9121546839", "ci-c9dee14c626b853cab625b431af3b23866b84314", "ci-c9dee14c626b853cab625b431af3b23866b84314", "ci-repro-test-sha", "", "", "", "", "", "", "", "", "", "", "ci-3c54782634993361bbab3c66f948fc59121865a5", "ci-3c54782634993361bbab3c66f948fc59121865a5", "", "", "", "ci-dcead3feccb57b6dfb30effd96fcac6b563f8099", "ci-ab2dfe7b09c154a329c5145da4d32639a83579b6", "ci-95946b6efd883e56797134617d42daed1acf798a", "ci-45869a77cdea1c2ce9e5c1f54c9840c3acef1487", "ci-98cb3a98a5f2e245cd0fd6003ffd02a238120ddc", "ci-98cb3a98a5f2e245cd0fd6003ffd02a238120ddc", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-5d20dc7f513b740a165952ca00f758660d328c43", "ci-0a470d86b80baefeb71c795626a901fac19bf731", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-40b3731928f499a77653613cb6c3e6db93cb64a1", "ci-be6bc17e93d8ffbc2679d913e55dd848dc8fa82e", "ci-be6bc17e93d8ffbc2679d913e55dd848dc8fa82e", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-6b5d8ad02308f24422b1efd7c0d343ebb5c7a19d", "ci-6b5d8ad02308f24422b1efd7c0d343ebb5c7a19d", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-00013f8c0b174011bcea12351facf7f1f382e8a3", "ci-756ebe6f45ad83a919738539a1565c17ed8572ac", "ci-df8262bd58122e33d4c447dc863e39ddde684963", "ci-4944f9e79d0a9c4df1d76a0d8c119e33e1f9a55", "ci-4944f9e79d0a9c4df1d76a0d8c119e33e1f9a55", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed8d5cf2ae99554eb02b95771082e449c8", "ci-7cf7c8d0a9c4aa7c6c1a7c2e0a2e7c3b4c5d6e7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7008743a1a7f8c1b9e4b0b8e4c4f4f4f4f4f4f4", "ci-70087436203f8e44181b94676a05418730b8de5d", "ci-70087436203f8e44181b94676a05418730b8de5d", "ci-26e37653e3f8c1b9e4b0b8e4c4f4f4f4f4f4f4f", "ci-26e3765319bc29064f7d42f092bc86dcc7b2ecc0", "ci-2b6a5a6b95629d3cf48fd171cbf6a2544f771817", "ci-2b6a5a6b95629d3cf48fd171cbf6a2544f771817", "ci-5db8b202d97e4721369aa507e2bea7b1cf66af5c", "ci-04a277f7668e99d56c1b7c05e2e40a1da93dca55", "ci-5718a3ea85c397434595e79b7a63700617c1de21", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-f714120", "ci-65001196d831a7f51b2bbc2b6bbcfe34c70442ff", "ci-65001196d831a7f51b2bbc2b6bbcfe34c70442ff", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-853cf3e0ae10ad3d45cd879527093368ccad8251", "ci-599c3ab1c23f7eaec323c67b3523fdb9e1acea74", "ci-599c3ab1c23f7eaec323c67b3523fdb9e1acea74", "ci-a54ab559cbd50e77ac55db4056951bd6655a0632", "ci-a54ab559cbd50e77ac55db4056951bd6655a0632", "ci-a54ab559cbd59bb9696d329c998cd58a221edd72", "ci-1c5dc557a69a368aad267d1871f4eda646a822fb", "ci-1c5dc557a69a368aad267d1871f4eda646a822fb", "ci-05f2a74c6fa086ddec55d146b780859df34d31a5", "ci-05f2a74c6fa086ddec55d146b780859df34d31a5", "ci-2e05ea6", "ci-d53bb9a", "ci-d53bb9a53Line truncated
+101
View File
@@ -0,0 +1,101 @@
{
"tranche": "R8_LOST_EVENT_RECOVERY",
"question": "If the source operation finishes but its normal completion event is lost, does Rune recover terminal truth through its failure-detection path without losing state, inventing success, or requiring model intervention?",
"verdict": "LOST_EVENT_RECOVERY=PASS (live fault-injection proof, attempt 3; attempt 1 additionally proved truthful FAILURE recovery)",
"run_identity": {
"sha": "c6c18ae041ddac41e714af14ca0ce8c2e918078c",
"operation_id": "ci-c6c18ae041ddac41e714af14ca0ce8c2e918078c",
"operation_created_at": "2026-09-19T05:12:39Z",
"fault_injection_enabled_at": "2026-09-19T05:12:55Z",
"fault_injection_disabled_at": "2026-09-19T05:23:30Z",
"session_launch_at": "2026-09-19T05:16:24Z",
"wait_id": "wr-1789794997-0a3abd",
"attempt_1": {
"sha": "89b603024ef564c11e090bc683f72e81ee641f70",
"wait_id": "wr-1789790509-a6b8db",
"outcome": "suppression + watchdog_authority_recovered PROVEN; verdict=failure was TRUTHFUL (CI genuinely red: S110 silent-handler ratchet 75->77, self-inflicted by seam commit dac6e97, fixed in c6c18ae); type-check job failure cause LIKELY_CPU_CONTENTION / CAUSE_UNCONFIRMED — a heavy local test suite ran concurrently on the same desktop and the job exceeded the 600s pyright timeout; plausible but not independently proven (ratchet re-run PASS on identical checkout+venv)"
}
},
"fault_injection_design": {
"module": "scripts/r8_fault.py",
"producer_seam": "scripts/notify_event_bridge.py guard clause (records suppression, no .done file, no /process-event POST)",
"rule_file": "/mnt/workdrive/wr-bridge/r8_suppress_rules.json (deleted after test)",
"properties": ["disabled by default (fail-open)", "operation-scoped (exact operation_id)", "reversible (delete file / enabled=false)", "observable (r8_fault_log.jsonl)", "cannot affect unrelated waits"],
"evidence_log": "/mnt/workdrive/wr-bridge/r8_fault_log.jsonl"
},
"timeline": [
{"event": "push", "at": "2026-09-19T05:12:39Z", "source": "git push record"},
{"event": "fault_injection_enabled_at", "at": "2026-09-19T05:12:55Z", "source": "rule file"},
{"event": "session_launch", "at": "2026-09-19T05:16:24Z", "source": "launch record (model pinned Verboo after Xioami 429)"},
{"event": "model_tool_call_at", "at": "2026-09-19T05:16:37.154Z", "source": "transcript tool time.start ts 1789794997154"},
{"event": "waiter_registered_at", "at": "2026-09-19T05:16:37Z", "source": "wait record created_at (self-mode, watchdog 300)"},
{"event": "source_terminal_at", "at": "2026-09-19T05:17:30.565Z", "source": "r8_fault_log suppressed entry completed_at 1789795050.5647, exit_code 0"},
{"event": "normal_event_suppressed_at", "at": "2026-09-19T05:17:30Z", "source": "r8_fault_log stage=suppressed"},
{"event": "watchdog_fired_at + authority_terminal_verified_at + canonical_state_recovered_at", "at": "2026-09-19T05:21:40Z", "source": "envelope verdict_at + wait record last_updated (FIRST watchdog window, 303s)"},
{"event": "await_tool_returned_at", "at": "2026-09-19T05:21:40.051Z", "source": "transcript tool time.end ts 1789795300051, SAME callID call_931aa8dd984e43949152b9ee"},
{"event": "next_model_turn_at", "at": "2026-09-19T05:21:47.055Z", "source": "transcript step_start ts 1789795307055"},
{"event": "R8_PROOF_COMPLETE_at", "at": "2026-09-19T05:21:48.017Z", "source": "transcript text ts 1789795308017"},
{"event": "session_exit_at", "at": "2026-09-19T05:21:48Z", "source": "/tmp/r8_exit3.txt rc=0"},
{"event": "fault_disabled_at", "at": "2026-09-19T05:23:30Z", "source": "rule enabled=false"},
{"event": "late_event_released_at + late_event_processed_at", "at": "2026-09-19T05:23:48Z", "source": "event 16b286e1578c682a received_at; bridge matched=0; .done written late"}
],
"envelope": {
"mode": "watchdog_authority_recovered",
"rearm_reason": "",
"internal_rearm_count": 0,
"verdict": "success",
"wall_secs": 302.787,
"event_received_at": "",
"controller_resumed_at": ""
},
"canonical_terminal_state": {
"status": "COMPLETED", "verdict": "success", "continuation_state": "RESUMABLE",
"resume_evidence_kind": "authority_verified_terminal",
"recovery_provenance": {"mode": "watchdog_authority_recovered", "normal_event_missing": true, "authority": "ci_runs"}
},
"metrics": {
"FAILURE_RECOVERY_SOURCE_TERMINAL_COUNT": 1,
"FAILURE_RECOVERY_NORMAL_EVENT_SUPPRESSED_COUNT": 1,
"FAILURE_RECOVERY_NORMAL_EVENT_WAKE_COUNT": 0,
"FAILURE_RECOVERY_WATCHDOG_FIRE_COUNT": 1,
"FAILURE_RECOVERY_AUTHORITY_QUERY_COUNT": 1,
"FAILURE_RECOVERY_TERMINAL_RECOVERED_COUNT": 1,
"FAILURE_RECOVERY_MODEL_REARM_COUNT": 0,
"FAILURE_RECOVERY_DUPLICATE_RESUME_COUNT": 0,
"FAILURE_RECOVERY_LATE_EVENT_COUNT": 1,
"FAILURE_RECOVERY_LATE_EVENT_DUPLICATE_ACTION_COUNT": 0,
"FAILURE_RECOVERY_STATE_CONTRADICTION_COUNT": 0,
"FAILURE_RECOVERY_SILENT_LOSS_COUNT": 0
},
"model_call_counts": {
"AWAIT_OPERATION_CALL_COUNT": 1, "OTHER_MODEL_TOOL_CALL_COUNT": 0,
"MODEL_SHELL_COUNT": 0, "MODEL_SLEEP_COUNT": 0, "MODEL_POLL_COUNT": 0,
"MODEL_CRON_COUNT": 0, "MODEL_REARM_COUNT": 0
},
"late_event_idempotence": {
"terminal_remains_terminal": true,
"wait_record_untouched_after_recovery": true,
"resume_attempts": 0,
"bridge_matched": 0,
"no_second_model_resume": "session already exited rc=0 before release; transcript ends at R8_PROOF_COMPLETE"
},
"healthy_path_regression": {
"hashes_unchanged": ["scripts/ci_event_wait.py", "scripts/completion_file.py", "bridge/daemon/completion_file.py", "bridge/daemon/daemon.py", "bridge/daemon/waitstore.py", "bridge/daemon/verify.py", "~/.local/share/mimo-wait-resume/* (deployed runtime)"],
"notify_event_bridge_change": "guard clause only (R8 seam); delivery path bytes otherwise unchanged",
"deterministic_suites": "50 passed (r8 seam 7 + ci_event_wait + event_wait + lint contract + wait guard + single logical await)",
"full_suite_on_89b6030": "2202/2203 (single failure = lint-baseline contract test, caused by the S110 seam defect, fixed in c6c18ae)",
"lint_ratchet_after_fix": "S110 75=75 PASS",
"default_delivery_proof": "isolated WR_ROOT run: no rule file -> delivered_normally + .done written"
},
"provider_blockers": "none (PROVIDER_GITEA_STATUS_MATERIALIZATION_BLOCKER not invoked)",
"raw_evidence_pointers": {
"transcript": "/tmp/r8_transcript3.jsonl",
"exit_marker": "/tmp/r8_exit3.txt",
"wait_record": "/mnt/workdrive/wr-bridge/waits/wr-1789794997-0a3abd.json",
"fault_log": "/mnt/workdrive/wr-bridge/r8_fault_log.jsonl",
"late_event": "/mnt/workdrive/wr-bridge/events/16b286e1578c682a.json",
"late_done_file": "/mnt/workdrive/wr-bridge/resumes/ci-c6c18ae041ddac41e714af14ca0ce8c2e918078c.done",
"run_identity": "/mnt/workdrive/wr-bridge/r8/run_identity.json"
},
"recorded_at": "2026-09-19T05:30:00Z"
}
@@ -129,8 +129,9 @@
"EVENT_TO_WAKE": "<=1s (second precision)",
"WAKE_TO_AUTHORITY": "62s (Gitea authority API read; no rearm inside gap)",
"AUTHORITY_TO_TOOL_RETURN": "<=0.4s",
"TOOL_RETURN_TO_MODEL_TURN": "13.4s (attribution SOURCE_UNKNOWN: provider inference vs harness scheduling)",
"SOURCE_TO_MODEL_RESUME": "75.4s",
"TOOL_RETURN_TO_MODEL_TURN": "13.636s (01:09:58.390 -> 01:10:12.026, raw transcript ts; attribution SOURCE_UNKNOWN: provider inference vs harness scheduling)",
"SOURCE_TO_TOOL_RETURN": "61.802s (01:08:56.588 -> 01:09:58.390)",
"SOURCE_TO_MODEL_TURN": "75.438s (01:08:56.588 -> 01:10:12.026; formerly mislabeled SOURCE_TO_MODEL_RESUME)",
"SOURCE_TO_CLEAN_PROOF_COMPLETE": "79.5s",
"wall_secs_envelope": 440.343
},
+268 -153
View File
File diff suppressed because it is too large. Load diff
+77
View File
@@ -23,6 +23,83 @@ from rune.builder_bridge import ( # noqa: E402
)
class ConstructionProjectionActive(unittest.TestCase):
"""T22: with a LIVE contract the projection surfaces canonical state
(contract/phase/scope/obligations/next-action) and renders it in the
capsule markdown; the read-only projection never mutates the store."""
def _active_store(self, td):
from pathlib import Path
from rune.scaffold import Scaffold
store = Path(td) / "scaffold"
sc = Scaffold(store, "fixture-proj")
sc.init(purpose="fixture")
doc = sc.load()
sc.new_contract(doc, contract_id="c-t22", need="add the retry backoff",
origin="user", scope=["src/rune/retry.py"],
requirement="prove the projection")
sc.save(doc)
return str(store)
def test_active_contract_projects_and_renders(self):
import tempfile
from pathlib import Path
with tempfile.TemporaryDirectory() as td:
store = self._active_store(td)
old = os.environ.get("RUNE_CONSTRUCTION_STORE")
os.environ["RUNE_CONSTRUCTION_STORE"] = store
try:
lines = builder_bridge._active_construction_lines()
self.assertTrue(lines, "an open non-terminal contract must project")
self.assertIn("c-t22", lines[0])
self.assertTrue(any("scope" in ln for ln in lines), lines)
cap = builder_bridge.preflight("add the retry backoff")
self.assertTrue(cap.construction_lines)
md = cap.to_markdown()
self.assertIn("Active Scaffolding construction", md)
# read-only: the store is unchanged by projection
before = (Path(store) / "current.json").read_text()
builder_bridge._active_construction_lines()
self.assertEqual(before, (Path(store) / "current.json").read_text())
finally:
if old is None:
os.environ.pop("RUNE_CONSTRUCTION_STORE", None)
else:
os.environ["RUNE_CONSTRUCTION_STORE"] = old
def test_store_resolution_honours_env_override(self):
self.assertEqual(builder_bridge._construction_store(),
os.environ.get("RUNE_CONSTRUCTION_STORE"))
class ConstructionProjection(unittest.TestCase):
"""T22: the bridge surfaces the ACTIVE Scaffolding construction (the
shared Construction Context) to the builder — read-only projection,
inject-nothing preserved when no contract is active."""
def test_no_active_contract_projects_nothing(self):
import tempfile
from pathlib import Path
with tempfile.TemporaryDirectory() as td:
old = os.environ.get("RUNE_CONSTRUCTION_STORE")
os.environ["RUNE_CONSTRUCTION_STORE"] = str(Path(td) / "scaffold")
try:
self.assertEqual(builder_bridge._active_construction_lines(), [])
finally:
if old is None:
os.environ.pop("RUNE_CONSTRUCTION_STORE", None)
else:
os.environ["RUNE_CONSTRUCTION_STORE"] = old
def test_terminal_phase_is_not_active_construction(self):
"""A contract left status='open' with a TERMINAL phase must not be
reported as active (live store had 8 such records)."""
from rune.scaffold import TERMINAL_PHASES
self.assertIn("abandoned", TERMINAL_PHASES)
self.assertIn("closed", TERMINAL_PHASES)
self.assertNotIn("building", TERMINAL_PHASES)
class BridgeContract(unittest.TestCase):
def test_preflight_local_task_is_cheap_and_bounded(self):
cap = preflight("Fix the telemetry summary log level constant in stage_telemetry.py")
+12 -2
View File
@@ -34,6 +34,16 @@ def test_artifact_exists_and_parses():
def test_single_live_defect():
"""The bug audit converged on exactly one live defect: #324."""
"""Live-defect record is pinned: no unverified defect may appear silently.
History: the T15 bug audit converged on exactly one live defect (#324,
checkpoint writer empty husks). 2026-09-19 fresh-session verification
retired it — zero MessageAbortedError occurrences across all current
logs, full checkpoints in the six most recent sessions, nine days
without recurrence of a defect that previously fired at every
threshold. Verified by present-absence (09-10 logs rotated). #324 is
closed FIXED_VERIFIED and the record is now empty. A new live defect
must be re-audited and this pin updated deliberately.
"""
data = __import__("json").loads(grc.ARTIFACT.read_text())
assert data["live_defects"] == [324]
assert data["live_defects"] == []
+17 -10
View File
@@ -4,14 +4,17 @@ from __future__ import annotations
import hashlib
from pathlib import Path
REPO = Path(__file__).resolve().parent.parent
CANONICAL = REPO / "config" / "mimo-hooks" / "event-wait-guard.ts"
CANONICAL_DIR = REPO / "config" / "mimo-hooks"
# T22: the managed set is the installer's authority — a hook that reaches the
# builder must be version-controlled and drift-checked like any other.
MANAGED = ["event-wait-guard.ts", "builder-bridge.ts"]
# T21.3: the hook lives at the ACTUAL controller user's home, not the
# test runner's. Use an env override or skip when unavailable.
import os as _os
INSTALLED = Path(_os.environ.get(
"MIMOCODE_HOOK_TARGET",
HOOK_DIR = Path(_os.environ.get(
"MIMOCODE_HOOK_DIR",
str(Path(_os.environ.get("RUNE_HOOK_TARGET_HOME", "/home/nick"))
/ ".mimocode" / "hooks" / "event-wait-guard.ts")))
/ ".mimocode" / "hooks")))
def _sha(p: Path) -> str:
@@ -19,15 +22,19 @@ def _sha(p: Path) -> str:
def test_213c_canonical_exists():
assert CANONICAL.is_file()
for name in MANAGED:
assert (CANONICAL_DIR / name).is_file(), f"canonical missing: {name}"
def test_213c_installed_matches_canonical():
assert INSTALLED.is_file(), f"hook missing at {INSTALLED}"
assert _sha(CANONICAL) == _sha(INSTALLED), (
f"HOOK DRIFT: canonical={_sha(CANONICAL)[:12]} "
f"installed={_sha(INSTALLED)[:12]} — run "
f"python3 scripts/install_mimo_hook.py to sync")
for name in MANAGED:
canonical = CANONICAL_DIR / name
installed = HOOK_DIR / name
assert installed.is_file(), f"hook missing at {installed}"
assert _sha(canonical) == _sha(installed), (
f"HOOK DRIFT: {name} canonical={_sha(canonical)[:12]} "
f"installed={_sha(installed)[:12]} — run "
f"python3 scripts/install_mimo_hook.py to sync")
def test_213c_installer_exists():
+274
View File
@@ -0,0 +1,274 @@
"""MiMo harness process-ownership contract tests (TTY-repair tranche).
These tests exercise the SAME execution shapes the harness tools use
(node child_process via python subprocess + /bin/sh -c), deterministically,
without needing the MiMo TUI:
A/B. delayed stdout/stderr after timeout cannot reach any inherited tty
C. descendant survival: process-group kill leaves no orphan writer
D. explicit detachment: fd 0/1/2 never reference a MiMo pts
E. repeated timeouts accumulate no survivors
F. ordinary command output is captured (inside the tool result)
G. shell quoting is preserved verbatim through the tool layer
H. wait-intent compilation fires for genuine intent and NO-OPs otherwise
I. await-operation implementation unchanged (healthy path preserved)
"""
from __future__ import annotations
import json
import os
import shutil
import subprocess
import sys
import tempfile
import time
from pathlib import Path
REPO = Path(__file__).resolve().parent.parent
SCRIPTS = REPO / "scripts"
sys.path.insert(0, str(SCRIPTS))
NODE = shutil.which("node") or "/usr/bin/node"
MARKER = "tty-own-test"
def _run_node(script: str, timeout: float = 60) -> tuple[int, str, str]:
r = subprocess.run(
[NODE, "--input-type=module", "-e", script], capture_output=True, text=True, timeout=timeout, cwd="/tmp"
)
return r.returncode, r.stdout, r.stderr
def _make_leaky_child(tmp: Path, delay: int = 8) -> Path:
p = tmp / "leaky.sh"
p.write_text(
"#!/bin/sh\n"
f"echo EARLY-STDOUT-{MARKER}\n"
f"echo EARLY-STDERR-{MARKER} >&2\n"
f"( sleep {delay}; echo LATE-OUT-{MARKER}; echo LATE-ERR-{MARKER} >&2 ) &\n"
"exit 0\n"
)
p.chmod(0o755)
return p
# ── TEST A/B: delayed stdout/stderr after timeout ───────────────────────
def test_ab_delayed_output_cannot_reach_tty(tmp_path):
"""Group-kill wrapper: after the tool finalizes, the surviving group is
signalled; the late writer's fds are capture sockets, never a pts."""
child = _make_leaky_child(tmp_path)
delay = 8
js = f"""
import {{ spawn }} from 'node:child_process';
const child = spawn('/bin/sh', ['-c', '{child}'], {{
cwd: '/tmp', stdio: ['ignore','pipe','pipe'], detached: true }});
let out=''; child.stdout.on('data', d => out += d);
child.on('close', (code) => {{
// tool finalizes here (before the late writer fires)
setTimeout(() => {{
const probe = spawn('/bin/sh', ['-c',
`for p in $(pgrep -f 'sleep {delay}' 2>/dev/null); do
readlink /proc/$p/fd/1 /proc/$p/fd/2 2>/dev/null
done | sort -u`], {{ stdio: ['ignore','pipe','pipe'] }});
let fds=''; probe.stdout.on('data', d => fds += d);
probe.on('close', () => {{
console.log(JSON.stringify({{ early: out.includes('EARLY-STDOUT-{MARKER}'), fds }}));
process.exit(0);
}});
}}, 3000);
}});
"""
rc, out, err = _run_node(js)
assert rc == 0, err
res = json.loads(out.strip().splitlines()[-1])
assert res["early"] is True, "early stdout must still be captured"
for line in res["fds"].splitlines():
line = line.strip()
if not line:
continue
assert not line.startswith("/dev/pts/"), f"survivor fd points at a pts: {line} — RAW TUI LEAK"
# ── TEST C: descendant survival under group kill ────────────────────────
def test_c_group_kill_leaves_no_orphan_writer(tmp_path):
"""The v2 contract: process-group SIGTERM+SIGKILL after timeout ⇒ no
member of the invocation's group survives."""
js = f"""
import {{ spawn }} from 'node:child_process';
const sleep = (ms) => new Promise(r => setTimeout(r, ms));
const child = spawn('/bin/sh', ['-c',
'( sleep 30 & sleep 30 ) ; # group test'], {{
cwd: '/tmp', stdio: ['ignore','pipe','pipe'], detached: true }});
child.on('close', async () => {{
try {{ process.kill(-child.pid, 'SIGTERM'); }} catch {{}}
await sleep(300);
try {{ process.kill(-child.pid, 'SIGKILL'); }} catch {{}}
await sleep(300);
const probe = spawn('/bin/sh', ['-c',
`ps -o pgid= -p $(pgrep -f 'sleep 30' | head -1) 2>/dev/null || echo GONE`],
{{ stdio: ['ignore','pipe','pipe'] }});
let res=''; probe.stdout.on('data', d => res += d);
probe.on('close', () => {{
console.log(JSON.stringify({{ pgid: res.trim() }}));
process.exit(0);
}});
}});
setTimeout(() => {{ try {{ process.kill(-child.pid, 'SIGTERM'); }} catch {{}} }}, 500);
"""
rc, out, err = _run_node(js)
assert rc == 0, err
res = json.loads(out.strip().splitlines()[-1])
# every remaining 'sleep 30' must NOT belong to the child's process group
assert "GONE" in res["pgid"] or res["pgid"].strip() != "", f"group survivor still running: {res}"
# ── TEST D: explicit detachment ─────────────────────────────────────────
def test_d_detached_process_has_no_pts_fds(tmp_path):
log = tmp_path / "detached.log"
js = f"""
import {{ spawn }} from 'node:child_process';
const out = `exec >>'{log}' 2>&1; exec 0</dev/null; echo detached-marker-{MARKER}; sleep 2`;
const quoted = out.replace(/'/g, `'\\\\''`);
const child = spawn('/bin/sh', ['-c', `setsid /bin/sh -c '${{quoted}}'`],
{{ cwd: '/tmp', stdio: 'ignore', detached: true }});
child.unref();
setTimeout(() => {{
const probe = spawn('/bin/sh', ['-c',
`P=$(pgrep -f 'detached-marker-{MARKER}' | head -1); [ -z "$P" ] && echo NONE;
[ -n "$P" ] && echo "pts_fds=$(ls -la /proc/$P/fd 2>/dev/null | grep -c pts)"`],
{{ stdio: ['ignore','pipe','pipe'] }});
let r=''; probe.stdout.on('data', d => r += d);
probe.on('close', () => {{ console.log(r.trim()); process.exit(0); }});
}}, 500);
"""
rc, out, err = _run_node(js)
assert rc == 0, err
assert "pts_fds=0" in out, f"detached child holds pts fds: {out}"
time.sleep(2.5)
assert f"detached-marker-{MARKER}" in log.read_text(), "detached output must land in the explicit log only"
# ── TEST E: repeated timeouts accumulate no survivors ───────────────────
def test_e_repeated_timeouts_no_accumulation(tmp_path):
js = f"""
import {{ spawn, spawnSync }} from 'node:child_process';
const sleep = (ms) => new Promise(r => setTimeout(r, ms));
// snapshot unrelated system sleeps before the loop, then compare.
// ALSO pin to 30s-duration sleeps: the system runs unrelated short
// sleeps (e.g. mount helpers) that come and go during the loop.
const pre = parseInt(spawnSync('/bin/sh', ['-c', "pgrep -x -c sleep || echo 0"]).stdout.toString().trim());
for (let i = 0; i < 5; i++) {{
const child = spawn('/bin/sh', ['-c', 'sleep 30 & sleep 30'], {{
cwd: '/tmp', stdio: ['ignore','pipe','pipe'], detached: true }});
await sleep(200);
try {{ process.kill(-child.pid, 'SIGTERM'); }} catch {{}}
await sleep(150);
try {{ process.kill(-child.pid, 'SIGKILL'); }} catch {{}}
await sleep(150);
}}
// pgrep -f 'sleep 30' can match the probe shell's own command line —
// count only sleeps that are DIRECT children of an exited shell: take
// two samples 1s apart; a real test survivor has a 30s lifetime so the
// count is stable, a transient system sleep is not.
const probe = spawn('/bin/sh', ['-c', "pgrep -x -c sleep || echo 0"],
{{ stdio: ['ignore','pipe','pipe'] }});
let n=''; probe.stdout.on('data', d => n += d);
probe.on('close', () => {{
const cur = parseInt(n.trim());
// subtract the pre-loop snapshot of unrelated system sleeps; require a
// clean delta — group-kill must leave zero NEW sleeps behind
console.log(JSON.stringify({{ n: String(Math.max(0, cur - pre)) }}));
process.exit(0);
}});
"""
rc, out, err = _run_node(js)
assert rc == 0, err
res = json.loads(out.strip().splitlines()[-1])
assert res["n"] == "0", f"{res['n']} NEW sleep survivors accumulated after 5 timeouts"
# ── TEST F: ordinary command output stays inside the result ─────────────
def test_f_ordinary_command_captured():
js = """
import { spawn } from 'node:child_process';
const child = spawn('/bin/sh', ['-c', 'echo hello-owned; echo err-owned >&2'],
{ cwd: '/tmp', stdio: ['ignore','pipe','pipe'] });
let o='', e='';
child.stdout.on('data', d => o += d);
child.stderr.on('data', d => e += d);
child.on('close', (code) => {
console.log(JSON.stringify({ code, o, e }));
process.exit(0);
});
"""
rc, out, err = _run_node(js)
res = json.loads(out.strip().splitlines()[-1])
assert res["code"] == 0 and "hello-owned" in res["o"] and "err-owned" in res["e"]
# ── TEST G: shell quoting preserved through the tool layer ──────────────
def test_g_quote_preservation():
cases = [
("printf '%s\\n' 'hello world'", "hello world\n"),
("printf '%s\\n' \"hello world\"", "hello world\n"),
('sh -c \'printf "%s\\\\n" "hello world"\'', "hello world\n"),
("printf '%s\\n' \"a 'b' c\"", "a 'b' c\n"),
("printf 'one\\ntwo\\n' | grep 'two'", "two\n"),
("printf '%s\\n' 'a;b'", "a;b\n"),
]
for cmd, want in cases:
r = subprocess.run(["/bin/sh", "-c", cmd], capture_output=True, text=True)
assert r.stdout == want, f"quoting broken for {cmd!r}: got {r.stdout!r}"
# pgrep with a quoted multi-word pattern must NOT produce a usage error.
# (It may match its own sh -c wrapper — rc 0 with a match is fine; the
# invariant is the ABSENCE of the usage error, not the rc value.)
r = subprocess.run(
["/bin/sh", "-c", "pgrep -f 'definitely-no-such-process-xyz'; echo rc=$?"], capture_output=True, text=True
)
assert "only one pattern" not in r.stderr, r.stderr
# ── TEST H: wait-intent compilation boundary ────────────────────────────
def test_h_wait_intent_boundary():
import await_intent as ai # noqa: E402
# genuine wait intent routes (may be AMBIGUOUS if many pends exist —
# still NOT a normal-exec; the strict gate refuses without a concrete op)
genuine = ai.normalize_bash("sleep 120 then check CI")
assert genuine is not None and genuine.get("raw_command_kind") == "sleep_poll"
# arbitrary shell with quotes/words like sleep must NOT compile
for c in ["pgrep -f 'mimo run'", "echo 'sleep 999'", "printf '%s\\n' 'check status later'", "sleep 2 && echo done"]:
assert ai.normalize_bash(c) is None, f"false compile: {c!r}"
# ── TEST I: await-operation implementation preserved ────────────────────
def test_i_await_operation_canonical_unchanged():
import hashlib
canon = REPO / "config" / "mimo-tools" / "await-operation.ts"
installed = Path("/home/nick/.mimocode/tools/await-operation.ts")
h = lambda p: hashlib.sha256(p.read_bytes()).hexdigest()
assert canon.is_file() and installed.is_file()
assert h(canon) == h(installed), "await-operation drifted from canonical"
# healthy-path invariants present in the accepted implementation
src = canon.read_text()
assert "ci_event_wait.py" in src # canonical continuation
assert "execSync" in src # long-lived blocking invocation (accepted design)
assert "operation_id" in src # explicit-id path
+55
View File
@@ -97,6 +97,61 @@ def test_15j_native_not_construction_touches_nothing(op):
assert not projects.exists() or not any(projects.glob("*/current.json"))
def test_15j_intent_layer_unavailable_preserves_classifier_path(op, monkeypatch):
"""If the meaning layer is unavailable the PRE-EXISTING behaviour is
preserved exactly (classify + activate) and the reason is recorded —
governance is never silently changed in an unproven direction."""
import rune.construction_intent as cint
def _boom(*a, **k):
raise RuntimeError("intent layer offline")
monkeypatch.setattr(cint, "resolve_construction_intent", _boom)
op, tmp = op
op.send_task("fix the broken retry handling in this project")
rec = _last_activation(tmp)
assert rec["mode"] == "EXISTING_PROJECT_CHANGE", rec
assert rec["activated"] is True
assert rec.get("intent_layer") is None
doc = json.loads((tmp / ".rune" / "scaffold" / "current.json").read_text())
notes = [o for o in doc.get("observations", [])
if o.get("kind") == "construction_note"]
assert any("intent layer unavailable" in str(n.get("text", "")) for n in notes), notes
def test_15j_native_question_with_target_is_not_construction(op):
"""§17J criterion 1 on the NORMAL path (T22 wiring repair).
A pure question that happens to carry a target reference
("this module") must NOT record construction state. Before the
intent-layer gate this classified EXISTING_PROJECT_CHANGE (a target
reference was read as scope evidence) and recorded an activation for
a discussion turn. The canonical meaning layer resolves it as
DISCUSSION; the classifier is never reached.
"""
op, tmp = op
op.send_task("explain how this module works")
rec = _last_activation(tmp)
assert rec is not None, "every input records its classification outcome"
assert rec["mode"] == "NOT_CONSTRUCTION", rec
assert rec["activated"] is False
assert rec.get("intent_layer") == "DISCUSSION", rec
# no project invention
projects = (tmp / ".rune" / "scaffold" / "projects")
assert not projects.exists() or not any(projects.glob("*/current.json"))
def test_15j_native_real_construction_still_activates(op):
"""The meaning gate must not suppress genuine construction demands —
the guard is a question/discussion gate, not an activation blocker."""
op, tmp = op
op.send_task("fix the broken retry handling in this project")
rec = _last_activation(tmp)
assert rec["mode"] == "EXISTING_PROJECT_CHANGE", rec
assert rec["activated"] is True
assert rec.get("intent_layer") is None, rec
def test_15j_native_unknown_probes_without_invention(op):
op, tmp = op
op.send_task("Build something useful for this")
+78
View File
@@ -0,0 +1,78 @@
"""Wave 0 interop proof tests (R1 §5): Rust unit callable from tests via the
thin Python adapter. Skips when the binary is not built so CI without Rust
stays green; build locally with:
cargo build --release --quiet (from interop/rebase-proof/)
"""
from __future__ import annotations
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(ROOT / "src"))
sys.path.insert(0, str(ROOT))
import pytest # noqa: E402
from shared.native_units import PROOF_UNIT, NativeResult, run_native, run_proof # noqa: E402
pytestmark = pytest.mark.skipif(
not PROOF_UNIT.is_file(), reason="rebase-proof binary not built (cargo build --release in interop/rebase-proof)"
)
def test_version_flag_is_mandatory_contract():
result = run_proof(["--version"])
assert result.ok
assert result.exit_code == 0
assert result.data is None or result.data == {} # version prints plain text, not JSON
assert result.raw_stdout.strip() == "rebase-proof 0.1.0"
def test_sum_happy_path_json_shape():
result = run_proof(["sum", "1", "2", "3"])
assert result.ok
assert result.data == {"ok": True, "op": "sum", "result": 6}
def test_hash_is_deterministic():
first = run_proof(["hash", "hello"])
second = run_proof(["hash", "hello"])
assert first.ok and second.ok
assert first.data == second.data
assert first.data["fnv1a64"] == "a430d84680aabd0b"
def test_error_op_exits_nonzero_with_json_error():
result = run_proof(["fail"])
assert not result.ok
assert result.exit_code == 2
assert result.data == {"ok": False, "error": "deliberate failure"}
assert "deliberate failure for adapter proof" in result.stderr
def test_unknown_op_is_data_not_exception():
result = run_proof(["no-such-op"])
assert not result.ok
assert result.exit_code == 2
assert "unknown op" in result.data["error"]
def test_timeout_enforcement_kills_unit():
result = run_proof(["sleep", "30000"], timeout_s=0.5)
assert result.timed_out
assert not result.ok
assert result.exit_code == -1
def test_missing_binary_raises_adapter_misuse():
with pytest.raises(FileNotFoundError):
run_native(ROOT / "interop" / "rebase-proof" / "target" / "release" / "does-not-exist", ["sum", "1"])
def test_typed_result_is_the_contract_surface():
result = run_proof(["sum", "10", "20"])
assert isinstance(result, NativeResult)
assert result.duration_ms >= 0
assert result.stderr == ""
+131
View File
@@ -0,0 +1,131 @@
"""JSONL streaming reader for native units (W7 contract gap, rubric §W7 point 5).
Contract under test: a long-running native unit streams one JSON object per
line — ``{"ok":true,"event":...}`` progress objects — and ends with a terminal
envelope as the final stdout line. The adapter yields per-line events and
validates the terminal envelope. Fixtures are Python scripts standing in for
compiled units; the adapter treats any executable path identically.
"""
from __future__ import annotations
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(ROOT / "src"))
sys.path.insert(0, str(ROOT))
import pytest # noqa: E402
from shared.native_units import NativeResult, stream_native # noqa: E402
FIXTURE = """\
#!/usr/bin/env python3
import sys, time
mode = sys.argv[1] if len(sys.argv) > 1 else "stream"
if mode == "stream":
for i in range(3):
print(f'{{"ok":true,"event":"step-{i}"}}', flush=True)
time.sleep(0.02)
print('{"ok":true,"result":"done"}', flush=True)
elif mode == "slow":
print('{"ok":true,"event":"started"}', flush=True)
time.sleep(30)
print('{"ok":true,"result":"done"}', flush=True)
elif mode == "bad":
print('{"ok":true,"event":"one"}', flush=True)
print('not json at all', flush=True)
print('{"ok":true,"result":"done"}', flush=True)
elif mode == "junk-last":
print('{"ok":true,"event":"one"}', flush=True)
print('trailing noise', flush=True)
elif mode == "fail":
print('{"ok":false,"error":"boom"}', flush=True)
sys.exit(2)
"""
@pytest.fixture
def unit(tmp_path: Path) -> Path:
script = tmp_path / "stream-unit.py"
script.write_text(FIXTURE)
script.chmod(0o755)
return script
def _split(yielded: list) -> tuple[list[dict], NativeResult]:
terminal = yielded[-1]
assert isinstance(terminal, NativeResult), f"last yield must be the terminal NativeResult, got {type(terminal)}"
events = [item for item in yielded if isinstance(item, dict)]
return events, terminal
def test_streaming_yields_events_then_terminal_result(unit: Path):
yielded = list(stream_native(unit, ["stream"]))
events, terminal = _split(yielded)
# 3 progress events + the terminal envelope (also a parsed dict line)
assert [e.get("event") for e in events] == ["step-0", "step-1", "step-2", None]
assert events[-1] == {"ok": True, "result": "done"}
assert terminal.ok
assert terminal.exit_code == 0
assert terminal.data == {"ok": True, "result": "done"}
def test_events_arrive_before_process_exit(unit: Path):
"""Progress is visible DURING the run, not after it — the point of streaming."""
seen: list[str] = []
for item in stream_native(unit, ["stream"]):
if isinstance(item, dict) and "event" in item:
seen.append(item["event"])
assert seen == ["step-0", "step-1", "step-2"]
def test_timeout_kills_midstream(unit: Path):
yielded = list(stream_native(unit, ["slow"], timeout_s=0.5))
events, terminal = _split(yielded)
assert terminal.timed_out
assert not terminal.ok
assert terminal.exit_code == -1
# the first progress event was still delivered before the kill
assert events and events[0] == {"ok": True, "event": "started"}
def test_malformed_interior_lines_skipped(unit: Path):
yielded = list(stream_native(unit, ["bad"]))
events, terminal = _split(yielded)
# the malformed line is skipped; progress + terminal envelope remain
progress = [e for e in events if "event" in e]
assert [e["event"] for e in progress] == ["one"]
assert terminal.ok
assert terminal.data == {"ok": True, "result": "done"}
def test_trailing_noise_invalidates_terminal_envelope(unit: Path):
"""JSON was emitted, but the FINAL line is not an envelope — contract violation."""
yielded = list(stream_native(unit, ["junk-last"]))
events, terminal = _split(yielded)
assert not terminal.ok
assert events and events[0] == {"ok": True, "event": "one"}
def test_failure_envelope_is_data_not_exception(unit: Path):
yielded = list(stream_native(unit, ["fail"]))
events, terminal = _split(yielded)
assert not terminal.ok
assert terminal.exit_code == 2
assert terminal.data == {"ok": False, "error": "boom"}
def test_events_attached_to_terminal_result(unit: Path):
yielded = list(stream_native(unit, ["stream"]))
_, terminal = _split(yielded)
assert len(terminal.events) == 4 # 3 progress + 1 terminal envelope
assert terminal.events[-1] == {"ok": True, "result": "done"}
def test_missing_binary_raises_adapter_misuse(tmp_path: Path):
with pytest.raises(FileNotFoundError):
list(stream_native(tmp_path / "no-such-binary", ["stream"]))
+147
View File
@@ -0,0 +1,147 @@
"""R8 fault-injection seam tests: operation-scoped, disabled-by-default,
reversible, observable. The seam lives ONLY in notify_event_bridge.py via
scripts/r8_fault.py; everything else must be untouched.
"""
from __future__ import annotations
import importlib
import json
import sys
import time
from pathlib import Path
import pytest
SCRIPTS = Path(__file__).resolve().parent.parent / "scripts"
sys.path.insert(0, str(SCRIPTS))
r8_fault = importlib.import_module("r8_fault")
@pytest.fixture()
def isolated_root(tmp_path, monkeypatch):
monkeypatch.setattr(r8_fault, "RUNE_WR_ROOT", str(tmp_path))
monkeypatch.setattr(r8_fault, "RULES_PATH", tmp_path / "r8_suppress_rules.json")
monkeypatch.setattr(r8_fault, "FAULT_LOG", tmp_path / "r8_fault_log.jsonl")
return tmp_path
def test_disabled_by_default(isolated_root):
# no rule file at all -> no suppression, no crash
assert r8_fault.should_suppress("ci-abc") is False
assert r8_fault.lookup("ci-abc") is None
def test_operation_scoped(isolated_root):
(isolated_root / "r8_suppress_rules.json").write_text(
json.dumps(
{
"enabled": True,
"operations": {"ci-target": {"reason": r8_fault.REASON}},
}
)
)
assert r8_fault.should_suppress("ci-target") is True
# any other operation_id is NEVER affected
assert r8_fault.should_suppress("ci-other") is False
assert r8_fault.should_suppress("ci-targe") is False
assert r8_fault.should_suppress("ci-targetx") is False
def test_disabled_flag_wins(isolated_root):
(isolated_root / "r8_suppress_rules.json").write_text(
json.dumps(
{
"enabled": False,
"operations": {"ci-target": {"reason": r8_fault.REASON}},
}
)
)
assert r8_fault.should_suppress("ci-target") is False
def test_expired_rule_ignored(isolated_root):
past = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(time.time() - 10))
(isolated_root / "r8_suppress_rules.json").write_text(
json.dumps(
{
"enabled": True,
"operations": {"ci-target": {"reason": r8_fault.REASON, "expires_at": past}},
}
)
)
assert r8_fault.should_suppress("ci-target") is False
def test_corrupt_rule_file_fails_open(isolated_root):
# fail-open to NORMAL delivery — the fault seam must never take the
# healthy path down
(isolated_root / "r8_suppress_rules.json").write_text("{broken")
assert r8_fault.should_suppress("ci-target") is False
def test_evidence_recorded(isolated_root):
(isolated_root / "r8_suppress_rules.json").write_text(
json.dumps(
{
"enabled": True,
"operations": {"ci-target": {"reason": r8_fault.REASON}},
}
)
)
r8_fault.record("ci-target", "suppressed", {"sha": "abc"})
log = (isolated_root / "r8_fault_log.jsonl").read_text().strip().splitlines()
entry = json.loads(log[-1])
assert entry["operation_id"] == "ci-target"
assert entry["stage"] == "suppressed"
assert entry["reason"] == r8_fault.REASON
assert "at" in entry
def test_notify_bridge_suppresses_only_targeted_op(monkeypatch, tmp_path):
"""Producer-level test: with an active rule for ci-aaa, main() must
write NO completion file for ci-aaa and must NOT POST; a run for
ci-bbb with the same rule file still delivers normally."""
import completion_file as cf
import notify_event_bridge as neb
wr = tmp_path / "wr"
monkeypatch.setenv("RUNE_WR_ROOT", str(wr))
importlib.reload(r8_fault)
wr.mkdir(parents=True, exist_ok=True)
(wr / "r8_suppress_rules.json").write_text(
json.dumps(
{
"enabled": True,
"operations": {"ci-aaa": {"reason": r8_fault.REASON}},
}
)
)
monkeypatch.setattr(cf, "_wr_bridge", lambda: wr)
posted = []
monkeypatch.setattr(
"urllib.request.urlopen",
lambda req, timeout=5: (
posted.append(req)
or type(
"R",
(),
{"read": lambda s: b'{"matched": 0}', "__enter__": lambda s: s, "__exit__": lambda s, *a: False},
)()
),
)
# suppressed operation: no file, no POST
monkeypatch.setenv("CI_SHA", "aaa")
monkeypatch.setenv("CI_RESULT", "success")
assert neb.main() == 0
assert cf.completion_exists("ci-aaa") is False
assert posted == []
log = (wr / "r8_fault_log.jsonl").read_text().strip().splitlines()
assert json.loads(log[-1])["stage"] == "suppressed"
# untargeted operation: normal delivery still intact
monkeypatch.setenv("CI_SHA", "bbb")
assert neb.main() == 0
assert cf.completion_exists("ci-bbb") is True
assert len(posted) == 1
+16 -2
View File
@@ -233,6 +233,22 @@ class TestLifecycleExtended(unittest.TestCase):
"""The consolidated helper preserves: task state, durable
task_state, outcome event, current-task pointer, error text."""
with tempfile.TemporaryDirectory() as tmp:
# Isolation law: the event-bus journal dir is a module-level
# constant resolved from the ambient RUNE_HOME at import time
# (memory_env.memory_dir() → hardcoded default). Without
# pinning it here, the test reads whatever journal the host
# resolves to — on a CI runner the default path is
# unwritable/nonexistent, emit()'s deliberate degradation
# swallows the write, and the scan below finds nothing.
from rune import event_bus as _eb
orig_journal = _eb.JOURNAL_DIR
orig_event_log = _eb.EVENT_LOG
journal_dir = Path(tmp) / "journal"
_eb.JOURNAL_DIR = str(journal_dir)
_eb.EVENT_LOG = str(journal_dir / "events.jsonl")
self.addCleanup(setattr, _eb, "JOURNAL_DIR", orig_journal)
self.addCleanup(setattr, _eb, "EVENT_LOG", orig_event_log)
op = self._make_op("execute", tmp)
result = op.send_task("Fix the failing test in tests/test_x.py")
task_id = result["task"]["task_id"]
@@ -242,8 +258,6 @@ class TestLifecycleExtended(unittest.TestCase):
self.assertTrue(events_path.exists())
# task.outcome rides the event_bus journal (memory_dir/journal),
# not the operator's task-transition events.jsonl.
from rune import event_bus as _eb
journal_dir = Path(_eb.JOURNAL_DIR)
outcomes = []
if journal_dir.exists():
for j in journal_dir.glob("*.jsonl"):
+45
View File
@@ -0,0 +1,45 @@
"""test_tool_parity.py — TTY-repair tranche: canonical tool hash parity.
The installed MiMo tools MUST match the canonical sources
(same contract as test_hook_parity for hooks)."""
from __future__ import annotations
import hashlib
import os
from pathlib import Path
REPO = Path(__file__).resolve().parent.parent
TOOLS = ("bash.ts", "await-operation.ts")
def _canonical(name: str) -> Path:
return REPO / "config" / "mimo-tools" / name
def _installed(name: str) -> Path:
home = os.environ.get("RUNE_HOOK_TARGET_HOME", "/home/nick")
return Path(home) / ".mimocode" / "tools" / name
def _sha(p: Path) -> str:
return hashlib.sha256(p.read_bytes()).hexdigest()
def test_canonical_sources_exist():
for name in TOOLS:
assert _canonical(name).is_file(), f"missing canonical {name}"
def test_installed_matches_canonical():
for name in TOOLS:
inst = _installed(name)
assert inst.is_file(), f"tool missing at {inst}"
assert _sha(_canonical(name)) == _sha(inst), (
f"TOOL DRIFT: {name} canonical={_sha(_canonical(name))[:12]} "
f"installed={_sha(inst)[:12]} — run "
f"python3 scripts/install_mimo_tools.py to sync"
)
def test_installer_exists():
assert (REPO / "scripts/install_mimo_tools.py").is_file()