git:20260522.34a8d75 to git:20260909.6778255

24 added, 107 removed. Audit A to A.

---
name: goal-contract-capture
- description: "Capture a FlowGoal contract as a project-local `.flow/goals/<id>.goal.yaml` file with outcome, acceptance criteria (with verification commands), specification elements (non-goals, failure modes, interface contracts), constraints, evaluator binding, continuation policy, and lifecycle frontmatter. Use when /flow:start passes the Spec Validation Gate, when /flow:goal create is invoked, or when /flow:review and /flow:address need a completion contract for a PR. This skill MUST be consulted because acceptance criteria alone do not constitute a contract — without an evaluator binding, boundaries, and lifecycle state, downstream phases cannot detect premature completion, the Stop hook cannot enforce evidence, and goals cannot resume across sessions."
+ description: "Capture a FlowGoal contract as `.flow/goals/<id>.goal.yaml` — outcome, acceptance criteria with verification commands, specification (non-goals, failure modes, interface contracts, risk map), constraints, evaluator binding, continuation policy, lifecycle. Use when /flow:start passes the Spec Validation Gate, when /flow:goal create runs, or when /flow:debug confirms a hypothesis. Acceptance criteria alone are not a contract: without an evaluator binding and boundaries the Stop hook cannot enforce evidence and goals cannot resume."
allowed-tools: Bash, Read, Write, Edit, AskUserQuestion
agent: general-purpose
---
# Goal Contract Capture
- You produce a FlowGoal contract — a durable completion contract that turns acceptance criteria + specification into a machine-readable, file-backed artifact. This skill is the 5th invoker of the existing `specification-capture` pattern; it wraps that skill (does NOT replace it) and adds the goal-specific fields needed for evaluator/Stop-hook enforcement.
-
- ## Iron Law
-
- **No `/flow:goal create` without a complete contract. No `.flow/goals/<id>.goal.yaml` without an evaluator binding. The contract is the source of truth for the Stop hook and `/flow:goal evaluate`; gaps here cascade into silent premature completion.**
-
- ## Relationship to existing skills
-
- This skill is a **wrapper**, not a fork:
-
- | Existing skill | What it gives us | What this skill adds |
- |---|---|---|
- | `specification-capture` | non-goals, failure modes, interface contracts | the `specification` block in the goal YAML |
- | `criterion-verification-map` | per-AC verification commands + expected evidence | the `objective.acceptance_criteria[].verification_command` field |
- | `evidence-based-development` | ASSERTION/EVIDENCE/VERIFIED discipline | the `evidence_ref` linking the AC back to a FlowEvidence sidecar |
+ ## Contract
- If those skills have already produced their outputs (decision journal manifest entries), this skill **reads from them** rather than re-asking the user.
+ Iron law: no `.flow/goals/<id>.goal.yaml` without an evaluator binding, and no contract element invented: every specification element is lifted from the journal or escalated. Invoked by `/flow:start` (Phase 1, after the Spec Validation Gate), `/flow:goal create`, and `/flow:debug` (after the confirmed hypothesis) with a goal id, scope, source, and invocation reason (`start | goal-create | review | address | debug`). Returns the written goal path plus a `goal-created` journal artifact; the caller then invokes `goal-lifecycle`. Permitted skips: `review` and `address` invocations skip the specification block (they inherit the issue's capture); `goal-create` with no linked issue skips the journal artifact. Nothing else may be skipped.
## Inputs
- The invoking command MUST pass:
-
- 1. **Goal id** — typically `issue-{N}`, `pr-{N}-review`, `pr-{N}-address`, or an ad-hoc slug. Validated against the schema's `^[a-z0-9][a-z0-9-]{0,63}$` pattern.
- 2. **Scope** — `repo`, `branch`, optionally `issue` and/or `pr`, optionally a `journal` path (`.decisions/issue-{N}.md`).
- 3. **Source** — typically the GitHub issue body (parsed for AC) or the PR description (parsed for review/address scope).
- 4. **Invocation reason** — `start | goal-create | review | address`. Used to choose the right outcome template and the right `evaluator.type`.
+ 1. **Goal id**: `issue-{N}`, `pr-{N}-review`, `pr-{N}-address`, or an ad-hoc slug matching `^[a-z0-9][a-z0-9-]{0,63}$`.
+ 2. **Scope**: `repo`, `branch`, optional `issue`/`pr`, optional `journal` path (`.decisions/issue-{N}.md`).
+ 3. **Source**: issue body, PR description, or user-supplied outcome.
+ 4. **Invocation reason**: selects the outcome template and `evaluator.type`.
## Outputs
- Single file: `.flow/goals/<id>.goal.yaml` conforming to `plugins/flow/schemas/v1/goal.schema.json`. Written via `bin/flow-goal-record.sh` (atomic, O_NOFOLLOW-defended).
-
- Plus: one `goal-created` artifact appended to the linked decision journal via `bin/journal-record.sh --type goal-created --metadata goal_id=<id> --metadata source=<src>`.
+ `.flow/goals/<id>.goal.yaml` conforming to `plugins/flow/schemas/v1/goal.schema.json`, written only through `bin/flow-goal-record.sh --create --goal-file <composed.yaml>` (atomic, O_NOFOLLOW-defended, schema-validated), plus `bin/journal-record.sh --issue {N} --type goal-created --metadata goal_id=<id> --metadata source=<src>`.
## Workflow
- 1. **Pre-flight check** — refuse if `.flow/goals/<id>.goal.yaml` already exists and `lifecycle.status` is not in `{cancelled, failed}`. Surface the existing goal to the user via the six-field escalation; never silently overwrite an active goal.
-
- 2. **Compose `metadata`**:
- ```yaml
- metadata:
- id: <derived-from-invocation>
- created_at: <ISO-8601 UTC now>
- created_by: <invoking command, e.g. /flow:start>
- owner: <git user.email or @me>
- ```
-
- 3. **Compose `scope`** — from inputs. Set `journal` to the linked decision journal path. Leave `run_id` empty until `run-state-management` wires FlowRun creation.
-
- 4. **Compose `objective`** — pull AC text + verification commands from the existing `criterion-verification-map` output. Each AC is one entry with `status: pending` and `evidence_ref: null` initially. The `outcome` is a one-sentence statement derived from invocation reason:
- - `start` → "Issue #{N} is implemented and verified."
- - `goal-create` → user-supplied via AskUserQuestion.
- - `review` → "PR #{N} review completed with findings posted or no-finding evidence recorded."
- - `address` → "All unresolved findings on PR #{N} are resolved, commented, or escalated."
-
- 5. **Compose `specification`** — lift from `specification-capture`'s journal entries:
- - `non_goals` from the `## Specification > ### Non-goals` body
- - `failure_modes` from `### Failure modes`
- - `interface_contracts` from `### Interface contracts`
-
- If any block is empty, raise the six-field escalation per `references/escalation-format.md` — do NOT silently fill with placeholders.
-
- 6. **Compose `constraints`** — default to `tdd_required: true`, `require_all_pass: true`, `no_calendar_estimates: true`, `no_tier3_without_confirmation: true`. Add `denied_paths` from settings (`flow.goals.denied_paths` cascade key); add `allowed_paths` only if the goal narrows the tier model (e.g., a focused refactor).
-
- 7. **Compose `evaluator`**:
- ```yaml
- evaluator:
- type: flow_verdict_judge # hybrid for fuzzy criteria; deterministic for command-only
- command: /flow:goal evaluate
- judge_agent: goal-evaluator-judge
- evidence_bundle_format: plugins/flow/references/evidence-bundle-format.md
- denied_context:
- - implementation_rationale
- - self_review_findings
- ```
-
- 8. **Compose `continuation`** — defaults: `mode: flow_managed`, `on_incomplete: continue_next_activity`, `on_blocked: six_field_escalation`, `on_complete: mark_achieved`, `max_iterations: <from settings, default 20>`.
-
- 9. **Compose `lifecycle`** — initial state:
- ```yaml
- lifecycle:
- status: active
- current_phase: <derived; start→explore, review→fan-out, address→categorize>
- current_activity: <first activity id>
- turns_evaluated: 0
- last_evaluation:
- result: incomplete
- reason: "Goal created; evidence not yet collected."
- at: <now>
- ```
-
- 10. **Write atomically** — call `bin/flow-goal-record.sh` with the composed YAML. Verify exit 0; surface stderr on any failure.
-
- 11. **Record journal artifact** — `bin/journal-record.sh --issue {N} --type goal-created --metadata goal_id=<id> --metadata source=<src>`.
-
- 12. **Verify the artifact** — read back `.flow/goals/<id>.goal.yaml` and validate against the schema (Python jsonschema if available). A schema mismatch here means the skill or the schema is broken; fail hard.
-
- ## Per-invoker scope
-
- | Invoker | Captures | Skips |
- |---|---|---|
- | `start` | All blocks; outcome derived from issue title | nothing |
- | `goal-create` | All blocks; outcome from AskUserQuestion | journal manifest if no issue |
- | `review` | Outcome + AC (= review checklist) + constraints | specification (use issue's existing capture) |
- | `address` | Outcome + AC (= one per unresolved PR comment) + constraints | specification (inherit from review goal) |
+ 1. **Pre-flight**: if the goal file exists with `lifecycle.status` outside `{cancelled, failed}`, stop and raise the six-field escalation (`references/escalation-format.md`). Never overwrite an active goal.
+ 2. **`metadata`**: `id`, `created_at` (ISO-8601 UTC), `created_by` (invoking command), `owner` (git `user.email` or `@me`).
+ 3. **`scope`**: from inputs; leave `run_id` unset (run-state-management fills it).
+ 4. **`objective`**: `outcome` by reason: `start`: "Issue #{N} is implemented and verified."; `review`: "PR #{N} review completed with findings posted or no-finding evidence recorded."; `address`: "All unresolved findings on PR #{N} are resolved, commented, or escalated."; `goal-create`: AskUserQuestion; `debug`: the caller's template. Each AC comes from `criterion-verification-map` output with `status: pending`, `evidence_ref: null`, and its `verification_command` when one exists.
+ 5. **`specification`**: lift from the journal's `## Specification` section written by `specification-capture`: `non_goals` from `### Non-goals`, `failure_modes` from `### Failure modes`, `interface_contracts` from `### Interface contracts`, and `risk_map` from the `### Risk map` table, where each row `Area | Plausible wrong version | Discriminating check` becomes `{area, plausible_wrong_version, discriminating_check}`. When the journal has no `### Risk map`, omit the `risk_map` key. Never invent rows or fill an empty block with placeholders; an empty non-goals, failure-modes, or interface-contracts block is a six-field escalation.
+ 6. **`constraints`**: `tdd_required`, `require_all_pass`, `no_calendar_estimates`, `no_tier3_without_confirmation` all `true`; `denied_paths` from `flow.goals.denied_paths`; `allowed_paths` only when the goal narrows scope.
+ 7. **`evaluator`**: `type: flow_verdict_judge` (`hybrid` when fuzzy criteria exist, `deterministic` when every AC has a command), `command: /flow:goal evaluate`, `judge_agent: goal-evaluator-judge`, `evidence_bundle_format: plugins/flow/references/evidence-bundle-format.md`, `denied_context: [implementation_rationale, self_review_findings]`.
+ 8. **`continuation`**: `mode: flow_managed`, `on_incomplete: continue_next_activity`, `on_blocked: six_field_escalation`, `on_complete: mark_achieved`, `max_iterations` from settings (default 20).
+ 9. **`lifecycle`**: `status: active`, `current_phase` by reason (`start`: explore, `review`: fan-out, `address`: categorize, `debug`: fix), `current_activity`, `turns_evaluated: 0`, `last_evaluation: {result: incomplete, reason: "Goal created; evidence not yet collected.", at: <now>}`. Never `achieved` at creation.
+ 10. **Write, record, verify**: run the helper, surface any non-zero exit with its stderr, append the journal artifact, then read the file back and confirm it parses and matches the schema.
- ## Anti-patterns
+ ## Trust
- - ❌ Silently overwriting an active goal — always surface and escalate.
- - ❌ Filling in empty specification blocks with placeholders — escalate via six-field.
- - ❌ Bypassing `bin/flow-goal-record.sh` for "speed" — atomicity + symlink defense matters.
- - ❌ Setting `lifecycle.status: achieved` at creation — the only way to `achieved` is through `/flow:goal evaluate`.
+ `bin/flow-goal-record.sh --create` also records the goal in the per-user trust ledger (`${FLOW_STATE_DIR:-~/.claude/flow-state}/goal-trust.jsonl`, via `bin/flow-goal-trust.sh record`). The Stop hook executes a goal's verification commands only when the goal is trusted or `flow.goals.executeVerificationCommands` is true. A goal is trusted only when it was created through flow in this user's environment; a goal that arrived with a checkout is not. Editing a `verification_command` by hand changes the hash and untrusts the goal until you run `bin/flow-goal-trust.sh record --goal-file .flow/goals/<id>.goal.yaml`.
- ## Reuse map
+ ## References
- - `plugins/flow/skills/specification-capture/SKILL.md` — read the per-invoker scope table; this skill adds row 5 (`goal-create`).
- - `plugins/flow/skills/criterion-verification-map/SKILL.md` — read for the AC verification-command shape.
- - `plugins/flow/schemas/v1/goal.schema.json` — the canonical schema this skill writes against.
- - `plugins/flow/bin/flow-goal-record.sh` — atomic writer.
- - `plugins/flow/bin/journal-record.sh` — for the `goal-created` manifest artifact.
- - `plugins/flow/references/escalation-format.md` — six-field escalation for any empty/ambiguous block.
+ - `plugins/flow/skills/specification-capture/SKILL.md`: the journal headings lifted in step 5.
+ - `plugins/flow/skills/criterion-verification-map/SKILL.md`: AC verification-command shape.
+ - `plugins/flow/references/flow-goals.md`: full YAML example and settings.