fix(major2): --proposal-review komponerer med --resume, og armen som beviser det
To funn, ETT commit, fordi de deler vitnet ved konstruksjon: 02159d21 (run.py:2738, PLAN_EXECUTE_DRIFT) er vakten, da485928 (tests/...:1344, MISSING_TEST) er armen som skulle sett den. AA dele dem ville krevd en kastbar duplikattest. VAKTEN: `if args.checkpoint_dir is not None` nektet --proposal-review for HVER argv med en checkpoint-katalog - men --resume KREVER --checkpoint-dir (run.py:2776), saa komposisjonen nekten selv anbefaler («pass --proposal-review at --resume instead») var unaabar, og run.py:2218-helpen, README.md:546 og MAJOR-2-raden beskrev en sti ingen argv kunne ta. Vakten nekter naa en PARK (en etappe som returnerer foer noen kandidat finnes), aldri et LOEFT. ARMEN: `test_the_door_composes_with_resume` sendte hverken --resume, --checkpoint-dir eller --review-inbox - den var en vanlig enkeltkjoering T13 allerede dekket, altsaa groenn mot nettopp den defekten den var navngitt for. Den driver naa en EKTE resume: dag 1 parkerer en ekte plan-review gjennom run.main, ekspertens svar legges i en ekte innboks, og dag N sender --resume ... --checkpoint-dir ... --review-inbox ... --proposal-review med run_project innspilt og _refuse_model som kontroll paa null modellkall. MAALT, i denne rekkefoelgen (Iron Law): armen skrevet FOERST og kjoert mot uendret vakt -> ROED med nettopp nektlinja i stderr («pass --proposal-review at --resume instead»), calls == []. Etter vakt-fiksen: 49 passed i fila, og park-nekten (test_the_door_and_a_parked_exploration_contradict, M39) staar groenn - den sender --explore uten --resume. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
9ed458c0ba
commit
c81a90c88a
2 changed files with 130 additions and 11 deletions
|
|
@ -2735,7 +2735,12 @@ def main(argv: list[str] | None = None) -> int:
|
||||||
file=sys.stderr,
|
file=sys.stderr,
|
||||||
)
|
)
|
||||||
return 1
|
return 1
|
||||||
if args.checkpoint_dir is not None:
|
# ``and args.resume is None`` is load-bearing, not defensive: --resume REQUIRES
|
||||||
|
# --checkpoint-dir (:2776 below), so a bare --checkpoint-dir test refused the very
|
||||||
|
# composition this message recommends, and the help text, README and the invariant row all
|
||||||
|
# described a path no argv could take. What is being refused is a PARK (a leg that returns
|
||||||
|
# before any candidate exists), never a LIFT (a leg that runs the pipeline to a candidate).
|
||||||
|
if args.checkpoint_dir is not None and args.resume is None:
|
||||||
print(
|
print(
|
||||||
"run refused: --proposal-review and --checkpoint-dir: a parked exploration "
|
"run refused: --proposal-review and --checkpoint-dir: a parked exploration "
|
||||||
"returns before any candidate exists, so the review would never be asked — pass "
|
"returns before any candidate exists, so the review would never be asked — pass "
|
||||||
|
|
|
||||||
|
|
@ -1325,14 +1325,124 @@ def test_the_door_and_a_parked_exploration_contradict(
|
||||||
assert "--resume" in err
|
assert "--resume" in err
|
||||||
|
|
||||||
|
|
||||||
def test_the_door_composes_with_resume(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
|
#: Day 1's parked exploration, driven exactly as an operator drives it: a real ``--explore`` leg
|
||||||
"""A3, VERIFIED rather than deferred: the resume block yields the parked exploration's mandate
|
#: with ``enable_plan_review`` armed and NO reviewer at the terminal, so the loop parks. The
|
||||||
and falls through to the SAME full-run dispatch, so the reviewer built at the CLI is reached.
|
#: proposal-review door is deliberately absent here — that argv is the refusal this arm's sibling
|
||||||
Detach point: refusing ``--resume`` together with the door, or forgetting to pass the reviewer
|
#: (``…and_a_parked_exploration_contradict``) keeps green.
|
||||||
on that path.
|
_RESUME_RUN_ID = "proposal-review-resume"
|
||||||
|
|
||||||
|
_RESUME_MANAGER_REPLY = json.dumps(
|
||||||
|
{
|
||||||
|
"is_request_satisfied": {"reason": "r", "answer": True},
|
||||||
|
"is_in_loop": {"reason": "r", "answer": False},
|
||||||
|
"is_progress_being_made": {"reason": "r", "answer": True},
|
||||||
|
"next_speaker": {"reason": "r", "answer": "hypothesiser"},
|
||||||
|
"instruction_or_question": {"reason": "r", "answer": "go"},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _resume_replies_file(tmp_path: Path) -> str:
|
||||||
|
"""Both time-scales' roles in one file: the exploration's three and the debate's two. A
|
||||||
|
missing ``navigator`` key is the ``KeyError`` M40 of økt 64 — the resume leg builds an
|
||||||
|
exploration too, so it needs the same roster the park leg did."""
|
||||||
|
path = tmp_path / "resume-replies.json"
|
||||||
|
path.write_text(
|
||||||
|
json.dumps(
|
||||||
|
{
|
||||||
|
"proposer": _run_reply(_CLI_MEASURE, 30_000),
|
||||||
|
"checker": "VERDICT: APPROVE",
|
||||||
|
"manager": _RESUME_MANAGER_REPLY,
|
||||||
|
"navigator": "NAVIGATOR: read the index.",
|
||||||
|
"hypothesiser": "HYPOTHESIS: "
|
||||||
|
+ json.dumps({"label": "Night setback", "rationale": "y"}),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
encoding="utf-8",
|
||||||
|
)
|
||||||
|
return str(path)
|
||||||
|
|
||||||
|
|
||||||
|
def _resume_config_file(tmp_path: Path) -> str:
|
||||||
|
path = tmp_path / "resume-exploration.json"
|
||||||
|
path.write_text(
|
||||||
|
json.dumps(
|
||||||
|
{
|
||||||
|
"max_rounds": 4,
|
||||||
|
"max_tokens": 200_000,
|
||||||
|
"max_stall_count": 2,
|
||||||
|
"max_reset_count": 1,
|
||||||
|
"max_plan_revisions": 2,
|
||||||
|
"enable_plan_review": True,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
encoding="utf-8",
|
||||||
|
)
|
||||||
|
return str(path)
|
||||||
|
|
||||||
|
|
||||||
|
def _park_then_answer(tmp_path: Path) -> None:
|
||||||
|
"""Day 1 and the days between: park a real plan review, then drop the expert's answer in the
|
||||||
|
inbox. Both halves go through the shipped surfaces — a hand-written question file would test
|
||||||
|
the fixture, not the door."""
|
||||||
|
outbox = tmp_path / "outbox"
|
||||||
|
assert (
|
||||||
|
run.main(
|
||||||
|
[
|
||||||
|
_RUN_PID,
|
||||||
|
"--docs-dir",
|
||||||
|
str(_BUNDLE_DIR),
|
||||||
|
"--bundle-dir",
|
||||||
|
str(_BUNDLE_DIR),
|
||||||
|
"--explore",
|
||||||
|
"Find the cheapest saving.",
|
||||||
|
"--explore-config",
|
||||||
|
_resume_config_file(tmp_path),
|
||||||
|
"--scripted-replies",
|
||||||
|
_resume_replies_file(tmp_path),
|
||||||
|
"--outbox-dir",
|
||||||
|
str(outbox),
|
||||||
|
"--checkpoint-dir",
|
||||||
|
str(tmp_path / "checkpoints"),
|
||||||
|
"--run-id",
|
||||||
|
_RESUME_RUN_ID,
|
||||||
|
]
|
||||||
|
)
|
||||||
|
== 0
|
||||||
|
)
|
||||||
|
question = json.loads(
|
||||||
|
(outbox / f"{_RESUME_RUN_ID}-plan-review.json").read_text(encoding="utf-8")
|
||||||
|
)
|
||||||
|
inbox = tmp_path / "review-inbox"
|
||||||
|
inbox.mkdir(parents=True, exist_ok=True)
|
||||||
|
(inbox / f"{_RESUME_RUN_ID}-plan-review-answer.json").write_text(
|
||||||
|
json.dumps(
|
||||||
|
{
|
||||||
|
"run_id": _RESUME_RUN_ID,
|
||||||
|
"request_id": question["request_id"],
|
||||||
|
"decision": "approve",
|
||||||
|
}
|
||||||
|
),
|
||||||
|
encoding="utf-8",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_the_door_composes_with_resume(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||||
|
"""A3, and the WITNESS the review found missing: the ``--checkpoint-dir`` refusal points the
|
||||||
|
operator at ``--resume``, and ``--resume`` itself REQUIRES ``--checkpoint-dir`` — so before
|
||||||
|
this arm the recommended composition was refused by the very message that recommended it, and
|
||||||
|
nothing in the suite could see it. Detach point: reverting the guard to a bare
|
||||||
|
``if args.checkpoint_dir is not None``.
|
||||||
|
|
||||||
|
The argv is a REAL resume: day 1 parks a real plan review through ``run.main``, the expert's
|
||||||
|
answer is dropped in a real inbox, and day N passes ``--resume … --checkpoint-dir …
|
||||||
|
--review-inbox … --proposal-review``. The arm it replaced sent none of those three flags and
|
||||||
|
was a plain single-project run T13 already covered — green against the defect it was named
|
||||||
|
for. ``run_project`` is a recorder, so what is measured is the WIRING at the fall-through, and
|
||||||
|
``_refuse_model`` proves the recorded call is the ONLY place a model would have been reached
|
||||||
|
from."""
|
||||||
|
_park_then_answer(tmp_path)
|
||||||
|
|
||||||
``run_project`` is replaced by a recorder, so the arm measures the WIRING rather than a whole
|
|
||||||
resumed exploration."""
|
|
||||||
calls: list[dict[str, Any]] = []
|
calls: list[dict[str, Any]] = []
|
||||||
|
|
||||||
async def _recorder(*args: Any, **kwargs: Any) -> Any:
|
async def _recorder(*args: Any, **kwargs: Any) -> Any:
|
||||||
|
|
@ -1349,15 +1459,19 @@ def test_the_door_composes_with_resume(tmp_path: Path, monkeypatch: pytest.Monke
|
||||||
"--bundle-dir",
|
"--bundle-dir",
|
||||||
str(_BUNDLE_DIR),
|
str(_BUNDLE_DIR),
|
||||||
"--scripted-replies",
|
"--scripted-replies",
|
||||||
_cli_replies_file(tmp_path),
|
_resume_replies_file(tmp_path),
|
||||||
"--outbox-dir",
|
"--outbox-dir",
|
||||||
str(tmp_path / "outbox"),
|
str(tmp_path / "outbox"),
|
||||||
"--run-id",
|
"--checkpoint-dir",
|
||||||
_RUN_ID,
|
str(tmp_path / "checkpoints"),
|
||||||
|
"--review-inbox",
|
||||||
|
str(tmp_path / "review-inbox"),
|
||||||
|
"--resume",
|
||||||
|
_RESUME_RUN_ID,
|
||||||
"--proposal-review",
|
"--proposal-review",
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
assert len(calls) == 1
|
assert len(calls) == 1, "the resume must fall through to the full-run dispatch, not be refused"
|
||||||
assert calls[0]["proposal_reviewer"] is not None
|
assert calls[0]["proposal_reviewer"] is not None
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue