# Card Schema

> Card schema reference — fields, status/stage/contribution/human_gate enums, canonical tags, DoD detection, relationship invariants, title convention. AUTO-INVOKE when other deck skills need schema context, or when the user asks about field semantics, status lifecycle, DoD format, or card titling. If the catalog location path is unreadable, fetch the body via the goc tool verb "skill", args ["card-schema"].

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

---


## When to invoke

Invoke when other deck skills need schema context, or when the user asks about field semantics, status lifecycle, DoD format, tags, decision gates, or card titling.

# Card Schema

The shared vocabulary that makes the deck a **contract**: defined
semantics, enums, and a validator that refuses unknown values. Read-only reference; mutations go through
the `create-card` skill / the `advance-card` skill / the `finish-card` skill.
The machine-readable schema ships as the sibling `schema.yaml`.

**Deep dives live in `reference.md`** (sibling file in this skill's
directory) — read the named section only when needed:

| Question | `reference.md` section |
|---|---|
| Why can't this close with an open `advanced_by`? | Value-chain rule |
| Epic vs governing cluster — reasoning + lint | Coordinating cards |
| Why do closed cards keep their edges? | Deck as scheduler vs record |
| What goes in `## Decision required`? | Decision-gate body contract |
| Stuck-model semantics + `blocked` migration | Three-axis model |
| Draft / DoD layers / timestamps / example | (same-named sections) |

## Layout

```
deck/<title>/             # one dir per card; never moves on state change
  README.md               # frontmatter + dashboard body — latest state
  log.md                  # append-only journal — history, decisions, flow
  reproduce.py, *.html …  # OPTIONAL artifacts, opaque to the engine
```

Status changes mutate frontmatter, never directories — references
survive every transition (artifacts: the `create-card` skill Step 7).

### What goes where (dashboard vs journal)

| File | Role | Edit discipline |
|---|---|---|
| `README.md` | **Dashboard** — latest knowledge, current state; a cold reader sees only what is true now | rewritten in place; outdated content replaced, never amended below |
| `log.md` | **Append-only journal** — history, decisions, flow for forensic readers | strictly appended; existing entries never rewritten |

If the README alone would mislead, update the dashboard; if the
value is in the sequence, append to the journal — most operations
want both. "Latest finding (DATE)" blocks appended to a README are
the antipattern: rewrite in place. Closure does not freeze the card
(the `finish-card` skill "After closure").

## Status semantics

| value | meaning |
|---|---|
| `open` | candidate for work; in the queue |
| `active` | work in progress (one author/agent at a time, by convention) |
| `done` | terminal; DoD all ticked — `goc done <title>` enforces this |
| `disproved` | terminal; hypothesis ruled out, body documents the rebuttal |
| `superseded` | terminal; replaced by another card, typed link routes forward |

`blocked` is deprecated — split into derived dependency-readiness and
the `waiting_on` overlay (`reference.md` § Three-axis model). There
is no `unverified` status: that is `status: open` +
`tags: [unverified]`.

## Field reference

### `created` / `closed_at` — timestamps

`created` at birth; `closed_at` on **every** terminal transition,
required iff terminal. Two ordering-compatible shapes: ISO 8601 UTC
datetime `YYYY-MM-DDTHH:MM:SSZ` (what the CLI writes) and legacy
date-only `YYYY-MM-DD`. UTC only (`reference.md` § Timestamps).

### `summary`

Optional free-form, ≤ 3 sentences, what + why (not the fix path), so
triage views (`goc -v`) can prioritize without opening the body.
Plain prose; renders inline. Convention, not validator-enforced.

### `stage`

Optional KEP-style maturity ladder for research items: `null` (the
default — no tracking) → `alpha` → `beta` → `stable`. `status: done`
+ `stage: alpha` is valid; subsequent maturity work files a new card.

### `contribution`

How much does closing this card *alone* deliver or unlock? `high` —
terminal milestone OR load-bearing infrastructure many cards depend
on; `medium` — improves a working system (optimization, hardening,
guard rail); `low` — editorial polish. The sort composes it across
the `advances` graph (Bellman discount γ=0.7) into the `value` score
driving `pull-card`.

### `human_gate`

Orthogonal to `status`: does progress require a human?

- `none` — autonomous-loop-safe; cron may auto-pick. An
  agent-checkable external wait is the `waiting_on` overlay, not a
  gate.
- `decision` — ONE human go/no-go. The body MUST already carry a
  `## Decision required` section: reasoning, ≥ 2 named options with
  pros/cons and a file:line preview, one-line recommendation
  (`reference.md` § Decision-gate body contract).
- `session` — needs an interactive working session.

Pickability: `none` → next-card picks; `decision` → session ends
cleanly, pointing at the parked card; `session` → only an interactive
session advances. Terminal closes refuse while the gate is raised
(`goc decide` first; `reference.md` § Gate symmetry). `goc new`
default: `decision`.

### `waiting_on` / `waiting_until` — impediment overlay

Stored, orthogonal to `status`; the exogenous waits the dependency
graph cannot derive. `waiting_on` ∈ `external` (third party) |
`resource` (person/skill unavailable) | `deferred` (calendar defer);
`waiting_until` is an optional ISO date (bare date implies
`deferred`). A future date — or a reason with no date — hides the
card from `--ready` / next-card / pull-card and self-clears when it
passes; an elapsed date surfaces as `WAITING_OVERDUE`. Set / clear
via `goc wait <title> [--reason <r>] [--until <date>] [--clear]`
(the `advance-card` skill Step 6).

Ready-to-pull predicate: `status == open ∧ human_gate == none ∧ not
waiting_impedes(card)`. An open `advances` prereq does NOT gate
pulling — advisory "awaiting" line only (`reference.md` § Three-axis
model).

### `worker`

Optional free-form assignee: flat string (`worker: rodja`) or mapping
(`worker: {who: rodja, where: feature/foo}`); unregistered values.
Auto-populated at claim time by `goc status <title> active`; persists
after close. Filter with `goc --worker <X>` or `GOC_WORKER`.

### `draft`

Boolean overlay marking an unauthored scaffold. `goc new` stamps it;
clears on claim or close, or via `goc publish <title>`. While set:
hidden from queues (visible under `--status all`, `✎` on the board),
protected from supersede/disprove closes, skipped by auto-commit; may
not be terminal. Details: `reference.md` § Draft contract.

### `advances` / `advanced_by` — value-flow axis

- `advances` — slugs whose progress this card contributes to ("X
  advances Y" = closing X delivers a piece of Y's value chain).
- `advanced_by` — the inverse; slugs contributing to this card.

**Invariant:** `A.advances` contains `B` ⇔ `B.advanced_by` contains
`A` — maintained atomically by `goc advance <title> --by <other>` /
`goc unadvance`; half-edges are validator errors; cycles forbidden.
Epics are just cards with `advanced_by: [children]`.

**Value-chain rule (short form):** a true edge means the target is
not closeable while the source is open — the `advanced-by-closed`
attest check enforces exactly this. When it fires: wait, or retract a
false edge with `goc unadvance` — never `--skip` past it
(`reference.md` § Value-chain rule).

**Coordinating cards (short form):** aggregation epic →
`child.advances: [epic]`; governing cluster (closes when *decided*) →
shared tag, NO edge; `epic.advances: [children]` is always wrong
(`BACKWARDS_EPIC_EDGE`; `reference.md` § Coordinating cards).

### `supersedes` / `superseded_by` — replacement axis

`superseded_by` — slugs replacing this card (on the *old* card);
`supersedes` — the inverse (on the *new* card).
`goc status <title> superseded --by <successor>` maintains both
endpoints atomically. Validator-enforced: bidirectional consistency;
non-empty `superseded_by` ⇒ `status: superseded`; every `supersedes`
entry points at a `superseded` card. The typed edge is the pointer;
the *rationale* still appends to the old card's `log.md`
(`reference.md` § Deck as scheduler vs record).

### `tags` — grouping

Canonical-set enforced (below). Soft grouping and governing clusters;
one conventional tag per epic-shaped body of work, retired when the
epic closes. Lineage is forensic prose for `log.md`, never
frontmatter.

**YAML format:** non-empty edge lists (`advances` etc.) render
block-style (one `- item` per line); empty lists inline `[]`; `tags`
stays inline flow style.

## Definition of Done (layer 1)

**Checkbox list (preferred):** `- [ ]` items mutating to `- [x]`;
`goc done` requires every box ticked. Detection: `^- \[[ x]\]` lines;
zero matches → free-form prose mode, which requires `goc done
--force`. Layers 2 (project-wide) and 3 (GoC-wide) are recorded at
closure by `goc attest` (`reference.md` § DoD layers).

### DoD method tags

Declare each item's closure class with a colon-suffixed prefix:

| Tag | Closure rule |
|---|---|
| `TDD:` | a deterministic predicate with a closed-form expected value holds |
| `EMPIRICAL:` | the experiment ran and the verdict is documented — direction does **not** gate closure |
| `MECHANICAL:` | a reviewer confirms the edit landed by reading |
| `PROCESS:` | an agreement, gate flip, or edge update happened |

Prefer `TDD:` whenever a closed-form expected value exists;
mislabelling a provable assertion as `EMPIRICAL:` lets a real failure
hide behind "the experiment ran". `goc validate` warns
(`UNTAGGED_DOD_ITEM`, non-fatal) on untagged boxes in non-terminal
cards.

## Title antipatterns (rejected at filing time)

Titles ARE the kanban label — a non-engineer reading `goc --board`
must understand each card without opening it. `goc new` rejects:

| Pattern | Example | Why bad |
|---|---|---|
| `\br\d+\b` | `r88-csubstrate-replication` | investigation-round reference |
| `\bpath-\d+\b` / `\bphase-\d+\b` | `path-2-recovery` | internal sequence step |
| `\bbug-\d+\b` | `bug-140-fix` | tracker numbering |
| `_md_` / `_py_` | `coupling-md-formula` | file infix — name the concept |
| camelCase | `runSimulation-fails` | function jargon |
| math symbols | `late-hr-≥-0.5` | slug allows `[a-z0-9-]` only |
| underscores | `my_first_card` | slug allows `[a-z0-9-]` only |

On rejection the CLI suggests a rephrasing from the *observable
problem*; the `refine-deck` skill's quality pass checks the same
dimensions across the existing deck.

## Canonical tags

Project-specific tags register in `.game-of-cards/canonical-tags.md`
(merged into the enum by `goc validate`); goc-shipped tags change via
PR (`reference.md` § Adding new tags). A tag is **load-bearing** iff
its row holds; when in doubt, drop it. Every row declares a `check`:

- **`state`** — satisfied out of frontmatter, edges, or card files.
  Scorable, so a disagreement is a fact.
- **`judgment`** — satisfied by what the card *means*. The row's
  patterns are recognition aids, never a membership test, so one that
  does not fire is not evidence the tag fails.

No sweep strips a tag mechanically. Both, plus the default pattern
surface: `reference.md` § Why rows split.

| tag | applies iff | check |
|---|---|---|
| `bug` | not `epic` and not `story` (default for findings) | state |
| `epic` | multiple cards block its closure (≥2 `advanced_by`) OR carry its epic-grouping tag | state |
| `story` | delivers new/changed capability, not a fix; disjoint from `bug` | judgment |
| `unverified` | no working `reproduce.py` AND tagged at filing | state |
| `documentation` | doc-quality failure (`doc`/`stale`/`drift`/`mismatch`/`cite`/`claim`/`readme-` in title, or body cites docstrings / `.md says`) | judgment |
| `test` | repairs or extends test coverage (title starts `test-` or contains `tolerance`/`vacuous`/`regression`, or body cites pytest / `tests/`) | judgment |
| `api-contract` | cites a public API surface callers depend on | judgment |
| `infra` | touches infrastructure (pre-commit, `pyproject.toml`, CI, packaging) | judgment |
| `meta-fix` | the card's scope is a family or its root cause, not one site — an umbrella, or an instance wired into one (aids: umbrella-shaped title, a body roster, a literal `meta-fix`, an edge to a `meta-fix` card — **none required**) | judgment |

Project-specific predicates appended below:

`cat .game-of-cards/canonical-tags.md 2>/dev/null || true`

## Sibling files on this host

This skill ships `reference.md`, `schema.yaml` alongside its body. If a direct file read fails (sandboxed sessions cannot see the plugin install path), fetch the file through the goc tool: `{verb: "skill", args: ["card-schema", "<file>"]}`.

