pair-workflow-contract-phase
Phase 0 of the delivery workflow: ensures the machine contract derived from a KB markdown template (verdict options, severities with explicit ranks, finding fields) is fresh — cache-by-hash via ensure
SKILL.md.claude/skills/pair-workflow-contract-phase/SKILL.md
GitHub/pair-workflow-contract-phase — The Template Is the Truth, the Contract Is Its Cache
Derive the machine contract from the human template so the reviewer's structured output and the human-facing report can never drift apart.
Arguments
| Argument | Required | Description |
|---|---|---|
$name |
Yes | Contract name (e.g. code-review). |
$template |
Yes | Path of the KB markdown template — the source of truth. |
$contract |
Yes | Path of the *.contract.json artifact (git-ignored derived cache). |
$skeleton |
Yes | JSON: the loose return-value schema to tighten. Only the fields $mirrors names become enums. |
$mirrors |
Yes | Which schema fields mirror which template vocabulary, and the severity-rank rule. |
Algorithm
Headless execution (single owner: .pair/knowledge/guidelines/technical-standards/ai-development/skill-conventions/headless-stage-execution.md) — this stage runs headless: never leave a command in the background and never end your turn while a command runs (a push with a pre-push gate, a quality gate): use the maximum tool timeout, poll to completion in the same turn, and ALWAYS end with the stage's structured result — on partial progress { status: "failed", reason: "incomplete", detail, branch, outputHead }.
Since 4.0.1 (t9d-2, AC-06) this skill is invoked by the FIRST review dispatch of a run (
$contractSpec), not by a generator-only dispatch: the same steps, the same cache-by-hash, returned as the review'stemplateContract.
- Run
node "$SKILL_DIR/scripts/ensure-contract.mjs" check $template $contract— where$SKILL_DIRis the directory this SKILL.md was loaded from; the script ships beside it (scripts/ensure-contract.mjs) — for ALL hash/cache/validation work; never hand-roll hashing or freshness logic. fresh⇒ return the cached contract file content unchanged withstatus: cache-hit.- Otherwise READ the template and generate the contract: take
$skeletonand tighten ONLY the fields$mirrorsnames intoenums, leaving every other field untouched. Fillvocabulary(verdictOptions,severities,findingFields, …) from the template, AND the top-levelseverityRanks: every name invocabulary.severities, spelled identically, mapped to an explicit unique integer, HIGHER = MORE SEVERE. Derive each rank from what the template SAYS the level means — a must-fix/merge-blocking level outranks an advisory one or a question — NEVER from the order the levels appear in: the consumer ignores array order, and a wrong rank silently converts a merge-blocking finding into an accepted one. If the levels carry no discernible relative severity, returnstatus: failedrather than inventing an order. - Persist via
node "$SKILL_DIR/scripts/ensure-contract.mjs" write $template $contract <draft.json>(it validates the draft and stamps the template hash); returnstatus: regeneratedplus the final contract content. - Never modify the template. If generation or validation fails after one retry, return
status: failedwith no contract.
Output Format
{ status: cache-hit | regenerated | failed, contract?: { $meta, vocabulary, severityRanks, schema } }.