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
|
**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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user