Contract grammar reference

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

ContractProduced byConsumed byGate
spec.mdAnalystArchitect, Reviewer, VerifierG0
plan.mdArchitectImplementers, ReviewerG1
work-item.yamlArchitect (or the human, in patch)Exactly one ImplementerG1
review-report.mdReviewerImplementer, gate G2—
verification-report.mdVerifiergate G2—
release-plan.mdOpsgate G3—
intent-brief.mdHumanAnalyst (in patch, the Implementer and Reviewer directly)—
state.yamlHuman + Orchestrator (co-written)Everyone—
docs-delta.mdHistorianHuman (branch review)—
integration-profile.mdIntegratorHumanGI

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.

ArtifactShapeExample
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):

  1. Plain-words opening sentence. The first sentence states the takeaway in plain words — no code spans, paths, or parenthetical cites.
  2. One idea per paragraph. At most 4 sentences and 120 words each.
  3. Lists, not semicolon chains. Three or more parallel items become a bulleted list under a lead-in sentence.
  4. One claim per sentence. Never join clauses with a semicolon.
  5. Name before cite. Give any id or file a noun phrase on first use, at most one parenthetical file:line cite 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:

WriterGrammarExample
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 the resolved|stands dispositions of later rounds.
  • packages/core/src/record/validate.ts: validates required sections (validateArtifact, missingSections, extractSections, BUILTIN_SECTIONS), reads the AUDIENCE: line (extractAudience) and the verification verdict (verdictLines, shared by the engine and Gatehouse).
  • packages/orchestrator/src/review-report.ts and verification-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 every DecisionAction: approve | decline | resolve-escalation | pause | resume | arm | close | reopen.