test(410): one guidance-topic registry, and a loss guard before anything moves (#4028)
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 13s
CI & Build / TypeScript typecheck (push) Successful in 56s
CI & Build / integration (push) Successful in 53s
CI & Build / Python tests (push) Successful in 1m26s
CI & Build / Build & push image (push) Successful in 14s

Step 1 of milestone 410 "One owner per piece of guidance". The later steps
delete duplicate copies of agent guidance; this guard stops the last copy of
a topic going with them.

- tests/test_guidance_ownership.py holds the registry: 30 topics from the
  ownership map in decision #4027, each with its owner and marker phrases,
  and one definition of a delivered surface (_INSTRUCTIONS, tool docstrings,
  each skill, the static context, the adapter commands, the live session
  context).
- The loss guard: every topic is stated in full, with all its markers
  together, on at least one delivered surface. A miss names the nearest
  partial match.
- The owner column is recorded but not asserted yet; step 6 adds the
  exactly-one-owner guard once the moves are done.
- test_the_loss_guard_can_fail proves split and absent markers are reported
  (rule 167).
- The old DISPLACED_TOPICS list in test_instruction_surfaces_agree is folded
  in, so there is one list rather than two.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-14 11:35:05 -04:00
co-authored by Claude Opus 5
parent 6c1fd28179
commit f3036f0cd7
2 changed files with 202 additions and 44 deletions
+4 -44
View File
@@ -211,50 +211,10 @@ def test_floor_names_the_snippet_recording_triggers():
)
# Topics displaced from _INSTRUCTIONS when it was cut to fit the fold. Each
# must remain stated on at least one DELIVERED surface: a tool docstring
# (arrives with the tool schema), the plugin static context (always arrives),
# or a bundled skill (arrives on trigger match). Keyed by a phrase distinctive
# enough that its disappearance means the guidance is gone, not reworded —
# update the phrase alongside a deliberate rewording.
DISPLACED_TOPICS = {
"supersedes": "supersedes",
"trash is recoverable": "deleted_batch_id",
"duplicate gate": "duplicate",
"systems tag-as-you-write": "system_ids",
"reference note vs dev-log": "reference note",
"work-logs over body rewrites": "add_task_log",
"rule homes / altitude": "create_project_rule",
"rules vs other entities": "standing instruction",
"shared records are suggestions": "shared",
"processes run verbatim": "verbatim",
"snippet reuse reflex": "when_to_use",
"compaction at seams": "compact",
"plans are milestones": "start_planning",
"scope to the entered project": "cross-project",
"project bootstrap needs confirmation": "never guessing a project",
}
def test_displaced_topics_live_on_a_delivered_surface():
corpus = ""
for p in (ROOT / "src" / "scribe" / "mcp" / "tools").glob("*.py"):
corpus += p.read_text()
corpus += (ROOT / "plugin" / "hooks" / "scribe_static_context.md").read_text()
for p in (ROOT / "plugin" / "skills").rglob("SKILL.md"):
corpus += p.read_text()
corpus = corpus.lower()
missing = [
f"{topic} (phrase: {phrase!r})"
for topic, phrase in DISPLACED_TOPICS.items()
if phrase.lower() not in corpus
]
assert not missing, (
f"guidance displaced from _INSTRUCTIONS has fallen off every delivered "
f"surface (tool docstrings / static context / skills): {missing}. It "
f"was cut from _INSTRUCTIONS deliberately (#2562) on the premise it "
f"lives elsewhere — restore it somewhere that delivers."
)
# The "displaced from _INSTRUCTIONS" topics (#2562) used to be listed here with
# their own delivered-surface check. They are folded into the one topic registry
# in tests/test_guidance_ownership.py (milestone 410), which covers every topic
# of the ownership map and defines "delivered surface" once.
def test_no_surface_names_the_push_without_stating_the_ask():