# Gate Validation Governance

> Partial Skill: invoke by name only — the SDD gate-legality contract. Loaded by spec-gate, the conductor, and the spec-judge, not user-triggered.

- Skill: `cyberuni/gate-validation-governance` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add cyberuni/gate-validation-governance`
- Raw SKILL.md: https://api.skillmd.com/api/skills/cyberuni/gate-validation-governance/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: cyberuni (https://skillmd.com/u/cyberuni)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/cyberuni/gate-validation-governance

---


# SDD Gate-Validation Governance

What makes a spec's state legal, and how a gate records its verdict. The field schema and transitions
are in `sdd:lifecycle-governance`; this skill is the legality layer on top of them. It carries **no
leash** — the self-clear-vs-escalate bar that derives how far an agent may self-assert is the
conductor's autonomy bar (baked into `start-mission`), a hard floor + a three-dimension gradient.

## Legal-state tuples

The mechanical authority is `spec-gate/scripts/check-spec-state.mts` — run it
(`node <skill>/scripts/check-spec-state.mts`) to enforce; if `node` is unavailable, apply the same
rules by reading frontmatter. The `(status, markers, .feature, approval)` tuple of the root
`spec.md` — plus the durable gate lines globbed from its sibling `ledger/` shards (a legacy `ledger.jsonl` still counts) — is **illegal** when:

- `status: approved` with no `.feature` — a spec requires a frozen `.feature` to be approved.
- `status: approved` or `implemented` with any `<!-- open: -->` markers — markers block the gate.
- `approval` names a gate other than `spec` or `impl`.
- an `approval.<gate>` has a `verdict` other than `approve`, `pause`, or `reject`.
- an `approval.<gate>` is `verdict: pause` carrying a `by` — a pause is always the agent's act and omits `by`.
- an `approval.<gate>` is `verdict: approve` with no `by` — an approve must record its approver.
- an `approval.<gate>` is `by: agent` with no `why` block — a self-assertion must record its derivation.
- an `approval.<gate>` has an off-enum `cause` (not `dimension` / `clearance` / `ceiling`) **without** a `cause-candidate: true` flag — the stop cause is a closed enum grown only by ratification, so an unflagged off-enum value fails closed; a `cause-candidate: true`-flagged off-enum value is **legal** (the off-enum candidate discipline, `sdd:combat-log-governance`).
- an `approval.<gate>` is `verdict: pause` on a gate the spec has already passed (spec once `approved`/`implemented`, impl once `implemented`).
- `status: approved` or `implemented` with no `approval.spec` `verdict: approve` + `by` — the spec gate has no recorded ratification.
- `status: implemented` with no `approval.impl` `verdict: approve` + `by` — the impl gate has no recorded ratification.
- `status: approved` or `implemented` with no `gate` line `gate: spec`, `verdict: approve` in the sibling `ledger/` shards — **the durable gate floor is missing**. The `approval` map is the overwritten current-state twin; the ledger line is the **immutable durable twin**, so a status advance with no ledger gate line is an unenforced gate.
- `status: implemented` with no `gate` line `gate: impl`, `verdict: approve` in the ledger — the impl-gate durable floor is missing.

`implemented` is backed by the impl gate's runtime suite run, not a stored flag (ADR-0017); its
static guard here is the recorded `approval.impl` ratification. Open markers at `draft` are permitted
(they block only the *gate*, not the draft state). A `draft` requires **no** ledger shard (no gate
has run); the durable floor applies only once a gate has advanced the status.

Reject illegal tuples **before** any other gate work. If `check-spec-state.mts` changes, this list
follows it — the script is the source of truth, this prose is the readable mirror.

## Per-node `spec-type` checks

Same fail-closed class, enforced by the same helper. A capability node README's `spec-type` marker
must agree with its shape (`sdd:spec-format-governance`):

- `spec-type: reference` with a sibling `.feature` — illegal (a reference artifact is suite-less by design).
- `spec-type: reference` with no `## Subject` section — illegal (the reference descriptor is required).
- `spec-type: behavioral` with no `## Use Cases` section — illegal (a behavioral spec maps use cases to scenarios).
- a node README carrying any **lifecycle field** (`status`, `project-path`, `approval`, `produced-by`,
  or a retired `aligned` / `spec-layout` / `strategy`) — illegal: lifecycle frontmatter is
  **root-`spec.md`-only** (`sdd:lifecycle-governance`); a node carries only its `spec-type` marker.

## The two gates

| Gate | Transition | Object judged |
|---|---|---|
| spec gate | Draft → Approved | `spec.md` + the `.feature` (no implementation required) |
| impl gate | Approved → Implemented | the implementation vs the frozen `.feature` |

`producer ≠ judge` survives the gate fold: even though gates are no longer a fixed station, the judge
stays a distinct actor from the producer, and never patches what it grades.

## Sync is derived, not stored (no `aligned` flag)

There is no `aligned` field (ADR-0017). "Synced" is two properties at two layers, each derived or
judged — never a stored boolean:

- **Contract layer** (`spec.md` ↔ `.feature`) — **judged** at the spec gate by the Builder coverage
  lens; implementation is not required, and spike code is excluded as scaffolding.
- **Impl layer** (impl ↔ frozen `.feature`) — derived by **running the frozen suite**; the impl gate
  advances to `implemented` only when **every** impl-judge passes, else it stays `approved` and
  surfaces the blocker.
- **Per-node settled state** is the **`@frozen`** scan; **what is in flux now** is the `.plan.md`
  todos.

`status` alone carries the lifecycle — no segment-level toggle.

## No-resolvable-producer fails closed

A required production role **always** resolves to a real producer — a plugin agent or the SDD default
for that role. When a gate runs and a required role has **no resolvable producer** (not a plugin
agent and not even an SDD default), the gate **fails closed** with a blocker; it advances nothing.
This is a **structural** error, the same fail-closed class as a malformed `produced-by` entry or an
**unflagged** off-enum `cause` (a `cause-candidate: true`-flagged one is legal; `sdd:combat-log-governance`). Distinct from availability: a recorded
producer whose plugin is merely uninstalled is **flagged**, not blocked.

