CI Pipeline / best-practices (push) Successful in 8s
CI Pipeline / documentation (push) Successful in 4s
CI Pipeline / canary (push) Successful in 35s
CI Pipeline / lint (push) Successful in 44s
Auto-version and Release / release (push) Successful in 46s
CI Pipeline / gitea-offline (push) Successful in 17s
CI Pipeline / unit-tests (push) Failing after 1m0s
CI Pipeline / type-check (push) Successful in 28s
CI Pipeline / required-checks (push) Successful in 1s
deploy / deploy (push) Successful in 2m51s
PART 6 of the overnight handoff. IntentRecord (7 fields: objective, parent_intent, active_detour, return_when, return_to, unresolved_obligations, success_condition) + IntentLedger (JSON persistence, no LLM). Classifications: BLOCKER | FIX | EXTENSION | SUPERSEDING | ORTHOGONAL | LATER. All 7 invariants tested: new ideas never replace the active objective; detours preserve parents; resolving a detour exposes the return point; supersession accounts for open obligations; child completion never resolves the parent; persist/reload round-trips; transitions are deterministic. 1309 green.
79 lines
2.8 KiB
Python
79 lines
2.8 KiB
Python
"""Intent continuity foundation (overnight handoff PART 6): deterministic
|
|
state machine, persistence, and all seven invariants."""
|
|
|
|
import json
|
|
import sys
|
|
import tempfile
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parent.parent
|
|
sys.path.insert(0, str(ROOT / "src"))
|
|
|
|
from rune.intent_continuity import IntentLedger, IntentRecord, CLASSIFICATIONS # noqa: E402
|
|
|
|
|
|
class TestIntentLedger:
|
|
def _fresh(self):
|
|
return IntentLedger(Path(tempfile.mkdtemp()) / "intent.json")
|
|
|
|
def test_create_and_reload(self):
|
|
"""Invariant 6: state is persistable/reloadable."""
|
|
led = self._fresh()
|
|
led.create(
|
|
id="root",
|
|
objective="ship PL1",
|
|
classification="BLOCKER",
|
|
success_condition="held-out transfer demonstrated",
|
|
)
|
|
led2 = IntentLedger(led.path)
|
|
assert "root" in led2.records
|
|
assert led2.records["root"].status == "ACTIVE"
|
|
|
|
def test_detour_preserves_parent(self):
|
|
"""Invariants 1-3."""
|
|
led = self._fresh()
|
|
led.create(id="root", objective="ship PL1", classification="BLOCKER")
|
|
detour = led.create_detour(
|
|
id="d",
|
|
objective="add scaffolding",
|
|
classification="EXTENSION",
|
|
parent_intent="root",
|
|
return_when="PL1 done",
|
|
return_to="root",
|
|
)
|
|
assert detour.status == "DETOUR"
|
|
assert led.records["root"].status == "PARKED"
|
|
parent = led.resolve_detour("d")
|
|
assert parent.id == "root"
|
|
assert parent.status == "ACTIVE"
|
|
assert led.records["d"].status == "RESOLVED"
|
|
|
|
def test_supersession_carries_obligations(self):
|
|
"""Invariant 4."""
|
|
led = self._fresh()
|
|
led.create(id="old", objective="old plan", classification="FIX")
|
|
led.records["old"].unresolved_obligations = ["review PR", "update docs"]
|
|
new = led.supersede("old", "new", objective="new plan", classification="FIX")
|
|
assert "review PR" in new.unresolved_obligations
|
|
assert led.records["old"].status == "SUPERSEDED"
|
|
|
|
def test_child_doesnt_resolve_parent(self):
|
|
"""Invariant 5: resolving a child doesn't resolve the parent."""
|
|
led = self._fresh()
|
|
led.create(id="p", objective="parent", classification="BLOCKER")
|
|
led.create_detour(
|
|
id="c", objective="child", classification="FIX", parent_intent="p", return_when="done", return_to="p"
|
|
)
|
|
led.resolve("c")
|
|
assert led.records["p"].status == "PARKED" # still parked
|
|
led.resolve_detour("c")
|
|
assert led.records["p"].status == "ACTIVE"
|
|
|
|
def test_classification_validated(self):
|
|
led = self._fresh()
|
|
try:
|
|
led.create(id="bad", objective="x", classification="UNICORN")
|
|
assert False, "should have raised"
|
|
except ValueError:
|
|
pass
|