Skip to content

Commit 0538faa

Browse files
committed
test(semantics): pin rename laundering on an injected fork, not a rented one
PR loopx-project#4643 retired the AGENT/USER_TODO_HEADER_MARKERS forks, which four drift tests from loopx-project#4614 had rented as samples for the rename-laundering limit. Track A retires real forks one by one, so renting them makes every retirement a test breakage -- this PR included. The pins now inject their own synthetic fork (one name, two modules, two disagreeing value sets) and measure against the live baseline instead of hardcoded counts, so they pin the machinery -- the RFC Section 9 known limit -- independently of the debt population: - the laundering test measures base / base+1 / base instead of 3/2; - the declaration test proves exclusion by removing SOURCE_SURFACES from the registry and watching the count rise by exactly one, instead of asserting today's undeclared count; - the three-case rename boundary runs its undeclared cases on the synthetic fork; Case 1 (declared rename refused) still uses SOURCE_SURFACES, which is still declared and still 4-way divergent; - the advisory test keeps one real assertion: RAW_MATERIAL_KEY_HINTS, the only undeclared fork surviving this PR, must stay listed, with a comment that the assertion retires with the fork. Signed-off-by: song <22676124+songoow@users.noreply.github.com>
1 parent 5308c75 commit 0538faa

1 file changed

Lines changed: 88 additions & 40 deletions

File tree

‎tests/architecture/test_semantic_vocabulary_drift.py‎

Lines changed: 88 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -185,12 +185,65 @@ def test_registry_cannot_add_unanchored_output_selectors(name, metadata, selecti
185185
smoke['check_coverage_floor'](registry)
186186

187187

188+
SYNTHETIC_FORK_NAME = "SYNTHETIC_RENAME_SAMPLE_MARKERS"
189+
SYNTHETIC_FORK_MODULES = (
190+
"loopx/state_projection.py",
191+
"loopx/control_plane/goals/active_state_metadata.py",
192+
)
193+
194+
195+
def _with_synthetic_fork(smoke, sources):
196+
"""Inject a synthetic multi-value fork into two in-memory modules.
197+
198+
The rename-laundering limit is a property of the inventory machinery, not
199+
of whichever real fork happens to be undeclared today. Track A retires real
200+
forks one by one (PR #4643 retired two of the three this file used to rent),
201+
so these pins carry their own sample instead: two modules, one name, two
202+
disagreeing value sets -- exactly what makes a multi-value fork.
203+
"""
204+
texts = {
205+
SYNTHETIC_FORK_MODULES[0]: f'\n{SYNTHETIC_FORK_NAME} = ("synthetic_left", "left_two")\n',
206+
SYNTHETIC_FORK_MODULES[1]: f'\n{SYNTHETIC_FORK_NAME} = ("synthetic_right", "right_two")\n',
207+
}
208+
return [
209+
smoke["SourceFile"](source.path, source.suffix, source.text + texts[source.path])
210+
if source.path in texts
211+
else source
212+
for source in sources
213+
]
214+
215+
216+
def _rename_synthetic_side(smoke, sources, path):
217+
return [
218+
smoke["SourceFile"](
219+
source.path,
220+
source.suffix,
221+
source.text.replace(SYNTHETIC_FORK_NAME, SYNTHETIC_FORK_NAME + "_RENAMED", 1),
222+
)
223+
if source.path == path
224+
else source
225+
for source in sources
226+
]
227+
228+
188229
def test_bounded_context_scope_excludes_only_declared_multi_value_fork() -> None:
230+
"""A declaration is what removes a fork from the budget; prove it by removal.
231+
232+
The undeclared count itself is debt population, not a pin -- Track A lowers
233+
it PR by PR. What must hold is the exclusion: dropping a declaration puts
234+
its fork back into the semantic budget, exactly one.
235+
"""
189236
smoke = runpy.run_path(str(SMOKE))
190237
registry = smoke["load_registry"]()
191238
sources = smoke["load_sources"](REPO_ROOT)
192239
inventory = smoke["build_inventory"](REPO_ROOT, sources=sources)
193-
assert smoke["check_scope_declarations"](registry, inventory) == 3
240+
with_declaration = smoke["check_scope_declarations"](registry, inventory)
241+
242+
without = copy.deepcopy(registry)
243+
del without["scope_declarations"]["SOURCE_SURFACES"]
244+
assert (
245+
smoke["check_scope_declarations"](without, inventory) == with_declaration + 1
246+
), "a declared fork is excluded from the semantic budget only while declared"
194247

195248

196249
def test_renaming_one_side_of_a_fork_launders_the_semantic_budget() -> None:
@@ -204,20 +257,16 @@ def test_renaming_one_side_of_a_fork_launders_the_semantic_budget() -> None:
204257
"""
205258
smoke = runpy.run_path(str(SMOKE))
206259
registry = smoke["load_registry"]()
207-
sources = smoke["load_sources"](REPO_ROOT)
208-
before = smoke["build_inventory"](REPO_ROOT, sources=sources)
209-
assert smoke["check_scope_declarations"](registry, before) == 3
260+
plain = smoke["load_sources"](REPO_ROOT)
261+
base = smoke["check_scope_declarations"](registry, smoke["build_inventory"](REPO_ROOT, sources=plain))
210262

211-
path = "loopx/state_projection.py"
212-
name = "AGENT_TODO_HEADER_MARKERS"
213-
renamed = [
214-
smoke["SourceFile"](source.path, source.suffix, source.text.replace(name, name + "_RENAMED", 1))
215-
if source.path == path
216-
else source
217-
for source in sources
218-
]
263+
forked = _with_synthetic_fork(smoke, plain)
264+
before = smoke["build_inventory"](REPO_ROOT, sources=forked)
265+
assert smoke["check_scope_declarations"](registry, before) == base + 1
266+
267+
renamed = _rename_synthetic_side(smoke, forked, SYNTHETIC_FORK_MODULES[0])
219268
after = smoke["build_inventory"](REPO_ROOT, sources=renamed)
220-
assert smoke["check_scope_declarations"](registry, after) == 2, (
269+
assert smoke["check_scope_declarations"](registry, after) == base, (
221270
"a rename no longer lowers the semantic budget; the RFC known-limits entry "
222271
"('Renames launder a collision') is now stale and must be revised"
223272
)
@@ -237,9 +286,14 @@ def test_divergent_value_sets_lists_the_names_a_rename_would_hide() -> None:
237286

238287
smoke = runpy.run_path(str(SMOKE))
239288
sources = smoke["load_sources"](REPO_ROOT)
240-
inventory = smoke["build_inventory"](REPO_ROOT, sources=sources)
241-
listed = {row["name"] for row in divergent_value_sets(inventory)}
242-
assert {"AGENT_TODO_HEADER_MARKERS", "USER_TODO_HEADER_MARKERS", "RAW_MATERIAL_KEY_HINTS"} <= listed
289+
inventory = smoke["build_inventory"](REPO_ROOT, sources=_with_synthetic_fork(smoke, sources))
290+
rows = divergent_value_sets(inventory)
291+
listed = {row["name"] for row in rows}
292+
assert SYNTHETIC_FORK_NAME in listed
293+
assert {row["value_sets"] for row in rows if row["name"] == SYNTHETIC_FORK_NAME} == {2}
294+
# The one real undeclared fork that survives PR #4643; when Track A retires
295+
# it, this assertion retires with it. Until then the advisory must name it.
296+
assert "RAW_MATERIAL_KEY_HINTS" in listed
243297

244298
# The advisory is not a budget input: it must not appear in the committed
245299
# inventory, which stays the single computed authority.
@@ -273,43 +327,37 @@ def test_rename_visibility_splits_into_three_cases() -> None:
273327

274328
smoke = runpy.run_path(str(SMOKE))
275329
registry = smoke["load_registry"]()
276-
sources = smoke["load_sources"](REPO_ROOT)
277-
name = "AGENT_TODO_HEADER_MARKERS"
278-
279-
def renamed_in(paths):
280-
out = sources
281-
for path in paths:
282-
out = [
283-
smoke["SourceFile"](source.path, source.suffix, source.text.replace(name, name + "_RENAMED", 1))
284-
if source.path == path
285-
else source
286-
for source in out
287-
]
288-
return out
330+
plain = smoke["load_sources"](REPO_ROOT)
331+
forked = _with_synthetic_fork(smoke, plain)
289332

290333
# Case 1: declared name, one side renamed -> the declaration no longer resolves.
291-
declared = _restate(smoke, sources, "loopx/global_todos.py", "SOURCE_SURFACES", "GT_SOURCE_SURFACES")
334+
declared = _restate(smoke, plain, "loopx/global_todos.py", "SOURCE_SURFACES", "GT_SOURCE_SURFACES")
292335
with pytest.raises(smoke["Drift"], match="every defining module"):
293336
smoke["check_scope_declarations"](registry, smoke["build_inventory"](REPO_ROOT, sources=declared))
294337

295338
# Case 2: undeclared name, one side renamed -> gone from the budget AND the advisory.
296-
partial = smoke["build_inventory"](REPO_ROOT, sources=renamed_in(["loopx/state_projection.py"]))
297-
assert name not in {entry["name"] for entry in partial["duplicate_definitions"]["multi_value_forks"]}
298-
assert name not in {row["name"] for row in divergent_value_sets(partial)}
339+
partial = smoke["build_inventory"](
340+
REPO_ROOT, sources=_rename_synthetic_side(smoke, forked, SYNTHETIC_FORK_MODULES[0])
341+
)
342+
assert SYNTHETIC_FORK_NAME not in {
343+
entry["name"] for entry in partial["duplicate_definitions"]["multi_value_forks"]
344+
}
345+
assert SYNTHETIC_FORK_NAME not in {row["name"] for row in divergent_value_sets(partial)}
299346

300347
# Case 3: every side renamed -> also invisible; indistinguishable from an honest rename.
301348
whole = smoke["build_inventory"](
302349
REPO_ROOT,
303-
sources=renamed_in([
304-
"loopx/state_projection.py",
305-
"loopx/control_plane/goals/active_state_metadata.py",
306-
]),
350+
sources=_rename_synthetic_side(
351+
smoke, _rename_synthetic_side(smoke, forked, SYNTHETIC_FORK_MODULES[0]), SYNTHETIC_FORK_MODULES[1]
352+
),
307353
)
308-
assert name not in {entry["name"] for entry in whole["duplicate_definitions"]["multi_value_forks"]}
309-
assert name not in {row["name"] for row in divergent_value_sets(whole)}
354+
assert SYNTHETIC_FORK_NAME not in {
355+
entry["name"] for entry in whole["duplicate_definitions"]["multi_value_forks"]
356+
}
357+
assert SYNTHETIC_FORK_NAME not in {row["name"] for row in divergent_value_sets(whole)}
310358

311359
# The surviving forks are what the advisory does list, by name.
312-
assert "USER_TODO_HEADER_MARKERS" in {row["name"] for row in divergent_value_sets(partial)}
360+
assert "RAW_MATERIAL_KEY_HINTS" in {row["name"] for row in divergent_value_sets(partial)}
313361

314362

315363
def test_bounded_context_scope_requires_every_distinct_defining_module() -> None:

0 commit comments

Comments
 (0)