CI Pipeline / best-practices (push) Successful in 8s
Auto-version and Release / release (push) Failing after 14s
CI Pipeline / documentation (push) Successful in 5s
CI Pipeline / lint (push) Failing after 34s
CI Pipeline / canary (push) Successful in 37s
CI Pipeline / type-check (push) Successful in 31s
CI Pipeline / gitea-offline (push) Successful in 16s
CI Pipeline / unit-tests (push) Successful in 1m4s
CI Pipeline / required-checks (push) Successful in 1s
deploy / deploy (push) Successful in 48s
CORRECTION 1: #314 reopened — recall_with_associations mode field defect CONFIRMED in current source and FIXED (mode: association_merged). CORRECTION 3: Gitea credential removed from remote URL (credential helper). TOKEN EXPOSED: yes (in diagnostic output). TOKEN ROTATED: not yet (requires Gitea web UI access). Remote URL now shows username only, no secret. CORRECTION 4: duplicate-release-commit defect ROOT CAUSE: convergence computed warranted bump from commits-since-tag without checking if master version already satisfies the bump. FIX: already-converged guard in version_convergence.py (master version > last tag → no commit). Repo-aware (args.repo passed to read_version/latest_tag). CORRECTION 6: lifecycle terminalization — execution exception now guarantees task terminalizes as failed with evidence (no immortal RUNNING). CORRECTION 7: route instruction task-scoped on RuneTask.route_instruction (NOT shared operator state). Read-only leading-verb override. Isolation tests prove no cross-contamination between interleaved tasks. PL1-01/02/03/05: pl1_records.py (route resolution, proof level, failure class, candidate status), metrics with honest NOT_YET_MEASURABLE semantics, route-instruction learning loop (PE-1789102658-0269 SEED). 1253 tests green; ratchet 352/80 (shrink); henxels clean.
145 lines
4.5 KiB
Python
145 lines
4.5 KiB
Python
"""Canonical orchestration records — round-trip and schema invariants."""
|
|
|
|
import json
|
|
|
|
from rune.orchestration.records import (
|
|
ApprovalRecord,
|
|
EffectRecord,
|
|
EventEnvelope,
|
|
EvidenceCapsule,
|
|
OutboxRecord,
|
|
PinRecord,
|
|
ProjectionCheckpoint,
|
|
ProposalRecord,
|
|
ReceiptRecord,
|
|
ResourceSnapshot,
|
|
SCHEMA_VERSION,
|
|
new_id,
|
|
)
|
|
|
|
|
|
def test_event_envelope_round_trip_and_invariants():
|
|
env = EventEnvelope(
|
|
event_type="work.requested",
|
|
partition_key="agent:rune",
|
|
actor_id="nick",
|
|
authorization="approval:plan-v7",
|
|
)
|
|
env.payload_hash = "sha256:abc"
|
|
restored = EventEnvelope.from_dict(env.to_dict())
|
|
assert restored == env
|
|
assert restored.event_id.startswith("evt_")
|
|
assert restored.parent_id is None
|
|
assert restored.schema_version == SCHEMA_VERSION
|
|
assert restored.timestamp # non-empty ISO timestamp
|
|
|
|
|
|
def test_envelope_requires_payload_hash_after_materialize():
|
|
env = EventEnvelope(event_type="tool.result", partition_key="p")
|
|
assert env.payload_hash == "" # pre-materialize
|
|
|
|
|
|
def test_evidence_capsule_content_hash_field():
|
|
cap = EvidenceCapsule(digest="sha256:deadbeef", size=12)
|
|
assert cap.to_dict()["digest"] == "sha256:deadbeef"
|
|
|
|
|
|
def test_receipt_record_carries_verifier_and_state():
|
|
rec = ReceiptRecord(
|
|
unit_id="batch:1",
|
|
verifier="canary:suite",
|
|
state="verified",
|
|
evidence_refs=("sha256:aaa",),
|
|
)
|
|
assert ReceiptRecord.from_dict(rec.to_dict()) == rec
|
|
|
|
|
|
def test_effect_record_has_idempotency_key_and_attempt_state():
|
|
eff = EffectRecord(unit_id="batch:1", idempotency_key="req_1", state="leased")
|
|
assert eff.to_dict()["idempotency_key"] == "req_1"
|
|
assert EffectRecord.from_dict(eff.to_dict()) == eff
|
|
|
|
|
|
def test_approval_records_plan_version_and_revoked_flag():
|
|
app = ApprovalRecord(approver="nick", plan_version="plan:v7", approved_items=("batch:1", "batch:2"))
|
|
assert app.revoked is False
|
|
assert ApprovalRecord.from_dict(app.to_dict()) == app
|
|
|
|
|
|
def test_pin_record_kind_and_owner_lease():
|
|
pin = PinRecord(kind="batch", item_id="batch:1", owner="scheduler")
|
|
assert PinRecord.from_dict(pin.to_dict()) == pin
|
|
|
|
|
|
def test_outbox_record_conflict_state_and_resolver():
|
|
out = OutboxRecord(
|
|
mutation_id="mut_1",
|
|
remote_target="gitea://rune/issues",
|
|
expected_remote_version=3,
|
|
state="conflict",
|
|
resolver="nick",
|
|
)
|
|
assert OutboxRecord.from_dict(out.to_dict()) == out
|
|
|
|
|
|
def test_projection_checkpoint_carries_offset_and_hash():
|
|
cp = ProjectionCheckpoint(offset=42, state_hash="sha256:state")
|
|
assert ProjectionCheckpoint.from_dict(cp.to_dict()) == cp
|
|
|
|
|
|
def test_new_id_prefixes():
|
|
assert new_id("evt").startswith("evt_")
|
|
assert len(new_id("evt")) > 8
|
|
|
|
|
|
def test_proposal_record_round_trip():
|
|
prop = ProposalRecord(worker="n1", action="surface", evidence_refs=("sha256:a",), confidence=0.8)
|
|
assert ProposalRecord.from_dict(prop.to_dict()) == prop
|
|
|
|
|
|
def test_resource_snapshot_round_trip():
|
|
snap = ResourceSnapshot(
|
|
resource_id="provider:zai",
|
|
healthy=False,
|
|
capabilities=("chat",),
|
|
locality="local",
|
|
evidence_age_s=1.5,
|
|
)
|
|
assert ResourceSnapshot.from_dict(snap.to_dict()) == snap
|
|
|
|
|
|
def test_evidence_capsule_round_trip():
|
|
cap = EvidenceCapsule(digest="sha256:abc", size=3, source="tool:read")
|
|
assert EvidenceCapsule.from_dict(cap.to_dict()) == cap
|
|
|
|
|
|
def test_json_round_trip_preserves_tuples():
|
|
prop = ProposalRecord(
|
|
worker="n1",
|
|
action="surface",
|
|
evidence_refs=("sha256:a", "sha256:b"),
|
|
confidence=0.8,
|
|
)
|
|
restored = ProposalRecord.from_dict(json.loads(json.dumps(prop.to_dict())))
|
|
assert restored == prop
|
|
assert restored.evidence_refs == ("sha256:a", "sha256:b")
|
|
|
|
|
|
def test_json_round_trip_approval_items_and_receipt_refs():
|
|
app = ApprovalRecord(approver="nick", plan_version="plan:v7", approved_items=("batch:1", "batch:2"))
|
|
assert ApprovalRecord.from_dict(json.loads(json.dumps(app.to_dict()))) == app
|
|
rec = ReceiptRecord(
|
|
unit_id="batch:1",
|
|
verifier="suite",
|
|
state="verified",
|
|
evidence_refs=("sha256:a",),
|
|
)
|
|
assert ReceiptRecord.from_dict(json.loads(json.dumps(rec.to_dict()))) == rec
|
|
|
|
|
|
def test_json_round_trip_resource_capabilities():
|
|
snap = ResourceSnapshot(resource_id="p", healthy=True, capabilities=("chat", "tools"), locality="local")
|
|
restored = ResourceSnapshot.from_dict(json.loads(json.dumps(snap.to_dict())))
|
|
assert restored == snap
|
|
assert restored.capabilities == ("chat", "tools")
|