fix(validate): make judgment contract executable

This commit is contained in:
boshu
2026-07-12 10:43:55 -04:00
parent 9a3318398b
commit 07e82ba459
10 changed files with 726 additions and 669 deletions
+4 -10
View File
@@ -346,7 +346,7 @@
"path": "skills/validate/",
"has_skill_md": true,
"has_references": true,
"reference_count": 23
"reference_count": 24
},
{
"name": "domain",
@@ -666,9 +666,7 @@
"path": "cli/cmd/ao/",
"purpose": "Check AgentOps health",
"bounded_context": "BC4",
"driven_by_skills": [
"validate"
]
"driven_by_skills": []
},
{
"name": "ao done",
@@ -2861,12 +2859,10 @@
],
"drives_commands": [
"ao beads exec",
"ao doctor",
"ao goals measure",
"ao pawl"
],
"path": "skills/validate/",
"references": 23
"references": 24
},
{
"sku": "skill:workflow-builder",
@@ -3009,9 +3005,7 @@
"bounded_context": "BC4",
"purpose": "Check AgentOps health",
"status": "active",
"driven_by_skills": [
"validate"
],
"driven_by_skills": [],
"flags": [
"--before",
"--config",
+2 -2
View File
@@ -933,8 +933,8 @@
{
"name": "validate",
"source_skill": "skills/validate",
"source_hash": "80f8ce29d25e19886b727cc3ee8039fa9766d4366b4633c2b9b4644e51f3f8d6",
"generated_hash": "faa16ceda4eeaa7c85ab39e4a572e562e697fce4d1a8c39f68a797584a4adf38"
"source_hash": "365a0640f005f086b211669d0bb4eca3aa9947bd43d2733f3d4098deafd18550",
"generated_hash": "407e3bdfa5aa67be1d3ba89ae60a20bb01e234dad9b0be1d4c8ab135dc01503f"
},
{
"name": "workflow-builder",
@@ -2,6 +2,6 @@
"generator": "codex-sync",
"source_skill": "skills/validate",
"layout": "modular",
"source_hash": "80f8ce29d25e19886b727cc3ee8039fa9766d4366b4633c2b9b4644e51f3f8d6",
"generated_hash": "faa16ceda4eeaa7c85ab39e4a572e562e697fce4d1a8c39f68a797584a4adf38"
"source_hash": "365a0640f005f086b211669d0bb4eca3aa9947bd43d2733f3d4098deafd18550",
"generated_hash": "407e3bdfa5aa67be1d3ba89ae60a20bb01e234dad9b0be1d4c8ab135dc01503f"
}
+120 -326
View File
@@ -2,371 +2,170 @@
name: validate
description: Produce PASS/WARN/FAIL verdicts for
---
# $validate — Canonical Validator Skill
# $validate — Canonical Validator
> **Loop position:** move 6 (prove acceptance) of the [operating loop](../../docs/architecture/operating-loop.md) — the driving adapter for the `validate_acceptance` port: every Given/When/Then must map to a passing test before a bead closes, and the verdict binds to the SLICE's own acceptance test (its ATDD contract), not only the parent intent issue. This is S5 of the [narrow-waist micro-cycle](../../docs/architecture/operating-loop.md#the-narrow-waist-micro-cycle-canonical--every-loop-skill-cites-this).
> **Purpose:** Move 6 of the operating loop: independently remeasure a bounded artifact or slice, prove its acceptance, and emit one schema-valid PASS/WARN/FAIL verdict with an executable next action.
> **Role:** validator. Input = artifact (plan, spec, code, PR, fitness gate). Output = `verdict.v1` (PASS / WARN / FAIL with rationale + findings).
## Critical Constraints
`$validate` is a driving adapter for the `validate_acceptance` port in the
[Intent-to-Loop Hexagon](../../docs/architecture/intent-to-loop-hexagon.md).
When the artifact contains a `hexagon:` block, preserve the bounded context,
context packet, guard adapters, and done state in the verdict.
When the artifact claims DONE/closed/green, apply the
[Completion-Claim Kernel](../shared/validation-contract.md#completion-claim-kernel)
before returning PASS.
- **One role: validator.** Never edit the artifact, commit, push, close tracker work, or operate infrastructure. **Why:** a judge that mutates the subject destroys independence.
- Rerun cited commands on the actual artifact; never accept author evidence, conversational memory, or uncited figures as proof. **Why:** validation remeasures rather than agrees.
- PASS requires every mandatory check green, all blockers resolved, disclosed `not_checked` coverage, and an independent judge when the mode claims independence. **Why:** missing evidence cannot be laundered into confidence.
- `judge_id == author_id` cannot independently PASS; inline `--quick` fallback is stamped waived. **Why:** self-grading is guidance, not assurance.
- Every judge brief says: **"READ-ONLY except writing your single verdict file at `<path>`. Do NOT commit, push, or run tracker/infra ops (git push, br/bd, dolt)."** **Why:** role scope is model-independent.
- This skill validates work; `ao pawl` certifies landing with a commit-bound verdict. **Why:** a pre-work PASS never pre-authorizes a main write.
- Use runtime-native judges for a requested multi-judge mode; never start NTM, Agent Mail, managed agents, Gas City, or another runtime unless explicitly selected. **Why:** judgment does not silently broaden orchestration.
- `WARN|FAIL|REFUTED -> AUTO-REDO`: consult the pawl, return findings as re-plan evidence, repair through the owning producer, and rerun the same checks. **Why:** ordinary negative verdicts are self-correction, not human andons.
- `BREAKER -> HOLD -> ONE-HELPER`; `HELPER-UNSTUCK -> AUTO-REDO`. Hold judgment and use one bounded local-shell helper to inspect contradictory evidence or a broken validator. **Why:** one recovery pass distinguishes tooling failure from a real stop.
- `HELPER-ESCALATE -> HUMAN`; `REFUSAL-LANE|EXPLICIT-JUDGMENT|EXHAUSTED-BUDGET -> HUMAN`. **Why:** waivers, risk acceptance, unavailable authority, refusal, or exhausted recovery require the operator.
**A verdict is re-plan evidence, not just a retry trigger.** A FAIL/WARN (and its
findings) surfaces UP to the [operating loop](../../docs/architecture/operating-loop.md):
the *remaining* moves may be refactored, inserted, dropped, or reordered in response
— not only the failed objective re-run. `$rpi` is one turn's executor over that loop,
not an autonomous `--auto` re-planner (the old rpi CLI command surface was removed in f61c5f0e7 — historical).
Looping a failed objective forever without asking whether the plan should change is
the waterfall anti-pattern.
## Modes
## Modes (≤8 per Fix-F mode-flag budget)
| Mode | Purpose | Replaces / absorbs |
| Mode | Judge shape | Purpose |
|---|---|---|
| (default) | 2-judge multi-judge consensus on any artifact | `$council` default |
| `--quick` | Inline single-agent structured review | `$council --quick` |
| `--deep` | 4-judge thorough review | `$council --deep` |
| `--mixed` | Cross-vendor (Claude + Codex), N×2 judges | `$council --mixed` |
| `--debate` | Adversarial 2-round refinement | `$council --debate`; `/red-team` (absorbed 2026-07-07) |
| `--mode=post-impl` | Code-readiness pipeline (complexity → bug-hunt → council) | `vibe` (absorbed) |
| `--mode=pre-impl [--target=X]` | Plan/spec validation; target ∈ {scenario,fitness,ratchet,scope,skill,health} | `$pre-mortem`, `$goals measure`, `$scope`, `$heal-skill` (deep audit), `ao doctor`; `/eval-outcomes` + `/flywheel` (absorbed 2026-07-07) |
| `--mode=pr` | PR-shape verdict (diff review + acceptance check) | `/review` (absorbed 2026-07-07) |
| default | 2 independent | general artifact consensus |
| `--quick` | inline, waived | bounded sanity/readiness check |
| `--deep` | 4 perspectives | thorough requirement/feasibility/scope review |
| `--mixed` | explicitly selected families | cross-family review |
| `--debate` | 2+ judges, 2 rounds | adversarial critique/rebuttal |
| `--mode=post-impl` | pipeline + isolated judges | acceptance and completion audit |
| `--mode=pre-impl [--target=X]` | 2–4 judges | plan/spec/fitness/scope/skill/health audit |
| `--mode=pr` | diff + acceptance judges | submission readiness |
**Mode-budget assertion:** 8 modes. Adding a 9th requires demoting an existing one OR refusing the addition (per Fix-F § continuous CI gate).
**Mode-budget assertion:** 8 modes. Adding a ninth requires merging or removing an existing mode.
### Folded skills (cp-ki8): `validation` + `pr-validate` retired into these modes
The retired validation and pr-validate lanes were the Phase-1 placeholders for `--mode=post-impl`
and `--mode=pr`; both are now retired (cp-ki8) and their load-bearing contract folded
here so no capability is lost:
- **`--mode=post-impl` (was the validation lane) — full close-out + no-self-grading invariant.**
Beyond the inline `complexity → bug-hunt → council` pipeline, this mode owns the
`validate_acceptance` port: every Given/When/Then from the intent issue must map to a
passing test (criterion→test roll-up; activity logs do not close beads), and the
acceptance verdict **must be produced by a blind, context-isolated sub-agent judge that
did not author the code** (author ≠ validator — `ag-9jle.5` / `ag-lmdx.4`). Refuse to
certify acceptance when `judge_id == author_id`; the only escape is an inline-fallback
self-grade that is stamped as *waived, not independently validated*. Apply the
[Completion-Claim Kernel](../shared/validation-contract.md#completion-claim-kernel)
before accepting any DONE/closed/green claim. For epic-scope close-out this mode may
delegate to `vibe`, `$post-mortem`, and `/curate --mode=forge` rather than inlining them.
- **`--mode=pr` (was the pr-validate lane) — submission-readiness checks.** In addition to the
diff/acceptance verdict, run, in order: (1) **upstream alignment FIRST** (BLOCKING —
`git rev-list --count HEAD..origin/main`; fail if many commits behind or merge would
conflict), (2) CONTRIBUTING.md compliance (BLOCKING), (3) **isolation** — single commit
type + thematic files + atomic scope, (4) scope-creep containment, (5) quality gate
(tests/lint, non-blocking). On FAIL, emit remediation steps (split-by-type cherry-pick,
rebase-on-upstream) so the verdict is actionable.
### Folded triggers (ag-s43tg wave 1): `vibe` + `bead-completion-audit` route here
- **`vibe` → `--mode=post-impl`.** Use when doing a quick readiness or sanity check
that code is ready to commit or ship, short of a full review — the post-impl
pipeline (complexity → bug-hunt → council) is the vibe check.
- **`bead-completion-audit` → `--mode=post-impl` close-out.** Use when
auditing closed beads for real shipped evidence, acceptance proof, and truthful
closeout — the Completion-Claim Kernel and the no-self-grading invariant above
own this audit.
Folded triggers remain load-bearing: **`vibe` → `--mode=post-impl`** for code
readiness, and `bead-completion-audit` routes to post-implementation closeout.
Detailed target and evidence rules live in
[canonical-validation-protocol](references/canonical-validation-protocol.md).
## Quick Start
```bash
$validate path/to/plan.md # default 2-judge consensus
$validate --quick path/to/plan.md # inline single-agent
$validate --deep path/to/spec.md # 4-judge thorough
$validate --mode=pre-impl path/to/plan.md # pre-mortem mode
$validate --mode=post-impl recent # vibe mode (post-implement)
$validate --mode=pr 123 # PR review by PR number
$validate --mode=pre-impl --target=fitness # fitness gate against GOALS.md
$validate path/to/artifact
$validate --quick path/to/artifact
$validate --deep path/to/spec.md
$validate --mode=pre-impl --target=skill skills/example
$validate --mode=post-impl recent
$validate --mode=pr 123
```
Default uses runtime-native subagent spawning. Falls back to `--quick` (inline) when no multi-agent capability detected.
## Execution Workflow
## Execution
### 1. Resolve mode, artifact, and authority
### Step 1: Resolve mode + target
Parse `--mode` and `--target`. Default mode is multi-judge. Validate combinations:
| Mode | Allowed `--target` |
|---|---|
| default, --quick, --deep, --mixed, --debate | n/a |
| --mode=post-impl | n/a (pipeline scope is recent code changes) |
| --mode=pre-impl | scenario, fitness, ratchet, scope, skill, health (default: pre-mortem on plan) |
| --mode=pr | n/a (PR ID/path is positional) |
Reject invalid combinations (e.g., `--mode=pr --target=fitness`).
### Step 2: Load artifact + context
Reject invalid mode/target combinations. Confirm the artifact exists, is within
scope, and has explicit acceptance. For a goal-design packet, run:
```bash
# resolve artifact:
ARTIFACT="${1:-recent}" # path, PR ID, or "recent"
# load FAIL patterns:
# (folded into skill body; not a separate hook)
scripts/check-goal-design-packet.sh <packet-dir>
```
If `ARTIFACT` is a goal-design packet directory containing `intent.md` and
`driver.md`, run the deterministic packet checker before spawning or judging:
Nonzero is deterministic FAIL evidence. Load only the selected section of
[canonical-validation-protocol](references/canonical-validation-protocol.md)
plus the relevant language/risk standards.
```bash
scripts/check-goal-design-packet.sh "$ARTIFACT"
```
**Checkpoint:** record artifact identity, commit/digest, mode, targets, author id,
required checks, and `not_checked` before dispatch.
Non-zero exit is a FAIL verdict. Include the command and output in
`COMMANDS RUN:`. This is a pre-check inside the existing validator role, not a
new mode.
### 2. Run deterministic prechecks
For `--mode=pre-impl`, also load:
- `.agents/planning-rules/*.md` (compiled planning rules)
- `.agents/findings/registry.jsonl` (active findings)
- `.agents/pre-mortem-checks/*.md` (compiled prevention)
- pre-implementation: target rubric, temporal/error-rescue checks, test pyramid;
- post-implementation: complexity, bug sweep, slice acceptance, completion kernel;
- PR: upstream alignment first, contribution rules, atomicity, scope, tests/lint;
- all modes: source precedence, artifact freshness, and output-schema availability.
For `--mode=post-impl`, run pre-checks:
- complexity audit (radon for python, gocyclo for go)
- bug-hunt sweep (skill-body convention; no `/review` skill needed)
A deterministic red result is a FAIL verdict; do not spend judge tokens to
rediscover it.
For `--mode=pr`, fetch the PR diff (`gh pr diff <id>` or path).
### 3. Dispatch isolated judges
> **LIVE-PATH — where this judge orchestration is operative, and where the pawl is.**
> Steps 3–7 (spawn backend → run judges → write the `.agents/council/` verdict) are the live path
> for **PRE-work and non-merge validation**: plans, specs, artifacts, fitness gates, mid-arc
> completion checks, and the `--mode=pre-impl` / `post-impl` / `pr` verdicts. **At the merge-to-main
> door this orchestration is NOT the operative machinery** — that door is driven by the pawl scripts:
> `scripts/pawl-review.sh` runs the cross-family refuter and, on CONFIRMED, `scripts/pawl-verdict.sh`
> writes the commit-bound verdict the pre-push gate enforces (see [`$push`](../push/SKILL.md) and
> [`pawl-review`](../pawl-review/SKILL.md)). Use this skill to validate the WORK; use
> `ao pawl` to certify the LANDING — they compose, not compete. The judge machinery below is retained for
> that pre-work / non-merge scope, not deleted.
Register dispatch intent before spawning. Use the current runtime's native
subagents for multi-judge modes; if unavailable, degrade only to explicit
`--quick` and stamp the independence waiver.
### Step 3: Determine spawn backend
Each judge receives the artifact path/digest, bounded context, mandatory checks,
verdict path, and exact read-only clamp. It independently reruns commands.
1. `spawn_agent` available → Codex sub-agent
2. `TeamCreate` available → Claude native team
3. `task` (read-only skill tool, OpenCode) → opencode subagent
4. None → fall back to `--quick` (inline single-agent)
**Checkpoint:** author and judge identities differ, dispatch scopes do not
collide, and every claimed judge produced a nonempty verdict artifact.
Log selected backend in the verdict frontmatter.
### 4. Consolidate fail-closed
### Step 4: Run judges
- PASS: all required judges/checks PASS (or the declared deep-mode majority), no blocker.
- WARN: nonblocking concern or explicit coverage gap remains.
- FAIL: any deterministic failure, blocker, counterfeit/self judge, stale artifact, or malformed evidence.
| Mode | Judges | Perspectives |
|---|---|---|
| default | 2 | independent (no labeled perspectives) |
| --deep | 4 | missing-requirements, feasibility, scope, spec-completeness |
| --mixed | 2N (default N=3) | same N perspectives across Claude + Codex |
| --debate | 2+ rounds | adversarial; 2 rounds with critique-rebuttal |
| --quick | 0 (inline self) | structured review |
| --mode=post-impl | 2 + pipeline | complexity → bug-hunt → 2-judge council |
| --mode=pre-impl | 2-4 | per target preset |
| --mode=pr | 2 | diff-review + acceptance-check |
Contradictory verdicts are FAIL until reconciled; never average away a blocker.
Each judge gets:
- artifact path
- relevant context (planning rules, findings)
- council FAIL pattern check prompt (top 8)
- temporal interrogation prompt (--deep + --target=plan)
### 5. Write and validate outputs
### Step 5: Mandatory checks (auto-trigger)
Write `.agents/council/YYYY-MM-DD-validate-<slug>.md` with exactly one anchored
`## Council Verdict: PASS|WARN|FAIL`, plus `result.json` matching
`schemas/verdict.v1.schema.json`. The report contains exactly one anchored
`VERDICT:`, a nonempty `COMMANDS RUN:`, `REASONS:`, findings, and `not_checked`.
For `--mode=pre-impl --target=plan`:
- temporal interrogation (auto for plans with 5+ files or 3+ deps)
- error & rescue map
- council FAIL pattern check (top 8)
- test pyramid coverage check
- input validation check (enum-like fields)
**Checkpoint:** run both validators in Output Specification; PASS is illegal if
either output is missing, malformed, stale, self-graded, or unsupported by commands.
For `--mode=post-impl`:
- L0/L1/L2 coverage check on changed files
- **refactor-under-green check:** if the diff is a refactor, assert no acceptance/unit test text changed (`git diff` of test files is empty) — a refactor that edits a test changed behavior and is a new slice, not a refactor (S4). FAIL if a refactor diff also edits a test.
### 6. Route the verdict
For `--mode=pre-impl --target=fitness`:
- read GOALS.md
- evaluate each gate against current state
- report PASS/WARN/FAIL per gate + aggregate
### Step 6: Consolidate to verdict
Each judge returns a per-judge result. Consolidate:
- PASS only if all judges PASS (or majority for --deep)
- WARN if any judge raises a warning the others don't dispute
- FAIL if any judge raises a blocker the others don't override
### Step 7: Write verdict
Output path: `.agents/council/YYYY-MM-DD-validate-<topic-slug>.md`
```markdown
---
id: validate-YYYY-MM-DD-<slug>
type: verdict
date: YYYY-MM-DD
mode: <mode>
target: <target or n/a>
artifact: <path>
backend: <codex-subagents | claude-teams | opencode | inline>
---
# Validate Verdict — <topic>
## Council Verdict: PASS / WARN / FAIL
| Failure mode | Risk | Severity | Addressed? |
|---|---|---|---|
| ... | ... | ... | ... |
## Pseudocode Fixes (when WARN/FAIL)
(copy-pastable into affected issues per pre-mortem 4.6 contract)
## FAIL Pattern Check
(top 8 patterns — status per pattern)
## Verdict
PASS — proceed
WARN — review concerns, accept risk, or apply fixes
FAIL — block; revise artifact and rerun
```
The exact heading `## Council Verdict: PASS / WARN / FAIL` is mandatory — downstream validators and ledger readers parse it with anchored regex.
### Step 8: Persist findings (when applicable)
For `--mode=pre-impl` reusable findings: append to `.agents/findings/registry.jsonl` (atomic temp+rename). Every FAIL finding must be emitted as a next-loop producer — a `$pre-mortem` check or `$plan` planning-rule keyed by dedup_key (the escape→check ratchet, S6), not just a logged finding; a defect the membrane caught that produces no next-loop check will recur. See [operating-loop.md → move 7](../../docs/architecture/operating-loop.md).
### Step 9: Report
1. Verdict (PASS/WARN/FAIL).
2. Key concerns (when not PASS).
3. Output path.
4. Recommended next action.
## --target taxonomy (pre-impl)
| `--target` | What gets graded | Replaces |
|---|---|---|
| (default) | Plan/spec for an upcoming `$implement` | `$pre-mortem` |
| scenario | Holdout scenario gate | `/eval-outcomes` |
| fitness | GOALS.md fitness gates | `$goals measure`, `ao goals measure` |
| ratchet | Brownian Ratchet checkpoint | `/flywheel`, `ao ratchet status` |
| scope | Frozen-dirs declaration | `$scope` |
| skill | SKILL.md hygiene + audit | `$heal-skill` (heal.sh hygiene + audit.sh deep audit) |
| health | Repo health probe | `ao doctor` |
Each target has its own inline check rubric until Phase 2 extraction.
## Validation discipline (2026-06-09, cards 6–10, cp-hhd7)
### Verdict form — the gate parses these lines anchored
```
VERDICT: PASS
(blank line)
COMMANDS RUN:
<actual commands + verbatim output snippets>
REASONS:
- bullet citing a COMMANDS RUN line
```
A verdict with no `COMMANDS RUN:` section is **unverified** — reject it and
dispatch a fresh validator. A verdict whose `COMMANDS RUN:` lists only commands
the **author** ran (not the judge) is a **counterfeit judge** — treat as FAIL and
re-route to a genuinely independent validator. No `##` headings or parentheticals
on `VERDICT:` or `COMMANDS RUN:` lines; the gate parses them anchored.
### Cross-family floor (POLICY → gate icb6 enforces; this skill supports)
For **assurance closes** (the control-plane verdict-gate, cp-icb6), the floor is
≥2 verdicts from ≥2 distinct model families, author family excluded, fail-closed.
**This skill supports that policy via `--mixed` mode and the verdict form above;
the policy itself lives in the gate, not here.** A same-model council is valid for
non-assurance decisions (design brainstorms, quick checks) — do not refuse those.
Tier mapping:
- **STRICT** (irreversible, security, production close): Codex + strong-Gemini (A1); or Fable + Codex (A2).
- **ROUTINE** (everyday close): Codex + non-author-Claude (A3); or Fable + non-author (A4).
The A7 ruling (2026-06-09, memory `validation-family-policy-risk-tiered`):
Gemini is currently **benched** for STRICT validation — use Codex + Fable for A1/A2
tiers. Gemini may return for STRICT when Bo graduates it from the bench. Do not
present Gemini paths as live for tier A1/A2 until then.
### Judge empirically on a differentiating fixture (card 9, cp-8720)
When two implementations of the same intent exist, do NOT award based on
authorship or surface aesthetics. Run both on a **differentiating fixture** (an
input that exposes their behavioral difference), record the outputs verbatim, and
graft the loser's unique assets onto the winner. "My worker wrote it" is not
evidence.
### Dispatch record first (card 3, cp-hhtu)
Before dispatching a validator, register intent on the bead graph (update status,
assign actor). **Two parallel validators on the same bead produce a dedup incident,
not a cross-family quorum.** Check for an existing actor before spawning.
### Judge lanes carry an explicit write-scope clamp (2026-07-02, showcase kernel R2)
Every judge brief states, verbatim: **"READ-ONLY except writing your single verdict
file at `<path>`. Do NOT commit, push, or run tracker/infra ops (git push, br/bd,
dolt)."** The clamp is role-scoped, not model-scoped — crank workers legitimately
hold broad write scopes; judges re-measure, they never mutate. Proven live: an
unclamped codex acceptance judge pushed the feature branch unprompted and attempted
`bd dolt push` twice mid-judgment. A judge that mutates while judging can corrupt
the artifact under judgment or preempt the pawl.
### Judges re-measure; they do not read (card 8)
A judge re-runs the cited commands on the actual artifacts. It does not read the
author's evidence file and agree. Attest `judge_source: <model>` inside `COMMANDS RUN`
so the gate can confirm the judge identity. A judge that ran nothing is a reader, not
a verifier — discard its verdict.
## Evidence figures are measured, never inferred (the cp-801l lesson)
A worker's evidence file may only contain numbers and outputs that were **captured** —
pasted verbatim from a command's output — never reconstructed from memory. The
canonical failure: "36 checks — 35 pass" stated with confidence was inference; the
measured reality was 36 run / 34 pass / 1 fail / 1 skip, on a different commit.
- **Validators:** treat any uncited figure (a count, a pass-rate, a timing, a commit
hash) as **unverifiable → FAIL** until a log is produced or the claim is corrected.
- **Corrections happen by APPENDED erratum** — a dated erratum block crediting the
source measurement — never by silently editing the original figure. A silently
edited evidence file is indistinguishable from a fabricated one.
## Constraints (one-role-per-skill)
- **One role: validator.** Output is always a verdict. Never mutates code (delegates to `$implement` for fixes).
- **No new modes** without dropping/merging an existing one (Fix-F mode-budget cap = 8).
- **Verdict heading is regex-anchored** — do not alter the `## Council Verdict: ...` text format.
Report verdict, key findings, artifact paths, and one executable next action.
WARN/FAIL re-enters the operating loop through the owning producer. Reusable
failures compile into a planning/pre-mortem check instead of becoming a dead log.
## Output Specification
**Format:** a PASS/WARN/FAIL validation verdict plus a markdown council summary to stdout; machine-readable `result.json`.
**Files:** writes `.agents/council/YYYY-MM-DD-validate-<slug>.md` and `result.json`; appends reusable findings to `.agents/findings/registry.jsonl`; may refresh `.agents/planning-rules/` and `.agents/pre-mortem-checks/`.
**Exit signal:** FAIL re-cranks on the same objective (up to 3 attempts). Exhaustion enters HOLD and permits exactly one bounded fresh-context or cross-family helper pass; HELPER-UNSTUCK resumes with the new approach, while only HELPER-ESCALATE (or a refusal/explicit-judgment or spent hard-ceiling class) routes to the human. DONE requires a fully-green acceptance roll-up.
**Artifact directory:** markdown verdicts under `.agents/council/`; machine-readable `result.json` at the invocation output root.
## See Also
**Filename convention:** `.agents/council/YYYY-MM-DD-validate-<topic-slug>.md` plus `result.json`.
- `skills/rpi/SKILL.md` — orchestrator that fires `$validate --mode=pre-impl` after `$plan`
- `skills/curate/SKILL.md` — miner role (paired canonical skill)
- `schemas/verdict.v1.schema.json` — output contract
- [`pawl-review`](../pawl-review/SKILL.md) — executes immutable fresh reviewer lanes and hands evidence to `ao pawl`; the membrane alone binds the commit verdict
**Serialization/schema format:** `result.json` follows closed `schemas/verdict.v1.schema.json`; markdown has one `## Council Verdict: PASS|WARN|FAIL` and the anchored evidence form in the protocol reference.
**Validator command:** validate `result.json` with `Draft202012Validator(schema, format_checker=FormatChecker())`, an explicit timezone-aware RFC3339 parse of `validated_at`, and the pinned author identity so a PASS requires `validator_session != author_session`; then verify the markdown has exactly one council verdict, exactly one matching `VERDICT:`, and a `judge=<validator_session> command=<command>` evidence line under `COMMANDS RUN:` before `REASONS:`. The executable fixture suite is `bash skills/validate/scripts/validate.sh`.
**Downstream handoff:** pass mode/target, artifact path/digest/commit, author and judge identities/families, deterministic commands and exit codes, verdict/report paths, findings, `not_checked`, waiver/breaker state, and the exact next action; landing still requires `ao pawl`.
## Quality Checklist
- [ ] Artifact identity and acceptance are pinned before checks run.
- [ ] Judges are read-only, independent when claimed, and rerun commands themselves.
- [ ] Every number, timing, and commit is captured from cited output.
- [ ] PASS has no blockers, counterfeit judges, stale evidence, or undisclosed gaps.
- [ ] Markdown and JSON agree and pass their deterministic validators.
- [ ] WARN/FAIL/REFUTED returns to AUTO-REDO; only real breakers reach a human.
- [ ] Validation PASS is never substituted for the commit-bound landing verdict.
## Examples
### Reject a counterfeit completion claim
**User says:** `$validate --mode=post-impl recent`
**What happens:** the isolated judge reruns the slice acceptance command and
finds the author's reported count was inferred and the test exits nonzero.
**Result:** FAIL with captured output, corrected count, owning producer, and the
same validation command as next action; no human andon and no landing claim.
## Troubleshooting
| Problem | Response |
|---|---|
| Judge unavailable | Use explicit waived `--quick` or HOLD only if independence is required |
| Artifact changed mid-review | Mark stale, pin the new digest, rerun all checks |
| Judges disagree | FAIL until the blocker is reproduced and reconciled |
| Empty `COMMANDS RUN:` | Discard the verdict and dispatch a real verifier |
## Reference Documents
- [references/validate.feature](references/validate.feature) — Executable spec: verdict.v1 PASS/WARN/FAIL for any artifact, --mode selects shape, 8-mode budget (soc-qk4b)
## Reference library (incl. rescued vibe references, ag-s43tg)
- [references/canonical-validation-protocol.md](references/canonical-validation-protocol.md) — modes, targets, evidence, isolation, landing boundary
- [references/report-format.md](references/report-format.md) — markdown detail
- [references/deep-audit-protocol.md](references/deep-audit-protocol.md) — deep-mode perspectives
- [references/test-pyramid-inventory.md](references/test-pyramid-inventory.md) — coverage selection
- [references/post-verdict-actions.md](references/post-verdict-actions.md) — bounded follow-through
- [references/validate.feature](references/validate.feature) — executable behavior
- [references/complexity-analysis.md](references/complexity-analysis.md)
- [references/deep-audit-protocol.md](references/deep-audit-protocol.md)
- [references/deep-checks.md](references/deep-checks.md)
- [references/examples.md](references/examples.md)
- [references/go-patterns.md](references/go-patterns.md)
@@ -374,13 +173,10 @@ measured reality was 36 run / 34 pass / 1 fail / 1 skip, on a different commit.
- [references/json-standards.md](references/json-standards.md)
- [references/markdown-standards.md](references/markdown-standards.md)
- [references/patterns.md](references/patterns.md)
- [references/post-verdict-actions.md](references/post-verdict-actions.md)
- [references/python-standards.md](references/python-standards.md)
- [references/quick-mode-vibe.md](references/quick-mode-vibe.md)
- [references/report-format.md](references/report-format.md)
- [references/rust-standards.md](references/rust-standards.md)
- [references/shell-standards.md](references/shell-standards.md)
- [references/test-pyramid-inventory.md](references/test-pyramid-inventory.md)
- [references/test-pyramid-weighting.md](references/test-pyramid-weighting.md)
- [references/typescript-standards.md](references/typescript-standards.md)
- [references/verification-report.md](references/verification-report.md)
@@ -388,6 +184,4 @@ measured reality was 36 run / 34 pass / 1 fail / 1 skip, on a different commit.
- [references/vibe-suppressions.md](references/vibe-suppressions.md)
- [references/write-time-quality.md](references/write-time-quality.md)
- [references/yaml-standards.md](references/yaml-standards.md)
- [references/validate.feature](references/validate.feature)
- [references/vibe.feature](references/vibe.feature) — rescued vibe executable spec
- [scripts/prescan.sh](scripts/prescan.sh) — rescued vibe pre-scan helper
- [references/vibe.feature](references/vibe.feature)
@@ -0,0 +1,116 @@
# Canonical Validation Protocol
This reference carries the detailed mode, target, and evidence rules for the
`validate` kernel. Load only the sections selected by the current mode.
## Mode details
- Default: two independent judges; PASS requires both PASS.
- `--quick`: inline structured review. It may guide work but is stamped
`waived`, never independently validated.
- `--deep`: four perspectives—missing requirements, feasibility, scope, and
specification completeness. PASS uses the declared majority rule, with any
unresolved blocker still failing closed.
- `--mixed`: the same perspectives across explicitly selected model families.
- `--debate`: two adversarial rounds with critique and rebuttal.
- `--mode=post-impl`: complexity, bug sweep, acceptance roll-up, then isolated
judges. A refactor that changes acceptance/unit test text is a new behavior
slice, not a refactor.
- `--mode=pre-impl`: plan/spec checks, optionally specialized by `--target`.
- `--mode=pr`: upstream alignment first, contribution rules, atomic isolation,
scope containment, then tests/lint.
The eight-mode budget is fixed. A ninth mode must replace or merge an existing
mode rather than growing the public surface.
## Pre-implementation targets
| Target | Required checks |
|---|---|
| default plan | temporal interrogation, error/rescue map, FAIL patterns, test pyramid, enum/input validation |
| scenario | holdout scenario and falsifying edge |
| fitness | each GOALS.md gate against current measured state |
| ratchet | current checkpoint, evidence, and legal next transition |
| scope | frozen paths, authority boundary, and escape prevention |
| skill | strict hygiene plus profile-aware deep audit |
| health | executable repository health probes and disclosed gaps |
A goal-design packet containing `intent.md` and `driver.md` first runs
`scripts/check-goal-design-packet.sh <packet-dir>`; nonzero is FAIL evidence.
## Post-implementation acceptance
Every Given/When/Then maps to a passing acceptance test for its own vertical
slice. Activity logs and parent-issue summaries do not close a bead. Apply the
Completion-Claim Kernel in `skills/shared/validation-contract.md` to every
DONE/closed/green claim.
The acceptance judge is blind and context-isolated. `judge_id == author_id`
cannot independently PASS. Inline fallback is marked waived and cannot satisfy
an assurance close.
## PR checks
Run in order:
1. upstream alignment (`git rev-list --count HEAD..origin/main`) and conflict risk;
2. repository contribution rules;
3. one thematic/atomic change shape;
4. scope-creep containment;
5. relevant tests and lint.
FAIL includes executable remediation such as rebase or split-by-type; it never
mutates the branch from the judge lane.
## Evidence discipline
The validator reruns cited commands on the actual artifact. It does not accept
the author's evidence file as proof. Every count, timing, commit, and pass rate
is pasted from captured output. Uncited figures fail until measured.
Corrections are appended as dated errata crediting the source measurement;
silently rewriting an evidence claim is forbidden.
Verdict text uses anchored lines:
```text
VERDICT: PASS
COMMANDS RUN:
judge=<validator_session> command=<command rerun by this judge>
<bounded output excerpts produced by this judge>
REASONS:
- each reason cites a command or artifact
```
Exactly one verdict is allowed. `COMMANDS RUN:` must include at least one
`judge=<validator_session> command=<command>` line, and the pinned author identity
must differ from that validator session for PASS. A judge that ran nothing is a
reader, not a verifier.
## Judge isolation
Every judge brief includes this exact clamp:
> READ-ONLY except writing your single verdict file at `<path>`. Do NOT commit,
> push, or run tracker/infra ops (git push, br/bd, dolt).
Register dispatch intent before spawning. Two validators accidentally assigned
to the same lane/bead are a dedup incident, not an independent quorum.
## Assurance and landing
Non-merge validation may use runtime-native judges. Assurance close requires the
policy-selected independent-family floor. Benched families are not presented as
live strict lanes.
Landing is a different door: `ao pawl` produces the commit-bound verdict and the
pre-push gate authorizes the remote-main write. A validation PASS never replaces
or pre-authorizes that landing proof.
## Failure routing
WARN/FAIL/REFUTED findings return to the operating loop as re-plan evidence.
Repair and remeasure automatically while the bounded budget has progress.
HOLD/ESCALATE occurs only on a breaker: exhausted attempts/time/cost, oscillation,
refusal, unavailable authority, or explicit risk/waiver judgment.
+122
View File
@@ -0,0 +1,122 @@
#!/usr/bin/env bash
set -euo pipefail
SKILL_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
REPO_ROOT="$(cd "$SKILL_DIR/../.." && pwd)"
SKILL_MD="$SKILL_DIR/SKILL.md"
SCHEMA="$REPO_ROOT/schemas/verdict.v1.schema.json"
PASS=0
FAIL=0
record() {
local label="$1"
shift
if "$@"; then echo "PASS: $label"; PASS=$((PASS + 1));
else echo "FAIL: $label"; FAIL=$((FAIL + 1)); fi
}
validate_contract() {
local skill_md="$1"
[[ "$(awk '/^---$/{n++;next} n==2 && /^## /{print;exit}' "$skill_md")" == "## Critical Constraints" ]] &&
grep -Fq 'WARN|FAIL|REFUTED -> AUTO-REDO' "$skill_md" &&
grep -Fq 'BREAKER -> HOLD -> ONE-HELPER' "$skill_md" &&
grep -Fq 'HELPER-UNSTUCK -> AUTO-REDO' "$skill_md" &&
grep -Fq 'HELPER-ESCALATE -> HUMAN' "$skill_md" &&
grep -Fq 'REFUSAL-LANE|EXPLICIT-JUDGMENT|EXHAUSTED-BUDGET -> HUMAN' "$skill_md" &&
grep -Fq '**Mode-budget assertion:** 8 modes.' "$skill_md" &&
grep -Fq 'vibe` → `--mode=post-impl`' "$skill_md" &&
grep -Fq 'READ-ONLY except writing your single verdict file' "$skill_md" &&
grep -Fq 'This skill validates work; `ao pawl` certifies landing' "$skill_md" &&
grep -Fq '**Checkpoint:**' "$skill_md" &&
grep -Fq '**Artifact directory:**' "$skill_md" &&
grep -Fq '**Filename convention:**' "$skill_md" &&
grep -Fq '**Serialization/schema format:**' "$skill_md" &&
grep -Fq '**Validator command:**' "$skill_md" &&
grep -Fq '**Downstream handoff:**' "$skill_md" &&
grep -Fq '## Quality Checklist' "$skill_md"
}
validate_result() {
local result="$1"
local author_session="$2"
python3 -c 'import json,re,sys; from datetime import datetime; from jsonschema import Draft202012Validator,FormatChecker; schema=json.load(open(sys.argv[1])); instance=json.load(open(sys.argv[2])); author=sys.argv[3]; Draft202012Validator.check_schema(schema); Draft202012Validator(schema,format_checker=FormatChecker()).validate(instance); ts=instance["validated_at"]; assert re.fullmatch(r"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})",ts); assert datetime.fromisoformat(ts.replace("Z","+00:00")).tzinfo is not None; assert instance["verdict"] != "PASS" or (instance["validator_session"] and instance["validator_session"] != author and not any(f["severity"] in {"critical","significant"} for f in instance["findings"]) and not instance["not_checked"])' "$SCHEMA" "$result" "$author_session" >/dev/null 2>&1
}
validate_report() {
local report="$1"
local validator_session="$2"
local author_session="$3"
local council_verdict report_verdict
council_verdict="$(sed -nE 's/^## Council Verdict: (PASS|WARN|FAIL)$/\1/p' "$report")"
report_verdict="$(sed -nE 's/^VERDICT: (PASS|WARN|FAIL)$/\1/p' "$report")"
[[ "$(grep -Ec '^## Council Verdict: (PASS|WARN|FAIL)$' "$report")" -eq 1 ]] &&
[[ "$(grep -Ec '^VERDICT: (PASS|WARN|FAIL)$' "$report")" -eq 1 ]] &&
[[ "$council_verdict" == "$report_verdict" ]] &&
[[ -n "$validator_session" ]] &&
[[ "$report_verdict" != "PASS" || "$validator_session" != "$author_session" ]] &&
awk -v judge="$validator_session" 'BEGIN{state=0;commands=0;reasons=0;seen=0;sourced=0;invalid=0;prefix="judge=" judge " command="} /^COMMANDS RUN:$/{commands++;if(state!=0)invalid=1;state=1;next} /^REASONS:$/{reasons++;if(state!=1||!seen)invalid=1;state=2;next} state==1&&NF{seen=1;if(index($0,prefix)==1&&length($0)>length(prefix))sourced=1} END{exit !(commands==1&&reasons==1&&seen&&sourced&&state==2&&!invalid)}' "$report"
}
record "validate contract is complete" validate_contract "$SKILL_MD"
record "verdict schema exists" test -s "$SCHEMA"
record "protocol reference exists" test -s "$SKILL_DIR/references/canonical-validation-protocol.md"
record "kernel stays within 250 lines" test "$(wc -l < "$SKILL_MD")" -le 250
pawl_fixture="$(mktemp)"
output_fixture="$(mktemp)"
valid_result="$(mktemp)"
invalid_result="$(mktemp)"
invalid_date_result="$(mktemp)"
self_judge_result="$(mktemp)"
blocking_finding_result="$(mktemp)"
significant_finding_result="$(mktemp)"
unchecked_result="$(mktemp)"
valid_report="$(mktemp)"
invalid_report="$(mktemp)"
wrong_order_report="$(mktemp)"
unsupported_report="$(mktemp)"
trap 'rm -f "$pawl_fixture" "$output_fixture" "$valid_result" "$invalid_result" "$invalid_date_result" "$self_judge_result" "$blocking_finding_result" "$significant_finding_result" "$unchecked_result" "$valid_report" "$invalid_report" "$wrong_order_report" "$unsupported_report"' EXIT
sed 's/HELPER-UNSTUCK -> AUTO-REDO/HELPER-UNSTUCK -> MANUAL/' "$SKILL_MD" >"$pawl_fixture"
awk '!/\*\*Validator command:\*\*/' "$SKILL_MD" >"$output_fixture"
if validate_contract "$pawl_fixture"; then echo "FAIL: missing helper transition rejected"; FAIL=$((FAIL + 1));
else echo "PASS: missing helper transition rejected"; PASS=$((PASS + 1)); fi
if validate_contract "$output_fixture"; then echo "FAIL: incomplete output handoff rejected"; FAIL=$((FAIL + 1));
else echo "PASS: incomplete output handoff rejected"; PASS=$((PASS + 1)); fi
printf '%s\n' '{"verdict_id":"01ARZ3NDEKTSV4RRFFQ69G5FAV","bead_id":"01ARZ3NDEKTSV4RRFFQ69G5FAW","verdict":"PASS","confidence":"HIGH","briefing_learnings":[],"findings":[],"not_checked":[],"validated_at":"2026-07-12T13:00:00Z","validator_session":"judge-1","schema_version":1}' >"$valid_result"
printf '%s\n' '{"verdict_id":"short","bead_id":"bad","verdict":"MAYBE","confidence":"HIGH","briefing_learnings":[],"findings":[],"not_checked":[],"validated_at":"not-a-date","validator_session":"author","schema_version":1}' >"$invalid_result"
printf '%s\n' '{"verdict_id":"01ARZ3NDEKTSV4RRFFQ69G5FAV","bead_id":"01ARZ3NDEKTSV4RRFFQ69G5FAW","verdict":"PASS","confidence":"HIGH","briefing_learnings":[],"findings":[],"not_checked":[],"validated_at":"not-a-date","validator_session":"judge-1","schema_version":1}' >"$invalid_date_result"
printf '%s\n' '{"verdict_id":"01ARZ3NDEKTSV4RRFFQ69G5FAX","bead_id":"01ARZ3NDEKTSV4RRFFQ69G5FAW","verdict":"PASS","confidence":"HIGH","briefing_learnings":[],"findings":[],"not_checked":[],"validated_at":"2026-07-12T13:00:00Z","validator_session":"author","schema_version":1}' >"$self_judge_result"
printf '%s\n' '{"verdict_id":"01ARZ3NDEKTSV4RRFFQ69G5FAY","bead_id":"01ARZ3NDEKTSV4RRFFQ69G5FAW","verdict":"PASS","confidence":"HIGH","briefing_learnings":[],"findings":[{"severity":"critical","description":"release gate is bypassed","location":"scripts/release.sh:10"}],"not_checked":[],"validated_at":"2026-07-12T13:00:00Z","validator_session":"judge-1","schema_version":1}' >"$blocking_finding_result"
printf '%s\n' '{"verdict_id":"01ARZ3NDEKTSV4RRFFQ69G5FB0","bead_id":"01ARZ3NDEKTSV4RRFFQ69G5FAW","verdict":"PASS","confidence":"HIGH","briefing_learnings":[],"findings":[{"severity":"significant","description":"required regression is missing","location":"tests/release.bats"}],"not_checked":[],"validated_at":"2026-07-12T13:00:00Z","validator_session":"judge-1","schema_version":1}' >"$significant_finding_result"
printf '%s\n' '{"verdict_id":"01ARZ3NDEKTSV4RRFFQ69G5FAZ","bead_id":"01ARZ3NDEKTSV4RRFFQ69G5FAW","verdict":"PASS","confidence":"HIGH","briefing_learnings":[],"findings":[],"not_checked":["release gate"],"validated_at":"2026-07-12T13:00:00Z","validator_session":"judge-1","schema_version":1}' >"$unchecked_result"
record "result validator accepts complete verdict.v1" validate_result "$valid_result" "author"
if validate_result "$invalid_result" "author"; then echo "FAIL: result validator rejects malformed verdict"; FAIL=$((FAIL + 1));
else echo "PASS: result validator rejects malformed verdict"; PASS=$((PASS + 1)); fi
if validate_result "$invalid_date_result" "author"; then echo "FAIL: result validator rejects invalid RFC3339 timestamp"; FAIL=$((FAIL + 1));
else echo "PASS: result validator rejects invalid RFC3339 timestamp"; PASS=$((PASS + 1)); fi
if validate_result "$self_judge_result" "author"; then echo "FAIL: PASS result rejects author as validator"; FAIL=$((FAIL + 1));
else echo "PASS: PASS result rejects author as validator"; PASS=$((PASS + 1)); fi
if validate_result "$blocking_finding_result" "author"; then echo "FAIL: PASS result rejects critical or significant findings"; FAIL=$((FAIL + 1));
else echo "PASS: PASS result rejects critical or significant findings"; PASS=$((PASS + 1)); fi
if validate_result "$significant_finding_result" "author"; then echo "FAIL: PASS result rejects significant findings"; FAIL=$((FAIL + 1));
else echo "PASS: PASS result rejects significant findings"; PASS=$((PASS + 1)); fi
if validate_result "$unchecked_result" "author"; then echo "FAIL: PASS result rejects nonempty not_checked"; FAIL=$((FAIL + 1));
else echo "PASS: PASS result rejects nonempty not_checked"; PASS=$((PASS + 1)); fi
printf '%s\n' '## Council Verdict: PASS' 'VERDICT: PASS' 'COMMANDS RUN:' 'judge=judge-1 command=go test ./...' 'REASONS:' '- command exited zero' >"$valid_report"
printf '%s\n' '## Council Verdict: PASS' 'VERDICT: FAIL' 'COMMANDS RUN:' 'judge=judge-1 command=go test ./...' 'REASONS:' '- contradictory headings' >"$invalid_report"
printf '%s\n' '## Council Verdict: PASS' 'VERDICT: PASS' 'REASONS:' '- wrong order' 'COMMANDS RUN:' 'judge=judge-1 command=go test ./...' >"$wrong_order_report"
printf '%s\n' '## Council Verdict: PASS' 'VERDICT: PASS' 'COMMANDS RUN:' 'tests looked good' 'REASONS:' '- unsupported prose' >"$unsupported_report"
record "report validator accepts measured single verdict" validate_report "$valid_report" "judge-1" "author"
if validate_report "$invalid_report" "judge-1" "author"; then echo "FAIL: report validator rejects contradictory verdict headings"; FAIL=$((FAIL + 1));
else echo "PASS: report validator rejects contradictory verdict headings"; PASS=$((PASS + 1)); fi
if validate_report "$wrong_order_report" "judge-1" "author"; then echo "FAIL: report validator rejects REASONS before COMMANDS RUN"; FAIL=$((FAIL + 1));
else echo "PASS: report validator rejects REASONS before COMMANDS RUN"; PASS=$((PASS + 1)); fi
if validate_report "$unsupported_report" "judge-1" "author"; then echo "FAIL: report validator rejects commands without judge source"; FAIL=$((FAIL + 1));
else echo "PASS: report validator rejects commands without judge source"; PASS=$((PASS + 1)); fi
echo
echo "Results: $PASS passed, $FAIL failed"
(( FAIL == 0 ))
+2 -2
View File
@@ -1,6 +1,6 @@
{
"schema_version": "2",
"generated_at": "2026-07-12T19:00:13Z",
"generated_at": "2026-07-12T20:26:54Z",
"skill_count": 62,
"skills": [
{
@@ -1702,7 +1702,7 @@
"llm-eval-harness"
],
"context_rel": [],
"references_count": 23,
"references_count": 24,
"codex_override_present": true
},
{
+120 -327
View File
@@ -26,372 +26,170 @@ metadata:
dependencies: [pawl-review]
output_contract: schemas/verdict.v1.schema.json
---
# /validate — Canonical Validator
# /validate — Canonical Validator Skill
> **Purpose:** Move 6 of the operating loop: independently remeasure a bounded artifact or slice, prove its acceptance, and emit one schema-valid PASS/WARN/FAIL verdict with an executable next action.
> **Loop position:** move 6 (prove acceptance) of the [operating loop](../../docs/architecture/operating-loop.md) — the driving adapter for the `validate_acceptance` port: every Given/When/Then must map to a passing test before a bead closes, and the verdict binds to the SLICE's own acceptance test (its ATDD contract), not only the parent intent issue. This is S5 of the [narrow-waist micro-cycle](../../docs/architecture/operating-loop.md#the-narrow-waist-micro-cycle-canonical--every-loop-skill-cites-this).
## Critical Constraints
> **Role:** validator. Input = artifact (plan, spec, code, PR, fitness gate). Output = `verdict.v1` (PASS / WARN / FAIL with rationale + findings).
- **One role: validator.** Never edit the artifact, commit, push, close tracker work, or operate infrastructure. **Why:** a judge that mutates the subject destroys independence.
- Rerun cited commands on the actual artifact; never accept author evidence, conversational memory, or uncited figures as proof. **Why:** validation remeasures rather than agrees.
- PASS requires every mandatory check green, all blockers resolved, disclosed `not_checked` coverage, and an independent judge when the mode claims independence. **Why:** missing evidence cannot be laundered into confidence.
- `judge_id == author_id` cannot independently PASS; inline `--quick` fallback is stamped waived. **Why:** self-grading is guidance, not assurance.
- Every judge brief says: **"READ-ONLY except writing your single verdict file at `<path>`. Do NOT commit, push, or run tracker/infra ops (git push, br/bd, dolt)."** **Why:** role scope is model-independent.
- This skill validates work; `ao pawl` certifies landing with a commit-bound verdict. **Why:** a pre-work PASS never pre-authorizes a main write.
- Use runtime-native judges for a requested multi-judge mode; never start NTM, Agent Mail, managed agents, Gas City, or another runtime unless explicitly selected. **Why:** judgment does not silently broaden orchestration.
- `WARN|FAIL|REFUTED -> AUTO-REDO`: consult the pawl, return findings as re-plan evidence, repair through the owning producer, and rerun the same checks. **Why:** ordinary negative verdicts are self-correction, not human andons.
- `BREAKER -> HOLD -> ONE-HELPER`; `HELPER-UNSTUCK -> AUTO-REDO`. Hold judgment and use one bounded local-shell helper to inspect contradictory evidence or a broken validator. **Why:** one recovery pass distinguishes tooling failure from a real stop.
- `HELPER-ESCALATE -> HUMAN`; `REFUSAL-LANE|EXPLICIT-JUDGMENT|EXHAUSTED-BUDGET -> HUMAN`. **Why:** waivers, risk acceptance, unavailable authority, refusal, or exhausted recovery require the operator.
`/validate` is a driving adapter for the `validate_acceptance` port in the
[Intent-to-Loop Hexagon](../../docs/architecture/intent-to-loop-hexagon.md).
When the artifact contains a `hexagon:` block, preserve the bounded context,
context packet, guard adapters, and done state in the verdict.
When the artifact claims DONE/closed/green, apply the
[Completion-Claim Kernel](../shared/validation-contract.md#completion-claim-kernel)
before returning PASS.
## Modes
**A verdict is re-plan evidence, not just a retry trigger.** A FAIL/WARN (and its
findings) surfaces UP to the [operating loop](../../docs/architecture/operating-loop.md):
the *remaining* moves may be refactored, inserted, dropped, or reordered in response
— not only the failed objective re-run. `/rpi` is one turn's executor over that loop,
not an autonomous `--auto` re-planner (the old rpi CLI command surface was removed in f61c5f0e7 — historical).
Looping a failed objective forever without asking whether the plan should change is
the waterfall anti-pattern.
## Modes (≤8 per Fix-F mode-flag budget)
| Mode | Purpose | Replaces / absorbs |
| Mode | Judge shape | Purpose |
|---|---|---|
| (default) | 2-judge multi-judge consensus on any artifact | `/council` default |
| `--quick` | Inline single-agent structured review | `/council --quick` |
| `--deep` | 4-judge thorough review | `/council --deep` |
| `--mixed` | Cross-vendor (Claude + Codex), N×2 judges | `/council --mixed` |
| `--debate` | Adversarial 2-round refinement | `/council --debate`; `/red-team` (absorbed 2026-07-07) |
| `--mode=post-impl` | Code-readiness pipeline (complexity → bug-hunt → council) | `vibe` (absorbed) |
| `--mode=pre-impl [--target=X]` | Plan/spec validation; target ∈ {scenario,fitness,ratchet,scope,skill,health} | `/pre-mortem`, `/goals measure`, `/scope`, `/heal-skill` (deep audit), `ao doctor`; `/eval-outcomes` + `/flywheel` (absorbed 2026-07-07) |
| `--mode=pr` | PR-shape verdict (diff review + acceptance check) | `/review` (absorbed 2026-07-07) |
| default | 2 independent | general artifact consensus |
| `--quick` | inline, waived | bounded sanity/readiness check |
| `--deep` | 4 perspectives | thorough requirement/feasibility/scope review |
| `--mixed` | explicitly selected families | cross-family review |
| `--debate` | 2+ judges, 2 rounds | adversarial critique/rebuttal |
| `--mode=post-impl` | pipeline + isolated judges | acceptance and completion audit |
| `--mode=pre-impl [--target=X]` | 2–4 judges | plan/spec/fitness/scope/skill/health audit |
| `--mode=pr` | diff + acceptance judges | submission readiness |
**Mode-budget assertion:** 8 modes. Adding a 9th requires demoting an existing one OR refusing the addition (per Fix-F § continuous CI gate).
**Mode-budget assertion:** 8 modes. Adding a ninth requires merging or removing an existing mode.
### Folded skills (cp-ki8): `validation` + `pr-validate` retired into these modes
The retired validation and pr-validate lanes were the Phase-1 placeholders for `--mode=post-impl`
and `--mode=pr`; both are now retired (cp-ki8) and their load-bearing contract folded
here so no capability is lost:
- **`--mode=post-impl` (was the validation lane) — full close-out + no-self-grading invariant.**
Beyond the inline `complexity → bug-hunt → council` pipeline, this mode owns the
`validate_acceptance` port: every Given/When/Then from the intent issue must map to a
passing test (criterion→test roll-up; activity logs do not close beads), and the
acceptance verdict **must be produced by a blind, context-isolated sub-agent judge that
did not author the code** (author ≠ validator — `ag-9jle.5` / `ag-lmdx.4`). Refuse to
certify acceptance when `judge_id == author_id`; the only escape is an inline-fallback
self-grade that is stamped as *waived, not independently validated*. Apply the
[Completion-Claim Kernel](../shared/validation-contract.md#completion-claim-kernel)
before accepting any DONE/closed/green claim. For epic-scope close-out this mode may
delegate to `vibe`, `/post-mortem`, and `/curate --mode=forge` rather than inlining them.
- **`--mode=pr` (was the pr-validate lane) — submission-readiness checks.** In addition to the
diff/acceptance verdict, run, in order: (1) **upstream alignment FIRST** (BLOCKING —
`git rev-list --count HEAD..origin/main`; fail if many commits behind or merge would
conflict), (2) CONTRIBUTING.md compliance (BLOCKING), (3) **isolation** — single commit
type + thematic files + atomic scope, (4) scope-creep containment, (5) quality gate
(tests/lint, non-blocking). On FAIL, emit remediation steps (split-by-type cherry-pick,
rebase-on-upstream) so the verdict is actionable.
### Folded triggers (ag-s43tg wave 1): `vibe` + `bead-completion-audit` route here
- **`vibe` → `--mode=post-impl`.** Use when doing a quick readiness or sanity check
that code is ready to commit or ship, short of a full review — the post-impl
pipeline (complexity → bug-hunt → council) is the vibe check.
- **`bead-completion-audit` → `--mode=post-impl` close-out.** Use when
auditing closed beads for real shipped evidence, acceptance proof, and truthful
closeout — the Completion-Claim Kernel and the no-self-grading invariant above
own this audit.
Folded triggers remain load-bearing: **`vibe` → `--mode=post-impl`** for code
readiness, and `bead-completion-audit` routes to post-implementation closeout.
Detailed target and evidence rules live in
[canonical-validation-protocol](references/canonical-validation-protocol.md).
## Quick Start
```bash
/validate path/to/plan.md # default 2-judge consensus
/validate --quick path/to/plan.md # inline single-agent
/validate --deep path/to/spec.md # 4-judge thorough
/validate --mode=pre-impl path/to/plan.md # pre-mortem mode
/validate --mode=post-impl recent # vibe mode (post-implement)
/validate --mode=pr 123 # PR review by PR number
/validate --mode=pre-impl --target=fitness # fitness gate against GOALS.md
/validate path/to/artifact
/validate --quick path/to/artifact
/validate --deep path/to/spec.md
/validate --mode=pre-impl --target=skill skills/example
/validate --mode=post-impl recent
/validate --mode=pr 123
```
Default uses runtime-native subagent spawning. Falls back to `--quick` (inline) when no multi-agent capability detected.
## Execution Workflow
## Execution
### 1. Resolve mode, artifact, and authority
### Step 1: Resolve mode + target
Parse `--mode` and `--target`. Default mode is multi-judge. Validate combinations:
| Mode | Allowed `--target` |
|---|---|
| default, --quick, --deep, --mixed, --debate | n/a |
| --mode=post-impl | n/a (pipeline scope is recent code changes) |
| --mode=pre-impl | scenario, fitness, ratchet, scope, skill, health (default: pre-mortem on plan) |
| --mode=pr | n/a (PR ID/path is positional) |
Reject invalid combinations (e.g., `--mode=pr --target=fitness`).
### Step 2: Load artifact + context
Reject invalid mode/target combinations. Confirm the artifact exists, is within
scope, and has explicit acceptance. For a goal-design packet, run:
```bash
# resolve artifact:
ARTIFACT="${1:-recent}" # path, PR ID, or "recent"
# load FAIL patterns:
# (folded into skill body; not a separate hook)
scripts/check-goal-design-packet.sh <packet-dir>
```
If `ARTIFACT` is a goal-design packet directory containing `intent.md` and
`driver.md`, run the deterministic packet checker before spawning or judging:
Nonzero is deterministic FAIL evidence. Load only the selected section of
[canonical-validation-protocol](references/canonical-validation-protocol.md)
plus the relevant language/risk standards.
```bash
scripts/check-goal-design-packet.sh "$ARTIFACT"
```
**Checkpoint:** record artifact identity, commit/digest, mode, targets, author id,
required checks, and `not_checked` before dispatch.
Non-zero exit is a FAIL verdict. Include the command and output in
`COMMANDS RUN:`. This is a pre-check inside the existing validator role, not a
new mode.
### 2. Run deterministic prechecks
For `--mode=pre-impl`, also load:
- `.agents/planning-rules/*.md` (compiled planning rules)
- `.agents/findings/registry.jsonl` (active findings)
- `.agents/pre-mortem-checks/*.md` (compiled prevention)
- pre-implementation: target rubric, temporal/error-rescue checks, test pyramid;
- post-implementation: complexity, bug sweep, slice acceptance, completion kernel;
- PR: upstream alignment first, contribution rules, atomicity, scope, tests/lint;
- all modes: source precedence, artifact freshness, and output-schema availability.
For `--mode=post-impl`, run pre-checks:
- complexity audit (radon for python, gocyclo for go)
- bug-hunt sweep (skill-body convention; no `/review` skill needed)
A deterministic red result is a FAIL verdict; do not spend judge tokens to
rediscover it.
For `--mode=pr`, fetch the PR diff (`gh pr diff <id>` or path).
### 3. Dispatch isolated judges
> **LIVE-PATH — where this judge orchestration is operative, and where the pawl is.**
> Steps 3–7 (spawn backend → run judges → write the `.agents/council/` verdict) are the live path
> for **PRE-work and non-merge validation**: plans, specs, artifacts, fitness gates, mid-arc
> completion checks, and the `--mode=pre-impl` / `post-impl` / `pr` verdicts. **At the merge-to-main
> door this orchestration is NOT the operative machinery** — that door is driven by the pawl scripts:
> `scripts/pawl-review.sh` runs the cross-family refuter and, on CONFIRMED, `scripts/pawl-verdict.sh`
> writes the commit-bound verdict the pre-push gate enforces (see [`/push`](../push/SKILL.md) and
> [`pawl-review`](../pawl-review/SKILL.md)). Use this skill to validate the WORK; use
> `ao pawl` to certify the LANDING — they compose, not compete. The judge machinery below is retained for
> that pre-work / non-merge scope, not deleted.
Register dispatch intent before spawning. Use the current runtime's native
subagents for multi-judge modes; if unavailable, degrade only to explicit
`--quick` and stamp the independence waiver.
### Step 3: Determine spawn backend
Each judge receives the artifact path/digest, bounded context, mandatory checks,
verdict path, and exact read-only clamp. It independently reruns commands.
1. `spawn_agent` available → Codex sub-agent
2. `TeamCreate` available → Claude native team
3. `task` (read-only skill tool, OpenCode) → opencode subagent
4. None → fall back to `--quick` (inline single-agent)
**Checkpoint:** author and judge identities differ, dispatch scopes do not
collide, and every claimed judge produced a nonempty verdict artifact.
Log selected backend in the verdict frontmatter.
### 4. Consolidate fail-closed
### Step 4: Run judges
- PASS: all required judges/checks PASS (or the declared deep-mode majority), no blocker.
- WARN: nonblocking concern or explicit coverage gap remains.
- FAIL: any deterministic failure, blocker, counterfeit/self judge, stale artifact, or malformed evidence.
| Mode | Judges | Perspectives |
|---|---|---|
| default | 2 | independent (no labeled perspectives) |
| --deep | 4 | missing-requirements, feasibility, scope, spec-completeness |
| --mixed | 2N (default N=3) | same N perspectives across Claude + Codex |
| --debate | 2+ rounds | adversarial; 2 rounds with critique-rebuttal |
| --quick | 0 (inline self) | structured review |
| --mode=post-impl | 2 + pipeline | complexity → bug-hunt → 2-judge council |
| --mode=pre-impl | 2-4 | per target preset |
| --mode=pr | 2 | diff-review + acceptance-check |
Contradictory verdicts are FAIL until reconciled; never average away a blocker.
Each judge gets:
- artifact path
- relevant context (planning rules, findings)
- council FAIL pattern check prompt (top 8)
- temporal interrogation prompt (--deep + --target=plan)
### 5. Write and validate outputs
### Step 5: Mandatory checks (auto-trigger)
Write `.agents/council/YYYY-MM-DD-validate-<slug>.md` with exactly one anchored
`## Council Verdict: PASS|WARN|FAIL`, plus `result.json` matching
`schemas/verdict.v1.schema.json`. The report contains exactly one anchored
`VERDICT:`, a nonempty `COMMANDS RUN:`, `REASONS:`, findings, and `not_checked`.
For `--mode=pre-impl --target=plan`:
- temporal interrogation (auto for plans with 5+ files or 3+ deps)
- error & rescue map
- council FAIL pattern check (top 8)
- test pyramid coverage check
- input validation check (enum-like fields)
**Checkpoint:** run both validators in Output Specification; PASS is illegal if
either output is missing, malformed, stale, self-graded, or unsupported by commands.
For `--mode=post-impl`:
- L0/L1/L2 coverage check on changed files
- **refactor-under-green check:** if the diff is a refactor, assert no acceptance/unit test text changed (`git diff` of test files is empty) — a refactor that edits a test changed behavior and is a new slice, not a refactor (S4). FAIL if a refactor diff also edits a test.
### 6. Route the verdict
For `--mode=pre-impl --target=fitness`:
- read GOALS.md
- evaluate each gate against current state
- report PASS/WARN/FAIL per gate + aggregate
### Step 6: Consolidate to verdict
Each judge returns a per-judge result. Consolidate:
- PASS only if all judges PASS (or majority for --deep)
- WARN if any judge raises a warning the others don't dispute
- FAIL if any judge raises a blocker the others don't override
### Step 7: Write verdict
Output path: `.agents/council/YYYY-MM-DD-validate-<topic-slug>.md`
```markdown
---
id: validate-YYYY-MM-DD-<slug>
type: verdict
date: YYYY-MM-DD
mode: <mode>
target: <target or n/a>
artifact: <path>
backend: <codex-subagents | claude-teams | opencode | inline>
---
# Validate Verdict — <topic>
## Council Verdict: PASS / WARN / FAIL
| Failure mode | Risk | Severity | Addressed? |
|---|---|---|---|
| ... | ... | ... | ... |
## Pseudocode Fixes (when WARN/FAIL)
(copy-pastable into affected issues per pre-mortem 4.6 contract)
## FAIL Pattern Check
(top 8 patterns — status per pattern)
## Verdict
PASS — proceed
WARN — review concerns, accept risk, or apply fixes
FAIL — block; revise artifact and rerun
```
The exact heading `## Council Verdict: PASS / WARN / FAIL` is mandatory — downstream validators and ledger readers parse it with anchored regex.
### Step 8: Persist findings (when applicable)
For `--mode=pre-impl` reusable findings: append to `.agents/findings/registry.jsonl` (atomic temp+rename). Every FAIL finding must be emitted as a next-loop producer — a `/pre-mortem` check or `/plan` planning-rule keyed by dedup_key (the escape→check ratchet, S6), not just a logged finding; a defect the membrane caught that produces no next-loop check will recur. See [operating-loop.md → move 7](../../docs/architecture/operating-loop.md).
### Step 9: Report
1. Verdict (PASS/WARN/FAIL).
2. Key concerns (when not PASS).
3. Output path.
4. Recommended next action.
## --target taxonomy (pre-impl)
| `--target` | What gets graded | Replaces |
|---|---|---|
| (default) | Plan/spec for an upcoming `/implement` | `/pre-mortem` |
| scenario | Holdout scenario gate | `/eval-outcomes` |
| fitness | GOALS.md fitness gates | `/goals measure`, `ao goals measure` |
| ratchet | Brownian Ratchet checkpoint | `/flywheel`, `ao ratchet status` |
| scope | Frozen-dirs declaration | `/scope` |
| skill | SKILL.md hygiene + audit | `/heal-skill` (heal.sh hygiene + audit.sh deep audit) |
| health | Repo health probe | `ao doctor` |
Each target has its own inline check rubric until Phase 2 extraction.
## Validation discipline (2026-06-09, cards 6–10, cp-hhd7)
### Verdict form — the gate parses these lines anchored
```
VERDICT: PASS
(blank line)
COMMANDS RUN:
<actual commands + verbatim output snippets>
REASONS:
- bullet citing a COMMANDS RUN line
```
A verdict with no `COMMANDS RUN:` section is **unverified** — reject it and
dispatch a fresh validator. A verdict whose `COMMANDS RUN:` lists only commands
the **author** ran (not the judge) is a **counterfeit judge** — treat as FAIL and
re-route to a genuinely independent validator. No `##` headings or parentheticals
on `VERDICT:` or `COMMANDS RUN:` lines; the gate parses them anchored.
### Cross-family floor (POLICY → gate icb6 enforces; this skill supports)
For **assurance closes** (the control-plane verdict-gate, cp-icb6), the floor is
≥2 verdicts from ≥2 distinct model families, author family excluded, fail-closed.
**This skill supports that policy via `--mixed` mode and the verdict form above;
the policy itself lives in the gate, not here.** A same-model council is valid for
non-assurance decisions (design brainstorms, quick checks) — do not refuse those.
Tier mapping:
- **STRICT** (irreversible, security, production close): Codex + strong-Gemini (A1); or Fable + Codex (A2).
- **ROUTINE** (everyday close): Codex + non-author-Claude (A3); or Fable + non-author (A4).
The A7 ruling (2026-06-09, memory `validation-family-policy-risk-tiered`):
Gemini is currently **benched** for STRICT validation — use Codex + Fable for A1/A2
tiers. Gemini may return for STRICT when Bo graduates it from the bench. Do not
present Gemini paths as live for tier A1/A2 until then.
### Judge empirically on a differentiating fixture (card 9, cp-8720)
When two implementations of the same intent exist, do NOT award based on
authorship or surface aesthetics. Run both on a **differentiating fixture** (an
input that exposes their behavioral difference), record the outputs verbatim, and
graft the loser's unique assets onto the winner. "My worker wrote it" is not
evidence.
### Dispatch record first (card 3, cp-hhtu)
Before dispatching a validator, register intent on the bead graph (update status,
assign actor). **Two parallel validators on the same bead produce a dedup incident,
not a cross-family quorum.** Check for an existing actor before spawning.
### Judge lanes carry an explicit write-scope clamp (2026-07-02, showcase kernel R2)
Every judge brief states, verbatim: **"READ-ONLY except writing your single verdict
file at `<path>`. Do NOT commit, push, or run tracker/infra ops (git push, br/bd,
dolt)."** The clamp is role-scoped, not model-scoped — crank workers legitimately
hold broad write scopes; judges re-measure, they never mutate. Proven live: an
unclamped codex acceptance judge pushed the feature branch unprompted and attempted
`bd dolt push` twice mid-judgment. A judge that mutates while judging can corrupt
the artifact under judgment or preempt the pawl.
### Judges re-measure; they do not read (card 8)
A judge re-runs the cited commands on the actual artifacts. It does not read the
author's evidence file and agree. Attest `judge_source: <model>` inside `COMMANDS RUN`
so the gate can confirm the judge identity. A judge that ran nothing is a reader, not
a verifier — discard its verdict.
## Evidence figures are measured, never inferred (the cp-801l lesson)
A worker's evidence file may only contain numbers and outputs that were **captured** —
pasted verbatim from a command's output — never reconstructed from memory. The
canonical failure: "36 checks — 35 pass" stated with confidence was inference; the
measured reality was 36 run / 34 pass / 1 fail / 1 skip, on a different commit.
- **Validators:** treat any uncited figure (a count, a pass-rate, a timing, a commit
hash) as **unverifiable → FAIL** until a log is produced or the claim is corrected.
- **Corrections happen by APPENDED erratum** — a dated erratum block crediting the
source measurement — never by silently editing the original figure. A silently
edited evidence file is indistinguishable from a fabricated one.
## Constraints (one-role-per-skill)
- **One role: validator.** Output is always a verdict. Never mutates code (delegates to `/implement` for fixes).
- **No new modes** without dropping/merging an existing one (Fix-F mode-budget cap = 8).
- **Verdict heading is regex-anchored** — do not alter the `## Council Verdict: ...` text format.
Report verdict, key findings, artifact paths, and one executable next action.
WARN/FAIL re-enters the operating loop through the owning producer. Reusable
failures compile into a planning/pre-mortem check instead of becoming a dead log.
## Output Specification
**Format:** a PASS/WARN/FAIL validation verdict plus a markdown council summary to stdout; machine-readable `result.json`.
**Files:** writes `.agents/council/YYYY-MM-DD-validate-<slug>.md` and `result.json`; appends reusable findings to `.agents/findings/registry.jsonl`; may refresh `.agents/planning-rules/` and `.agents/pre-mortem-checks/`.
**Exit signal:** FAIL re-cranks on the same objective (up to 3 attempts). Exhaustion enters HOLD and permits exactly one bounded fresh-context or cross-family helper pass; HELPER-UNSTUCK resumes with the new approach, while only HELPER-ESCALATE (or a refusal/explicit-judgment or spent hard-ceiling class) routes to the human. DONE requires a fully-green acceptance roll-up.
**Artifact directory:** markdown verdicts under `.agents/council/`; machine-readable `result.json` at the invocation output root.
## See Also
**Filename convention:** `.agents/council/YYYY-MM-DD-validate-<topic-slug>.md` plus `result.json`.
- `skills/rpi/SKILL.md` — orchestrator that fires `/validate --mode=pre-impl` after `/plan`
- `skills/curate/SKILL.md` — miner role (paired canonical skill)
- `schemas/verdict.v1.schema.json` — output contract
- [`pawl-review`](../pawl-review/SKILL.md) — executes immutable fresh reviewer lanes and hands evidence to `ao pawl`; the membrane alone binds the commit verdict
**Serialization/schema format:** `result.json` follows closed `schemas/verdict.v1.schema.json`; markdown has one `## Council Verdict: PASS|WARN|FAIL` and the anchored evidence form in the protocol reference.
**Validator command:** validate `result.json` with `Draft202012Validator(schema, format_checker=FormatChecker())`, an explicit timezone-aware RFC3339 parse of `validated_at`, and the pinned author identity so a PASS requires `validator_session != author_session`; then verify the markdown has exactly one council verdict, exactly one matching `VERDICT:`, and a `judge=<validator_session> command=<command>` evidence line under `COMMANDS RUN:` before `REASONS:`. The executable fixture suite is `bash skills/validate/scripts/validate.sh`.
**Downstream handoff:** pass mode/target, artifact path/digest/commit, author and judge identities/families, deterministic commands and exit codes, verdict/report paths, findings, `not_checked`, waiver/breaker state, and the exact next action; landing still requires `ao pawl`.
## Quality Checklist
- [ ] Artifact identity and acceptance are pinned before checks run.
- [ ] Judges are read-only, independent when claimed, and rerun commands themselves.
- [ ] Every number, timing, and commit is captured from cited output.
- [ ] PASS has no blockers, counterfeit judges, stale evidence, or undisclosed gaps.
- [ ] Markdown and JSON agree and pass their deterministic validators.
- [ ] WARN/FAIL/REFUTED returns to AUTO-REDO; only real breakers reach a human.
- [ ] Validation PASS is never substituted for the commit-bound landing verdict.
## Examples
### Reject a counterfeit completion claim
**User says:** `/validate --mode=post-impl recent`
**What happens:** the isolated judge reruns the slice acceptance command and
finds the author's reported count was inferred and the test exits nonzero.
**Result:** FAIL with captured output, corrected count, owning producer, and the
same validation command as next action; no human andon and no landing claim.
## Troubleshooting
| Problem | Response |
|---|---|
| Judge unavailable | Use explicit waived `--quick` or HOLD only if independence is required |
| Artifact changed mid-review | Mark stale, pin the new digest, rerun all checks |
| Judges disagree | FAIL until the blocker is reproduced and reconciled |
| Empty `COMMANDS RUN:` | Discard the verdict and dispatch a real verifier |
## Reference Documents
- [references/validate.feature](references/validate.feature) — Executable spec: verdict.v1 PASS/WARN/FAIL for any artifact, --mode selects shape, 8-mode budget (soc-qk4b)
## Reference library (incl. rescued vibe references, ag-s43tg)
- [references/canonical-validation-protocol.md](references/canonical-validation-protocol.md) — modes, targets, evidence, isolation, landing boundary
- [references/report-format.md](references/report-format.md) — markdown detail
- [references/deep-audit-protocol.md](references/deep-audit-protocol.md) — deep-mode perspectives
- [references/test-pyramid-inventory.md](references/test-pyramid-inventory.md) — coverage selection
- [references/post-verdict-actions.md](references/post-verdict-actions.md) — bounded follow-through
- [references/validate.feature](references/validate.feature) — executable behavior
- [references/complexity-analysis.md](references/complexity-analysis.md)
- [references/deep-audit-protocol.md](references/deep-audit-protocol.md)
- [references/deep-checks.md](references/deep-checks.md)
- [references/examples.md](references/examples.md)
- [references/go-patterns.md](references/go-patterns.md)
@@ -399,13 +197,10 @@ measured reality was 36 run / 34 pass / 1 fail / 1 skip, on a different commit.
- [references/json-standards.md](references/json-standards.md)
- [references/markdown-standards.md](references/markdown-standards.md)
- [references/patterns.md](references/patterns.md)
- [references/post-verdict-actions.md](references/post-verdict-actions.md)
- [references/python-standards.md](references/python-standards.md)
- [references/quick-mode-vibe.md](references/quick-mode-vibe.md)
- [references/report-format.md](references/report-format.md)
- [references/rust-standards.md](references/rust-standards.md)
- [references/shell-standards.md](references/shell-standards.md)
- [references/test-pyramid-inventory.md](references/test-pyramid-inventory.md)
- [references/test-pyramid-weighting.md](references/test-pyramid-weighting.md)
- [references/typescript-standards.md](references/typescript-standards.md)
- [references/verification-report.md](references/verification-report.md)
@@ -413,6 +208,4 @@ measured reality was 36 run / 34 pass / 1 fail / 1 skip, on a different commit.
- [references/vibe-suppressions.md](references/vibe-suppressions.md)
- [references/write-time-quality.md](references/write-time-quality.md)
- [references/yaml-standards.md](references/yaml-standards.md)
- [references/validate.feature](references/validate.feature)
- [references/vibe.feature](references/vibe.feature) — rescued vibe executable spec
- [scripts/prescan.sh](scripts/prescan.sh) — rescued vibe pre-scan helper
- [references/vibe.feature](references/vibe.feature)
@@ -0,0 +1,116 @@
# Canonical Validation Protocol
This reference carries the detailed mode, target, and evidence rules for the
`validate` kernel. Load only the sections selected by the current mode.
## Mode details
- Default: two independent judges; PASS requires both PASS.
- `--quick`: inline structured review. It may guide work but is stamped
`waived`, never independently validated.
- `--deep`: four perspectives—missing requirements, feasibility, scope, and
specification completeness. PASS uses the declared majority rule, with any
unresolved blocker still failing closed.
- `--mixed`: the same perspectives across explicitly selected model families.
- `--debate`: two adversarial rounds with critique and rebuttal.
- `--mode=post-impl`: complexity, bug sweep, acceptance roll-up, then isolated
judges. A refactor that changes acceptance/unit test text is a new behavior
slice, not a refactor.
- `--mode=pre-impl`: plan/spec checks, optionally specialized by `--target`.
- `--mode=pr`: upstream alignment first, contribution rules, atomic isolation,
scope containment, then tests/lint.
The eight-mode budget is fixed. A ninth mode must replace or merge an existing
mode rather than growing the public surface.
## Pre-implementation targets
| Target | Required checks |
|---|---|
| default plan | temporal interrogation, error/rescue map, FAIL patterns, test pyramid, enum/input validation |
| scenario | holdout scenario and falsifying edge |
| fitness | each GOALS.md gate against current measured state |
| ratchet | current checkpoint, evidence, and legal next transition |
| scope | frozen paths, authority boundary, and escape prevention |
| skill | strict hygiene plus profile-aware deep audit |
| health | executable repository health probes and disclosed gaps |
A goal-design packet containing `intent.md` and `driver.md` first runs
`scripts/check-goal-design-packet.sh <packet-dir>`; nonzero is FAIL evidence.
## Post-implementation acceptance
Every Given/When/Then maps to a passing acceptance test for its own vertical
slice. Activity logs and parent-issue summaries do not close a bead. Apply the
Completion-Claim Kernel in `skills/shared/validation-contract.md` to every
DONE/closed/green claim.
The acceptance judge is blind and context-isolated. `judge_id == author_id`
cannot independently PASS. Inline fallback is marked waived and cannot satisfy
an assurance close.
## PR checks
Run in order:
1. upstream alignment (`git rev-list --count HEAD..origin/main`) and conflict risk;
2. repository contribution rules;
3. one thematic/atomic change shape;
4. scope-creep containment;
5. relevant tests and lint.
FAIL includes executable remediation such as rebase or split-by-type; it never
mutates the branch from the judge lane.
## Evidence discipline
The validator reruns cited commands on the actual artifact. It does not accept
the author's evidence file as proof. Every count, timing, commit, and pass rate
is pasted from captured output. Uncited figures fail until measured.
Corrections are appended as dated errata crediting the source measurement;
silently rewriting an evidence claim is forbidden.
Verdict text uses anchored lines:
```text
VERDICT: PASS
COMMANDS RUN:
judge=<validator_session> command=<command rerun by this judge>
<bounded output excerpts produced by this judge>
REASONS:
- each reason cites a command or artifact
```
Exactly one verdict is allowed. `COMMANDS RUN:` must include at least one
`judge=<validator_session> command=<command>` line, and the pinned author identity
must differ from that validator session for PASS. A judge that ran nothing is a
reader, not a verifier.
## Judge isolation
Every judge brief includes this exact clamp:
> READ-ONLY except writing your single verdict file at `<path>`. Do NOT commit,
> push, or run tracker/infra ops (git push, br/bd, dolt).
Register dispatch intent before spawning. Two validators accidentally assigned
to the same lane/bead are a dedup incident, not an independent quorum.
## Assurance and landing
Non-merge validation may use runtime-native judges. Assurance close requires the
policy-selected independent-family floor. Benched families are not presented as
live strict lanes.
Landing is a different door: `ao pawl` produces the commit-bound verdict and the
pre-push gate authorizes the remote-main write. A validation PASS never replaces
or pre-authorizes that landing proof.
## Failure routing
WARN/FAIL/REFUTED findings return to the operating loop as re-plan evidence.
Repair and remeasure automatically while the bounded budget has progress.
HOLD/ESCALATE occurs only on a breaker: exhausted attempts/time/cost, oscillation,
refusal, unavailable authority, or explicit risk/waiver judgment.
+122
View File
@@ -0,0 +1,122 @@
#!/usr/bin/env bash
set -euo pipefail
SKILL_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
REPO_ROOT="$(cd "$SKILL_DIR/../.." && pwd)"
SKILL_MD="$SKILL_DIR/SKILL.md"
SCHEMA="$REPO_ROOT/schemas/verdict.v1.schema.json"
PASS=0
FAIL=0
record() {
local label="$1"
shift
if "$@"; then echo "PASS: $label"; PASS=$((PASS + 1));
else echo "FAIL: $label"; FAIL=$((FAIL + 1)); fi
}
validate_contract() {
local skill_md="$1"
[[ "$(awk '/^---$/{n++;next} n==2 && /^## /{print;exit}' "$skill_md")" == "## Critical Constraints" ]] &&
grep -Fq 'WARN|FAIL|REFUTED -> AUTO-REDO' "$skill_md" &&
grep -Fq 'BREAKER -> HOLD -> ONE-HELPER' "$skill_md" &&
grep -Fq 'HELPER-UNSTUCK -> AUTO-REDO' "$skill_md" &&
grep -Fq 'HELPER-ESCALATE -> HUMAN' "$skill_md" &&
grep -Fq 'REFUSAL-LANE|EXPLICIT-JUDGMENT|EXHAUSTED-BUDGET -> HUMAN' "$skill_md" &&
grep -Fq '**Mode-budget assertion:** 8 modes.' "$skill_md" &&
grep -Fq 'vibe` → `--mode=post-impl`' "$skill_md" &&
grep -Fq 'READ-ONLY except writing your single verdict file' "$skill_md" &&
grep -Fq 'This skill validates work; `ao pawl` certifies landing' "$skill_md" &&
grep -Fq '**Checkpoint:**' "$skill_md" &&
grep -Fq '**Artifact directory:**' "$skill_md" &&
grep -Fq '**Filename convention:**' "$skill_md" &&
grep -Fq '**Serialization/schema format:**' "$skill_md" &&
grep -Fq '**Validator command:**' "$skill_md" &&
grep -Fq '**Downstream handoff:**' "$skill_md" &&
grep -Fq '## Quality Checklist' "$skill_md"
}
validate_result() {
local result="$1"
local author_session="$2"
python3 -c 'import json,re,sys; from datetime import datetime; from jsonschema import Draft202012Validator,FormatChecker; schema=json.load(open(sys.argv[1])); instance=json.load(open(sys.argv[2])); author=sys.argv[3]; Draft202012Validator.check_schema(schema); Draft202012Validator(schema,format_checker=FormatChecker()).validate(instance); ts=instance["validated_at"]; assert re.fullmatch(r"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})",ts); assert datetime.fromisoformat(ts.replace("Z","+00:00")).tzinfo is not None; assert instance["verdict"] != "PASS" or (instance["validator_session"] and instance["validator_session"] != author and not any(f["severity"] in {"critical","significant"} for f in instance["findings"]) and not instance["not_checked"])' "$SCHEMA" "$result" "$author_session" >/dev/null 2>&1
}
validate_report() {
local report="$1"
local validator_session="$2"
local author_session="$3"
local council_verdict report_verdict
council_verdict="$(sed -nE 's/^## Council Verdict: (PASS|WARN|FAIL)$/\1/p' "$report")"
report_verdict="$(sed -nE 's/^VERDICT: (PASS|WARN|FAIL)$/\1/p' "$report")"
[[ "$(grep -Ec '^## Council Verdict: (PASS|WARN|FAIL)$' "$report")" -eq 1 ]] &&
[[ "$(grep -Ec '^VERDICT: (PASS|WARN|FAIL)$' "$report")" -eq 1 ]] &&
[[ "$council_verdict" == "$report_verdict" ]] &&
[[ -n "$validator_session" ]] &&
[[ "$report_verdict" != "PASS" || "$validator_session" != "$author_session" ]] &&
awk -v judge="$validator_session" 'BEGIN{state=0;commands=0;reasons=0;seen=0;sourced=0;invalid=0;prefix="judge=" judge " command="} /^COMMANDS RUN:$/{commands++;if(state!=0)invalid=1;state=1;next} /^REASONS:$/{reasons++;if(state!=1||!seen)invalid=1;state=2;next} state==1&&NF{seen=1;if(index($0,prefix)==1&&length($0)>length(prefix))sourced=1} END{exit !(commands==1&&reasons==1&&seen&&sourced&&state==2&&!invalid)}' "$report"
}
record "validate contract is complete" validate_contract "$SKILL_MD"
record "verdict schema exists" test -s "$SCHEMA"
record "protocol reference exists" test -s "$SKILL_DIR/references/canonical-validation-protocol.md"
record "kernel stays within 250 lines" test "$(wc -l < "$SKILL_MD")" -le 250
pawl_fixture="$(mktemp)"
output_fixture="$(mktemp)"
valid_result="$(mktemp)"
invalid_result="$(mktemp)"
invalid_date_result="$(mktemp)"
self_judge_result="$(mktemp)"
blocking_finding_result="$(mktemp)"
significant_finding_result="$(mktemp)"
unchecked_result="$(mktemp)"
valid_report="$(mktemp)"
invalid_report="$(mktemp)"
wrong_order_report="$(mktemp)"
unsupported_report="$(mktemp)"
trap 'rm -f "$pawl_fixture" "$output_fixture" "$valid_result" "$invalid_result" "$invalid_date_result" "$self_judge_result" "$blocking_finding_result" "$significant_finding_result" "$unchecked_result" "$valid_report" "$invalid_report" "$wrong_order_report" "$unsupported_report"' EXIT
sed 's/HELPER-UNSTUCK -> AUTO-REDO/HELPER-UNSTUCK -> MANUAL/' "$SKILL_MD" >"$pawl_fixture"
awk '!/\*\*Validator command:\*\*/' "$SKILL_MD" >"$output_fixture"
if validate_contract "$pawl_fixture"; then echo "FAIL: missing helper transition rejected"; FAIL=$((FAIL + 1));
else echo "PASS: missing helper transition rejected"; PASS=$((PASS + 1)); fi
if validate_contract "$output_fixture"; then echo "FAIL: incomplete output handoff rejected"; FAIL=$((FAIL + 1));
else echo "PASS: incomplete output handoff rejected"; PASS=$((PASS + 1)); fi
printf '%s\n' '{"verdict_id":"01ARZ3NDEKTSV4RRFFQ69G5FAV","bead_id":"01ARZ3NDEKTSV4RRFFQ69G5FAW","verdict":"PASS","confidence":"HIGH","briefing_learnings":[],"findings":[],"not_checked":[],"validated_at":"2026-07-12T13:00:00Z","validator_session":"judge-1","schema_version":1}' >"$valid_result"
printf '%s\n' '{"verdict_id":"short","bead_id":"bad","verdict":"MAYBE","confidence":"HIGH","briefing_learnings":[],"findings":[],"not_checked":[],"validated_at":"not-a-date","validator_session":"author","schema_version":1}' >"$invalid_result"
printf '%s\n' '{"verdict_id":"01ARZ3NDEKTSV4RRFFQ69G5FAV","bead_id":"01ARZ3NDEKTSV4RRFFQ69G5FAW","verdict":"PASS","confidence":"HIGH","briefing_learnings":[],"findings":[],"not_checked":[],"validated_at":"not-a-date","validator_session":"judge-1","schema_version":1}' >"$invalid_date_result"
printf '%s\n' '{"verdict_id":"01ARZ3NDEKTSV4RRFFQ69G5FAX","bead_id":"01ARZ3NDEKTSV4RRFFQ69G5FAW","verdict":"PASS","confidence":"HIGH","briefing_learnings":[],"findings":[],"not_checked":[],"validated_at":"2026-07-12T13:00:00Z","validator_session":"author","schema_version":1}' >"$self_judge_result"
printf '%s\n' '{"verdict_id":"01ARZ3NDEKTSV4RRFFQ69G5FAY","bead_id":"01ARZ3NDEKTSV4RRFFQ69G5FAW","verdict":"PASS","confidence":"HIGH","briefing_learnings":[],"findings":[{"severity":"critical","description":"release gate is bypassed","location":"scripts/release.sh:10"}],"not_checked":[],"validated_at":"2026-07-12T13:00:00Z","validator_session":"judge-1","schema_version":1}' >"$blocking_finding_result"
printf '%s\n' '{"verdict_id":"01ARZ3NDEKTSV4RRFFQ69G5FB0","bead_id":"01ARZ3NDEKTSV4RRFFQ69G5FAW","verdict":"PASS","confidence":"HIGH","briefing_learnings":[],"findings":[{"severity":"significant","description":"required regression is missing","location":"tests/release.bats"}],"not_checked":[],"validated_at":"2026-07-12T13:00:00Z","validator_session":"judge-1","schema_version":1}' >"$significant_finding_result"
printf '%s\n' '{"verdict_id":"01ARZ3NDEKTSV4RRFFQ69G5FAZ","bead_id":"01ARZ3NDEKTSV4RRFFQ69G5FAW","verdict":"PASS","confidence":"HIGH","briefing_learnings":[],"findings":[],"not_checked":["release gate"],"validated_at":"2026-07-12T13:00:00Z","validator_session":"judge-1","schema_version":1}' >"$unchecked_result"
record "result validator accepts complete verdict.v1" validate_result "$valid_result" "author"
if validate_result "$invalid_result" "author"; then echo "FAIL: result validator rejects malformed verdict"; FAIL=$((FAIL + 1));
else echo "PASS: result validator rejects malformed verdict"; PASS=$((PASS + 1)); fi
if validate_result "$invalid_date_result" "author"; then echo "FAIL: result validator rejects invalid RFC3339 timestamp"; FAIL=$((FAIL + 1));
else echo "PASS: result validator rejects invalid RFC3339 timestamp"; PASS=$((PASS + 1)); fi
if validate_result "$self_judge_result" "author"; then echo "FAIL: PASS result rejects author as validator"; FAIL=$((FAIL + 1));
else echo "PASS: PASS result rejects author as validator"; PASS=$((PASS + 1)); fi
if validate_result "$blocking_finding_result" "author"; then echo "FAIL: PASS result rejects critical or significant findings"; FAIL=$((FAIL + 1));
else echo "PASS: PASS result rejects critical or significant findings"; PASS=$((PASS + 1)); fi
if validate_result "$significant_finding_result" "author"; then echo "FAIL: PASS result rejects significant findings"; FAIL=$((FAIL + 1));
else echo "PASS: PASS result rejects significant findings"; PASS=$((PASS + 1)); fi
if validate_result "$unchecked_result" "author"; then echo "FAIL: PASS result rejects nonempty not_checked"; FAIL=$((FAIL + 1));
else echo "PASS: PASS result rejects nonempty not_checked"; PASS=$((PASS + 1)); fi
printf '%s\n' '## Council Verdict: PASS' 'VERDICT: PASS' 'COMMANDS RUN:' 'judge=judge-1 command=go test ./...' 'REASONS:' '- command exited zero' >"$valid_report"
printf '%s\n' '## Council Verdict: PASS' 'VERDICT: FAIL' 'COMMANDS RUN:' 'judge=judge-1 command=go test ./...' 'REASONS:' '- contradictory headings' >"$invalid_report"
printf '%s\n' '## Council Verdict: PASS' 'VERDICT: PASS' 'REASONS:' '- wrong order' 'COMMANDS RUN:' 'judge=judge-1 command=go test ./...' >"$wrong_order_report"
printf '%s\n' '## Council Verdict: PASS' 'VERDICT: PASS' 'COMMANDS RUN:' 'tests looked good' 'REASONS:' '- unsupported prose' >"$unsupported_report"
record "report validator accepts measured single verdict" validate_report "$valid_report" "judge-1" "author"
if validate_report "$invalid_report" "judge-1" "author"; then echo "FAIL: report validator rejects contradictory verdict headings"; FAIL=$((FAIL + 1));
else echo "PASS: report validator rejects contradictory verdict headings"; PASS=$((PASS + 1)); fi
if validate_report "$wrong_order_report" "judge-1" "author"; then echo "FAIL: report validator rejects REASONS before COMMANDS RUN"; FAIL=$((FAIL + 1));
else echo "PASS: report validator rejects REASONS before COMMANDS RUN"; PASS=$((PASS + 1)); fi
if validate_report "$unsupported_report" "judge-1" "author"; then echo "FAIL: report validator rejects commands without judge source"; FAIL=$((FAIL + 1));
else echo "PASS: report validator rejects commands without judge source"; PASS=$((PASS + 1)); fi
echo
echo "Results: $PASS passed, $FAIL failed"
(( FAIL == 0 ))