docs(6209): coverage, guidance-ownership, shape, warnings tests and shared fixtures
CI & Build / Python lint (push) Successful in 2s
CI & Build / Plugin hooks (push) Successful in 12s
CI & Build / TypeScript typecheck (push) Successful in 52s
CI & Build / integration (push) Successful in 1m12s
CI & Build / Python tests (push) Successful in 1m56s
CI & Build / Build & push image (push) Successful in 13s

test_pattern_coverage, test_guidance_ownership, test_integration_shape_classify,
test_instruction_surfaces_agree, test_retrieval_warnings, helpers.py and
conftest.py state the property each test or fixture holds. The issue and
milestone numbers, consolidation dates and one-install measurements that
recorded how each was found are dropped; fixture dates and ids stay.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-21 21:21:52 -04:00
co-authored by Claude Opus 5.5
parent 8518afb54d
commit 91c96a8b8a
7 changed files with 199 additions and 256 deletions
+24 -45
View File
@@ -1,29 +1,11 @@
"""What the instruction surfaces must say that one owner per topic cannot enforce.
WHY THIS FILE IS SMALLER THAN IT WAS
Until milestone 410 this file pinned REDUNDANCY: every session-start surface —
the MCP `_INSTRUCTIONS`, the plugin's static context, the `using-scribe` skill —
had to restate how a rule reaches a session, what an empty session means, the
Systems reflex and the snippet-recording triggers. That was the design #2494
chose after #2497 (two surfaces disagreeing about who loads the rules) and
#2198 (every hook silently inert): say it everywhere, so no single failure
loses it.
Decision #4027 replaced that with ownership, and tests/test_guidance_ownership.py
now enforces it: every topic stated in full by exactly one owner, with a
one-line pointer in the server's index. The tests that required every surface
to repeat itself were retired there, because they enforced the very duplication
that drifted (#4022). What they protected is still protected:
- "state how to ask for a rule" / "say an empty session is not an empty
rulebook" → the rules topic: owned by using-scribe, indexed in
`_INSTRUCTIONS` with both phrases;
- the Systems reflex and the snippet-recording triggers → their topics'
markers, required on their owners;
- "never name the SessionStart push without stating the ask" (#2497's exact
shape) → retired outright. Since milestone 394 the push carries no rules,
so naming it can no longer imply rules were handled, and requiring every
surface that mentions it to restate the ask would force a copy.
tests/test_guidance_ownership.py enforces who states each topic: every topic
stated in full by exactly one owner, with a one-line pointer in the server's
index. How to ask for a rule and what an empty session means are the rules
topic, owned by using-scribe and indexed in `_INSTRUCTIONS`; the Systems
reflex and the snippet-recording triggers are their topics' markers, required
on their owners.
WHAT STAYS HERE
@@ -46,7 +28,7 @@ def _all_surfaces() -> list[tuple[str, str]]:
what the hook does is not the same act as telling an agent it need not pull.
The boundary is "does a session read this", which is skills (loaded by
description match, and each reference file a skill links is read on its
own, so it is its own surface — #4398), the hook-injected static context, and the MCP server's
own, so it is its own surface), the hook-injected static context, and the MCP server's
own instructions.
"""
found = [(str(p.relative_to(ROOT)), p.read_text())
@@ -68,10 +50,9 @@ def _instructions_text() -> str:
# Claude Code injects only the first ~2,048 characters of an MCP server's
# instructions and silently cuts the rest mid-word (#2562: observed live —
# the previous 20k-char version delivered ~10% of itself, and none of the
# Systems tagging guidance ever reached a session). The budget is set below
# the cap, not at it: the field runs ~600–1,600 characters (spike #4389), and
# instructions and silently cuts the rest mid-word, so guidance past the cap
# never reaches a session. The budget is set below the cap, not at it: the
# field runs ~600–1,600 characters, and
# a block pressed against 2,048 is being used for depth that belongs in a
# skill.
INSTRUCTIONS_BUDGET = 1600
@@ -81,18 +62,17 @@ def test_instructions_fit_the_fold():
text = _instructions_text()
assert len(text) <= INSTRUCTIONS_BUDGET, (
f"_INSTRUCTIONS is {len(text)} chars; Claude Code injects only ~2,048 "
f"and silently cuts the rest (#2562). This block is an INDEX — state "
f"the topic in full on its owner (a skill or the tool's docstring, "
f"decision #4027) and give it at most a line here; see the comment "
f"and silently cuts the rest. This block is an INDEX — state "
f"the topic in full on its owner (a skill or the tool's docstring) "
f"and give it at most a line here; see the comment "
f"above _INSTRUCTIONS."
)
# ── force: a surface that says rules bind must say what does not ────────
#
# Added with the preference kind (milestone 399). Before it, "rules bind" was
# the whole truth and every surface said so flatly. It is now half of one, and
# the half that is missing is the dangerous half to omit: a session reading
# With a preference kind beside rules, "rules bind" is half of the truth, and
# the missing half is the dangerous half to omit: a session reading
# only "rules bind" and then receiving a preference has been told, by the most
# authoritative surface it has, to treat it as binding.
#
@@ -107,7 +87,7 @@ def test_instructions_fit_the_fold():
# PINNED ON THE CLAIM, NOT THE WORD "bind". A bare substring also matches
# `bind_repo`, `list_repo_bindings` and the DNS-rebinding comment in
# server.py — so it would one day fail a skill that mentions repo binding and
# has nothing to do with force, which is rule 167's named failure: a guard
# has nothing to do with force — a guard
# raising a false alarm about the very thing it protects. These phrases are
# the ones that actually assert bindingness to a reader.
BINDING_CLAIMS = (
@@ -144,7 +124,7 @@ def test_a_surface_claiming_rules_bind_also_names_what_does_not():
# whole corpus; a session that meets a third line shape with no name for it
# falls back on the nearest one it has, which is the binding one.
#
# The currency half is the claim #3896 was written around: a preference is the
# The currency half is the central claim: a preference is the
# one record a session updates ITSELF, without asking. Stated only in the
# skill, it reaches a session that loaded the skill — which is exactly the
# session least likely to need telling. In the index it reaches everyone.
@@ -168,12 +148,12 @@ def test_the_index_names_all_three_strengths():
f"client receives, and a record kind it does not name is one the session "
f"has to guess the force of — which it does by reaching for the kind it "
f"does know. Keep it to a clause; the full statement lives on "
f"using-scribe (decision #4027)."
f"using-scribe."
)
def test_the_strength_guard_can_fail():
"""Rule 167. The guard has to be able to bite, and it bites on omission —
"""The guard has to be able to bite, and it bites on omission —
the failure that actually happens, when a kind is added to the product and
the index is left describing the corpus that came before it."""
text = "rules bind; preferences guide and you keep them current."
@@ -182,14 +162,13 @@ def test_the_strength_guard_can_fail():
assert missing == ["that lessons inform"]
# ── Reporting back (milestone 409 step 3) ──────────────────────────────
# ── Reporting back ─────────────────────────────────────────────────────
#
# The reporting-back skill carries the shapes, but a skill only helps if it
# fires. The reflex that sends a session to it is stated in using-scribe, and
# the in-band cue on update_task (`placement`, `report_back`) is the half that
# fires on its own in every client. The server's index carried a REPORT line
# until #4389: reporting is a mid-work stance, not a session-start practice. The
# static context was a second plugin-side copy until milestone 410.
# fires on its own in every client. The server's index carries no REPORT line:
# reporting is a mid-work stance, not a session-start practice.
REPORT_REFLEX = "report back in a shape the operator can read"
REPORT_SURFACES = (
@@ -211,8 +190,8 @@ def test_the_reporting_reflex_is_stated_in_using_scribe():
def test_the_reporting_reflex_takes_placement_from_the_record():
"""The failure milestone 409 began from: a placement reconstructed from
memory reads exactly like a real one when it is wrong."""
"""A placement reconstructed from memory reads exactly like a real one
when it is wrong."""
for path in REPORT_SURFACES:
text = " ".join(path.read_text().split())
assert "`placement`" in text, f"{path.relative_to(ROOT)} no longer points at the placement block"