instructions/CONTRACT.md: Skill-H1, Referenztiefe und Begruendungsprosa praezisiert (schliesst #71, #72, #79)
CI / verify (push) Successful in 57s
Release / release (push) Successful in 37s

Files changed:
- CHANGES.md
- VERSION
- instructions/CONTRACT.md
- instructions/wiki-ingest/SKILL.md
This commit is contained in:
2026-09-09 16:25:34 +02:00
parent 7bc5da6e0d
commit 663b1c046c
4 changed files with 177 additions and 21 deletions
+70 -1
View File
@@ -35,7 +35,7 @@ dev-checkout concern - readable here, never shipped as something to parse.
--- ---
## 4.8.0-beta.9 - 2026-09-09 - source_type ist Instanzsache: Profilkatalog, Setup-Frage, evolve-subtypes-Instruction (#68) ## 4.8.0-beta.10 - 2026-09-09 - instructions/CONTRACT.md: Skill-H1, Referenztiefe und Begruendungsprosa praezisiert (#71, #72, #79)
**Author:** Torben Nehmer **Author:** Torben Nehmer
@@ -50,6 +50,7 @@ dev-checkout concern - readable here, never shipped as something to parse.
- source_type: Default streichen, unclassified als sichtbares Fach, layout: fuer source (schliesst #66) - source_type: Default streichen, unclassified als sichtbares Fach, layout: fuer source (schliesst #66)
- raw accept: Datums-Shard statt Typverzeichnis, fidelity/authority am Drop-Punkt (schliesst #67) - raw accept: Datums-Shard statt Typverzeichnis, fidelity/authority am Drop-Punkt (schliesst #67)
- source_type ist Instanzsache: Profilkatalog, Setup-Frage, evolve-subtypes-Instruction (#68) - source_type ist Instanzsache: Profilkatalog, Setup-Frage, evolve-subtypes-Instruction (#68)
- instructions/CONTRACT.md: Skill-H1, Referenztiefe und Begruendungsprosa praezisiert (#71, #72, #79)
<!-- /wikitool:bumps --> <!-- /wikitool:bumps -->
Das Label `status/incoming` gibt es seit heute in Gitea: der Mensch legt einen Das Label `status/incoming` gibt es seit heute in Gitea: der Mensch legt einen
@@ -579,6 +580,74 @@ Geändert: `instructions/kb-profiles.md`, `instructions/setup-instance.md`,
Schließt #68. Schließt #68.
### `instructions/CONTRACT.md` § Writing an instruction: drei offene Fragen entschieden
Drei Issues aus der #65-Analyse zeigten auf denselben Abschnitt. Alle drei
enden dort, wo die Regel steht, nicht in einem Issue-Kommentar.
**Der Imperativ-Titel bindet eine Instruction, nicht ein `SKILL.md` (#71).**
Die Regel griff dem Wortlaut nach auf alle fünf Skills durch, deren H1
Nomenphrasen sind. Geprüft gegen die Primärquelle: Anthropic normiert `name`
und `description` und sagt zur Body-Überschrift nichts; die eigenen
Beispiel-Skills heißen `# PDF Processing`, `# BigQuery Data Analysis`. Dazu
das Sachargument — der H1 liegt auf keinem Retrieval-Pfad, weil über die
Aufnahme eines Skills die `description` entscheidet, die ab Sessionstart im
Kontext steht, während der Body erst beim Zugriff gelesen wird. In der Sitzung
kam ein Beleg dazu, den keines der Issues kannte: der vendorierte
`commonplace`-Korpus trägt dieselbe Imperativ-Titel-Regel, unabhängig
entstanden, und macht im selben Absatz dieselbe Ausnahme („for promoted skills,
the skill name is the title"). Die fünf Titel bleiben unverändert.
**Referenztiefe: Anthropics „one level deep" gilt gebündeltem Material (#72).**
Weg 2 der drei zur Wahl stehenden. Der Beleg für die Reichweite steht im
vendorierten `codex-skill-creator/SKILL.md`: die Beispiele der Regel sind
`DOCX-JS.md`, `REDLINING.md`, `OOXML.md` — alles Dateien *im Skill-Bündel*. Kein
Skill dieses Repos hat heute eine solche Datei, die Regel bindet hier also
wörtlich nichts. Für den Link von einem Skill auf einen repo-weiten Contract
fallen die beiden Hälften der Frage auseinander: die Mechanik (Zweit-Hop wird
womöglich nur angelesen) ist real und verzeichnisunabhängig, die Vorschrift ist
für diesen Fall von Anthropic nicht belegt. Die geteilten Contracts bleiben
geteilt — Invariante 8 hat sie dorthin gestellt, und § Frontload verlangt, dass
ein *Schritt* ohne Vorkontext entscheidbar ist, nicht dass jede Regel an ihm
wiederholt wird. Als Auflage bleibt das Billigere: ein Link sagt, was der
Schritt aus der Datei braucht.
Ob die Mechanik hier überhaupt beißt, wurde vor der Entscheidung im Eval-Aufbau
nachgesehen, und die Antwort ist: nicht messbar. Die L2-Trajectory-Regeln lesen
ausschließlich `wikitool.call`, `gate.*`, `publish.commit` und
`prompt.submitted` — keine Dateizugriffe eines Agenten; auf Claude Code ist
überhaupt kein Tool-Hook verdrahtet, ein `head -100` hinterlässt also keine
Spur. Die zweite Hälfte der Behauptung, was am Ende im Kontextfenster stand,
erzeugt konstruktionsbedingt nirgends ein Event. Ein kausaler A/B-Vergleich
bräuchte den L3-Runner, der entworfen und nicht gebaut ist. Das steht jetzt im
Contract: eine Festlegung über Reichweite, keine Messung. Der Nebenfund — L2
sieht auf dem primären Harness gar keine Tool-Calls — ist ein eigenes Issue
wert und nicht Teil dieser Änderung.
**Wieviel Begründung ein Schritt tragen darf, ist jetzt messbar (#79).** Der
alte Satz („Keep reasoning out of the body […] keep only enough reasoning to
decide edge cases") zog in zwei Richtungen, und die größte Instruction des
Repos lebte in der Lücke. Neu sind eine Keep/Cut-Tabelle und zwei Tests:
*Substitution* — die Passage streichen und den Schritt noch einmal lesen; rät
ein Agent ohne Vorkontext jetzt, war es eine Entscheidungshilfe und sie bleibt,
egal wie lang. *Once* — eine Entscheidungshilfe steht an dem Schritt, an dem die
Entscheidung fällt, und an genau einem solchen (Invariante 8). Danach gemessen
stand die `source_type`/Capture-Asymmetrie in `wiki-ingest` zweimal; sie steht
jetzt einmal, in Schritt 1, und Schritt 6 trägt die Anweisung plus Verweis.
Die beiden anderen in #79 genannten Stellen — Namenskollision in Schritt 1,
`## Not Extracted` in Schritt 6 — bestehen den Substitutionstest und bleiben.
214 → 211 Zeilen; die Kürzung ist nicht der Zweck, die Eindeutigkeit ist es.
**PATCH**, geprüft gegen den Drop-in-Test: eine Instanz kopiert
`instructions/` über sich, nichts wird umbenannt oder entfernt, kein Kommando,
kein Flag, kein maschinengelesenes Format, und der Rückweg funktioniert
genauso. Kein `--breaking`, kein Migrationsdokument.
Geändert: `instructions/CONTRACT.md` (§ Writing an instruction, drei neue
Unterabschnitte), `instructions/wiki-ingest/SKILL.md` (Schritte 1 und 6).
Schließt #71, #72 und #79.
--- ---
## 4.7.4 - 2026-09-04 - bootstrap.md nennt den session-id-WARN nach frischem Bootstrap explizit als erwartet ## 4.7.4 - 2026-09-04 - bootstrap.md nennt den session-id-WARN nach frischem Bootstrap explizit als erwartet
+1 -1
View File
@@ -1 +1 @@
4.8.0-beta.9 4.8.0-beta.10
+94 -5
View File
@@ -142,16 +142,105 @@ does not survive being archived or copied. The price of a copy is drift, and dri
Scaffold with `tools/wikitool new instruction --name "<name>"`; the contract is Scaffold with `tools/wikitool new instruction --name "<name>"`; the contract is
`tools/wikitool types describe instruction`. `tools/wikitool types describe instruction`.
- **Imperative title.** It answers "what does this tell me to do?". - **Imperative title.** It answers "what does this tell me to do?". This binds the flat
`instructions/<name>.md` form only - a skill's H1 is a different case, below.
- **`description` is the retrieval wire.** Write it to match the question an agent would ask - **`description` is the retrieval wire.** Write it to match the question an agent would ask
when it needs this procedure, not as a label for the file. when it needs this procedure, not as a label for the file.
- **Frontload.** Self-contained enough for an agent with no prior context: define terms - **Frontload.** Self-contained enough for an agent with no prior context: define terms
inline, do not assume other documents are loaded. inline, do not assume other documents are loaded. What this does and does not say about
- **Keep reasoning out of the body.** Cut the explanation of *why* each step exists. If it is linking a shared contract: below.
worth preserving, it is a concept page under `kb/concepts/`, linked from here. Keep only - **Reasoning earns its place by deciding something.** Keep what an agent needs in order to get
enough reasoning to decide edge cases. *this* decision right, at the step where it falls; cut the explanation of why the step exists
at all. If that is worth preserving, it is a concept page under `kb/concepts/`, linked from
here. Where the line runs, and how to test a passage against it: below.
- **State scope boundaries.** When does this *not* apply, and what to do instead. - **State scope boundaries.** When does this *not* apply, and what to do instead.
### A skill's H1 is a name, not an imperative
`instructions/<name>/SKILL.md` takes a name-shaped H1 matching its `name:` frontmatter -
`# Wiki Ingest`, not `# Ingest a source file into the wiki`. The imperative-title rule is
written for the flat form and stops there.
The heading lies on no retrieval path. What decides whether a skill is picked up is
`description`, which sits in the agent's context from session start; the body is read only once
the skill is already open, and by then the title has nothing left to decide. Anthropic's
skill-authoring guidance agrees by omission and by example: it normalises `name` and
`description` and says nothing about the body's heading, and its own worked examples are noun
phrases (`# PDF Processing`, `# BigQuery Data Analysis`). So does the vendored `commonplace`
corpus, which arrived at the imperative-title rule independently and carves out the same
exception in the same breath - "for promoted skills, the skill name is the title".
That is the whole exception. Everything else in this section binds a `SKILL.md` exactly as it
binds an instruction.
### Reference depth: bundled files, not repo-wide contracts
Anthropic's skill-authoring guidance asks that reference files stay **one level deep from
`SKILL.md`**, because a file reached at the second hop may be previewed rather than read -
`head -100` instead of the whole file - leaving the step to run on incomplete information.
That rule governs **skill-bundled** material: files sitting in `instructions/<name>/` beside the
`SKILL.md`. The guidance's own worked example is a bundle (`SKILL.md``REDLINING.md`,
`OOXML.md`), and it says nothing about files outside the skill directory. No skill in this repo
has a bundled file today, so as written the rule currently binds nothing here.
A link from a skill to a repo-wide contract - [kb/CONTRACT.md](../kb/CONTRACT.md),
[tools/CONTRACT.md](../tools/CONTRACT.md), [gates.md](gates.md) - is a different category, and
the two halves of the question have different answers:
- **The mechanic is real and directory-independent.** A contract reached at the second hop can
be read partially exactly as a bundled file would be. Nothing about the path makes it safe.
- **The rule is not.** Reading its scope wider than it states would attribute a rule to a source
that does not carry it - the same move invariant 3 forbids about facts.
So the shared contracts stay shared and stay linked once. AGENTS.md invariant 8 is what put them
there: copying `kb/CONTRACT.md` into five `SKILL.md` files is precisely the second copy that
drifts. § Frontload does not ask for that either - it asks that a **step** be decidable without
prior context, not that every rule the step obeys be restated at it.
What the mechanic does oblige is cheaper than either: **a link says what the step needs from the
file it points at.** A bare "read X first" leaves a partial read undetectable; naming what is to
be taken from it - the field, the section, the decision - keeps the step decidable even when the
read came up short, and tells the next author which reference is actually load-bearing.
`wiki-ingest` step 7 is the shape: three contracts linked, each with the clause that says why
this step needs it.
This is a narrower posture than the vendored `commonplace` corpus takes, which makes outbound
links exceptional in its instruction collection and frontloads the rest. That works for a corpus
whose procedures do not share a contract; here they do, and invariant 8 outranks the preview
risk.
**All of the above is a judgment, not a measurement**, and it is worth knowing why it cannot be
the second. Whether the mechanic bites here is not something this repo can currently observe:
the L2 trajectory scorers read `wikitool` calls, gates and publishes, never an agent's file
reads, and no tool hook is wired on the primary harness at all - so a `head -100` leaves nothing
to score. The other half of the claim, what ended up in the context window, produces no event
anywhere by construction. Gitea #72 records what a test would cost and why it was not bought.
### How much reasoning a step may carry
"Cut the reasoning" and "keep enough to decide an edge case" are one sentence pulling two ways,
and the largest instruction in this repo lives in the gap. The line runs here:
| Keep | Cut |
|---|---|
| What an agent must know to get this decision right, at the step where it falls | Why the step exists at all |
| The consequence of the wrong choice, when nothing later catches it | The consequence, when a validator, a gate or a later step catches it |
| Why a plausible-looking default is the wrong answer | Background about the design that produced the field |
Two tests, both cheap:
- **Substitution.** Delete the passage and read the step again. Does an agent with no prior
context still make the same call? If yes, it was background. If it now guesses, it was a
decision aid, and it stays - however long it runs.
- **Once.** A decision aid belongs at the step where the decision falls, and at exactly one such
step (AGENTS.md invariant 8). Where the same decision falls at two steps - `wiki-ingest` asks
for `fidelity`/`authority` in step 1 and again in step 6 - the reasoning is written at the
first and the second carries the instruction plus a pointer, never a second telling.
A passage that survives both is not an exception to the rule. Deciding an edge case is the part
the rule keeps; the length it takes to do that is not the measure.
## Instruction duality ## Instruction duality
These files are both content and running system. Changing one changes agent behaviour These files are both content and running system. Changing one changes agent behaviour
+12 -14
View File
@@ -24,13 +24,10 @@ pages should never have cost the concept contract. Field-level requirements alwa
two capture flags are not: `raw accept` refuses without them. two capture flags are not: `raw accept` refuses without them.
**Ask the user for `--fidelity` and `--authority` before this call, rather than guessing from **Ask the user for `--fidelity` and `--authority` before this call, rather than guessing from
a quick look at the file.** This is the one place in the whole skill where the asymmetry from a quick look at the file.** A guessed capture value is not "unknown": it is a claim about the
`source_type` (step 6 below) does not hold: a wrong `source_type` sits in a visible, capture that nothing later can correct, because the knowledge exists only at this drop point.
correctable catalog slot (`unclassified`), but a guessed capture value is not "unknown" - it Genuinely unclear how faithful the capture is, or what the material may claim about its
is a claim about the capture that cannot be corrected later, because the knowledge exists only subject? Say so and ask - there is no plausible-looking default to fall back on.
at this drop point. If it is genuinely unclear how faithful the capture is or what the
material may claim about its subject, say so to the user and ask directly - do not fall back
to a plausible-looking default.
```bash ```bash
tools/wikitool raw accept --fidelity <value> --authority <value> \ tools/wikitool raw accept --fidelity <value> --authority <value> \
@@ -79,7 +76,8 @@ pages should never have cost the concept contract. Field-level requirements alwa
which entities/concepts to create or update, any specific emphasis. which entities/concepts to create or update, any specific emphasis.
6. **Create the source page.** Read 6. **Create the source page.** Read
[kb/sources/COLLECTION.md](../../kb/sources/COLLECTION.md) first. [kb/sources/COLLECTION.md](../../kb/sources/COLLECTION.md) first - it holds what this
instance expects of a source page's sections and how it names one.
```bash ```bash
tools/wikitool new source --name "<Title>" \ tools/wikitool new source --name "<Title>" \
@@ -99,12 +97,12 @@ pages should never have cost the concept contract. Field-level requirements alwa
it later without moving or renaming the page. it later without moving or renaming the page.
`fidelity` and `authority` have no default either, and `new source` refuses without them the `fidelity` and `authority` have no default either, and `new source` refuses without them the
same way (Gitea #67) - but unlike `source_type` there is no catalog slot to fall back on. If same way (Gitea #67) - but here there is no catalog slot to fall back on, for the reason step
step 1 already ran `raw accept` without `--page`, its success message printed the exact 1 gives. If step 1 already ran `raw accept` without `--page`, its success message printed the
`--set fidelity=... --set authority=...` pair to reuse here verbatim; if it did not (the file exact `--set fidelity=... --set authority=...` pair to reuse here verbatim; if it did not (the
was already in `raw/`), ask the user the same question step 1 asks before promoting, rather file was already in `raw/`), ask the user, rather than inferring an answer from the file's
than inferring an answer from the file's content now. Never pass `unknown` here - that value content now. Never pass `unknown` here - that value is backfill-only, written only by
is backfill-only, written only by `wikitool touch` on a page predating this rule. `wikitool touch` on a page predating this rule.
List **every** raw file this ingest covers - a folder of related documents becomes one List **every** raw file this ingest covers - a folder of related documents becomes one
source page with all its files in `raw_files:`, not one page per file. For an external source page with all its files in `raw_files:`, not one page per file. For an external