Entwurf · Issue 5a95366
Die Kette wird am Merge geprüft
Entwurf zu Issue 5a95366, Meilenstein 5 von docs/plans/5a95366-chain-gate.md. Jedes Urteil unten wird beim Rendern von judgeChain erzeugt, keiner der Sätze ist abgeschrieben. Ändert sich eine Zurückweisung im Code, ändert sich diese Seite mit — oder der Build bricht.
AGENTS.md beschreibt eine Reihenfolge: erst das Issue, dann der Plan, dann der Entwurf, dann die Freigabe, dann der Code. Bitten war bisher alles, was daran hing. Ein Runner, der die Schritte überspringt, merkt nichts davon — und ein Runner, der sich daran hält, kann es nicht belegen. Beides ist derselbe Mangel: nichts an dieser Kette ist prüfbar.
Dieses Kapitel entwirft die Prüfung. Nicht die Regeln — die stehen schon im Kontrakt — sondern die Sätze, mit denen sie zurückweisen, und die Stelle, an der sie zurückweisen können.
01Die sieben Glieder
Ein Urteil meldet immer alle sieben, auch die, die es nicht prüfen konnte. Ein Bericht, der beim ersten Fehler abbricht, verbirgt die übrigen sechs — und wer eine Kette repariert, will die ganze Form auf einmal sehen.
patch— die Arbeit fügt genau einen Plan hinzu. Der Plan, den ein Patch schreibt, benennt sein Issue; einen bereits gemergten Plan zu ändern, beansprucht dessen Issue nicht.issue— die Id aus dem Front Matter liegt im COB-Store. Diese Frage stelltjust plan-checkbewusst nicht: sie brauchtradund einen laufenden Node, und eine Prüfung, die offline rot wird, wird abgeschaltet.plan— die Datei hat die Form eines Plans. Dieselbe Prüfung wie lokal, an der Stelle, an der sie zählt.draft— das Kapitel liegt im Baum. Zwei Zeiger, genau einer (entschieden inecdea18):draft:fügt ein Kapitel hinzu,settles:nennt das bestehende, das die Änderung wahr hält. Inplan-spec.tsoptional, hier verpflichtend: der Entwurf ist die Stufe, auf der eine Entscheidung noch billig ist.approval— eine Unterschrift auf dem Token deckt genau diesen Plan. Siehe 03.settled— der Plan trägt## What the work settled. Das wird nach der Arbeit geschrieben, also kann keine Prüfung, die vorher läuft, es je verlangen.proves— jedes**Ends when**trägt ein Kommando. Das ist der Unterschied zwischen „die Arbeit hängt an einem freigegebenen Plan" und „der freigegebene Plan wurde geliefert". Ausgeführt werden die Kommandos hier, nicht im Gate: sie gehören zur Werkzeugkette dieses Repos, und keine davon liegt auf dem Broker-Image. Das Gate hält, dass es sie gibt und dass sie im Digest der Freigabe stehen — ein nachträglich ausgetauschtes Kommando bricht die Signatur.
| ok | patch | names its issue through docs/plans/5a95366-chain-gate.md |
| ok | issue | issue 5a95366a19f5f8d0a3fbb9cb2faeb8c73093a466 exists |
| ok | plan | docs/plans/5a95366-chain-gate.md is well-formed, 1 milestone(s) |
| ok | draft | draft /docs/design/chain-gate is in the tree |
| ok | approval | approved by did:key:z6MkrNYyVNngbG1UVmt5xbB3wye4RQtVUgZUi4cvJ5v88v5N, on the token |
| ok | settled | the plan records what the work settled |
| ok | proves | 1 of 1 milestone command(s) ran green |
chain complete
02Drei Arten, nein zu sagen
Ein Gate, das „chain check failed" sagt, schickt jemanden dazu, den Prüfer zu lesen. Jeder Satz benennt deshalb das Glied, was erwartet wurde und was gefunden wurde — der nächste Schritt soll aus der Zurückweisung allein hervorgehen. Die Tests prüfen diese Sätze, nicht Booleans: der Satz ist der Teil, der weiter funktionieren muss.
| ok | patch | names its issue through docs/plans/5a95366-chain-gate.md |
| ok | issue | issue 5a95366a19f5f8d0a3fbb9cb2faeb8c73093a466 exists |
| ok | plan | docs/plans/5a95366-chain-gate.md is well-formed, 1 milestone(s) |
| ok | draft | draft /docs/design/chain-gate is in the tree |
| NO | approval | did:key:z6MkrNYyVNngbG1UVmt5xbB3wye4RQtVUgZUi4cvJ5v88v5N approved something else: planDigest changed since — a plan changed after approval is a plan nobody approved |
| ok | settled | the plan records what the work settled |
| ok | proves | 1 of 1 milestone command(s) ran green |
chain broken — the work does not hang on an approved plan
Das ist die Zurückweisung, wegen der es den Schritt überhaupt gibt. „Signatur ungültig" würde jemanden zur falschen Reparatur schicken — das Feld, das sich bewegt hat, steht deshalb im Satz.
| ok | patch | names its issue through docs/plans/5a95366-chain-gate.md |
| ok | issue | issue 5a95366a19f5f8d0a3fbb9cb2faeb8c73093a466 exists |
| ok | plan | docs/plans/5a95366-chain-gate.md is well-formed, 1 milestone(s) |
| ok | draft | draft /docs/design/chain-gate is in the tree |
| NO | approval | .chain/approvals/5a95366a19f5f8d0a3fbb9cb2faeb8c73093a466.sig verifies against no signer in .chain/allowed_signers, in namespace plan-approval@tessera.at — an approval is made on the token, and no key an agent can reach counts |
| ok | settled | the plan records what the work settled |
| ok | proves | 1 of 1 milestone command(s) ran green |
chain broken — the work does not hang on an approved plan
| ok | patch | names its issue through docs/plans/5a95366-chain-gate.md |
| -- | issue | not checked — could not read the COB store to look up 5a95366a19f5f8d0a3fbb9cb2faeb8c73093a466 |
| ok | plan | docs/plans/5a95366-chain-gate.md is well-formed, 1 milestone(s) |
| ok | draft | draft /docs/design/chain-gate is in the tree |
| ok | approval | approved by did:key:z6MkrNYyVNngbG1UVmt5xbB3wye4RQtVUgZUi4cvJ5v88v5N, on the token |
| ok | settled | the plan records what the work settled |
| ok | proves | 1 of 1 milestone command(s) ran green |
chain broken — the work does not hang on an approved plan
Ein Faktum, das nicht ermittelt werden konnte, ist null, nie false. Ein Gate, das „ich konnte den COB-Store nicht erreichen" als „das Issue existiert nicht" liest, weist gute Arbeit zurück; umgekehrt winkt es schlechte durch. null besteht nie — es sagt nur, dass niemand nachgesehen hat.
Genau dieser Fehler ist beim Bauen passiert: rad issue show <id> ist die naheliegende Schreibweise und eine Falle. Der Befehl endet mit 1, sobald stdout kein Terminal ist — für ein Issue, das offensichtlich existiert, und ohne ein Wort dazu. Das Gate las das als „nicht im Store" und wies korrekte Arbeit zurück. rad cob list antwortet ohne Terminal und meint es.
03Was eine Freigabe unterschreibt
Eine Unterschrift unter „Issue 5a95366 ist freigegeben" ist wertlos: sie verifiziert gegen jeden Patch, der dieses Issue nennt, auch gegen Arbeit, die der Freigebende nie gesehen hat. Unterschrieben wird deshalb ein Fingerabdruck dessen, was tatsächlich gelesen wurde.
chain-statement v1 issue=5a95366a19f5f8d0a3fbb9cb2faeb8c73093a466 plan-path=docs/plans/5a95366-chain-gate.md plan-digest=sha256:e4413b0b81d2aad54eacf5c19aa8ca2bf6dc4c17263ca26004fe82fc869c4e2e draft-path=app/docs/design/chain-gate draft-tree=89abcdef0123456789abcdef0123456789abcdef
Nicht gebunden sind der Commit und der Arbeitsbaum, und das ist Absicht. Die Freigabe fällt, bevor der Code existiert — genau darum geht die Reihenfolge so. Einen Commit zu binden hieße entweder, die Freigabe ans Ende zu verschieben, was den Prozess umdreht, oder nach jedem Commit neu freizugeben, was allen beibringt, durchzuklicken. Die Kette garantiert also, dass Arbeit an einem freigegebenen Plan hängt; dass die Arbeit dem Plan entspricht, kann sie nicht behaupten. Das ist Review, und das ist die Aufgabe eines Menschen.
plan-digest deckt die freigegebene Substanz, nicht die Bytes der Datei: Front Matter, Approach, jeden Meilenstein mit seinen Arbeitspaketen, seinem Endzustand und seinen Kommandos. Ausgenommen sind die Abschnitte, die es gibt, um hinterher festzuhalten, was geschah — ## What the work settled verlangt der Kontrakt bis zum Merge, und ein Digest, den diese eine Pflichtänderung zerstört, ist ein Digest, den niemand grün hält. Ein umbrochener Absatz ist derselbe Plan; ein geänderter Approach ist es nicht.
04Wo eine Regel binden kann
Nichts in diesem Repository kann einen Runner binden. .radicle/native.yaml, das Justfile, Hooks — alles davon ist von dem editierbar, den es einschränkt. Der Repo-Hook feuert aus einem Worktree ohnehin nie, weil git rev-parse --git-dir dort auf .git/worktrees/<name> zeigt, und alle Arbeit passiert in Worktrees.
- Im Repo: eine Leitplanke.
just chainsagt früh, was das Gate später sagt. Mehr behauptet es nicht — und sie weist genau das zurück, was auch das Gate zurückweist: bei roten Meilenstein-Kommandos warnt sie (Exit 2), statt den Push zu blockieren. Eine Leitplanke, die strenger ist als die Autorität, macht die Autorität nicht stärker, sie blockiert nur. - Auf dem Token: die einzige echte Grenze. Der Freigabe- schlüssel ist ein FIDO2-Schlüssel ohne
no-touch-required. Ein Agent unter derselben Kennung kann die Datei lesen und trotzdem nicht unterschreiben — auf dieser Hardware geprüft, nicht aus einer Dokumentation übernommen: fünf unbeaufsichtigte Signaturversuche hintereinander, keiner davon ergab eine Signatur. Der Git-Signing-Key dagegen erzeugt in derselben Namespace ohne jede Berührung eine gültige Signatur — und das Gate weist sie ab. - In
ci-build: das Gate. Auf dem Broker-Image gebacken, außerhalb der Reichweite des Runners. Es hält das Imagezurück, nicht den Merge: Radicle kann einen Merge nicht verweigern, seine Trigger sind sämtlich Ereignisse, die schon passiert sind.
namespaces= in .chain/allowed_signers heftet den Schlüssel an plan-approval@tessera.at. Git unterschreibt Commits und Tags unter git, also kann dieser Schlüssel keine Commit-Signatur erzeugen und eine Commit-Signatur nie als Freigabe durchgehen — OpenSSH weist die Prüfung ab, statt Bytes zu vergleichen, die zufällig passen.
Das Urteil selbst steht danach als Kommentar am Patch-COB, und was es zu einem Beleg macht, ist sein Autor: die DID des CI-Node, in .chain/gate benannt. Ein Runner kommentiert seinen eigenen Patch als er selbst und kann nicht als das Gate kommentieren. just gate-verdict liest ihn zurück — lokal rot, bis das Gate gelaufen ist, was korrekt ist: die Behauptung handelt von einer Maschine, die der Runner nicht kontrolliert.
Der Principal ist did:key:z6MkrNYyVNngbG1U…, eine DID, und zwar die des Account-Schlüssels, nicht die des Node-Keys dieser Maschine. Beide sind Delegates, „von einem Delegate unterschrieben" ließe einen Runner also seinen eigenen Plan freigeben. Eine E-Mail-Adresse kommt in der Kette nirgends vor: es gibt hier keinen Mailserver, nur DIDs und Handles, und eine Adresse wäre ein zweiter Identitätsraum, den nichts verankert.
05Was gebeten bleibt
Der Wert dieses Abschnitts liegt darin, dass die Linie sichtbar ist. Was das Gate nicht prüft:
- Ob die Arbeit dem Plan entspricht. Siehe 03 — die Freigabe geht dem Code voraus. Das ist Review.
- Ob eine Prüfung je rot war. Ein Issue sagt in
## Verify, was das Kommando heute tut; ein Meilenstein wird nur im fertigen Zustand gesehen. Das Gate kann grün verlangen, nicht, dass es je rot war. - Ob ein Meilenstein-Kommando grün ist. Auf dem Broker-Image liegt kein
bun, keinjust, keinrg. Eine Prüfung, die läuft, wenn das Werkzeug zufällig da ist, und sonst überspringt, wäre genau die Manchmal-Durchsetzung, die diese Kette beenden soll. Wer den Plan freigibt, stimmt dem zu, was laufen wird. - Ob der Weg der richtige war. Ein grünes Kommando belegt das beobachtbare Ergebnis, nie die Route — der Plan benennt absichtlich das Ziel und nicht die Schritte.
- Einen bösartigen Runner. Das Gate läuft mit den Zugangsdaten der Registry in seiner Umgebung. Es bindet den, der abkürzt, nicht den, der angreift.