Every artifact exchanged between agents is governed by a contract under
contracts/. Two rule families (ID/heading grammar and
READABILITY) are equally normative and equally bounceable: a consuming
agent's first duty when encountering a malformed artifact is to bounce
it, not to guess. A third tooling-parsed line, AUDIENCE:,
names the sections that are audit-time evidence, not decide-time reading.
Gatehouse folds those to their heading. The commit messages
that touch state.yaml
follow a separate grammar that distinguishes human decisions from orchestrator
bookkeeping.
Ten contracts
| Contract | Produced by | Consumed by | Gate |
|---|---|---|---|
spec.md | Analyst | Architect, Reviewer, Verifier | G0 |
plan.md | Architect | Implementers, Reviewer | G1 |
work-item.yaml | Architect (or the human, in patch) | Exactly one Implementer | G1 |
review-report.md | Reviewer | Implementer, gate G2 | — |
verification-report.md | Verifier | gate G2 | — |
release-plan.md | Ops | gate G3 | — |
intent-brief.md | Human | Analyst (in patch, the Implementer and Reviewer directly) | — |
state.yaml | Human + Orchestrator (co-written) | Everyone | — |
docs-delta.md | Historian | Human (branch review) | — |
integration-profile.md | Integrator | Human | GI |
The Gate column is DESIGN.md §4.1's mapping of artifacts to gates; the contract files themselves name no gate.
All contracts declare required sections. An artifact missing a required
section is malformed: the consuming agent bounces it, never guesses.
Tooling in packages/core/src/record/validate.ts
implements required-section checks (validateArtifact,
missingSections, extractSections,
BUILTIN_SECTIONS). It reads the required sections from the
target repository's own contracts/ at read time, with the
built-ins as the fallback, and the same module parses the
AUDIENCE: line (extractAudience) and the
verification verdict (verdictLines).
Rule family 1 — ID/heading grammar
The R, AC, and ADR shapes are parseable by tooling in
packages/core/src/view-model/lexicon.ts
and a deviation is a malformed artifact. The E‑block pattern
(E<k> — AC<n>.<m>) is parsed in a separate
module: packages/core/src/view-model/evidence.ts
(E_HEADING). The F‑finding shape
(F<n> — <severity> — <one‑line defect>) is
parsed by packages/core/src/view-model/review.ts
(FINDING_HEADING, which also tolerates
### F1 (blocking) — …), together with the round ≥ 2
disposition lines - **F<n> — resolved|stands** — …
(RESOLUTION). The review-report contract declares that
disposition grammar in its VERIFY ROUND block: tooling reads exactly those
two words and no others.
| Artifact | Shape | Example |
|---|---|---|
spec.md — requirements |
### R<n> — <short name> |
### R4 — Run profiles are fixed sets |
spec.md — acceptance criteria |
List item beginning AC<n>.<m> — (an optional [ ]/[x] checkbox may precede the id) |
AC4.1 — A run without a profile field parses as full |
plan.md — decisions |
### ADR-<n>: <decision> (optional (qualifier)) |
### ADR-3 (amended 2026-07-13): Keep the reviewer at G2 |
verification-report.md — evidence blocks |
### E<k> — AC<n>.<m>; Criterion column carries bare AC<n>.<m>; one **Verdict:** pass | fail | escalate line |
### E3 — AC4.1 |
review-report.md — findings |
### F<n> — <severity> — <one-line defect> |
### F2 — blocking — Budget cap is not enforced in dispatch path |
release-plan.md — preamble |
Bold-label lines **Change released:**, **Environment:**, **Rollback trigger:**, **Rollback exercised:**; Release steps as a numbered list |
**Rollback exercised:** yes — restored the previous image on staging |
The R/AC/ADR lexer in lexicon.ts extracts those three shapes with the
regular expressions R_HEADING, ADR_HEADING,
AC_ITEM. The id-reference pattern
ID_PATTERN = \b(?:R\d+|AC\d+\.\d+|ADR-\d+)\b is exported
as a regex source string so it can travel over an API as data.
Rule family 2 — READABILITY (human-facing sections)
Certain sections of each contract are designated "human-facing": the gate approver reads them as prose. Breaches are bounced like grammar deviations, with the rule cited. These sections are:
spec.md(Context): The problem, grounded in the system as it exists. Target ~150 words, cap 250.plan.md(Approach): The shape of the solution. Cap 350 words. Also: each ADR's Rejected and Consequences lines.review-report.md(Coverage): What the reviewer checked and found clean. Coverage carries its own three-rule set (see next paragraph).verification-report.md(Beyond the happy path, Gaps): Probes and risks.release-plan.md(CI health, Rollback plan, Verification after release, Blast radius): What the G3 approver ships on.
The spec.md, plan.md,
verification-report.md and release-plan.md
contracts declare a five‑rule READABILITY set with the same substance
(release-plan.md words (c) and (e) slightly differently, its
(e) covering environments as well as ids and files):
- Plain-words opening sentence. The first sentence states the takeaway in plain words — no code spans, paths, or parenthetical cites.
- One idea per paragraph. At most 4 sentences and 120 words each.
- Lists, not semicolon chains. Three or more parallel items become a bulleted list under a lead-in sentence.
- One claim per sentence. Never join clauses with a semicolon.
- Name before cite. Give any id or file a noun phrase
on first use, at most one parenthetical
file:linecite per sentence, full path at first mention only — short name after.
Coverage (review-report.md) is different. Its READABILITY
block declares three rules, not five, with one unique shape. (a) Open with
one plain‑words sentence stating overall coverage. (b) Then the Coverage
table, one row per requirement or area checked (the table is the shape,
and a bullet list or a paragraph in its place is in breach), with one cite
per row in the Where column and a clause, never a chain, in the Mechanism
column. (c) Name before cite, on first use in the opening sentence.
The columns are Requirement | Where | Mechanism checked | Status.
The same contract carries an AUDIENCE: line
(Coverage=audit; Boundary check=audit) and the normative
VERIFY ROUND block, beside BUDGET and ESCALATE SCOPE.
Commit-message grammar (human vs. orchestrator)
Every commit touching state.yaml follows structured
messages so the audit trail and metrics reader can distinguish human
decisions from machine bookkeeping:
| Writer | Grammar | Example |
|---|---|---|
| Human (reserved) | state(<slug>): G<N> approved by <name> [burden: …] — approve-and-hold appends and held (<reason>) |
state(creation-seam): G2 approved by Nathan Carter [burden: confirmation] |
| Human (reserved) | state(<slug>): staged by <name> — optional [client-key: <key>] suffix |
state(my-fix): staged by nthncrtr [client-key: ab12cd34] |
| Human (reserved) | state(<slug>): armed by <name> |
state(my-fix): armed by nthncrtr |
| Human (reserved) | state(<slug>): closed by <name> [disposition: <as>] |
state(my-fix): closed by nthncrtr [disposition: already-delivered] |
| Human (reserved) | state(<slug>): reopened to <phase> by <name> (was closed as <disposition>) |
state(my-fix): reopened to implement by nthncrtr (was closed as abandoned) |
| Orchestrator (bot identity) | state(<slug>): <verb> … — the union of the two sources' lists: dispatched | bounced | advanced | escalated | paused | metered | harvested (contracts/state.yaml lists the first six with a trailing "…"; ORCHESTRATOR.md §4.3 adds harvested). Sweep commits use sweep(<slug>): dispatched | metered. paused is also a human form (paused by <name>); only the author distinguishes them. |
state(creation-seam): dispatched implementer task 02-unit-tests |
The CLI's other decisions write in the same style without being
reserved forms: G<N> declined by <name>,
escalation #<i> resolved by <name>,
paused by <name> (<reason>) (the one verb both
writers use) and
resumed to <phase> by <name>.
The orchestrator commits under a dedicated bot identity
(gateline-orchestrator <orchestrator@gateline.invalid>,
one per install), never a person's git config. The human grammar is
reserved: the engine has no code path that
writes gates.* or closure, and it never
impersonates a human in commit
messages. The metrics reader treats the human grammar as authoritative.
Tooling that enforces the grammar
packages/core/src/view-model/lexicon.ts: parses R/ADR headings and AC list items at read time. Browser-safe leaf with zero imports.packages/core/src/view-model/evidence.ts: parses E‑block headings at read time (E_HEADING).packages/core/src/view-model/review.ts: parses F-finding headings and theresolved|standsdispositions of later rounds.packages/core/src/record/validate.ts: validates required sections (validateArtifact,missingSections,extractSections,BUILTIN_SECTIONS), reads theAUDIENCE:line (extractAudience) and the verification verdict (verdictLines, shared by the engine and Gatehouse).packages/orchestrator/src/review-report.tsandverification-report.ts: the engine's readers of the review verdict and the verification verdict.packages/core/src/record/actions.ts: the decision write path (planDecision) produces comment-preserving mutations with structured commit messages for everyDecisionAction:approve | decline | resolve-escalation | pause | resume | arm | close | reopen.