Files
DonchitosandClaude Opus 5.5 be8993bbc5 Release 1.1.3 — long skills keep their later steps
Fix release for 1.1.2: the 14 longest skills keep their later phases
after a compaction, a question nobody answered is never taken as an
answer, settings read the same from a subfolder, the commit check works
for a project in a subfolder of a larger repository, every skill opens
with a title, and the shipped allow rules no longer approve deleting a
branch or writing files without asking. Details in CHANGELOG.md; upgrade
steps in UPGRADING.md (v1.1.2 → v1.1.3).

Refs #83
Refs #133

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0185en4t76fPn7315q4c3nko
2026-10-08 17:52:48 +11:00

97 lines
4.2 KiB
Markdown

---
paths:
- ".claude/skills/**"
- ".claude/agents/**"
---
# Skill and Gate Authoring
**A check that cannot report that it did not run is not a check.**
The same shape recurs across unrelated subsystems, so treat it as the default
risk in any check you write, not as an unusual mistake.
The failure is always the same trade: a step that could not run produces output
indistinguishable from a step that ran and found nothing. Nobody reading the
output can tell which happened, and the permissive reading is the one that gets
believed, because it is the one that lets work proceed.
## The five obligations
### 1. Every gating verdict needs a "could not assess" value
If a skill emits a verdict something else depends on, its vocabulary must include
one — `NOT ASSESSED`, or the local equivalent — and the report must say *which*
of the reasons applied. A vocabulary of three confident verdicts forces every
unknown into a claim.
**Rank it deliberately.** It must outrank the pass value: a run that could not
assess part of its scope has not established that the scope is good. It must
**not** outrank the failure values: a known problem is more actionable than an
unknown, and demoting a real failure behind an access problem buries it.
**`NOT ASSESSED` is not a gentler failure verdict.** "I looked and found nothing"
and "I could not look" have different fixes — one needs work done, the other
needs access granted or an input classified. Collapsing them sends the reader to
the wrong fix.
### 2. An absent value may not default to the permissive one
Especially when **nothing in the framework writes that key**. Before defaulting,
check who sets it: a key with a reader and no writer takes its default branch on
every project that ever runs, so that branch is not an edge case — it is the
behaviour.
Over-running a check costs minutes. Under-running one ships the category unrun.
### 3. A skipped step announces itself
In the output, not only in the source. If a phase, category, or agent did not run
— wrong engine, missing config, unavailable input, a `team.size` that collapses
the pipeline — the artifact must say so by name. A silent skip and a successful
one are the same artifact.
A rule enforced in the body and never surfaced in the output is, to the reader,
identical to no rule at all.
### 4. Never assert what you cannot source — and wire the gap to the verdict
Where this repo pins external facts (`docs/engine-reference/**`), do not fill a
gap from training data. Write the gap down instead: `NOT SOURCEABLE — <what> is
not covered by <path>`.
**Flagging alone is not enough.** A named gap that does not reach the verdict is
just a comment. Wire it: a category with no sourced inputs must force obligation
1's value, so the gap makes the pass unreachable rather than sitting beside it.
A confidently wrong pattern list is worse than an absent one — it produces a scan
that looks thorough, finds nothing, and reads as a pass.
### 5. Gates derive their covered set; they do not enumerate it
An allowlist pins what was known when it was written and is silent about
everything added since. Derive the set from what the repo actually contains, so a
new skill or agent cannot ship outside coverage by simply not being on a list.
**If the category is not mechanically crisp, say so in the gate and keep the
list.** A gate that fires on forty files does not get fixed, it gets muted — and
a muted gate is worse than a narrow one, because it reads as coverage. When you
keep a list, record *why* derivation failed and state the obligation to extend it.
Two further gate rules:
- **Assert something that cannot be true by accident.** A check for the word
"unity" is satisfied by a file path, and case-insensitively by "community".
Assert a distinctive token instead.
- **A gate you have not watched fail is not a gate.** Break the thing it guards,
confirm it fails, restore. One mutation per tool invocation — a batch that
times out leaves the repo holding a broken file, and `trap … EXIT` does not
survive `SIGTERM`.
## The test to apply
Before shipping a skill or gate, ask: **if this step silently did not run, what
would the output look like?**
If the answer is "the same", it is not finished.