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.
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.
test_15k_build_manager_has_no_parallel_construction_state invoked
BuildManager.start_build for real, which runs 'git worktree add' against
the HARDCODED production path /mnt/workdrive/rune — a real VCS mutation
inside a unit test. Locally it polluted ~/.rune/work/builds; on the CI
runner it fails outright (dubious-ownership: runner checkout is a
different user). The test now redirects BUILDS_DIR/WORKTREE_DIR into tmp
and stubs create_worktree — the property under test (no canonical
construction state from the /build vehicle) is orthogonal to the git op.
This was the CI unit-tests failure on 193d819 (1 failed, 1852 passed).
15N: capabilities() now exposes full argument schemas (types, required
fields, per-item shape, notes), lifecycle phase map + legal transitions,
and scope-amendment authority — a fresh builder DISCOVERS the
report_observation contract instead of trial-and-error (the T14
dict-vs-list + missing-entity mistakes become impossible). Held-out:
schema-guided first report succeeds; schema-violating payload rejected.
15O: audit_scope is PROVENANCE-AWARE — residue paths present before the
builder ran (or explicitly runtime-declared) stay exempt and recorded;
NEW residue-looking paths appearing mid-session (.mimocode/evil,
.git/config) are SCOPE VIOLATIONS. The hostile lookalike can no longer
hide behind the T14 prefix rule.
15P: PROJECT_BUILD bootstrap twice = one project identity (no
duplication); event replay after restart = readback-only recovery
(idempotent by construction, contract-inspected).
15M: src/rune/programme_continuation.py — after EVERY stage completes the
canary asks 'is the programme objective satisfied?'; if open and eligible
stages remain the NEXT stage starts immediately (no user re-prompt, no
voluntary stop); event-wait is PROGRAMME_OPEN_WAITING (no polling);
blocked branches fall back to pre-authorized work; every stop carries an
honest verdict (PROGRAMME_COMPLETE/ALL_REMAINING_BLOCKED/APPROVAL_
REQUIRED/UNKNOWN). 7 held-outs incl. the required 4-stage auto-continuation
proof + durable persist/reload. Bounded to ONE construction programme —
not a Substrate scheduler.
15L: authority boundary record persisted (construction=Scaffolding,
wait=event bridge, research-state continuity=FUTURE Substrate (not
built), research execution=Research Core, TUI=client/projection) +
negative held-out: research intents never PROJECT_BUILD.
15J (native route through the REAL send_task path — TUI input →
RuneOperator.send_task → construction hook → classifier → activation →
durable state):
- 6 held-outs (tests/test_native_default.py): PROJECT_BUILD without any
command; EXISTING attaches Rune authority; LOCAL_CHANGE light; NOT_
CONSTRUCTION touches nothing; UNKNOWN probes without invention; manual
override (/scaffold-mode <MODE>) through the SAME classify_mode with
user provenance
- classifier: explicit FILE mentions ('the README', 'scheduler.js') now
bind scoped targets — deterministic lexical evidence + the ONE surface
authority (classify_surface), lazily imported (cycle-safe)
15K (bypass prevention):
- /build start hardened: classifies through the canonical machinery
BEFORE BuildManager mints any state; NOT_CONSTRUCTION refused;Build-
Manager remains execution vehicle, no longer a construction authority
- inventory: BuildManager provably creates NO canonical scaffolds
Process repairs caught during the stage (15X evidence):
- os.chdir pollution from a test leaked cwd into later tests (bare
os.chdir → monkeypatch.chdir)
- construction-hook tests were making REAL model calls (42s, provider
quota burned, starved stage-telemetry's model call → GATE_FAILED):
send_task's _execute_on_model now stubbed in hook tests — suite 144s
→ 54s and deterministic
- S110 noqa for the deliberate classifier degrade; new modules mapped
into config/umbrellas.json (perception: event_wait, stage_guards)
- suite: 1835 passed, 0 failed