fix(update): the orphan-marker known failure expires once its fix is in the tree

ORPHAN_MARKER_GAP excused the orphaned_update cell's marker assertion with no
expiry. PR CI never runs that cell (Windows, opt-in) nor strict acceptance,
so after #132354 (hand-off script names its update child as the line-4
delegate) and #132365 (the judge honours a live delegate) land, a regression
of exactly that contract would still pass as an expected failure.

Now the fix's footprint is read from the tree (ORPHAN_MARKER_FIX):
- while any half is absent, _orphan_gap_excuse applies known_failure as before;
- once every half is present the excuse is off, so the cell is strict on any
  runner whatever the wrapper says;
- tests/ci/test_windows_update_crash_oracles.py (runs on every PR) fails with
  "delete ORPHAN_MARKER_GAP ..." once the fix is in the tree, the same expiry
  shape as _LANDS_IN_SIBLING_PR, and fails if the Python half already on this
  branch (update_lock.delegate_live) loses its footprint, so a rename cannot
  keep the excuse alive.
Checked against the scripts branch: this tree + its marker.ps1/windows.ps1
reads no half missing.

Review CI1.
This commit is contained in:
Teknium
2026-10-05 01:40:39 -07:00
parent 1635fc7176
commit d6e201432b
2 changed files with 69 additions and 1 deletions

View File

@@ -148,3 +148,44 @@ def test_orphan_receipt_is_the_newest_one_written_after_the_baseline(tmp_path):
assert crash._new_receipt_outcome(machine, before) is None # an earlier run's success is not this run's
(receipts / "update_20261004_000100_2_b.json").write_text('{"outcome": "failed"}', encoding="utf-8")
assert crash._new_receipt_outcome(machine, before) == "failed"
# Review CI1: a run-time xfail outlives its fix unless something checks the tree. PR CI never runs
# the orphan cell (Windows, opt-in) nor strict acceptance, so this file is the expiry.
def test_orphan_marker_wrapper_expires_once_its_fix_is_in_the_tree():
missing = crash.orphan_marker_fix_missing()
assert missing, ("the orphan-marker fix (#132354 + #132365) is in the tree: delete ORPHAN_MARKER_GAP, "
"ORPHAN_MARKER_FIX, _orphan_gap_excuse and these guards, and assert the marker plainly")
# The halves already on this branch must still carry their footprint: a renamed judge would
# otherwise read as "not landed" forever and keep the excuse alive.
landed = {rel for rel, _ in crash.ORPHAN_MARKER_FIX} - {m.split(":")[0] for m in missing}
assert "hermes_cli/update_lock.py" in landed, f"the Python delegate judge lost its footprint: {missing}"
def test_orphan_marker_fix_footprint_is_read_from_the_tree(tmp_path):
for rel, footprint in crash.ORPHAN_MARKER_FIX:
(tmp_path / rel).parent.mkdir(parents=True, exist_ok=True)
(tmp_path / rel).write_text(f"x\n{footprint}\n", encoding="utf-8")
assert crash.orphan_marker_fix_missing(tmp_path) == []
(tmp_path / "scripts/desktop-update/windows.ps1").unlink()
assert crash.orphan_marker_fix_missing(tmp_path) == [
"scripts/desktop-update/windows.ps1: " + crash.ORPHAN_MARKER_FIX[2][1]]
_GAP_FAILURE = "orphaned_update: .hermes-update-in-progress read DEAD 3s after the script died"
@pytest.mark.parametrize("fix_in_tree", [False, True])
def test_orphan_gap_is_excused_only_while_its_fix_is_absent(monkeypatch, fix_in_tree):
monkeypatch.delenv("HERMES_E2E_STRICT_ACCEPTANCE", raising=False)
monkeypatch.setattr(crash, "orphan_marker_fix_missing", lambda: [] if fix_in_tree else ["a half"])
expected = AssertionError if fix_in_tree else pytest.xfail.Exception
with pytest.raises(expected, match="read DEAD"):
with crash._orphan_gap_excuse():
raise AssertionError(_GAP_FAILURE)
def test_orphan_marker_guard_fires_once_the_fix_lands(monkeypatch):
monkeypatch.setattr(crash, "orphan_marker_fix_missing", lambda: [])
with pytest.raises(AssertionError, match="delete ORPHAN_MARKER_GAP"):
test_orphan_marker_wrapper_expires_once_its_fix_is_in_the_tree()

View File

@@ -756,6 +756,33 @@ def test_desktop_handoff_killed_mid_run_leaves_a_runnable_install(journey: Journ
# (HERMES_E2E_STRICT_ACCEPTANCE=upd-txn) fails on it instead.
ORPHAN_MARKER_GAP = (r"orphaned_update: \.hermes-update-in-progress (read DEAD|survived)",
"upd-txn: the line-4 delegate lands in #132354 + #132365")
# The expiry PR CI can check (it never runs this cell, nor strict): the fix's footprint in the
# tree. Once every half is here the excuse is off, so the cell is strict on any runner, and
# tests/ci/test_windows_update_crash_oracles.py (every PR) fails until the wrapper is deleted.
ORPHAN_MARKER_FIX = (
("hermes_cli/update_lock.py", "def delegate_live("), # #132365: the judge honours a live delegate
("scripts/desktop-update/marker.ps1", "function Add-MarkerDelegate("), # #132354: the script names one
("scripts/desktop-update/windows.ps1", "Add-MarkerDelegate @($proc.Id)"), # ... its update child
)
_REPO = Path(__file__).resolve().parents[4]
def orphan_marker_fix_missing(root: Path = _REPO) -> list[str]:
"""The halves of the orphan-marker fix absent from ``root`` (``[]``: the gap is closed there)."""
missing = []
for rel, footprint in ORPHAN_MARKER_FIX:
try:
text = (root / rel).read_text(encoding="utf-8-sig", errors="replace")
except FileNotFoundError:
text = ""
if footprint not in text:
missing.append(f"{rel}: {footprint}")
return missing
def _orphan_gap_excuse() -> contextlib.AbstractContextManager[None]:
"""``known_failure`` for the orphan-marker gap while its fix is absent; nothing once it is here."""
return known_failure(*ORPHAN_MARKER_GAP) if orphan_marker_fix_missing() else contextlib.nullcontext()
def test_desktop_handoff_script_killed_alone_keeps_the_marker_live_until_its_update_ends(
@@ -786,5 +813,5 @@ def test_desktop_handoff_script_killed_alone_keeps_the_marker_live_until_its_upd
f"hermes update still ran: {r['dead_while_running'][1]} (at kill: {r['marker_at_kill']!r})")
if r["marker_after_orphan"] is not None:
gaps.append(f"{MARKER} survived the orphaned update's exit: {r['marker_after_orphan_text']}")
with known_failure(*ORPHAN_MARKER_GAP):
with _orphan_gap_excuse():
assert not gaps, fail_with(m, "orphaned_update: " + "; ".join(gaps))