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.
35 lines
1.1 KiB
Python
35 lines
1.1 KiB
Python
"""Content fingerprint and deterministic no-change suppression."""
|
|
|
|
from rune.orchestration.no_change import NoChangeGate, content_fingerprint
|
|
|
|
|
|
def test_content_fingerprint_is_order_insensitive():
|
|
assert content_fingerprint({"a": 1, "b": 2}) == content_fingerprint({"b": 2, "a": 1})
|
|
|
|
|
|
def test_content_fingerprint_is_sensitive_to_values():
|
|
assert content_fingerprint({"a": 1}) != content_fingerprint({"a": 2})
|
|
|
|
|
|
def test_gate_skips_only_identical_repeat():
|
|
gate = NoChangeGate()
|
|
fp = content_fingerprint({"x": 1})
|
|
assert gate.should_run(fp) is True # first occurrence
|
|
gate.record(fp)
|
|
assert gate.should_run(fp) is False # unchanged -> skip
|
|
assert gate.should_run(content_fingerprint({"x": 2})) is True # changed -> run
|
|
|
|
|
|
def test_gate_is_per_instance():
|
|
a = NoChangeGate()
|
|
b = NoChangeGate()
|
|
fp = content_fingerprint({"x": 1})
|
|
a.record(fp)
|
|
assert a.should_run(fp) is False
|
|
assert b.should_run(fp) is True # other cadence unaffected
|
|
|
|
|
|
def test_gate_never_skips_none_fingerprint():
|
|
gate = NoChangeGate()
|
|
assert gate.should_run(None) is True # no evidence seen yet -> must run
|