instructions/CONTRACT.md: Skill-H1, Referenztiefe und Begruendungsprosa praezisiert (schliesst #71, #72, #79)
Files changed: - CHANGES.md - VERSION - instructions/CONTRACT.md - instructions/wiki-ingest/SKILL.md
This commit is contained in:
+70
-1
@@ -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
|
||||
|
||||
@@ -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)
|
||||
- raw accept: Datums-Shard statt Typverzeichnis, fidelity/authority am Drop-Punkt (schliesst #67)
|
||||
- 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 -->
|
||||
|
||||
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.
|
||||
|
||||
### `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
|
||||
|
||||
@@ -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
|
||||
`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
|
||||
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
|
||||
inline, do not assume other documents are loaded.
|
||||
- **Keep reasoning out of the body.** Cut the explanation of *why* each step exists. If it is
|
||||
worth preserving, it is a concept page under `kb/concepts/`, linked from here. Keep only
|
||||
enough reasoning to decide edge cases.
|
||||
inline, do not assume other documents are loaded. What this does and does not say about
|
||||
linking a shared contract: below.
|
||||
- **Reasoning earns its place by deciding something.** Keep what an agent needs in order to get
|
||||
*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.
|
||||
|
||||
### 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
|
||||
|
||||
These files are both content and running system. Changing one changes agent behaviour
|
||||
|
||||
@@ -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.
|
||||
|
||||
**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
|
||||
`source_type` (step 6 below) does not hold: a wrong `source_type` sits in a visible,
|
||||
correctable catalog slot (`unclassified`), but a guessed capture value is not "unknown" - it
|
||||
is a claim about the capture that cannot be corrected later, because the knowledge exists only
|
||||
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.
|
||||
a quick look at the file.** A guessed capture value is not "unknown": it is a claim about the
|
||||
capture that nothing later can correct, because the knowledge exists only at this drop point.
|
||||
Genuinely unclear how faithful the capture is, or what the material may claim about its
|
||||
subject? Say so and ask - there is no plausible-looking default to fall back on.
|
||||
|
||||
```bash
|
||||
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.
|
||||
|
||||
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
|
||||
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.
|
||||
|
||||
`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
|
||||
step 1 already ran `raw accept` without `--page`, its success message printed the exact
|
||||
`--set fidelity=... --set authority=...` pair to reuse here verbatim; if it did not (the file
|
||||
was already in `raw/`), ask the user the same question step 1 asks before promoting, rather
|
||||
than inferring an answer from the file's content now. Never pass `unknown` here - that value
|
||||
is backfill-only, written only by `wikitool touch` on a page predating this rule.
|
||||
same way (Gitea #67) - but here there is no catalog slot to fall back on, for the reason step
|
||||
1 gives. If step 1 already ran `raw accept` without `--page`, its success message printed the
|
||||
exact `--set fidelity=... --set authority=...` pair to reuse here verbatim; if it did not (the
|
||||
file was already in `raw/`), ask the user, rather than inferring an answer from the file's
|
||||
content now. Never pass `unknown` here - that value is backfill-only, written only by
|
||||
`wikitool touch` on a page predating this rule.
|
||||
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user