# Skill Authoring

> How to write skills, CLAUDE.md/AGENTS.md, fix logs, and handoff documents that a weaker or zero-context model can actually execute. Load when authoring or updating any instruction file, SKILL.md, project memory, or institutional-knowledge document — including when converting lessons from a session into durable files — and when about to act on a recorded capability-negative ("no such flag", "the API can't do X") found in one. Not for writing user-facing docs or code comments.

- Skill: `f-e-u-e-r/skill-authoring` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add f-e-u-e-r/skill-authoring`
- Raw SKILL.md: https://api.skillmd.com/api/skills/f-e-u-e-r/skill-authoring/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: F-e-u-e-r (https://skillmd.com/u/f-e-u-e-r)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/f-e-u-e-r/skill-authoring

---


# Skill Authoring for Weaker Models

Institutional files are read by a model with zero context and less judgment
than the author. Write for that reader. Every rule must survive being
followed literally, without the author present.

## 1. The executable-rule format

An abstract demand ("keep quality high", "be careful", "verify appropriately")
without a judgment criterion is noise — it costs context and changes nothing.
Every load-bearing rule states:

- **Trigger** — the observable condition under which it applies.
- **Steps** — what to actually do, imperative, copy-pasteable where possible.
- **Done** — the completion definition; how the follower knows it worked.

And where misreading is costly or the judgment boundary is subtle, add:

- **One positive and one negative example** — the fastest way to transmit a
  judgment boundary to a weaker model. The strongest negative example quotes
  a rationalization actually observed ("tests are probably fine — the change
  is small") and names why it fails.
- **On failure** — the next step when it does not work (retry differently,
  escalate, mark unresolved), so failure does not improvise.

Placement is part of the format: **an eligibility or refusal hard-exit
gate precedes the first artifact-producing step, not mid-procedure.** A
refusal or scope check positioned after
generation has begun gets blown past by mid-build momentum — the executor
already has an artifact to protect and reads the gate as an obstacle. The
same check asked first costs one sentence and holds. Smoke-measured
fail-then-fix at the source (n=1 per cell): a weak-tier executor ran 68
tool calls and escaped its sandbox past a mid-procedure scope check; with
the identical check moved before the first generation step, six tool
calls, nothing generated, correct early exit. When a rule refuses or
scopes the work — "refuse red-line domains", "no adapter when the sector
is coding in disguise" — the skill's step order puts that test before
the executor has produced anything; done when every eligibility or
refusal test precedes the first artifact-producing step in the skill's
ordering. A verification gate whose input IS the produced work (tests
pass, a ship check) stays terminal — this rule moves eligibility and
refusal checks, not verification.
❌ "Stage 4: before finalizing, confirm the sector needed an adapter at
all" — by Stage 4 the adapter exists and the check reads as waste.
✅ the same sentence as Stage 1's first bullet, before any
artifact-producing step.
(`unprobed` in-house; external evidence — see Provenance.)

**Before a rule earns its place — the author-time pruning pass** (`unprobed`
— see Provenance). The format above says how to write a rule; this is the
cheap pre-filter for whether to, and where. Ask five questions — each hands
off to the section that owns the deep or empirical resolution; the pass
screens, it does not re-run those sections:
- **No-op** — would the weaker, zero-context reader this pack is written for
  behave any differently with the rule than without it? Judge at that target
  tier, not a strong model's; the empirical form is §7's bare-vs-ruled probe.
- **Default-delta** — is the behavior already the base default, or already
  compelled by a standing higher rule? A rule earns its line only in the delta
  over that default, measured at a stated tier, never assumed (§7).
- **Placement** — where does this rule belong, and is the always-loaded body
  really it? Decide with §4's Placement test. (Frontmatter/trigger metadata
  carries routing conditions, never rule content.)
- **Retrieval-cost** — does a clause only a minority of loads needs sit in the
  always-loaded body? Move the rare case on-demand (§4's earn-the-line).
- **Contradiction-pressure** — does it obviously collide with an existing
  authority, a stated exception, or an adjacent skill's rule? A detected
  collision escalates to §6's rule-by-rule doctrine walk — the screen here is
  that walk's trigger, not the walk itself.
Disposition: a rule earns its place only when all five questions pass. One it
fails sends the rule back — drop, re-home, or rewrite — before it lands; a
detected contradiction blocks it pending §6. Nothing here overrides §6's review
or §7's probe, which stay the empirical backstop.
Guardrail: this pass never deletes, weakens, or relocates a load-bearing
clause — a **safety, verification, fail-closed, or authorization-boundary**
rule, the eligibility/refusal/scope hard-exit gates §1 keeps before the first
artifact-producing step, or the user-confirmation gates §7 keeps for
destructive, spending, or publishing actions. Such a clause, however rarely it
fires, stays at the executor's decision point; that retrieval-cost is paid on
purpose. When you cannot tell whether a clause is load-bearing on one of these
axes, treat it as load-bearing — the pass fails closed.

## 2. Ground truth only

- Verify every command, flag, path, and claim against the actual repo/system
  before writing it down. **A wrong runbook is worse than none, because it is
  trusted.** That includes the pointer inside a rule you are writing: a
  cross-reference's section number is a claim about the target file — derive
  it by opening the file, or from search output that is current and shows
  the enclosing heading (a bare quoted body line does not establish its
  section), never
  from recall of the file's structure. Two mis-targeted §-references were
  written
  by one author in one day, each from memory while the correct location sat
  already-quoted in that author's working context. One reached main and cost
  a maintainer fix commit, verifiable in this repo as `8f8413f`; the second
  was caught in the author's own draft before submission
  (contributor-reported). (This clause ships `unprobed` — see Provenance.)
  ❌ "the sync contract is in §4" (recalled; the quoted line was in §3).
  The same discipline covers an incident NARRATIVE, not just a pointer:
  draft a Provenance paragraph from the re-opened primary source (the
  transcript, the PR thread, the finding file), never from a paraphrase
  carried across sessions — narrative drift reads plausible and passes a
  review scoped to the rule's text, and a reviewer told not to re-verify
  quoted incident details will not catch it; the discipline sits with the
  author at draft time. (`unprobed` — see Provenance.)
- **Verifying the incident does not verify the prescription.** Distilling an
  incident into a rule is a lossy transform that can introduce a bug the
  incident never had: the rule cites a real failure yet prescribes a
  mechanism that itself fails on exactly the case it targets (`git cherry`
  for squash-merge residue on a multi-commit branch — its per-commit
  patch-ids never match the single squash commit, canonical rule in
  operational-rigor §2; "ack a webhook before durably recording it" — a
  post-2xx crash then loses the event; "peek-then-commit" a spend cap — a
  TOCTOU overspend race under concurrent fan-out). One reviewed batch of 27
  incident-mined rules had 4 of exactly this shape, each passing the author's
  own self-review and caught only by a cross-family mechanism review before
  merge. So when a rule's fix is a specific mechanism — a command, protocol,
  or algorithm distilled from a failure — before it ships for an agent to
  execute verbatim: (1) fix the correct OUTCOME in advance for both its own
  motivating scenario — traced through the failure mode it names (the crash,
  the concurrent fan-out, the squash), not merely confirmed that the incident
  was real — AND the nearest variant with one property flipped (multi-commit →
  single-commit, crash → no crash, concurrent fan-out → one worker); (2) run the
  mechanism against both and confirm it matches each — correctness that flips
  across that boundary is the trap this catches (git cherry is wrong on the
  multi-commit squash it targets yet right on a single-commit branch); (3) get
  a cross-family mechanism review (`cross-model-review`) attacking the
  MECHANISM, not the prose. No second
  family available → `cross-model-review` §6's fallback (same-model
  fresh-context critic, gap recorded) applies here too.
- What cannot be verified is labeled `unverified` or `user-must-provide` —
  never silently invented. Unproven ideas stay labeled open/candidate; no
  oversell.
- **Verify-before-you-write-it bites hardest on a capability you describe for a
  weaker executor** (`unprobed` — private incident as shape; see Provenance).
  "The engine auto-searches every category", "this flag does X" — a weak model
  executes such a line verbatim, with none of your context to catch it when it
  is wrong, so an unverified capability claim is a false instruction to the one
  reader least able to notice. When the behavior is new or just-patched, order
  it: prove it against a real gate (ground-truth-gates), THEN finalize the doc
  that describes it. A scarce live session (an auth window about to expire, a
  costly remote setup) argues for verifying FIRST, not for shipping the doc on
  the theory it probably works.
  ❌ drafting "the engine now self-heals across categories" into the skill
  while the self-heal fix is still unproven, to spend the login session before
  it expires.
- Embed the knowledge itself; do not make private paths or one person's
  memory a load-bearing reference. A hard-coded machine-absolute path is worse
  than a broken link: a stale duplicate clone resolves *silently* to an
  outdated copy and gets trusted (more dangerous than a 404, which at least
  fails loud). Anchor to the VCS root (`git rev-parse --show-toplevel`) and
  verify the path prefix before reading.

## 3. Provenance and decay

- Date-stamp volatile facts (versions, flags, model names, defaults).
- **Staleness concentrates in the world-fact rules — audit there first**
  (first in-house probe 2026-07-27 did NOT discriminate — both arms
  produced the scoping, the bare one unaided; one run screens for a
  large effect only, so it is
  flagged for a demotion judgment rather than demoted — see Provenance). A
  rule encoding a
  mutable fact about the outside world (which model or tool is default, how a
  CLI behaves, a numeric threshold someone measured) can go stale within
  days; a rule encoding method (reproduce before trusting, verify by
  execution) goes stale rarely and slowly. A staleness audit therefore
  concentrates the search on the world-fact files and treats the
  method-encoding files as low-yield — not as exempt. One sweep of four rules
  files found every stale instance — 8 of 8 — in the single file that carried
  world-facts; the three method files were clean. This scopes the SEARCH only:
  a method file still gets corrected when something does surface in it.
- **Capability-negative claims rot the worst** (`unprobed` — private incident
  as shape; see Provenance). About to write "no such flag", "only works
  interactively", "the API can't do X" into an instruction file — or
  about to act on one already there: these are version-scoped
  observations that read as timeless
  rules. A stale positive claim is far likelier to be exercised and
  exposed the first time someone follows
  it; a stale negative fails silent — it steers every later session away
  from a capability that now exists, and nothing ever exercises it to
  expose the rot. One playbook's "model switching only works in the
  interactive UI; no flag" was actively wrong at the tool's current version
  and had been routing sessions into a degraded path. A negative about
  a hosted model's BEHAVIOR is the one class a version pin cannot
  hold — hosted endpoints drift behind unchanged strings; that class
  follows delegation-and-review §1's pinned-string rule, not this
  protocol: date-stamp the recorded claim where written, and any
  session acting on it — routing decision or not — re-probes at
  decision time before repeating or relying on the negative, the
  re-probe satisfied only under the pinned-string rule's own
  attribution and unknown-property-fallback clauses, carried verbatim:
  "an unattributed answer measures an unknown model, not the slug's",
  and probe unavailable or failing → "assume the ADVERSE plausible
  state for this decision"; on any wording disagreement, the
  pinned-string rule wins.
  Writing a tool-interface negative: pin
  it to the version and probe it was observed on — and a capability
  controlled server-side (an API feature, an account rollout, a
  remote configuration) additionally pins the instance/account and
  observation date, because it can flip with no version change.
  Acting on one: read
  its pin; the tool's version has changed, the pin is missing, or the
  capability is server-side and any pinned dimension (instance,
  account, configuration, or simply time since the dated
  observation) may have drifted →
  re-verify with one probe (`--help` for a local interface claim; a
  server-side capability probes against the CURRENT decision's
  resolved instance/account — re-probing the former pin is comparison
  evidence, never the acting gate, and a local help screen proves
  nothing about an account-controlled
  feature; an existence claim — a flag listed, a field accepted —
  settles on `--help` or a schema read, while a FUNCTIONAL claim
  needs a trial invocation exercising
  the claimed-absent capability, and a trial whose success would be
  consequential (a send, a delete, a purchase) runs as a safe
  synthetic or dry-run form, or under its own authorization
  (operational-rigor §2) — no safe form and no authorization → the
  capability stays unknown), recording the newly observed
  dimensions, before
  obeying it; probe unavailable or inconclusive → the capability is
  unknown, not absent — record that where the claim is used and do not
  repeat the negative as fact. Done: writing — the claim carries its
  version pin, the probe that observed it, and (server-side) its
  instance/account and date; acting — every applicable pinned
  dimension is matched current, or re-probed, or recorded unknown.
  ✅ "playbook says no flag (pinned v0.2.98); current binary v0.2.101 —
  --help lists the flag now (existence), a dry-run invocation
  accepted it (function); corrected the playbook in place."
  ❌ "the playbook says there's no flag, so drive it through the UI."
- **A recorded environment remedy is a hypothesis on reuse, not a fact —
  verify it fired this time, and retract it in place when it doesn't**
  (`unprobed` — private incident as shape; see Provenance). A fix for an
  environment quirk (a process restart, a service bounce, a config
  toggle) gets written to memory once it worked, then reused across
  sessions on the strength of that one success — but the underlying
  cause can be a different bug next time the same symptom appears, or
  the environment can have moved out from under the remedy entirely.
  Applying a recorded remedy without confirming the symptom actually
  cleared repeats the capability-negative failure above in the opposite
  direction: a false negative fails silent, a false remedy fails LOUD
  the first time someone trusts it and it doesn't work — but only if
  the session checks; skipped, it just re-applies the broken fix next
  time too. Before writing "X fixes Y" into a durable file: confirm Y
  actually cleared, not merely that X ran without erroring. Before
  reapplying a recorded remedy: confirm it fixed THIS occurrence before
  moving on, and when it doesn't, correct the rule in place (per the
  correction discipline below) rather than leaving the disproven fix
  for the next reader.
  ❌ "restart the service — that's the documented fix" written once,
  applied unverified in three later sessions, until a session that
  checked found the symptom persisted and the note was stale.
- Correct a stale rule in place — never append the correction below the old
  line. A zero-context reader obeys whichever sentence it reads first, not
  the latest one.
- End each skill with a short provenance note and a one-line re-verification
  command for anything that may drift. A skill without a re-verification path
  decays into exactly the stale-instruction problem it was meant to solve.
  **And that command has to hang off something the work already touches**
  (first in-house probe 2026-07-27 discriminated: bare arm documented the
  condition with nothing reading it, ruled arm bound it — see Provenance):
  an invalidation
  condition needing a separate act of remembering is inert no matter how
  precisely it is written. Bind it to a surface the next pass crosses anyway —
  a line in the maintenance entry that pass must read, an assertion in a gate
  that already runs, a trigger on a file someone edits regardless. A measured
  finding carrying the clause "re-test if either file grows past ~250 lines"
  sat at 297 and 318 for days, still cited as current: the threshold was
  right, the condition was true, and nothing was reading it.
  ❌ "the invalidation condition is documented at the end of the finding."
- **A merged upstream integration is not necessarily the end of the
  campaign** (`unprobed` — the upstream half of the incident is
  verifiable in this repo's PR history, the sync half
  contributor-reported; see Provenance). Before diff-verifying a local
  file against "upstream final" and closing the sync, check for
  continuation on the synced surfaces — a maintainer's review can
  continue in follow-up PRs rather than concluding in the one that
  first merged, and at sync time those rounds may not have merged YET.
  The synced surfaces are every file the sync contract couples (the
  change-X-update-Y pairs), not only the file in hand. Check BOTH
  lists, each with its own invocation, on the SAME upstream repo and
  target branch lineage (a backport into another release branch is not
  a hit) — OPEN first, then MERGED, so a PR that merges between the
  two queries leaves the first set only by entering the second: ALL
  currently-open PRs (no creation-time bound — a follow-up opened
  BEFORE the anchor merged still counts; e.g. `gh pr list --repo
  <upstream> --base <branch> --state open`), then PRs merged after
  the anchor by MERGE TIME, not PR number (e.g. `gh pr list --repo
  <upstream> --base <branch> --state merged --json
  number,mergedAt` — the repo/base flags and the mergedAt field are
  load-bearing: an unflagged query can read the wrong fork or
  default branch, and PR numbers do not order by merge time). **A CLOSED PR is
  not automatically a non-hit.** Some maintainers land contributions by
  rebuilding them (no cherry-pick) into a consolidated branch grouped by
  target file, merging that branch, then closing the original PRs with a
  disposition comment — GitHub never marks the originals MERGED even though
  their content is live on the anchor branch, and the OPEN/MERGED queries
  above never surface them (observed: `F-e-u-e-r/opus-pack` PRs #173–181,
  closed individually, landed via consolidated PRs #194–197). CLOSED ≠
  rejected — read the disposition comment, or diff the PR's own changes
  against the anchor branch, before excluding it as a non-hit; a closed PR
  with no disposition comment and no matching content on the anchor branch is
  the only shape that safely reads as declined. Each list is enumerated
  to EXHAUSTION — the tool's default page size (gh's is 30) silently
  truncates, and a date bound does not lift the cap: paginate until
  the last page is short, and record the total counted. "Touching" is
  decided from each candidate's CHANGED FILES read mechanically, with
  the per-PR query ALSO repo-scoped — PR numbers are repository-local,
  so an unflagged view from a fork checkout reads the wrong PR (e.g.
  `gh pr view <n> --repo <upstream> --json files` or
  `gh pr diff <n> --repo <upstream> --name-only`),
  never from titles or bodies — a continuation PR's title may carry
  no path token while it edits the synced file. File enumeration has
  its own caps (gh's files query returns the first 100; hosted diffs
  truncate around 300): verify the retrieved file count equals the
  PR's changedFiles total, and when completeness cannot be proven,
  treat that PR as TOUCHING (conservative) or keep the sync
  provisional. One OPEN+MERGED pass is a snapshot with
  blind windows at its edges — a PR can change state between any two
  queries — so REPEAT the pass until a full OPEN+MERGED pass adds NO new
  TOUCHING-OR-UNCLASSIFIED candidate versus the previous pass — every
  newcomer gets its changed-files classification, AND every still-open
  candidate is reclassified each pass — an open PR's files mutate with
  new commits (track head OIDs to skip provably-unchanged ones); a
  transition to touching-or-unclassified destabilizes, while
  non-touching classifications never do (else a busy repo livelocks
  into provisional despite zero synced-surface hits);
  each pass's merged query re-covers whatever the prior open query
  lost to a merge. Still unstable after three passes → record the
  sync provisional, no further queries owed. A rename touches when EITHER path side
  matches a synced surface — path-oriented file listings can hide the
  old path, so where the tool does not expose both sides, treat
  renames conservatively as touching. Any touching hit → do not close
  the sync as final: re-anchor to the newest touching merged state,
  RE-DIFF the local files against that new state, and re-run the
  checks, or — when touching rounds are still open — record the sync
  as provisional with the follow-up fold owed. The re-diff is a GATE,
  not a citation: final closure requires zero unexplained
  sync-contract differences (differences → fold them and re-run;
  unresolved → provisional). Done when the sync record cites the
  stable-pass checks (commands + date + totals) with ZERO TOUCHING
  HITS — the candidate lists may be nonempty — and a clean local
  diff against the anchor state; that makes the anchor safe AS OF the
  check, never forever; otherwise it carries the provisional label.
- **Contributing a rule is not adopting it — a merge of your own rule
  into a shared library opens an adoption debt** (`unprobed` — see
  Provenance). The campaign bullet above runs upstream; the same merge
  leaves a SECOND thing open in the other direction, and the author is
  the likeliest reader to miss it. The merge closes the contribution
  while your own always-loaded files still do not carry the rule — and
  because you have been applying it by hand all along (you wrote it; it
  is in your working context), nothing feels missing. It is not adopted,
  it is remembered, and remembering ends with the session; the next one
  reverts to whatever the files say. Bind the debt to a surface
  something re-reads — the same ledger row or sync record that logs the
  merge carries it, and the row closes only on the port done or a
  reasoned decline recorded; probe-then-port keeps it open (or moves the
  debt to another surface something re-reads). A debt parked only in
  a plan, a summary, or an owed-line nothing re-opens is the
  invalidation-clause failure this file already warns about, wearing a
  different hat.
  ❌ "the rules merged upstream and I have been following them all
  session, so that batch is done" — followed from conversation context,
  by the one reader who cannot notice their absence.
- When two files must agree, write the sync contract down ("change X → update
  Y") in the canonical file. Prose inventories rot; prefer "read the
  directory" over hand-kept lists, and pin unavoidable lists with a rule or test.
  Do not paraphrase a load-bearing clause in a secondary location — quote it
  verbatim or point to the canonical copy (a paraphrase drifts silently), and
  the sync contract must name which file wins on disagreement.
- **A skill's internal citations are addressed to ITS library — re-resolve
  every one against the destination on install** (`unprobed` — contributor
  incident as shape; see Provenance). A distributable skill
  cites siblings by section number and by name ("delegation-and-review §3",
  "the author-is-not-the-judge rule"). Those addresses are relative to the
  library it was written in. Installed into a library that numbers its
  sections differently, or that never adopted the sibling, each one still
  READS as valid and now points somewhere else — the silent failure the
  §2 absolute-path rule names, in citation form: a stale `§3` resolves
  to a real section with the wrong content, where a 404 would at least
  fail loud. So on install, resolve every citation against the
  DESTINATION file — first pin what it addresses upstream (the section
  heading or the named rule; a bare `§N` carries no greppable name until
  you do), then grep the destination for that, never the number alone —
  and classify each: retargeted (the local address
  differs), unchanged, or absent-here (the sibling rule does not exist
  locally; delete the pointer — rewriting the sentence to stand without
  it, not to absorb the missing sibling's semantics (the no-paraphrase
  rule above holds) — or replace it with a non-resolving gap marker,
  never a live `§N`
  that resolves locally to unintended content; the port note
  records either, so nothing is dropped silently or left dangling).
  Then record the retargets in the port note as upstream-citation →
  local-target pairs — each carrying its heading or named anchor, since
  numbers alone go stale on the next renumber; re-resolve anchors on
  every re-sync rather than replaying numeric pairs — and each
  absent-here outcome as delete-or-gap,
  because the edits are now local divergences from
  upstream: unrecorded, the next diff-against-upstream reads your own
  retargets or deletes as drift and a re-sync silently restores the
  broken pointers.
  The port note is what makes them re-applicable and lets the diff exclude
  them. Done when no citation in the installed copy resolves to a section
  the author did not mean, and every difference from upstream is either
  in the port note or a real drift.
  ❌ "the port is byte-identical to upstream" — byte-fidelity is the
  wrong test: into a differently-numbered library, byte-identical IS
  the bug.
- **Package a set with its own honesty ledger.** Alongside its START-HERE router
  (§4), a multi-skill project *library* ships two more companion files — a
  MANIFEST (one line per skill → what it is + the evidence backing it, so the next
  maintainer can re-verify and knows what would falsify it) and an UNCERTAINTY
  register that quarantines everything not settled, each item bucketed and ending
  in a safe default; the three together are the packaging trio. A one-off handoff
  needs neither companion file — just an uncertainty / safe-default section when
  claims are unsettled. Bucket shapes and the trio:
  `references/project-skill-templates.md`.

## 4. Memory architecture

- **One source of truth per fact.** One canonical instruction file per repo;
  other entry files include or point to it. Never maintain the same content
  in two places.
- **The always-loaded file is a short router.** CLAUDE.md/AGENTS.md holds
  only what every session needs plus pointers; long content lives in
  load-on-demand skills/docs. Every always-loaded line taxes every future
  session — it must earn that.
- **Fix log:** one incident per file (problem / root cause / fix, with
  frontmatter for search), written right after the incident while the cause
  is fresh. Batch-imported backlogs produce a pile, not a log.
- Memory, notes, and fix-log files never hold secrets — no keys, tokens, or
  credentials; name where a secret lives, never its value.
- **Compile, don't retrieve.** When a fix-log entry reveals a default rule,
  promote the rule into the standing instructions; the entry remains as the
  record of why. Retrieval re-derives the answer every session; compilation
  pays once.
- **Sort a durable note by its future reach, not its topic** (`unprobed` — see
  Provenance). Three tiers, one admission test each: useful only for the current
  task → that task's own working file; a record of what happened this session, of
  no standing use later → a session journal; something to be followed *every*
  future time this kind of work is done → the standing spec/rules. The tier is
  set by how far forward the note applies — not by how long it stays literally
  true (a session event stays true forever yet still belongs in the journal, not
  the standing rules), and not by what it is about. A "fix" that is really a
  permanent convention belongs in the spec (compile-don't-retrieve above), not
  left in a task file the next task never opens.
- **Flipping a current-state order does not retire the old one on its
  own — sweep the whole file** (`unprobed` — private incident as shape;
  see Provenance). The instruction-file analog of operational-rigor §3's
  call-site sweep: a flipped default is an interface change whose call
  sites are every older verdict block in the same file. Updating the top
  summary or the newest
  paragraph is not enough: an older evidence block can still carry its
  own bold imperative verdict ("KEEP X AS DEFAULT") lower in the same
  file, and a future reader — or a weaker model that greps by the old
  term, lands mid-file on a retrieved chunk, or reads a bottom-appended
  log in order — can meet that older verdict first and follow the
  superseded order. After any default/order flip: grep the file for the
  superseded term(s) and their aliases — an empty grep is not a clean
  sweep (§5's keyword-grep-absence rule: a stale verdict can phrase the
  incumbent without the term), so read every verdict-bearing block —
  and neutralize each stale verdict IN PLACE: rewrite the verdict line
  itself, never a note appended below it (§3's correct-in-place rule —
  a zero-context reader, or a retrieved chunk that starts at the old
  bold line, obeys whichever sentence it reads first). The old
  imperative stops being one: "KEEP X AS DEFAULT" becomes "SUPERSEDED
  `<date>` — was: keep X as default — see `<new order's anchor>`; this
  block is provenance, its verdict is no longer the order". Rewrite
  rather than delete — history stays legible, but only one verdict
  reads as current.
  ✅ "promoted the new default at the top, then grepped the file for the
  old model's name — found two older 'KEEP AS DEFAULT' blocks, rewrote
  both verdict lines in place as SUPERSEDED-with-date pointing at the
  new order."
  ❌ "updated the current-state summary; the old benchmark write-up down
  below is just history, nobody reads that far" (a weaker executor does).
- **A contradiction between two verified results is not automatically a
  supersession — diff their run conditions before either claim wins**
  (`unprobed` — private incident as shape; see Provenance). Two results
  that disagree can both be true, each on its own scope (task difficulty,
  version, environment, input shape); a bare recency heuristic
  ("pick one — more recent / more tested — say why, flag the other") is
  the right move only once you've confirmed the results are actually
  measuring the same thing. Before applying it: name the candidate
  explanation for the disagreement, then verify it — don't assume the
  first plausible story. A recorded finding said a model scored 0/20 on
  headless file-edits; a fresh bench on what looked like the same task
  scored 2/2 clean. The first guess was "version drift" — checked, and
  the binary build was identical between both benches, which killed that
  explanation; the real difference was task complexity (the old bench
  drove harder multi-file edits, the new one a single-file edit). Both
  scores stayed true, on different task shapes. The fix is to
  scope-annotate BOTH findings with the condition that actually differs,
  not to overwrite the older one — a naive recency pick would have
  retired the 0/20 finding and mis-taught every future reader that the
  model handles complex edits.
  ✅ "0/20 (harder multi-file dir-mode edits, frontier bench) vs. 2/2
  (simple single-file edit, this bench) — same binary build, different
  task shape; both stand, scoped."
  ❌ "the new bench says 2/2, so the model actually works now" — recency
  applied without checking whether the two benches tested the same thing.
- **Two-strike promotion trigger:** the second time a lesson's trigger
  fires, that event promotes it — into a standing rule, or a hook where
  machine-checkable — and the entry gets a `promoted-to:` line. One
  occurrence is an anecdote; two is a pattern.
- **Placement test** for any new rule: can it be a hook (machine-enforced)?
  If not, can it live on-demand (skill / fix log)? Only when both answers
  are no does it earn an always-loaded line. An always-loaded line still
  owes a second placement question: which existing bullet already owns
  its topic? Confirm the SECTION first — check the addition against the
  section's own scope, not merely the nearest bullet's — then read the
  target section's bullets in full and default to folding the new clause
  into the host bullet that owns it (a trailing sentence, an added
  example, an extra clause); a standalone new bullet is the fallback for
  content with no existing host, not the default shape. Genuinely unclear
  whether it is this bullet's topic or a neighbor's → flag for the §6
  reviewer rather than defaulting to standalone. (`unprobed` — see
  Provenance.)
- Log recurring *slop* the same way — agent output that compiles and looks
  plausible but is subtly wrong (the six patterns are canonical in
  operational-rigor §5). One category captured once prevents it forever.

## 5. Skill-set design

- One skill, one topic; no duplicate homes for a fact — cross-reference the
  sibling instead. Each skill states **when NOT to use it** and which sibling
  to use.
- **Keyword-grep absence is not absence** (`unprobed` — private incidents as
  shape; see Provenance). About to add a new fact or rule to an
  instruction file, or to conclude one does not cover a fact
  (wording-only and provenance edits are out of scope): an empty grep is
  not the dup-check the no-duplicate-homes rule above needs — rules
  phrased differently from the search term repeatedly produced false
  "not covered" verdicts in the contributor's private log (see
  Provenance), one a proposed addition whose content already sat in the
  target file under other wording, caught only by reading the section at
  drafting time. The check: grep the target file and its sibling skills
  (the skills shipped beside it — list the parent skills directory,
  don't recall it, and include each searched skill's references files
  when the topic plausibly lives there; when the repo also carries
  router or entry instruction files — CLAUDE.md, AGENTS.md, a memory
  index — those join the search too, since a fact canonical in an
  entry file makes any skill addition a second home; a router file
  like CLAUDE.md as the TARGET has
  no siblings — its "siblings" are the files it points into) for the
  concept's name plus at least two alternates drawn from how the file
  might phrase it (the outcome it produces, the operation's other names,
  its domain jargon); list the actual section headings of the target AND
  of every file searched; from that real outline — never from memory —
  name the candidate homes (every section with a hit, plus every section
  the fact would live in if it existed) and read each in full before any
  verdict. A headingless file is read in full. When the candidate
  reads end with no duplicate found — and always when every search
  came back empty — read every searched file in full before any
  absence verdict: the trigger for the full read is failing to find
  the duplicate, never grep emptiness (one irrelevant hit must not
  disable the fallback), and the incidents' catch was the read, not
  the grep. Duplicate
  found → no second home, wherever it lives: in the target, no addition;
  in a sibling, cross-reference it — the "A cross-reference is not a
  load" rule below still applies as written. Otherwise the change record
  — the PR description or commit message when one is being created,
  otherwise the completion report — carries the result line: the terms
  searched, each file searched with what was read of it (named sections,
  or "read in full"), and "not found under the searches and sections
  listed". For a landing addition, the fresh-context reviewer (§6)
  re-runs those searches against the pre-addition text (the file at the
  revision the change branches from AND at the landing target's
  current pre-merge state — the base can gain an equivalent rule
  after the branch point; never the edited working copy) and
  reads at least one candidate of their own choosing — and before
  CONFIRMING an absence verdict, runs the author's own fallback:
  every searched file read in full when the duplicate was not found
  (a one-file sample confirms nothing — short of the full read, the
  verdict stays provisional and says so); a batch landing multiple
  additions — to one file or across files in the search set (targets,
  siblings, routers/entry files) — also READS each added rule body
  against the other additions in the batch, searches alone never
  discharging it (two additions can express one doctrine with
  disjoint vocabulary, exactly the empty-grep blind spot this rule
  opens with), plus searches the merged result
  across all added hunks (two additions can duplicate each other
  while neither exists in any base); a standalone not-covered verdict
  with no reviewer stays provisional in the report until a fresh-context
  reader without the author's session confirms it there. A bare "not
  covered" backed only by empty greps is the failure this rule exists to
  stop; no plausible home in the outline for a fact the task says is
  covered or being relocated, or doubt that the candidate list is
  complete → the placement is unresolved — escalate it, and under those
  conditions never assert absence.
  ✅ "grep for 'revert', 'rollback', 'undo' across the playbook and its
  two siblings returned nothing; read all three files end to end — the
  rule exists in the playbook under 'restore': duplicate found, no
  addition; cross-referenced the playbook's rule instead."
  ✅ "all searches empty — read both searched files end to end; recorded
  'not found under the searches and sections listed: revert, rollback,
  undo; playbook.md (read in full), helpers.md (read in full)' — then
  added the rule."
  ❌ "grep returned nothing, so the file doesn't cover it."
  ❌ "three synonyms, all empty — not covered" (no file was ever read).
- **A cross-reference is not a load** (`unprobed` in-house; external
  evidence — see Provenance). On weak tiers, discovering that a sibling
  skill applies is a judgment act: fable-method published a smoke-grade
  negative on exactly this — in-skill pointers went essentially unpicked-up
  by a weak executor across their rewordings (shape cited; their log
  carries the numbers). A clause a specific decision cannot afford to miss
  travels WITH the trigger point — quoted verbatim at the site that fires
  (§3's no-paraphrase rule; the quote inherits §3's sync contract naming
  which copy wins), not only pointed at; the cross-reference serves the
  strong reader.
- The frontmatter `description` is the trigger: write it as the exact
  conditions under which a model should load the skill, not as a title.
  Phrase triggers as observed states ("a test failed twice"), not topic
  labels ("debugging") — states fire; labels drift.
  A skill that never fires is dead weight; a skill that always fires is a tax.
- **A description is a rule too — probe its ROUTING, never just its
  prose** (`unprobed` — see Provenance). The description is the
  layer loaded before the skill fires at all, and a rule §6's
  behavioral probe never reaches: that probe hands a fresh reader the
  file already loaded, which tests whether the loaded content is
  u

…(truncated)
