Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
804c2f62df | ||
|
|
e5d10f18ae | ||
|
|
6c997b6af4 | ||
|
|
55f268f978 |
No files matched your search
@@ -1,6 +1,6 @@
|
||||
# Rune
|
||||
|
||||
**Current release: v0.99.3**
|
||||
**Current release: v0.99.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.**
|
||||
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "rune"
|
||||
version = "0.99.3"
|
||||
version = "0.99.4"
|
||||
description = "Rune — a stateful coding assistant with persistent memory, orchestration, and TUI"
|
||||
requires-python = ">=3.10"
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ This is the main entry point for the Rune program.
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
__version__ = "0.99.3"
|
||||
__version__ = "0.99.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
|
||||
|
||||
@@ -233,7 +233,7 @@ def main() -> int:
|
||||
)
|
||||
check(
|
||||
"Rune minor version advertises provisioning and restore verification",
|
||||
'__version__ = "0.99.3"' in rune_version,
|
||||
'__version__ = "0.99.4"' in rune_version,
|
||||
failures,
|
||||
)
|
||||
# #169 policy update: auto-bump on merge is sanctioned (Nick directive:
|
||||
|
||||
@@ -171,3 +171,98 @@ def _accept(command_id: str, construction_id: str, correlation_id: str,
|
||||
"recorded_at": time.strftime("%Y-%m-%dT%H:%M:%SZ",
|
||||
time.gmtime()),
|
||||
"idempotent_replay": False}
|
||||
|
||||
|
||||
def dispatch(command_type: str, *, construction_id: str,
|
||||
correlation_id: str = "", command_id: str = "",
|
||||
payload: dict | None = None,
|
||||
store_path: str = "store/scaffold") -> dict:
|
||||
"""The SERVING layer (T5.15 slice 2): validate the command against the
|
||||
canonical store, execute the accepted intent through the Construction
|
||||
Interface, and return the interface's envelope with the command
|
||||
provenance attached.
|
||||
|
||||
Single entry point for `rune scaffold <command>` (the Go proxy) and
|
||||
any future transport. Idempotency: a repeated command_id replays the
|
||||
recorded outcome without re-executing.
|
||||
|
||||
Refusal still returns success=False envelope? NO — a refused command
|
||||
is a VALID protocol outcome: the envelope carries accepted=False and
|
||||
success=True (the dispatch itself worked; the lifecycle refused the
|
||||
intent). Execution failures carry success=False.
|
||||
"""
|
||||
iface_path = None
|
||||
if store_path and store_path != "store/scaffold":
|
||||
iface_path = store_path
|
||||
try:
|
||||
from rune import construction_interface as ci
|
||||
|
||||
# store_path carries the serving layer's "path|project_id" contract
|
||||
# (a bare path = last segment is the project id, matching how the
|
||||
# Go proxy and the interface's own default name it).
|
||||
if iface_path:
|
||||
path_part, _, proj_part = iface_path.partition("|")
|
||||
proj = proj_part or path_part.rstrip("/").split("/")[-1]
|
||||
iface = ci.ConstructionInterface(builder="substrate",
|
||||
project_store=path_part,
|
||||
project_id=proj)
|
||||
else:
|
||||
iface = ci.ConstructionInterface(builder="substrate")
|
||||
except Exception as exc: # noqa: BLE001 — serving failure is an envelope, not a crash
|
||||
return {"accepted": False, "executed": False,
|
||||
"success": False, "error": f"serving unavailable: {exc}"[:200],
|
||||
"command_type": command_type,
|
||||
"construction_id": construction_id}
|
||||
|
||||
intent = command(command_type, construction_id=construction_id,
|
||||
correlation_id=correlation_id, command_id=command_id,
|
||||
payload=payload, scaffold=iface.scaffold)
|
||||
if intent.get("idempotent_replay"):
|
||||
# Repeated delivery: return the recorded outcome WITHOUT executing
|
||||
# again (the ledger's whole point). The first execution's envelope
|
||||
# is not re-derivable here, so the replay carries the intent and
|
||||
# the flag — the caller knows the effect already happened.
|
||||
return {"accepted": True, "executed": False,
|
||||
"success": True, "idempotent_replay": True,
|
||||
"op": intent.get("op"),
|
||||
"command_type": command_type,
|
||||
"construction_id": construction_id,
|
||||
"correlation_id": intent.get("correlation_id", ""),
|
||||
"command_id": intent.get("command_id", "")}
|
||||
if not intent.get("accepted"):
|
||||
return {"accepted": False, "executed": False, "success": True,
|
||||
"reason": intent.get("reason"),
|
||||
"command_type": command_type,
|
||||
"construction_id": construction_id,
|
||||
"correlation_id": intent.get("correlation_id", ""),
|
||||
"command_id": intent.get("command_id", ""),
|
||||
"idempotent_replay": intent.get("idempotent_replay", False)}
|
||||
|
||||
op = intent["op"]
|
||||
args = intent["args"]
|
||||
ops = {
|
||||
"resume": lambda: iface.resume(args["contract_id"]),
|
||||
"transition": lambda: iface.transition(
|
||||
args["contract_id"], args["phase"],
|
||||
evidence_ref=f"command:{intent['command_id']}"
|
||||
+ (f" approved_by:{args['approved_by']}" if args.get("approved_by") else "")),
|
||||
"amend_scope": lambda: iface.amend_scope(
|
||||
args["contract_id"], args["add_paths"],
|
||||
reason=args.get("reason", "substrate context"),
|
||||
authority=args.get("authority", "substrate")),
|
||||
}
|
||||
fn = ops.get(op)
|
||||
if fn is None:
|
||||
return {"accepted": True, "executed": False, "success": False,
|
||||
"error": f"no executor for op {op!r}",
|
||||
"command_type": command_type,
|
||||
"construction_id": construction_id}
|
||||
env = fn()
|
||||
return {"accepted": True, "executed": True,
|
||||
"success": bool(env.get("success")),
|
||||
"envelope": env,
|
||||
"command_type": command_type,
|
||||
"construction_id": construction_id,
|
||||
"correlation_id": intent.get("correlation_id", ""),
|
||||
"command_id": intent.get("command_id", ""),
|
||||
"idempotent_replay": False}
|
||||
@@ -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.99.3
|
||||
Version: v0.99.4
|
||||
Features: 41 (24 original + 17 new native commands)
|
||||
|
||||
Usage:
|
||||
@@ -1895,7 +1895,7 @@ class RuneApp(App):
|
||||
# Show version info
|
||||
self.chat_channel.add_message(
|
||||
"system",
|
||||
f"[dim]Rune v0.99.3 | Textual TUI | {len(loaded)} native modules[/dim]",
|
||||
f"[dim]Rune v0.99.4 | Textual TUI | {len(loaded)} native modules[/dim]",
|
||||
)
|
||||
|
||||
# Auto-show night mode suggestion if evening/night hours
|
||||
|
||||
@@ -174,3 +174,76 @@ def test_16k_projection_schema_validated(tmp_path):
|
||||
assert proj.validate(bad) != []
|
||||
bad2 = dict(p, schema_version=999)
|
||||
assert proj.validate(bad2) != []
|
||||
|
||||
|
||||
# ── T5.15 slice 2: the dispatch wire (command → interface execution) ────────
|
||||
|
||||
|
||||
def test_dispatch_executes_accepted_transition_end_to_end(tmp_path):
|
||||
"""A START command on a draft contract executes through the interface:
|
||||
the phase actually moves — not just an accepted intent."""
|
||||
store = str(tmp_path / ".rune" / "scaffold")
|
||||
iface = cmds if False else None # noqa: F841 — readability anchor
|
||||
from rune import construction_interface as ci
|
||||
ciface = ci.ConstructionInterface(builder="seed", project_store=store, project_id="proj")
|
||||
ciface.scaffold.init(purpose="t")
|
||||
doc = ciface.scaffold.load()
|
||||
sc.add_entity(doc, id="contract:disp-1", kind="contract",
|
||||
identities={"objective": "dispatch"}, evidence_refs=["e"])
|
||||
doc["entities"][-1]["phase"] = "draft"
|
||||
ciface.scaffold.commit(doc, what="seed")
|
||||
out = cmds.dispatch("START", construction_id="disp-1",
|
||||
store_path=store + "|proj")
|
||||
# external-project store path: dispatch builds its own interface bound
|
||||
# to the same store
|
||||
assert out["executed"] is True, out
|
||||
assert out["success"] is True, out
|
||||
doc2 = ciface.scaffold.load()
|
||||
c = sc.entity(doc2, "contract:disp-1")
|
||||
assert c["phase"] == "approved"
|
||||
|
||||
|
||||
def test_dispatch_refusal_is_a_valid_protocol_outcome(tmp_path):
|
||||
"""START on a non-draft contract: the lifecycle refuses — the dispatch
|
||||
itself succeeds (success=True) with accepted=False."""
|
||||
store = str(tmp_path / ".rune" / "scaffold")
|
||||
from rune import construction_interface as ci
|
||||
ciface = ci.ConstructionInterface(builder="seed", project_store=store, project_id="proj")
|
||||
ciface.scaffold.init(purpose="t")
|
||||
doc = ciface.scaffold.load()
|
||||
sc.add_entity(doc, id="contract:disp-2", kind="contract",
|
||||
identities={"objective": "x"}, evidence_refs=["e"])
|
||||
doc["entities"][-1]["phase"] = "draft"
|
||||
ciface.scaffold.commit(doc, what="seed")
|
||||
out = cmds.dispatch("START", construction_id="disp-2",
|
||||
payload={"phase": "building"},
|
||||
store_path=store + "|proj")
|
||||
# contract starts in draft so START is ACCEPTED here; drive to building
|
||||
# first to prove the refusal shape:
|
||||
assert out["executed"] and out["success"]
|
||||
out2 = cmds.dispatch("START", construction_id="disp-2",
|
||||
store_path=store + "|proj")
|
||||
assert out2["accepted"] is False and out2["executed"] is False
|
||||
assert out2["success"] is True
|
||||
assert "draft" in out2["reason"]
|
||||
|
||||
|
||||
def test_dispatch_idempotent_replay_does_not_double_execute(tmp_path):
|
||||
"""Same command_id twice: the second is a replay — the phase does not
|
||||
move twice and idempotent_replay=True comes back."""
|
||||
store = str(tmp_path / ".rune" / "scaffold")
|
||||
from rune import construction_interface as ci
|
||||
ciface = ci.ConstructionInterface(builder="seed", project_store=store, project_id="proj")
|
||||
ciface.scaffold.init(purpose="t")
|
||||
doc = ciface.scaffold.load()
|
||||
sc.add_entity(doc, id="contract:disp-3", kind="contract",
|
||||
identities={"objective": "idem"}, evidence_refs=["e"])
|
||||
doc["entities"][-1]["phase"] = "draft"
|
||||
ciface.scaffold.commit(doc, what="seed")
|
||||
first = cmds.dispatch("START", construction_id="disp-3",
|
||||
command_id="fixed-cmd-1", store_path=store + "|proj")
|
||||
assert first["executed"] and first["success"]
|
||||
second = cmds.dispatch("START", construction_id="disp-3",
|
||||
command_id="fixed-cmd-1", store_path=store + "|proj")
|
||||
assert second["idempotent_replay"] is True
|
||||
assert second.get("executed") in (False, None) # replay ≠ execution
|
||||
Reference in new issue
Block a user