docs(6209): rulebooks, pull telemetry, lesson usage, duplicate arm, cited status, trigger shape
CI & Build / Python lint (push) Successful in 2s
CI & Build / Plugin hooks (push) Successful in 14s
CI & Build / TypeScript typecheck (push) Successful in 54s
CI & Build / integration (push) Successful in 1m3s
CI & Build / Python tests (push) Successful in 1m55s
CI & Build / Build & push image (push) Successful in 13s

Six more test files state their pinned properties without the issue and
milestone history: the pull-telemetry guard explains enumerating kinds
instead of listing two getter incidents, cited-record status explains why
a hint's id needs its status instead of recounting one misreported step,
and the trigger-shape guard keeps its reasoning about why prose heuristics
fail while dropping the dated corpus audit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-21 21:28:35 -04:00
co-authored by Claude Opus 5.5
parent ff08500128
commit 17e1931c0b
6 changed files with 91 additions and 112 deletions
+21 -27
View File
@@ -1,19 +1,17 @@
"""Every rule-write surface SHOWS what a trigger looks like (#3855).
"""Every rule-write surface SHOWS what a trigger looks like.
WHY THIS EXISTS
`when_to_apply` is not documentation. `rule_document()` uses it twice — as
the embedded title's second half and again above the body — so it dominates
the vector, and a rule whose trigger names a CATEGORY rather than a moment
collapses toward its title and never arrives. Measured in #3835 across 113
rules, then again in #3855 on eight preferences.
collapses toward its title and never arrives.
The corpus damage traced to an uneven contract rather than to careless
authors. `create_rule` had carried the full argument since 2026-08-27, and
the two preferences written that day got good triggers; the six written
before it — "during hard debugging", "when reading any request from the
operator" — got categories. The guidance worked wherever it existed. It
simply did not exist on either `update_*` surface, which is where every
Bad triggers come from an uneven contract rather than from careless authors.
Triggers written where the guidance exists name a moment; triggers written
without it — "during hard debugging", "when reading any request from the
operator" — name categories. The guidance has to exist on the `update_*`
surfaces too, which is where every
RETROFITTED trigger is written, and retrofitting is most of the work: a
trigger that already reads fine as English is the one nobody rewrites.
@@ -21,9 +19,8 @@ WHAT THIS PINS
Two properties, neither of them wording:
1. A tool accepting `when_to_apply` mentions it. Exactly what
`update_preference` failed before #3855 — the parameter existed and
the docstring never said so.
1. A tool accepting `when_to_apply` mentions it — a parameter the
docstring never names is one nobody fills well.
2. It carries a worked CONTRAST: one `RETRIEVES:` example and one
`COLLAPSES:` example, quoted, and different from each other.
@@ -31,23 +28,21 @@ WHY A CONVENTION RATHER THAN A PROSE HEURISTIC
The second property guards the softer regression — guidance kept but
abstracted back to "name the moment in session vocabulary", which is advice
about being concrete that is not itself concrete, and is the shape that was
already on file while the corpus filled with categories.
about being concrete that is not itself concrete.
Two attempts to detect that in free prose were written and discarded, and
the reason is worth keeping because it generalises:
Two ways to detect that in free prose fail, and the reason generalises:
- Counting quoted multi-word phrases anywhere in the docstring measured
ambient quotation, not demonstrated triggers. It PASSED the abstracted
ambient quotation, not demonstrated triggers. It PASSES the abstracted
version by scoring unrelated prose, and text with an odd number of
quote characters produced matches spanning the gap BETWEEN two
unrelated phrases.
- Scoping that count to a window after each "trigger"/"when_to_apply"
mention then FAILED `create_preference` in its correct state, because
mention FAILS `create_preference` in its correct state, because
its examples sit further from the first mention than any defensible
window reaches.
Both were proxies trying to infer demonstration from prose. The fix was to
Both are proxies trying to infer demonstration from prose. The answer is to
stop inferring: a two-line labelled contrast is unambiguous to parse, free
in its wording, and a better teaching form than the sentences it replaced —
`RETRIEVES:`/`COLLAPSES:` names the mechanism, so the label does work for
@@ -56,7 +51,7 @@ measured, changing the shape of the thing is cheaper than a cleverer
measurement.
What it still cannot do is judge whether a GOOD example is good. It catches
what actually happened: a write surface shipping with the contrast absent,
the likely failure: a write surface shipping with the contrast absent,
half-present, or tidied back into abstract advice.
THE SURFACE LIST IS DERIVED, NEVER HAND-KEPT. It comes from what
@@ -64,7 +59,7 @@ THE SURFACE LIST IS DERIVED, NEVER HAND-KEPT. It comes from what
taking `when_to_apply`, so a rule-write tool added later is in scope on the
day it is added. A hand-kept list has to be remembered by the person least
likely to know it exists — the argument `RANKED_SOURCES` makes in
services/rule_usage.py, and the reason #3855 happened at all.
services/rule_usage.py.
"""
import inspect
import re
@@ -111,8 +106,8 @@ def _trigger_writers() -> list[str]:
if "when_to_apply" in inspect.signature(fn).parameters
]
# An empty list would make every case below vacuous and the guard would
# pass by having nothing to check — absence read as non-existence, the
# #3720 shape. Fail loudly instead.
# pass by having nothing to check — absence read as non-existence. Fail
# loudly instead.
assert names, "no rule-write surface takes when_to_apply; the guard is blind"
return sorted(names)
@@ -123,10 +118,9 @@ def test_a_trigger_writing_surface_documents_the_field(name):
doc = _doc(_MODULE, name)
assert "when_to_apply" in doc, (
f"{name} accepts when_to_apply but never mentions it in its "
"docstring. The tool docstring is the agent-facing contract "
"(rule 119), and a trigger written against no contract is the #3855 "
"defect: six preferences named a category instead of a moment, and "
"a category is not a thing any session ever types."
"docstring. The tool docstring is the agent-facing contract, and a "
"trigger written against no contract names a category instead of a "
"moment — and a category is not a thing any session ever types."
)