Files
rune/scripts/admit_wave_factory_p2.py
Nick 7dad3e6ce4 feat(runtime+facade): factory protocol phase 2 — TUI surface, seam socket, real queue wiring
- tui/factory: read-only projection — waves as threads in the task tree
  ([r] RESEARCH/[b] BUILD/[d] LANDED + receipt leaves + rung/pin line),
  contracts readable, receipts live, fold into the face's live derivation
- seam socket: factory-orchestration registered (v1.1.0, three current
  consumers, deletion test trips, compat passes, registry GREEN)
- real queue wiring: reconcile kernel spawns real waves from
  docs/factory/spawn-queue.md (mechanical grammar: priority groups
  spawn, deferred blocks on owner, in-flight skipped); proven live via
  CLI; live migration is a main-session actuation
- domain row: factory-protocol registered in domains.json
2026-10-18 01:35:43 +01:00

224 lines
9.2 KiB
Python

"""Admission dispatch for wave wave-factory-p2: B-FACTORY-PROTOCOL
phase 2 — the factory gains its TUI surface + the seam-registry socket
+ the reconcile kernel wired to the REAL spawn queue.
classify + activate + admit (the headless scaffolding entry law,
tests/test_construction_admission.py pattern), admitted through the
research gate on the EXISTING chain research/factory-protocol/
qualify.json (verdict PROCEED, phased: phase 2 = TUI surface + seam
socket + queue wiring), plus the declared owner-directive exemption
for the factory machinery itself: this dispatch's owner approval is
approval_ref 'user:wave-factory-p2 dispatch' and the src/go/factory
change is ADDITIVE queue wiring (queue.go + CLI); the 13-stage
protected-class pipeline binds future non-additive modifications of
the factory runtime, exactly as the phase-1 bootstrap declared.
Artifacts this wave admits: the queue parser + ReconcileQueue + CLI
(src/go/factory/internal/factory/queue.go), the TUI factory surface
(tui/factory — read-only projection + fold into the task tree, wired
into the face's live derivation), the factory-orchestration socket in
the seam registry (schema + consumer fixture + deletion/compat tests),
and the factory-protocol domain row (docs/factory/domains.json).
"""
import json
import os
import subprocess
import sys
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "src"))
from rune import construction_activation as cact # noqa: E402
from rune import construction_admission as cadm # noqa: E402
from rune import construction_mode as cmode # noqa: E402
from rune import scaffold as sc # noqa: E402
ROOT = os.path.join(os.path.dirname(__file__), "..")
SLUG = "wave-factory-p2"
RESEARCH_SLUG = "factory-protocol"
OBJECTIVE = (
"B-FACTORY-PROTOCOL phase 2 — the factory becomes visible and "
"real: (1) the TUI factory surface (tui/factory): a read-only "
"projection of the kernel's durable state (contract store + "
"journal + ladder) that folds waves as threads into the task tree "
"the face renders — worker (phase) states on screen, contracts "
"readable as briefs (key/ref/approval), gate receipts live as "
"journal-activity leaves; wired into the live derivation at the "
"face chain. (2) the factory-orchestration socket in the seam "
"registry (SA-D6 sockets-first) with minimal versioned schema, "
"consumer fixture naming the three current consumers (Go kernel, "
"TUI surface, Python twin), and the frozen deletion + "
"compatibility tests tripping. (3) the reconcile kernel wired to "
"the REAL spawn queue (docs/factory/spawn-queue.md): a mechanical "
"queue grammar derives desired briefs (priority groups spawn, "
"deferred briefs block on owner, in-flight never re-spawns), "
"ReconcileQueue runs ticks over it, and the frozen battery spawns "
"real waves from the real queue document. Plus the "
"factory-protocol domain row in docs/factory/domains.json."
)
AFFECTED = [
"src/go/factory/",
"tui/factory/",
"tui/tasks/tasks.go",
"tui/cmd/rune-tui/main.go",
"docs/seams/registry.json",
"schemas/seams/factory-orchestration.schema.json",
"tests/fixtures/seams/factory-orchestration.json",
"docs/factory/domains.json",
]
EXPECTED_NEW = [
"src/go/factory/internal/factory/queue.go",
"src/go/factory/internal/factory/queue_test.go",
"tui/factory/factory.go",
"tui/factory/fold.go",
"tui/factory/factory_test.go",
"schemas/seams/factory-orchestration.schema.json",
"tests/fixtures/seams/factory-orchestration.json",
"scripts/admit_wave_factory_p2.py",
]
def record_research_gate(marker: str, exemption: str) -> int:
"""Post-mint: pin the gate evidence on the contract's ext.research_gate
record so the contract resolves through the factory-protocol chain +
declared exemption, never through a registry glob. Idempotent."""
store_dir = os.path.join(ROOT, "store", "scaffold")
scaffold = sc.Scaffold(store_dir, "rune")
doc = scaffold.load()
c = scaffold.contract(doc, f"ADMIT-{SLUG}")
if c is None:
print("contract ADMIT-<slug> not found — nothing to record")
return 1
ext = c.setdefault("ext", {})
rg = ext.get("research_gate") or {}
rg.update({
"chain": f"research/{RESEARCH_SLUG}/qualify.json",
"verdict": "PROCEED",
"marker": marker,
"exemption": {
"category": "owner-directive",
"reason": "factory machinery itself — phase-2 ADDITIVE wiring "
"(queue parser + TUI surface + seam socket) under the "
"owner dispatch user:wave-factory-p2; the protected-"
"class 13-stage pipeline binds future non-additive "
"modifications",
"marker": exemption,
},
})
ext["research_gate"] = rg
scaffold.commit(doc, what=f"record research_gate evidence for {SLUG}")
print("research_gate record committed on ADMIT-" + SLUG)
return 0
def main() -> int:
# ── research gate (layer 1, pre-mint): cite the PROCEED chain AND
# declare the owner-directive exemption — both markers land in the
# contract evidence, never silent.
gate = subprocess.run(
[sys.executable, os.path.join("scripts", "check_research_gate.py"),
"admit", "--slug", SLUG, "--objective", OBJECTIVE,
"--research-slug", RESEARCH_SLUG],
capture_output=True, text=True, cwd=ROOT,
)
print(gate.stdout.strip())
if gate.returncode != 0:
print("research gate REFUSED — the law holds even for the factory")
return 1
marker = ""
for line in gate.stdout.splitlines():
if line.startswith("research-gate:ALLOW") or line.startswith("exempt:research-gate:"):
marker = line.strip()
break
if not marker:
print("no ALLOW marker in gate output — refusing to mint unrecorded")
return 1
exemption = (
"exempt:research-gate:owner-directive: factory machinery itself — "
"phase-2 additive wiring (real spawn-queue parser in src/go/factory, "
"TUI factory surface, factory-orchestration seam socket) under the "
"owner dispatch approval_ref user:wave-factory-p2; the "
"protected-class 13-stage pipeline binds future non-additive "
f"modifications; chain research/{RESEARCH_SLUG}/qualify.json "
"verdict=PROCEED also cited"
)
store = os.path.join(ROOT, "store", "scaffold")
scaffold = sc.Scaffold(store, "rune")
md = cmode.classify_mode(
OBJECTIVE,
target_project="rune",
project_exists=True,
affected_surface=AFFECTED,
)
print("classified mode:", md.mode)
need = {
"need_id": f"need-{SLUG}",
"objective": OBJECTIVE,
"origin": "worker",
"project": "rune",
"task_ref": SLUG,
"affected_surface": AFFECTED,
"evidence_refs": [
marker,
exemption,
"research/factory-protocol/qualify.json",
"research/factory-protocol/synthesis.json",
"docs/factory/spawn-queue.md",
],
}
act = cact.activate(md, need=need, scaffold=scaffold,
builder=SLUG)
print("activated:", act.get("activated"), act.get("mode"))
# a re-run mint fails closed on the duplicate contract id (the law
# holding) — the evidence record step below still runs
env = cadm.admit(
act,
objective=OBJECTIVE,
builder=SLUG,
affected_surface=AFFECTED,
evidence_refs=need["evidence_refs"],
origin="worker",
task_ref=SLUG,
expected_new_entities=EXPECTED_NEW,
expected_runtime_effects=[
"factory reconcile --queue: desired state derived mechanically "
"from docs/factory/spawn-queue.md; priority briefs spawn, "
"deferred briefs alert the owner, in-flight never re-spawns; "
"idempotent ticks (content-key identity)",
"TUI task tree gains the factory fold: waves as threads with "
"phase worker-states, contracts readable, gate receipts live "
"as journal leaves; read-only — the surface never actuates",
"seam registry carries the factory-orchestration socket "
"(schema 1.0.0) with passing deletion + compatibility tests "
"and three named current consumers",
],
verification_obligations=[
"go test ./... green in src/go/factory (frozen queue battery: "
"grammar, real-queue parse, real wave spawned + idempotence)",
"go test ./factory/... ./tasks/... ./cmd/... green in tui "
"(frozen TUI surface render battery, -race clean)",
"pytest tests/test_seam_deletion.py + tests/test_seam_compat.py "
"green incl the factory-orchestration cases; "
"scripts/check_seam_registry.py VERDICT GREEN",
],
approval_ref="user:wave-factory-p2 dispatch",
contract_id=f"ADMIT-{SLUG}",
project_store=store,
project_id="rune",
)
print(json.dumps(env, indent=2, default=str)[:2400])
rc = 0 if env.get("success") else 1
if record_research_gate(marker, exemption) != 0:
return 1
return rc
if __name__ == "__main__":
sys.exit(main())