diff --git a/api/services/forge_projection.py b/api/services/forge_projection.py index 7773269..28f1f35 100644 --- a/api/services/forge_projection.py +++ b/api/services/forge_projection.py @@ -732,7 +732,13 @@ async def reset_repository_projection( # which is then deliberately un-retired below. matched[key] = row continue - if row.projection_retired_at is not None: + if row.projection_retired_at is not None or RETIRED_SLUG_MARK in (row.slug or ""): + # A stamped slug is itself evidence of a retirement, so a row + # carrying the mark with a cleared flag is a contradiction to + # repair rather than a live record — six rows reached that state + # before the resurrection was fixed, and nothing else can see them: + # they path-match their own file and report `noop` forever. + # # Past this point only the heuristics remain, and a retired row must # not be matched by those. Retirement is a # decision, and re-deriving the same file must not silently undo it. diff --git a/tests/test_forge_projection.py b/tests/test_forge_projection.py index 3787c31..a1ff7ac 100644 --- a/tests/test_forge_projection.py +++ b/tests/test_forge_projection.py @@ -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:") + skip_at = src.index("if row.projection_retired_at is not None or RETIRED_SLUG_MARK") 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:" + "if row.projection_retired_at is not None or RETIRED_SLUG_MARK" ) def test_a_row_that_derives_again_is_not_tombstoned(self): @@ -930,3 +930,9 @@ class TestRetirementIsNotUndoneByPath: rel = src.index("outcome.released.append(before)") guard = src.index('in want or str(r.id) in want_by_uuid') assert guard < rel, "the release must exempt records the forge still derives" + + def test_a_stamped_slug_counts_as_retired_even_if_the_flag_is_clear(self): + """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