feat(phrases): canonical phrases the model invokes by key #409

Merged
coilyco-ops merged 2 commits from feat/canonical-phrases-by-key into main 2026-08-13 12:14:16 +00:00
Member

closes #408

Slice of #176 — approved by Kai, recorded by Delphi at 07:06Z as "build it. This is the real fix.", and unbuilt for seven hours.

The model writes {{phrase:no-tool}}; the harness renders the git-tracked text in the blockquote-code form it already uses.

Why a key beats a prompt rule

A prompt rule asking for terseness is a behaviour, and behaviours are re-verified on every model. Sycophancy erodes exactly this kind of instruction — a member who pushes back gets a longer, softer, more apologetic answer than the rule asked for.

A key is a lookup. Same text on every model, and a wrong key fails loudly instead of drifting quietly. Same reasoning as the content classifier and the post-hoc claim check: put the guarantee in the harness, not in prose the model can be argued out of.

What the registry enforces, and why each rule is there

  • A phrase must survive the notice alphabet unchanged, checked at load. A phrase that says one thing in git and another in the channel is worse than no registry.
  • Keys are lowercase and hyphenated — never need quoting, never read as prose.
  • Duplicates refused. A shadowed phrase is one nobody finds by reading the file.
  • An unknown key is an error, not a rendered marker. {{phrase:typo}} reaching a member is worse than a failed turn: the failure is recoverable through the repair loop, the leaked marker is not recoverable once it is on screen.

The repo caught me before I caught myself

Two existing tests — TestTheGateNamesEveryPackUnderAgent and TestEveryTrackedPackReachesPolicyCheck — failed the moment I added the YAML, demanding it be verified by policy-check. That is the guard against the declared-but-unread pattern this backlog keeps turning up, and it worked on me.

Deliberately not here

Making the model reach for a key. Whether the keys exist and render is separable from whether they get used, and shipping the registry first means the prompt half can be measured against something real rather than argued about.

ward exec gate green: build, policy-check, vet, test, test-skips, pre-commit.

closes #408 Slice of https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/176 — approved by Kai, recorded by Delphi at 07:06Z as *"build it. This is the real fix."*, and unbuilt for seven hours. The model writes `{{phrase:no-tool}}`; the harness renders the git-tracked text in the blockquote-code form it already uses. ## Why a key beats a prompt rule A prompt rule asking for terseness is a **behaviour**, and behaviours are re-verified on every model. Sycophancy erodes exactly this kind of instruction — a member who pushes back gets a longer, softer, more apologetic answer than the rule asked for. A key is a lookup. Same text on every model, and a wrong key fails loudly instead of drifting quietly. Same reasoning as the content classifier and the post-hoc claim check: put the guarantee in the harness, not in prose the model can be argued out of. ## What the registry enforces, and why each rule is there - **A phrase must survive the notice alphabet unchanged**, checked at load. A phrase that says one thing in git and another in the channel is worse than no registry. - **Keys are lowercase and hyphenated** — never need quoting, never read as prose. - **Duplicates refused.** A shadowed phrase is one nobody finds by reading the file. - **An unknown key is an error, not a rendered marker.** `{{phrase:typo}}` reaching a member is worse than a failed turn: the failure is recoverable through the repair loop, the leaked marker is not recoverable once it is on screen. ## The repo caught me before I caught myself Two existing tests — `TestTheGateNamesEveryPackUnderAgent` and `TestEveryTrackedPackReachesPolicyCheck` — failed the moment I added the YAML, demanding it be verified by policy-check. That is the guard against the declared-but-unread pattern this backlog keeps turning up, and it worked on me. ## Deliberately not here **Making the model reach for a key.** Whether the keys exist and render is separable from whether they get used, and shipping the registry first means the prompt half can be measured against something real rather than argued about. `ward exec gate` green: build, policy-check, vet, test, test-skips, pre-commit.
feat(phrases): canonical phrases the model invokes by key
All checks were successful
ci / test (pull_request) Successful in 35s
ci / publish-echo-image (pull_request) Has been skipped
ci / publish-observed (pull_request) Has been skipped
ci / image-build (pull_request) Successful in 19s
db60bf8683
A prompt rule asking for terse boundary responses is a behaviour, and
behaviours have to be re-verified on every model. Sycophancy erodes exactly
this kind of instruction: a member who pushes back gets a longer, softer answer
than the rule asked for. A key is a lookup. It renders the same text on every
model and fails loudly when it is wrong.

The registry refuses a phrase that would not survive rendering, at load rather
than at reply time, because a phrase that says one thing in git and another in
the channel is worse than no registry. Keys are lowercase and hyphenated so
they never need quoting and never read as prose, and duplicates are refused
since a shadowed phrase is one nobody finds by reading the file.

An unknown key is an error rather than a rendered marker. A failed turn is
recoverable through the repair loop and a leaked marker is not recoverable at
all once a member has read it.

policy-check verifies the registry. Two existing tests demanded that before I
thought to, which is the guard against exactly the declared-but-unread pattern
this backlog keeps turning up.

Making the model reach for a key is deliberately not here. Whether the keys
exist and render is separable from whether they get used, and shipping this
first means the prompt half can be measured against something real.

closes #408

Co-authored-by: Kai Siren <coilysiren@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
Merge branch 'main' into feat/canonical-phrases-by-key
All checks were successful
ci / test (pull_request) Successful in 33s
ci / publish-echo-image (pull_request) Has been skipped
ci / publish-observed (pull_request) Has been skipped
ci / image-build (pull_request) Successful in 3s
8ee689fc09
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
coilyco-gaming/sirens-echo!409
No description provided.