mirror of
https://github.com/razzant/ouroboros.git
synced 2026-10-02 19:58:46 +00:00
Plan review: hot-index eviction never drops the newest paid wave
Delta review round 4 found the last boundary of the same seam: the hot index keeps at most 64 waves and evicted the OLDEST entries, so after 64 unpaid revisions (every seat refused at $0) the only paid wave left the index, the next revision judged against nothing and a refused objector's finding vanished into GREEN. Eviction now drops the oldest entries other than the newest paid wave, within the same limit; waves_omitted counts what was dropped. Test: the 63/64 boundary pin through the engine (64 unpaid revisions, then a refused objector still carries the paid wave's finding). Co-authored-by: Ouroboros <311266734+ouroboros-agent@users.noreply.github.com>
This commit is contained in:
parent
e09cb1851b
commit
bb93c9eb34
2 changed files with 31 additions and 3 deletions
|
|
@ -1502,9 +1502,11 @@ def record_plan_review_wave(
|
|||
for idx, w in enumerate(waves)
|
||||
]
|
||||
overflow = max(0, len(waves) - _PLAN_REVIEW_MAX_WAVES)
|
||||
if overflow:
|
||||
state["waves_omitted"] = int(state.get("waves_omitted") or 0) + overflow
|
||||
waves = waves[overflow:]
|
||||
if overflow: # the newest PAID wave stays reachable: the next dispatch judges against it
|
||||
keep = next((i for i in range(len(waves) - 1, -1, -1) if waves[i].get("paid")), None)
|
||||
dropped = set([i for i in range(len(waves)) if i != keep][:overflow])
|
||||
state["waves_omitted"] = int(state.get("waves_omitted") or 0) + len(dropped)
|
||||
waves = [w for i, w in enumerate(waves) if i not in dropped]
|
||||
# I-02: size-fitting (older-wave compaction, then the last-resort text cut) runs for
|
||||
# EVERY writer in `_update_plan_review_state` → `_fit_plan_review_state`.
|
||||
state["waves"] = waves
|
||||
|
|
|
|||
|
|
@ -164,6 +164,32 @@ def test_a_predecessor_without_an_operative_spec_is_unresolved_history_not_a_cha
|
|||
assert _walk([], None) == {} # no predecessor at all is a first wave
|
||||
|
||||
|
||||
def test_the_last_paid_wave_survives_hot_index_eviction(harness, monkeypatch):
|
||||
"""The hot index keeps at most 64 waves; eviction drops the oldest entries but never the
|
||||
newest PAID wave, so after 64 unpaid revisions the next revision still judges against A
|
||||
and a refused objector carries A's finding (the 63/64 boundary)."""
|
||||
from ouroboros.task_results import _PLAN_REVIEW_MAX_WAVES
|
||||
|
||||
monkeypatch.setenv("OUROBOROS_REVIEW_MAX_CYCLES", "20")
|
||||
_patch_health(monkeypatch, lambda slots: {})
|
||||
_effort_aware_builder(harness, monkeypatch)
|
||||
harness.install({"s1": _objection("n1", "Friday is impossible"), "s2": CLEAN, "s3": CLEAN})
|
||||
ctx = harness.make_ctx()
|
||||
assert _control(_call(ctx)) == {"outcome": "REVIEW_REQUIRED", "closed": False}
|
||||
a_fp = _state(harness)["waves"][-1]["request_fingerprint"]
|
||||
for n in range(_PLAN_REVIEW_MAX_WAVES):
|
||||
_install_barrier_substrate(monkeypatch, [], refused={"s1", "s2", "s3"})
|
||||
_call(ctx, plan=f"Revision {n}: outline, then draft.")
|
||||
_collect(ctx, _state(harness)["waves"][-1]["request_fingerprint"])
|
||||
state = _state(harness)
|
||||
assert state["waves_omitted"] >= 1 and len(state["waves"]) == _PLAN_REVIEW_MAX_WAVES
|
||||
assert any(w["request_fingerprint"] == a_fp and w.get("paid") for w in state["waves"])
|
||||
_install_barrier_substrate(monkeypatch, [], refused={"s1"})
|
||||
_call(ctx, plan="The final revision: draft, then outline.")
|
||||
assert _control(_collect(ctx, _state(harness)["waves"][-1]["request_fingerprint"])) == {"outcome": "REVIEW_REQUIRED", "closed": False}
|
||||
assert _carried(harness) == ["s1:n1"]
|
||||
|
||||
|
||||
def test_a_compacted_last_paid_wave_still_owes_its_objection(harness, monkeypatch):
|
||||
"""The hot index keeps eight full waves and compacts older ones. After A (paid, s1
|
||||
objecting) and eight unpaid revisions (every seat refused at $0), A is compact; the
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue