- K27 receipt presentation: full decision+evidence+effect packages, expandable sections, UNKNOWN-never-success in every dimension state, spine verdicts via evidence.Evaluate (read-only import) - 2.6-depth compaction: append-per-message (O(1) tail line, 198 bytes steady-state), compaction every 64 appends (512/channel hot), cool archives per memory-continuity contract, nothing deleted, exact-by-ID across compaction+restart+tamper, legacy checkpoints heal on load - K27 composer depth: 3-line input per old TUI contracts (§2.3 history walk, placeholder, stash/restore), deterministic natural-language resolution (40+ pinned phrases), palette natural-tier + ctrl+p bind, Accessibility profile (keyboard-only/no-color/reduced-motion) - K27 themes: 10 fixed Go theme tables (byte-exact from Textual 8.2.8, not guessed; nord/dracula-default/monokai/solarized/catppuccin/tokyo- night/flexoki/gruvbox), /theme command (mirrors _cmd_theme exactly), live-editor data shape (staged per-token preview overrides), base bg rgb(30,30,40), no-drift drift test anchoring Go to retiring Python - Sleight live wiring: operator._context_broker registers seventh contributor 'continuity' (bucket 2, fail-closed); K16 allowlist amended (memory_continuity.working_set); matrices now run against the live road; 102 tests green - .gitignore hygiene: directory-level traps fixed (internal/ re-includes .go/.json/.md only; root-anchored /index/ /journal/ /state/; fixtures + testdata re-included at any depth); 6-test frozen gate; unified_check member wired; real git add (no -f) proven on testmod/internal - Receipts, compaction, composer, themes, sleight-wiring, hygiene all under ADMIT contracts (101+ contracts, 0 research-gate violations) - main.go NOT landed (chat-live P1 wave owns it, still in flight)
201 lines
8.1 KiB
Python
201 lines
8.1 KiB
Python
"""Admission dispatch for wave wave-compaction: spec 2.6 depth — the
|
|
conversation checkpoint stops growing unbounded.
|
|
|
|
classify + activate + admit (the headless scaffolding entry law,
|
|
scripts/admit_wave_chat_live_p1.py pattern), admitted through the
|
|
research gate on the chain research/factory-chat-live/07-qualify.json
|
|
(verdict PROCEED — the chain's terminal QUALIFY artifact). The chain's
|
|
adversarial break #5 ("CHECKPOINT GROWTH / WRITE AMPLIFICATION",
|
|
6372 msgs / 1.7MB rewritten on EVERY append) names this exact work and
|
|
its mitigation (O(1) msg_id dedupe + append-only JSONL tail + periodic
|
|
snapshot compaction); the synthesis lists it as the phase-3 depth item.
|
|
|
|
Artifacts this wave admits: (a) incremental append — one JSONL line per
|
|
message, fsync'd, NO full checkpoint rewrite per message (the hot
|
|
checkpoint moves only on compaction); (b) the compaction policy —
|
|
compaction keeps the last N messages per channel hot and cools older
|
|
messages through the memory-continuity runtime's cooling contract
|
|
(durable per-channel checkpoint files with content digests, typed
|
|
exact-by-ID reads, cooling is attention release, never deletion); (c)
|
|
red-first frozen tests: append-per-message proof, exact-by-ID reads
|
|
across compaction, cool-path search.
|
|
"""
|
|
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-compaction"
|
|
RESEARCH_SLUG = "factory-chat-live"
|
|
|
|
OBJECTIVE = (
|
|
"Build the spec-2.6-depth conversation checkpoint compaction: the "
|
|
"ConversationStateRepository stops rewriting the full hot checkpoint "
|
|
"on every message (6372 msgs / 1.7MB per append today, write "
|
|
"amplification compounding forever). (a) Incremental append: each "
|
|
"message appends one fsync'd JSONL line to a tail file with an O(1) "
|
|
"msg_id dedupe set (replacing the O(bucket) scan); the hot "
|
|
"checkpoint moves ONLY on compaction, never per message. "
|
|
"(b) Compaction policy, periodic: the checkpoint is rewritten from "
|
|
"the tail keeping the last N messages per channel hot while older "
|
|
"messages cool through the memory-continuity runtime's cooling "
|
|
"contract — durable per-channel cool files carrying each record "
|
|
"with a content digest, cooling releases the hot window without "
|
|
"deleting anything, and recovery replays checkpoint + tail with "
|
|
"corrupt files a typed loud error. (c) Red-first frozen tests: "
|
|
"append-per-message proof (byte-identical checkpoint across "
|
|
"appends, exactly one tail line per message), compaction preserves "
|
|
"exact-by-ID reads (every msg_id, hot and cooled, returns the exact "
|
|
"record pre- and post-restart), cool path preserves search (cool-tier "
|
|
"messages remain searchable by content with tier attribution)."
|
|
)
|
|
AFFECTED = [
|
|
"src/rune/orchestration/conversation_state.py",
|
|
"tests/test_conversation_checkpoint_compaction.py",
|
|
"docs/conversation-state.md",
|
|
"scripts/admit_wave_compaction.py",
|
|
]
|
|
|
|
EXPECTED_NEW = [
|
|
"tests/test_conversation_checkpoint_compaction.py",
|
|
"scripts/admit_wave_compaction.py",
|
|
]
|
|
|
|
|
|
def record_research_gate(marker: str) -> int:
|
|
"""Post-mint: pin the gate evidence on the contract's ext.research_gate
|
|
record so the contract resolves through the chat-live chain, 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}/07-qualify.json",
|
|
"verdict": "PROCEED",
|
|
"marker": marker,
|
|
})
|
|
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:
|
|
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")
|
|
return 1
|
|
marker = ""
|
|
for line in gate.stdout.splitlines():
|
|
if line.startswith("research-gate:ALLOW"):
|
|
marker = line.strip()
|
|
break
|
|
if not marker:
|
|
print("no ALLOW marker in gate output — refusing to mint unrecorded")
|
|
return 1
|
|
|
|
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,
|
|
"research/factory-chat-live/07-qualify.json",
|
|
"research/factory-chat-live/06-synthesis.json",
|
|
"research/factory-chat-live/05-adversarial.json",
|
|
"docs/openspec/changes/add-native-rune-tui/tasks.md",
|
|
"src/rune/orchestration/conversation_state.py",
|
|
],
|
|
}
|
|
act = cact.activate(md, need=need, scaffold=scaffold,
|
|
builder=SLUG)
|
|
print("activated:", act.get("activated"), act.get("mode"))
|
|
|
|
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=[
|
|
"appending a conversation message writes one fsync'd JSONL "
|
|
"line and rewrites nothing else — the hot checkpoint file is "
|
|
"byte-identical (same inode) across appends below the "
|
|
"compaction threshold",
|
|
"msg_id dedupe is O(1) (a loaded id set), not a bucket scan",
|
|
"compaction folds the tail into the hot checkpoint keeping "
|
|
"the last N messages per channel hot; older messages cool "
|
|
"into per-channel memory-continuity cool files carrying "
|
|
"content digests — nothing is deleted",
|
|
"exact-by-ID reads (get_message) span hot, tail, and cool "
|
|
"tiers with typed statuses (FOUND_VERIFIED / "
|
|
"SOURCE_CORRUPT / NOT_FOUND_CONFIRMED) and survive restart",
|
|
"search spans hot and cool tiers with tier attribution, so "
|
|
"cooled history stays searchable",
|
|
"recovery = checkpoint + tail replay with msg_id dedupe; a "
|
|
"corrupt tail or checkpoint is a typed loud error, never a "
|
|
"silent reset",
|
|
],
|
|
verification_obligations=[
|
|
"PYTHONPATH=src python -m pytest "
|
|
"tests/test_conversation_checkpoint_compaction.py -q green "
|
|
"(red-first: RED before implementation)",
|
|
"PYTHONPATH=src python -m pytest "
|
|
"tests/test_orchestration_conversation_state.py "
|
|
"tests/test_orchestration_atomic.py "
|
|
"tests/test_orchestration_event_store.py -q green (no "
|
|
"regressions in the orchestration persistence stack)",
|
|
],
|
|
approval_ref=f"user:{SLUG} 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) != 0:
|
|
return 1
|
|
return rc
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|