The verb registry gains a `seamTier` carrier field — IR-002 step 2, blocked on step 1's ratification
Date: 2026-09-12 Status: closed — ratified 2026-09-13 Supersedes: none Superseded-by: none — current
Context
Section titled “Context”irina/SYNTHESIS.md §1.1 found that FR-003’s seam-class ceilings have no
carrier anywhere in this repo: the verb envelope
(spec/verbs/_common.schema.json Envelope) carries {verb, target_repo, idempotency_key, dry_run, actor, triggered_by} and nothing else, the
registry row (registry.yaml: slug, url, default_branch, contract_sha, role, profile, fleets_allowed) carries no class axis, and host/src/ registry.ts’s PetrovaTool interface carries only mutating. A ceiling
that is ruled in prose and attaches to nothing is not enforced by
anything — the same shape mary-wiki F-097 found in a check that could
never fail.
docs/decisions/2026-09-12-seam-class-taxonomy.md (IR-002 step 1, amended
2026-09-12 to reconcile against mary-wiki PR #653) names the taxonomy
this field carries (AT0–AT3) and rules the assignment mechanism: a
verb’s tier is set by a named, dated decision document, and the
verb’s own schema PR cites that decision by id rather than proposing a
tier inline. That doc’s first sign-off box is what this act depends on.
This doc is IR-002 step 2 — the schema act itself — drafted now, per
FR-017’s direction (justification authored before the act), but it may
not be applied until step 1’s first box is ticked, because applying a
carrier for a taxonomy that isn’t yet ratified would let the schema act
itself stand in for the ratification it’s supposed to consume.
Decision
Section titled “Decision”One canonical home, not two. host/src/registry.ts’s own header
already documents three prior forks of this exact file, each caused by a
second copy of tool metadata drifting from the first. PetrovaTool gains
two optional fields, following the same shape as the existing mutating
flag rather than duplicating anything into spec/verbs/<verb>.schema.json
as a second, separately-maintained copy:
export interface PetrovaTool { name: string; description: string; schema: Record<string, unknown>; handler: ToolHandler; mutating?: boolean; /** AT0-AT3, per docs/decisions/2026-09-12-seam-class-taxonomy.md. Required * when mutating is true; absent only for read tools (implicitly AT0). */ seamTier?: "AT0" | "AT1" | "AT2" | "AT3"; /** Path to the decision doc that assigned this tool's seamTier. Required * whenever seamTier is set. A tier with no citation is not a grant. */ authorizingDecision?: string;}spec/verbs/_common.schema.json gains a matching $defs.SeamTier (enum
["AT0","AT1","AT2","AT3"]) and $defs.AuthorizingDecision (a string
pattern requiring a docs/decisions/*.md path), for schemas that need to
reference the type — but the registry.ts entries remain the source of
truth an enforcing test reads, exactly as mutating is today. A verb
schema file may echo its tier for human readability; it never sets it
independently.
Enforcement, extending the existing test rather than adding a parallel
one. host/tests/registry.test.ts already has
"flags every mutating tool, including the one with no act. prefix"
(:46). A new case in the same file asserts, for every tool where
mutating === true: seamTier is set, authorizingDecision is set, and
authorizingDecision resolves to a file that exists in docs/decisions/
at the checked-out ref. This is a narrowing — it cannot fail a build
today because no tool carries either field yet — so it does not engage
FR-017’s widening test on its own; populating the four tools the seam-
class doc names as examples (open_decision, update_milestone,
registry_edit/phase transitions, sweeps_trigger) is a separate,
subsequent act once step 1 is ratified, not bundled into this one.
What this act explicitly does not do. It does not populate any tool’s
seamTier — every entry in TOOLS keeps seamTier and
authorizingDecision absent until a decision names it. It does not
implement min-of-both composition with registry profile — that
remains docs/decisions/2026-09-12-seam-class-taxonomy.md’s second,
separately-gated sign-off box, itself withheld pending a named
falsification. It does not touch registry.yaml or .petrova/ contract.yaml — the taxonomy doc’s Context surveyed both as candidate
carriers and the seam-class doc’s Decision section places the tier on the
verb, not the repo, so neither file needs a new column for this.
Alternatives considered
Section titled “Alternatives considered”- Carry
seamTierinspec/verbs/<verb>.schema.jsononly, per the seam- class doc’s literal wording (“spec/verbs/<verb>.schema.jsongains a requiredseam_tierfield”) — rejected: that file already documents itself as “the contract the CLI and Fleet MCP host implementations compile against,” separate fromregistry.ts’sTOOLSarray, andregistry.ts’s own header names three past forks caused by exactly this shape (two lists of the same metadata, kept in step by hand). Mirroringmutating’s existing home avoids manufacturing a fourth fork. - Per-invocation credential minting keyed to
(verb, target_repo, scope), per the earlier cross-system synthesis stream that reviewed this proposal — not rejected, deferred: that is a materially larger build (a minting authority, a verification step at call time) and the seam-class doc’s ratified assignment mechanism is static, per-verb, set-at-schema-time. A credential-scoped carrier is a candidate replacement for this field oncemin-of-bothand the wider autonomy-ladder ruling (mary-wikiF-072) are further along, not a reason to withhold the simpler static carrier now. - Apply this act immediately, ahead of step 1’s ratification —
rejected: the fields would exist with nothing yet permitted to set them
meaningfully, and a later session finding
seamTierfields already wired could read that as evidence the taxonomy was already load- bearing, which is exactly the “narrow ruling reads as complete” shapemary-wikiF-100 names. Drafted now, applied after step 1 signs. - Fold this into step 1’s document as one combined act — rejected: the seam-class doc’s own Consequences section says steps 2-4 are “unblocked once the taxonomy/assignment box below is ticked,” naming them as separate acts; bundling would make the taxonomy ruling and the code change one thing to countersign instead of two, weakening what the human is actually attesting to at each step.
Consequences
Section titled “Consequences”For code: none yet. This document specifies the PetrovaTool field
addition, the _common.schema.json $defs addition, and the
registry.test.ts extension; none is implemented pending sign-off, and
implementation is blocked a second time behind
2026-09-12-seam-class-taxonomy.md’s first countersign box independent of
this doc’s own.
For docs: irina/tickets/IR-002-seam-class-sequence.xml step 2 is
this document; steps 3 (validator: does a schema PR’s cited decision
actually assign the tier it claims) and 4 (population: assigning
seamTier to the four named verbs) remain separately gated and are not
scoped here.
For in-flight phases: none.
For invariants: none changed by this doc alone. Once applied, it gives FR-003’s ceiling a field to attach to for the first time in this repo, but attaches no ceiling to any verb — that is steps 3 and 4’s work, each its own decision.
References
Section titled “References”docs/decisions/2026-09-12-seam-class-taxonomy.md(IR-002 step 1 — this act’s precondition; specifically its Assignment authority section and first sign-off box)mary-wikiPR #653,docs/decisions/2026-09-12-autonomy-tier-taxonomy-drafted-f-072.md(the reconcilingAT0-AT3taxonomy this field carries)irina/SYNTHESIS.md§1.1 (source of the “no carrier” finding)irina/tickets/IR-002-seam-class-sequence.xml(this doc is step 2 of 4)host/src/registry.ts(three prior forks of this exact file, cited as the reason this doc keeps one canonical home rather than a second list)host/tests/registry.test.ts:46(the existingmutatingenforcement test this doc extends rather than parallels)
Sign-off
Section titled “Sign-off”- Subagent: claude-sonnet-5 (session_01ASqvWd4BQWQfLQEqSgjEDz)
- Human: alex@devarno.com (2026-09-13) — ratifies the
seamTier/authorizingDecisionfield shape and its home inhost/src/registry.ts. Precondition met: step 1’s first box ticked 2026-09-13.