fix(projection): a resurrected row must enter matched to be seen
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Build and Publish Multi-Context Image / build-and-push (push) Successful in 21s

The previous commit made a stamped slug count as retired, and skipped such rows
before the heuristics. That is right for a genuinely retired row and wrong for a
resurrected one: `stale` is computed from `matched`, so a row that never enters
`matched` is invisible — not retired, so not stale; path-matching its own file,
so never reported. All six kept returning `noop`.

A row whose slug carries the mark while its flag is clear now lands in `matched`
under its own key, which is what makes it stale and therefore retirable. A row
that is actually retired is still skipped outright: nothing to do, nothing to
re-decide.

This is the same mistake as the original path fallback, in the opposite
direction: there a row was matched when it should not have been, here it was not
matched when it had to be.

748 pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 2583210@bnt-lap001
Assistant-Session: f2bff2d5-e9b2-4338-92ca-10282a927006
This commit is contained in:
tegwick 2026-08-28 11:48:51 +02:00
parent 95672e0c47
commit 5686b79d8c
2 changed files with 26 additions and 9 deletions

View file

@ -907,7 +907,7 @@ class TestRetirementIsNotUndoneByPath:
def test_retired_rows_are_skipped_before_path_matching(self):
import inspect
src = inspect.getsource(fp.reset_repository_projection)
skip_at = src.index("if row.projection_retired_at is not None or RETIRED_SLUG_MARK")
skip_at = src.index("if row.projection_retired_at is not None:")
path_at = src.index("if bp and _path_key(bp) in want_paths:")
assert skip_at < path_at, "retired rows must be skipped before path matching"
@ -916,7 +916,7 @@ class TestRetirementIsNotUndoneByPath:
import inspect
src = inspect.getsource(fp.reset_repository_projection)
assert src.index("want_by_uuid.get(str(row.id))") < src.index(
"if row.projection_retired_at is not None or RETIRED_SLUG_MARK"
"if row.projection_retired_at is not None:"
)
def test_a_row_that_derives_again_is_not_tombstoned(self):
@ -935,4 +935,17 @@ class TestRetirementIsNotUndoneByPath:
"""Otherwise a resurrected row path-matches its file and reports noop forever."""
import inspect
src = inspect.getsource(fp.reset_repository_projection)
assert 'projection_retired_at is not None or RETIRED_SLUG_MARK in' in src
assert "projection_retired_at is None and RETIRED_SLUG_MARK in" in src
def test_a_resurrected_row_becomes_stale_rather_than_being_skipped(self):
"""Skipping it outright is what left six rows reporting noop forever.
`stale` is computed from `matched`, so a row that never enters `matched`
is invisible: not retired, so not stale; path-matching its own file, so
never reported.
"""
import inspect
src = inspect.getsource(fp.reset_repository_projection)
zombie = src.index("projection_retired_at is None and RETIRED_SLUG_MARK in")
tail = src[zombie:zombie + 700]
assert "matched[key] = row" in tail, "a resurrected row must enter `matched`"