flow-next-refine · diff
git:20260928.b67e58e to git:20261001.25a2947
118 added, 264 removed. Audit A to A.
---
name: flow-next-refine
description: Refine a spec or task before building: one Q&A interview, optionally focused by a scope lens, or a read-only research pass over external docs. Use to refine requirements or read up on a new library.
user-invocable: false
---
# Flow refine
- Refine a task/spec: ask only the questions whose answers would change what gets built, and write the answers back, or (`--scope=research`) resolve the spec's external-library unknowns from official docs and write them back. The `interview` name remains a forwarding alias for one release.
+ Refine a spec, task, or spec file: settle the decisions that would change what gets built and that only the person can make, then write the answers back. Everything else you resolve by investigation, record, or leave to implementation. `--scope=research` is a separate pass that asks nothing and writes the spec's external-library unknowns back from official docs.
- **`.flow/` is the only task tracker.** A run that recorded task state in a markdown TODO, a plan file, TodoWrite, or any other tracker has broken this — all task state is read and written via `flowctl`.
+ All task state is read and written through `flowctl`; `.flow/` is the only tracker (no markdown TODOs, plan files or TodoWrite).
- ### Chart boundary
+ Refine clarifies a spec that can already be specified. Route back to `/flow-next:chart` only when the answers show the effort itself is not yet specifiable; unsure of the hop, use `$flow-next-flow --explain`.
- Existing-spec clarification stays **primary**. Interview refines a valid spec with unresolved judgment questions. Do **not** reopen discovery as `/flow-next:chart` unless the answers reveal that the **effort itself is not yet specifiable** - only then route backward to chart. Clear work that never needed a chart stays out of chart. Unsure of the hop: `$flow-next-flow --explain`.
+ Read [working-rules.md](../../references/working-rules.md) first unless you already have this run; it holds for every step of this skill.
## Preamble
- **CRITICAL: flowctl is BUNDLED — NOT installed globally.** `which flowctl` will fail (expected). Define once; subsequent blocks use `$FLOWCTL`:
+ **flowctl is bundled, not installed globally** (`which flowctl` fails). Define once; later blocks use `$FLOWCTL`:
```bash
FLOWCTL="${CODEX_HOME:-$HOME/.codex}/scripts/flowctl"
[ -x "$FLOWCTL" ] || FLOWCTL="<plugin-root>/scripts/flowctl" # <plugin-root> = the directory two levels above this skill's SKILL.md file (the harness gave you that file's absolute path when the skill loaded); substitute it literally
[ -x "$FLOWCTL" ] || FLOWCTL=".flow/bin/flowctl"
```
- **Role**: technical interviewer, spec refiner
- **Goal**: settle the decisions that would change what gets built and that only the user can make; resolve, record, or leave everything else to implementation
-
## Input
Full request: $ARGUMENTS
- Accepts a Flow spec ID, a Flow task ID, a resolvable tracker handle, a file path, or nothing — recognition rules and the fetch command per type are in "Detect Input Type" below (single copy; the write-back command per type is in `references/write-back.md`).
+ A Flow spec id, a Flow task id, a tracker handle linked to one, or a file path. Examples:
- Examples:
- - `/flow-next:refine fn-1-add-oauth`
- - `/flow-next:refine fn-1-add-oauth.3`
- - `/flow-next:refine fn-1` (legacy formats fn-1, fn-1-xxx still supported)
+ - `/flow-next:refine fn-1-add-oauth` (legacy `fn-1`, `fn-1-xxx` and task ids like `fn-1-add-oauth.3` work too)
- `/flow-next:refine docs/oauth-spec.md`
- `/flow-next:refine fn-1-add-oauth --scope=qa` (the same interview, focused on what QA decides)
- `/flow-next:refine fn-1-add-oauth --scope=research` (external-docs pass; no questions)
- If empty, ask: "What should I interview you about? Give me a Flow ID (e.g., fn-1-add-oauth) or file path (e.g., docs/spec.md)"
+ Empty: ask "What should I refine? Give me a Flow ID (e.g. fn-1-add-oauth) or a file path (e.g. docs/spec.md)."
## Setup
- ### Read the scope lens
-
- `--scope=<value>` is an optional free-text lens: `business`, `technical`, `qa`, `security`, or any other audience. `--biz` means `--scope=business` and `--tech` means `--scope=technical`. Take these tokens out of the arguments before input detection; several values combine into one lens. There is one interview whatever the lens: the lens focuses which open decisions you look for and ask about (a QA lens looks for what QA would decide: what counts as done, which failures matter, what must be testable), and you interpret it from its words. No lens means no filter. Never ask which scope to run.
-
- **`--scope=research` is a different pass and asks no questions.** Skip the doc-aware autodetect and the interview: run Detect Input Type below, then read [`references/research-scope.md`](references/research-scope.md) and follow it. The interview never reads that file.
-
- ### Parse `--docs` / `--no-docs` / `--strategy` / `--no-strategy` flags
-
- The four doc-aware override flags must be stripped from `$ARGUMENTS` before input-type detection so they don't get confused for a Flow ID or path. Two force variables carry the result — `""` = autodetect, `"on"` = forced on, `"off"` = forced off:
-
- ```bash
- RAW_ARGS="$ARGUMENTS"
- DOC_AWARE_FORCE="" # controls glossary + decisions
- STRATEGY_AWARE_FORCE="" # controls strategy independently
- ```
-
- **When the invocation carried ANY of `--docs` / `--no-docs` / `--strategy` / `--no-strategy`**, STOP and read [`references/doc-aware.md`](references/doc-aware.md) § Flag parsing before proceeding — it holds the strip block (both pairs mutually exclusive, negation wins on conflict), the cascade rules, and the flag matrix that is the contract for each combination. A bare invocation skips it: no flag token is present, so `RAW_ARGS` is `$ARGUMENTS` unchanged (whitespace-normalized) and both force variables stay empty (autodetect).
+ **Scope lens.** `--scope=<value>` is an optional free-text lens: `business`, `technical`, `qa`, `security`, or any other audience; `--biz` means `--scope=business` and `--tech` means `--scope=technical`. Take these tokens out of the arguments before detecting the input; several values combine into one lens. There is one interview whatever the lens: interpret the lens from its words and let it focus which open decisions you look for (a QA lens looks for what counts as done, which failures matter, what must be testable). No lens means no filter. Never ask which scope to run.
- ### Doc-aware autodetect
+ **Research pass.** With `--scope=research`, skip the doc-aware gate and the interview: detect the input, then read [references/research-scope.md](references/research-scope.md) and follow it. The interview never reads that file.
- Decide whether doc-aware mode activates. `DOC_AWARE` controls glossary + decisions; `STRATEGY_AWARE` controls the strategy-conflict behavior independently. Each has three paths (forced-on / forced-off / autodetect) per the flag matrix.
+ **Doc flags.** When the arguments carry any of `--docs`, `--no-docs`, `--strategy`, `--no-strategy`, read [references/doc-flags.md](references/doc-flags.md) § Flag parsing before detecting the input; it strips them and sets the two force values used below.
- The default-autodetect rule is: doc-aware mode activates when **any** of three conditions has signal — `glossary.total_terms > 0` (a) OR a decision entry exists (b) OR `strategy.sections_filled >= 1` (c). The two flag pairs override (a)+(b) and (c) independently. Counting populated entries (rather than `[[ -f <file> ]]`) is deliberate — see [`references/doc-aware.md`](references/doc-aware.md) § Why counts, not file presence.
+ **Doc-aware gate.** Doc-aware mode adds glossary, decision-record and strategy behaviours to the interview. It turns on when the repo has a glossary term, a decision entry, or a filled strategy section (counts, not file presence); the doc flags override. Run once per interview:
```bash
- # One preflight bundle for this run. Missing/failed values retain fail-open gates.
- REFINE_PREFLIGHT="${TMPDIR:-/tmp}/flow-refine-preflight-<suffix>.json" # reuse this literal path
+ REFINE_PREFLIGHT="${TMPDIR:-/tmp}/flow-refine-preflight-<suffix>.json" # literal path; reused after the write-back
+ # One preflight bundle per interview. A failed, missing or empty probe counts as signal (fail open).
"$FLOWCTL" preflight --json > "$REFINE_PREFLIGHT" 2>/dev/null || printf '{}' > "$REFINE_PREFLIGHT"
- # DOC_AWARE: glossary + decisions. Probes and parses fail OPEN (|| DOC_AWARE=1).
- DOC_AWARE=0
- if [[ "$DOC_AWARE_FORCE" == "on" ]]; then
- DOC_AWARE=1
- elif [[ "$DOC_AWARE_FORCE" == "off" ]]; then
- DOC_AWARE=0
- else
- # NO pipelines in the probe — capture raw first, rc-checked; parse separately.
- GLOSSARY_RAW="$(jq -ce 'if .probes.glossary.status == "ok" then .probes.glossary.value else error("glossary probe") end' "${TMPDIR:-/tmp}/flow-refine-preflight-<suffix>.json" 2>/dev/null)" || DOC_AWARE=1
- DECISIONS_RAW="$(jq -ce 'if .probes.decisions.status == "ok" then .probes.decisions.value else error("decisions probe") end' "${TMPDIR:-/tmp}/flow-refine-preflight-<suffix>.json" 2>/dev/null)" || DOC_AWARE=1
- if [ "$DOC_AWARE" = "0" ]; then
- TERMS="$(printf '%s' "$GLOSSARY_RAW" | jq -r '.total_terms // 0' 2>/dev/null)" || DOC_AWARE=1
- DECS="$(printf '%s' "$DECISIONS_RAW" | jq -r '.entry_count // 0' 2>/dev/null)" || DOC_AWARE=1
- fi
- if [ "$DOC_AWARE" = "0" ] && { [ "${TERMS:-0}" -gt 0 ] || [ "${DECS:-0}" -gt 0 ]; }; then
- DOC_AWARE=1
- fi
- fi
-
- # STRATEGY_AWARE: strategy (independent of DOC_AWARE — autodetects on its own signal)
- STRATEGY_AWARE=0
- if [[ "$STRATEGY_AWARE_FORCE" == "on" ]]; then
- STRATEGY_AWARE=1
- elif [[ "$STRATEGY_AWARE_FORCE" == "off" ]]; then
- STRATEGY_AWARE=0
- else
- STRATEGY_RAW="$(jq -ce 'if .probes.strategy.status == "ok" then .probes.strategy.value else error("strategy probe") end' "${TMPDIR:-/tmp}/flow-refine-preflight-<suffix>.json" 2>/dev/null)" || STRATEGY_AWARE=1
- if [ "$STRATEGY_AWARE" = "0" ]; then
- STRAT_FILLED="$(printf '%s' "$STRATEGY_RAW" | jq -r '.sections_filled // 0' 2>/dev/null)" || STRATEGY_AWARE=1
- fi
- if [ "$STRATEGY_AWARE" = "0" ] && [ "${STRAT_FILLED:-0}" -ge 1 ]; then
- STRATEGY_AWARE=1
- fi
- fi
-
- if [ "$DOC_AWARE" = "1" ] || [ "$STRATEGY_AWARE" = "1" ]; then
- echo "DOC-AWARE GATE ACTIVE — STOP. Read references/doc-aware.md before drafting the first question."
+ # DOC_AWARE_FORCE / STRATEGY_AWARE_FORCE keep the "on" / "off" that doc-flags.md § Flag parsing set; unset = autodetect.
+ GATES="$(jq -er '
+ def v(p): if p.status == "ok" then p.value else null end;
+ [ (if v(.probes.glossary) == null or v(.probes.decisions) == null
+ or (v(.probes.glossary).total_terms // 0) > 0 or (v(.probes.decisions).entry_count // 0) > 0 then 1 else 0 end),
+ (if v(.probes.strategy) == null or (v(.probes.strategy).sections_filled // 0) >= 1 then 1 else 0 end)
+ ] | join(" ")' "$REFINE_PREFLIGHT" 2>/dev/null)" || GATES="1 1"
+ DOC_AWARE="${GATES% *}"; STRATEGY_AWARE="${GATES#* }"
+ case "${DOC_AWARE_FORCE:-}" in on) DOC_AWARE=1 ;; off) DOC_AWARE=0 ;; esac
+ case "${STRATEGY_AWARE_FORCE:-}" in on) STRATEGY_AWARE=1 ;; off) STRATEGY_AWARE=0 ;; esac
+ if [ "$DOC_AWARE$STRATEGY_AWARE" != "00" ]; then
+ echo "DOC-AWARE GATE ACTIVE (DOC_AWARE=$DOC_AWARE STRATEGY_AWARE=$STRATEGY_AWARE) — STOP. Read references/doc-aware.md before drafting the first question."
fi
```
- When the sentinel prints, STOP and **read [`references/doc-aware.md`](references/doc-aware.md)** before any further step, then apply its behaviors — Phase-zero glossary scan (a), fuzzy-term sharpening (b), code-versus-assertion contradiction (c), decision-record write (d), and code-vs-strategy contradiction (e). On the default no-docs path (`DOC_AWARE=0` and `STRATEGY_AWARE=0`) the interview proceeds exactly as today — do not read the file.
-
- ## Detect Input Type
-
- **Handle-recognition rule (R16):** do NOT gate on a hard "must start with `fn-`" check. Before treating a single-token arg as a file path or freeform, route it through `$FLOWCTL show <arg> --json` — flowctl's widened resolver maps a tracker key (`wor-17` / `wor-17.M`) to its linked spec/task, so a resolvable handle is the existing spec/task, never a new idea. Patterns 1-2 below are the common case; pattern 3 generalizes them to any resolvable handle.
-
- 1. **Flow spec ID pattern**: matches `fn-\d+(-[a-z0-9-]+)?` (e.g., fn-1-add-oauth, fn-12, fn-2-fix-login-bug)
- - Fetch: `$FLOWCTL show <id> --json`
- - Read spec: `$FLOWCTL cat <id>`
-
- 2. **Flow task ID pattern**: matches `fn-\d+(-[a-z0-9-]+)?\.\d+` (e.g., fn-1-add-oauth.3, fn-12.5)
- - Fetch: `$FLOWCTL show <id> --json`
- - Read spec: `$FLOWCTL cat <id>`
- - Also get parent spec context: `$FLOWCTL cat <spec-id>`
+ When the sentinel prints, read [references/doc-aware.md](references/doc-aware.md) and apply the behaviours its gates enable. Otherwise do not read it.
- 3. **Resolvable tracker handle**: any single-token arg (not an `.md` path) that `$FLOWCTL show <arg> --json` resolves — e.g. a Linear key `wor-17` (spec) or `wor-17.3` (task). Use the canonical id from the JSON; a `.`-containing handle is a task (fetch parent spec too), otherwise a spec. Treat exactly like patterns 1-2; never re-create.
+ ## Detect the input
- 4. **File path**: a path-like token / `.md` extension that does NOT resolve via `flowctl show`
- - Read file contents
- - If file doesn't exist, ask user to provide valid path
+ Route every single-token argument that is not an `.md` path through `$FLOWCTL show <arg> --json` before calling it a file: flowctl resolves spec ids, task ids, and tracker keys linked to them (`wor-17` / `wor-17.3`). Use the canonical id from the JSON.
- Done when: the argument is classified as exactly one of the four patterns, every non-`.md` single-token arg was routed through `$FLOWCTL show <arg> --json` before that classification, and the target's content (spec body, task + parent spec, or file) is in hand for the interview.
+ - **Spec** (`fn-12`, `fn-1-add-oauth`, or a handle that resolves to one): read it with `$FLOWCTL cat <id>`.
+ - **Task** (`fn-1-add-oauth.3`, or a handle with a `.`): `$FLOWCTL cat <id>`, plus the parent spec with `$FLOWCTL cat <spec-id>`.
+ - **File path** (does not resolve): read the file; if it does not exist, ask for a valid path.
- ## Interview Process
+ Keep the text you read: the write-back compares against it.
- **CRITICAL REQUIREMENT**: For every question, you MUST ask via the plain-text numbered prompt described below.
+ ## Interview
- **Ask the user via plain text.** Render the options below as a numbered list `1.` … `N.`, followed by a final option `N+1. Other — type your own answer`. Print the question, then the numbered list, then **stop and wait for the user's next message before continuing**. Parse the reply as: a bare number `1`–`N+1` → that option; the literal text of an option label → that option; free text after `Other` → custom answer.
+ ### Ask through the question tool
- - ONLY ask via the plain-text numbered prompt
- - Ask in rounds: each round carries the whole frontier (see Question Order below), split across plain-text numbered prompt calls of up to 4 questions each
+ Every question goes through `plain-text numbered prompt` (load it with `ToolSearch` `select:plain-text numbered prompt` when its schema is not loaded); fall back to numbered plain-text options only when the tool is unreachable. Never print questions as narration ("Question 1: ... Options: a) b) c)").
### The one test
- Ask a question only when all three hold: a wrong guess would build the wrong thing or ship behaviour the user would reject; the code, the docs, a quick experiment, or implementation itself cannot settle it; and it is the answerer's call. Everything else you resolve (Investigate Before Asking below), record, or leave to work. A topic on the check-list below is not a reason to ask.
-
- Check the spec for these, and ask about one only when the spec leaves it unclear and the question passes the test: who it is for; what done looks like; what is explicitly out; a constraint the domain implies (a regulation, a contract, a partner commitment); an irreversible data or contract change (a data model, a migration, a public contract); an external interface; a security boundary. A lens adds its audience's own open decisions to this list. Technical detail, performance and edge cases that implementation, review and QA will surface are left to them.
-
- Stop as soon as no question that passes the test remains. Asking nothing is a good outcome: report "Nothing worth asking; the spec is clear enough to build." and skip the write-back unless investigation resolved something worth recording.
-
- ### Question Format: Lead with Recommendation
-
- Every `plain-text numbered prompt` body must include the agent's recommended option AND a confidence tier. Mirrors the canonical phrasing in `flow-next-audit/SKILL.md` Interaction Principles ("Lead with the recommended option and a one-sentence rationale").
-
- Pattern:
-
- - `question.body`: "<stakes>. <options summary>. Recommended: <X> — <one-sentence rationale>. Confidence: [high | judgment-call | your-call]."
- - `question.options`: neutral labels (no "(recommended)" markers — recommendation goes in the body; neutral options reduce anchoring)
-
- ### Plain-language question contract (field feedback, eval-validated)
-
- Applies to EVERY question. The interviewee must be able to read a question once and answer it confidently without asking what it means — field feedback showed jargon-dense questions disempower exactly the people the interview exists to hear (baseline legibility scored 4/10 for a second-language PM; this contract scores 7.5+ at ~30% fewer tokens).
-
- - **Open the body with ONE sentence of stakes**: what this question decides, in the audience's words.
- - **Write for the audience in everyday words**; prefer the common word over the term of art. A term of art you genuinely need gets a plain-word gloss in ≤1 clause at first use (e.g. "counter-metrics — things we'd hate to make worse").
- - **No unexplained acronyms or tool/repo shorthand.** A product question, or any question under a non-technical lens, carries no implementation vocabulary (no schemas, endpoints, config keys).
- - **Every option description states its consequence in plain words**: "Choose this if…" / "This means…".
- - **Gloss referenced acceptance criteria.** When a question cites a spec R-ID, attach a short plain-words gist at first mention — "R3 (the audit line's required fields)" — never a bare "R3" the interviewee must open the spec to decode. Gist, not quote: pasting full criterion text bloats the question body.
-
- Required content and trim order (priorities — NOT a length cap; never trade required content for brevity):
-
- - **ALWAYS keep, in this order:** the stakes sentence; the recommendation + its one-sentence rationale; the confidence tier; the gloss for any term of art used; each option's consequence.
- - **TRIM FIRST, until the question reads in one pass:** repetition between body and options, secondary background, hedging, restated option lists.
- - **Target shape** (calibration, not a ceiling): a body around 40-60 words with option descriptions around a dozen words each is what "done" usually looks like — reach it by trimming the trim-first list, never by dropping required content.
-
- Confidence tiers (mandatory — pick one per question):
+ Ask a question only when all three hold: a wrong guess would build the wrong thing or ship behaviour the person would reject; the code, the docs, a quick experiment, or implementation cannot settle it; and it is the answerer's call. A topic on the list below is not a reason to ask.
- - `[high]` — strong codebase signal or convention match. Recommendation is load-bearing; user can usually accept.
- - `[judgment-call]` — slight lean but reasonable people disagree. User's call carries weight.
- - `[your-call]` — agent has no signal. "I genuinely don't know — your priority / domain knowledge / preference."
+ Check the spec for these, and ask about one only when the spec leaves it unclear and it passes the test: who it is for; what done looks like; what is explicitly out; a constraint the domain implies (a regulation, a contract, a partner commitment); an irreversible data or contract change (a data model, a migration, a public contract); an external interface; a security boundary. A lens adds its audience's open decisions. Technical detail, performance, failure modes, concurrency, scale and edge cases qualify only when they pass the test; implementation, review and QA surface the rest. Cosmetic polish (message wording, flag spelling, formatting) never gets its own question: fold it into a related question's options or state it as a default the person can veto at write-back. Refine never asks for success metrics or latency budgets unless the spec is about them.
- The `[your-call]` tier is **mandatory** when the agent has no basis for a recommendation. Skills that always recommend train users to defer (RLHF imitation of human bravado). Say so explicitly.
+ Stop when no question that passes the test remains. Asking nothing is a good outcome: report "Nothing worth asking; the spec is clear enough to build." and skip the write-back unless investigation resolved something worth recording.
- Examples (one per tier):
+ ### Investigate before asking
- - `[high]`: "This decides where the new validation code lives so the next person can find it. Recommended: `src/utils/validation.ts` — three sibling validators already live there and the tests import from that module. Confidence: [high]." Options: `src/utils/validation.ts`, `src/validators/`, `new module` — each description says what choosing it means (e.g. "This means it sits beside the three existing validators").
- - `[judgment-call]`: "This decides how long the rate-limiter remembers a result before re-checking (the cache TTL — time-to-live). Recommended: 60 seconds — short enough that stale answers stay rare, long enough to be worth caching. Confidence: [judgment-call]." Options: `30s`, `60s`, `300s`, `no cache` — with plain consequences ("Choose this if freshness matters more than speed").
- - `[your-call]`: "This decides what error callers see when the upstream service times out. Recommended: none — it depends on what your callers expect and I found no existing convention to copy. Confidence: [your-call]." Options: `502`, `503`, `504`, `408`.
+ Before the first round, read `STRATEGY.md` and search the other project docs for what the spec touches rather than reading them end to end: `README.md`, `CHANGELOG.md`, `GLOSSARY.md`, the decisions track (`$FLOWCTL memory list --track knowledge --category decisions --json`), the titles of open specs (`$FLOWCTL specs --json`), and `docs/` when present. Then sort each candidate question:
- ### Skipped Questions Are Not Answers
+ - **The code answers it** (what exists, how it is wired, which conventions hold): read and search; log it under `## Resolved via Codebase` with `file:line` evidence.
+ - **The project docs answer it** (what the strategy says, what shipped, what was decided): log it under `## Resolved via Project Docs` with `path:line` evidence.
+ - **Running something settles it** (behaviour, timing, layout, output, whether an eval separates two options): run a throwaway experiment in `.flow/tmp/experiments/` and log the question, what ran, what you observed and the decision under `## Resolved via Experiment`. Run it without asking only when it is read-only or fully disposable; one that needs live or shared state, credentials, the network, or a destructive command (a migration, a deployment, a write API) becomes a question. An inconclusive result (noise larger than the difference) is logged as inconclusive and goes to the person with the data. The experiment is evidence, never product code.
+ - **It is a judgment** (what should exist, which trade-off, what priority): ask it.
- **Leading with a recommendation never implies consent.** Distinguish three answer shapes:
+ Answering a "should" question by grep is the bug; so is asking something the docs already answer. Use multi-select for options that are not exclusive, and probe answers that contradict each other. When independent sources disagree wildly on the same question, reframe it more precisely and re-run it instead of averaging or picking a favourite.
- - **Explicit answer** (an option picked, or a typed answer) → use it.
- - **Explicit delegation** ("you decide", "go with your recommendation") → adopt the recommendation and note it as user-delegated; that is a real decision with a named consenter.
- - **Skip / decline / no-signal** (question dismissed, "skip", "I don't know", "not my call", "ask someone else") → the question is unresolved. **A skipped question's recommendation never enters a spec section as decided content.** A spec line that reads as settled while no answer, no explicit delegation, and no `## Open Questions` entry stands behind it has broken this — silently filling skipped questions with assumptions is the exact failure this rule exists to prevent.
+ While the person answers a round you may dispatch one read-only fact scout for lookups that gate the next round; before dispatching one, read [references/fact-scouts.md](references/fact-scouts.md). Investigating inline needs nothing from it.
- For every skipped question:
+ ### Rounds over the decision tree
- 1. Park it under `## Open Questions` with an owner hint and the agent's unconfirmed leaning: `**<question>** — skipped during interview; leaning <X>, unconfirmed. *(owner: engineering | product)*`
- 2. A skipped user-judgment question STAYS user-judgment-required — never demote it to codebase-/docs-answerable to backfill an answer (see Investigate Before Asking below).
- 3. Keep a running skip count for the write-back checkpoint below and the Completion summary.
+ Treat the open decisions as a tree: each decision opens the ones that hang off it. The frontier is every question whose prerequisites are settled. Work in rounds:
- **Write-back consent checkpoint** — when the skip count is ≥1, ask ONE `plain-text numbered prompt` BEFORE writing the spec back:
+ 1. Each round asks the whole current frontier. A question whose answer depends on another question still open belongs to a later round; never ask a question alongside its own prerequisite.
+ 2. Split the round across `plain-text numbered prompt` calls of up to 4 questions, closest-related together, announced as one round ("Round 2, part 1/2"). Never pad a call to 4 and never hold a frontier question back to smooth pacing.
+ 3. Recompute the frontier from the answers; deeper rounds are discovered, not pre-scripted.
+ 4. When an answer prunes a branch, say so at the next round's opener ("Skipping persistence questions; you said no database.").
+ 5. Go at most 4 rounds down any one branch.
+ 6. If part of a round was never asked (tool error, interruption), ask it before moving on.
- - **header**: `Skipped items`
- - **body**: `<N> question(s) were skipped during this interview. Recommended: park-open — record them under ## Open Questions with my unconfirmed leanings; nothing skipped becomes a decision. Confidence: [high].`
- - **options** (frozen): `park-open` (default — Open Questions entries only), `fill-assumptions` (write the agent's recommendation into the relevant spec section, each marked inline `*(assumed — unconfirmed)*`, plus one Open Questions entry pointing at the markers for later ratification), `re-ask` (walk the skipped questions once more — answers and explicit delegations resolve normally; anything skipped again parks per park-open)
+ Standalone checkpoints (the code-mismatch question, the skipped-items checkpoint, the mark-ready offer, doc-aware prompts that have their own per-round budget in doc-aware.md) sit outside rounds, are never labelled "Round N" and never count against round depth. A doc-aware prompt deferred by that budget is pending for a later round, not dropped.
- ### Question Order: Rounds over the Decision Tree
+ The interview is done when every decision the tree opened is answered, delegated, parked under `## Open Questions`, or pruned with its branch named.
- Map the interview as a **design tree**: every decision branches into the decisions that hang off it. The **frontier** is every question whose prerequisites are already settled — the questions you can ask NOW without guessing at answers you haven't heard yet. Work the tree in **rounds**: ask the whole frontier, wait for answers, recompute, repeat.
+ ### Question shape
- Concrete rules:
+ Write each question so the person can read it once and answer it confidently.
- 1. **Each round asks the entire current frontier.** A question whose answer depends on another question still open in this round belongs to a *later* round, not this one — never ask a question alongside its own prerequisite.
- 2. **Split the frontier across `plain-text numbered prompt` calls of up to 4 questions each**, grouped by topic (closest-related together), announced as one round ("Round N — part 1/2"). Never pad a call to reach 4; never hold a genuine frontier question back to a later round just to smooth pacing.
- **A frontier slot is earned** by passing the one test. Failure modes, concurrency, scale, portability, and testing qualify only when they pass it; implementation, review, and QA surface the rest. Pure-cosmetic polish (message wording, label/flag spelling, visual formatting) does not get its own question: fold it into a related question's options, or carry it as a stated default the user can veto at write-back.
- Standalone checkpoint questions (the code-mismatch question, the write-back consent checkpoint, the mark-ready offer) sit outside rounds — never labeled "Round N", never counted against round depth. Doc-aware meta-questions keep their own per-round budget (references/doc-aware.md): a meta-question deferred by that budget is pending for a later round, not dropped — the one sanctioned hold-back.
- 3. **Recompute the frontier after each round.** Answers reshape the tree — settled decisions unblock their dependents; adapt the next round to what you heard. Don't lock the whole tree before you start: deeper rounds are discovered from answers, not pre-scripted.
- 4. **Surface abandoned branches.** When an answer prunes a sub-tree, say so explicitly at the next round's opener: "Skipping persistence questions — you said no DB."
- 5. **Cap branch depth at 4 rounds** down any one branch. Research shows >4 prior turns rarely improves question quality — drop deeper threads, ask about something else. Heuristic; revisit if too restrictive in real use.
- 6. **Finish the round before recomputing.** If a later part of a round never got asked (tool error, interruption), ask the missed part first — never silently drop frontier questions and move on.
+ - **Body:** one sentence of stakes (what this decides, in the audience's words), then the recommendation with a one-sentence rationale, then one confidence tier: `<stakes>. Recommended: <X> — <why>. Confidence: [high | judgment-call | your-call].`
+ - **Options:** neutral labels, no "(recommended)" marker. Each description says what choosing it means ("Choose this if…", "This means…").
+ - **Plain words.** Prefer the common word; a term of art you genuinely need gets a short gloss at first use ("counter-metrics — things we'd hate to make worse"). No unexplained acronyms or repo shorthand. A product question, or any question under a non-technical lens, carries no implementation vocabulary (schemas, endpoints, config keys). A cited criterion gets a short gist: "R3 (the audit line's required fields)", never a bare "R3".
+ - **Length:** never drop the stakes, recommendation, tier, gloss or option consequences. Trim repetition, background and hedging first; a body of about 40-60 words is usually right.
- Example flow:
+ Tiers: `[high]` when the code or a convention gives strong signal and the person can usually accept; `[judgment-call]` when you lean one way but reasonable people disagree; `[your-call]` when you have no basis. Use `[your-call]` whenever that is true and say so ("I found no convention to copy; this depends on what your callers expect"). Always recommending trains people to defer.
- > Round 1 (frontier: persistence?, auth model?, error surface?) — asked together in one call.
- > A: "No persistence — ephemeral is fine. API-key auth. Errors: existing JSON convention."
- > [agent prunes the {DB choice, schema design, migration plan} sub-tree]
- > Round 2 opener: "Skipping DB questions — you said ephemeral." (frontier now: reload survival?, key-tier limits? — the questions those answers unblocked)
+ Example: "This decides how long the rate limiter remembers a result before checking again. Recommended: 60 seconds — short enough that stale answers stay rare, long enough to be worth caching. Confidence: [judgment-call]." Options `30s`, `60s`, `300s`, `no cache`, each with its plain consequence.
- Done when: the frontier is empty — every decision the tree opened is answered, explicitly delegated, parked under `## Open Questions`, or pruned with its abandoned branch named at a round opener — and every part of every round was actually asked (a part lost to a tool error is re-asked, never dropped).
+ ### Skipped questions are not answers
- ### Investigate Before Asking
+ A recommendation never implies consent. Three answer shapes:
- Before drafting the first round, read `STRATEGY.md` (repo root) and search the other project docs for what the spec touches rather than reading them end to end: `README.md`, `CHANGELOG.md`, `GLOSSARY.md`, the decisions track (`$FLOWCTL memory list --track knowledge --category decisions --json`), the titles of open specs (`$FLOWCTL specs --json`), and a `docs/` directory when there is one. Then classify every question before asking it:
+ - **An answer** (an option or typed text): use it.
+ - **Delegation** ("you decide", "go with your recommendation"): adopt the recommendation and note it as delegated by the person.
+ - **A skip** (dismissed, "skip", "I don't know", "not my call"): the question stays open. Its recommendation never enters a spec section as decided content.
- - **Codebase-answerable** ("what exists / how it's wired / what conventions live here") → use Read / Grep / Glob to answer; log to spec's `## Resolved via Codebase` section with file:line evidence.
- - **Project-docs-answerable** ("what does the strategy say / what have we already shipped / what did we decide about X") → resolve from the docs; log to spec's `## Resolved via Project Docs` section with `path:line` evidence.
- - **Glossary-lookup-answerable** (`DOC_AWARE=1` only) — terms with a canonical entry in the nearest-ancestor `GLOSSARY.md` → silently resolve from the entry; log to spec's `## Glossary Conflicts` section only when the user's wording diverges from canonical AND the term is load-bearing (behavior (a) in [`references/doc-aware.md`](references/doc-aware.md)).
- - **Experiment-answerable** — a fork that running something can settle (behaviour, timing, layout, output, performance, whether an eval separates two options) → run a throwaway experiment in `.flow/tmp/experiments/` instead of asking; log it to spec's `## Resolved via Experiment` section with the question, what was run, what was observed, and the decision it settled. The ask is the slow path: a question the user must relay back to the machine costs a round-trip the experiment answers in seconds. Safety predicate: an experiment runs automatically only when it is read-only or fully disposable (a scratch copy, a throwaway environment). One that needs live or shared state, credentials, the network, or a destructive command — a migration, a deployment, a write API — goes to the plain-text numbered prompt path. An inconclusive result (noise larger than the difference) is logged as inconclusive and the question goes to the user with the data attached. The experiment is evidence, never product code: discard it or fold its numbers into the spec.
- - **User-judgment-required** ("what should exist / what tradeoff to make / what priority") → ask via `plain-text numbered prompt`.
+ Park each skip under `## Open Questions` as `**<question>** — skipped during refine; leaning <X>, unconfirmed. *(owner: engineering | product)*`. A skipped judgment question stays a judgment question; never backfill it by grep. Keep a skip count.
- If you find yourself answering a "should" question via grep, that's the bug. Stop and ask the user. Asking the user something the project docs already answer is the same bug in the other direction. Don't ask obvious questions, group related ones (multi-select for non-exclusive options), and probe answers that contradict each other.
+ With one or more skips: read [references/skipped-items.md](references/skipped-items.md) and ask its checkpoint before the write-back.
- **Divergent independent answers mean the question was underspecified.** When independent sources (scouts, docs, probes) return wildly divergent answers to the same question, do not average them and do not quietly pick a favorite — reframe the question more precisely and re-run it; divergence is a signal about the framing, not a vote to be tallied.
+ ### Out of scope
- **Async fact-scouts (optional, rounds mode):** while the user answers the current round you MAY dispatch ONE read-only fact-scout subagent to resolve codebase lookups that gate NEXT-round questions. Before dispatching one, read [`references/fact-scouts.md`](references/fact-scouts.md) — the brief contract, scout tier, digest discipline, and the never-block rule are binding. Not dispatching a scout needs no reading: investigate inline as usual.
+ Refine settles requirements; plan and work own the rest. No task creation, sizing, dependency ordering, phased implementation or file references. No time estimates, deadlines, durations or "ship before X" framing; when the person volunteers a deadline, acknowledge it without re-asking scope because of it.
## Where answers go
- Each answer is written into the section it belongs in, whatever the lens: a target user goes to `## Goal & Context`, an out-of-scope call to `## Boundaries`, a contract to `## API Contracts`, a testable commitment to `## Acceptance Criteria`, a rationale to `## Decision Context`. The section structure lives in `plugins/flow-next/templates/spec.md` (never re-embed the section list inline; cross-link the template). A section the project added through its own repo-root `SPEC.md` is a section like any other: an answer that belongs there goes there.
-
- Every section no answer belongs in comes back byte-for-byte, and the read-back names every section this session changed, so a person refining their own layer sees any change outside it. Keep the layout the spec already has: when `## Decision Context` carries `### Motivation` / `### Implementation Tradeoffs` sub-headings (older refine runs and capture write them), put a rationale under the one it fits and never add or remove sub-headings to restructure the section.
-
- ### Auxiliary sections
-
- The auxiliary sections — `Strategy Alignment` / `Strategy Conflicts` / `Glossary Conflicts` / `Conversation Evidence` / `Resolved via Codebase` / `Resolved via Project Docs` / `Resolved via Experiment` / `Resolved via Research` / `Parked unknowns` — come back byte-for-byte: refine never deletes or rewrites an entry an earlier session wrote. It only adds its own entries to `Resolved via Codebase`, `Resolved via Project Docs` and `Resolved via Experiment`, below any already there. `Resolved via Research` belongs to the research pass, the one writer allowed to replace it (under `--force`).
-
- `Parked unknowns` is the one auxiliary section refine may take FROM, and only in the one way described in [`references/write-back.md`](references/write-back.md) § Parked unknowns: a bullet this session resolved graduates into the canonical section that owns it and is deleted here. Every other bullet comes back byte-for-byte, and no bullet this session did not resolve is rewritten, reordered, or reworded.
-
- ### Declined-scope ledger
-
- When the user declines a feature or scope **as product judgment** — we could build this, we are choosing not to — record it in `.flow/memory/declined/<concept-slug>.md` on the FIRST such refusal: title, the decision in one line, short reasoning, then `## Prior requests` opened with today's date and the request that just came in. File already there → append the dated line to `## Prior requests` and leave the decision untouched. Agent-written prose, like the rest of `.flow/memory/` — no flowctl verb. The entry body follows the artifact prose contract in [docs/prose.md](../../docs/flow-next/prose.md); proceed without it when the doc is absent.
-
- **Never write one for scope declined because it already exists**, is already planned, or lives in another spec. That is an answer, not a refusal, and filing it teaches the next planner that shipped capability is rejected scope. A skipped question is not a decline either — skips go to `## Open Questions` per the skip contract.
-
- ### Acceptance-criteria rule
-
- `## Acceptance Criteria` R-IDs are **append-only** across sessions — never renumber, never replace; take the next unused number. Source-tag each criterion this session appends (`[user]` = the human answering in this session, `[paraphrase]`, `[inferred]`, `[strategy:<track>]`); never tag or retag a criterion an earlier session wrote — see `references/write-back.md` § Source tags on acceptance criteria.
-
- **Record an answer at the precision the user gave it.** A preference ("performance matters here") goes to `## Decision Context` as guidance, not an acceptance criterion. A number or measurable commitment becomes a criterion only when the user stated it; your recommended options never become thresholds. Refine does not ask for success metrics or latency budgets unless the spec is about them.
-
- ## Spec-count check (split proposal)
+ Write each answer into the section it belongs in, whatever the lens: a target user in `## Goal & Context`, an out-of-scope call in `## Boundaries`, a contract in `## API Contracts`, a testable commitment in `## Acceptance Criteria`, a rationale in `## Decision Context`. The sections come from the resolved template ([templates/spec.md](../../templates/spec.md), or the repo's own `SPEC.md`); a section the project added is a section like any other.
- Interviews grow specs - and an epic-shaped input sometimes turns out to be more than one spec. Before the write-back, when the refined criteria set trips the spec-count tripwire, read [`spec-count.md`](../flow-next-flow/references/spec-count.md) (it owns the tripwire, what counts, and the independence partition) and propose a split only when its partition yields more than one spec.
+ - **Everything else comes back byte-for-byte**, and the read-back names every section this session changed. Keep the layout the spec has: when `## Decision Context` carries `### Motivation` / `### Implementation Tradeoffs`, put a rationale under the one it fits and never add or remove sub-headings.
+ - **Auxiliary sections** (`Strategy Alignment`, `Strategy Conflicts`, `Glossary Conflicts`, `Conversation Evidence`, `Resolved via Codebase`, `Resolved via Project Docs`, `Resolved via Experiment`, `Resolved via Research`, `Parked unknowns`) come back byte-for-byte. Refine only appends its own entries to the three `Resolved via` sections it owns (Codebase, Project Docs, Experiment). `Resolved via Research` belongs to the research pass. The one thing refine may take out is a `Parked unknowns` bullet this session resolved; write-back.md says how.
+ - **Precision.** Record an answer at the precision given: a preference ("performance matters here") goes to `## Decision Context` as guidance; a number becomes a criterion only when the person stated it. Your recommended options never become thresholds.
+ - **Acceptance criteria** are append-only: never renumber or replace an R-ID; take the next unused number. Leave criteria an earlier session wrote exactly as they are. For the criteria you add, the person's own words stay untagged and anything else carries a tag (write-back.md § Source tags).
- Present the concrete allocation as ordinary printed markdown (per-spec titles, allocated criteria, dependency edges), then one short `plain-text numbered prompt`: `keep-single` (default) / `split-as-proposed` / `adjust`. On split: create each sibling via one `spec create --plan-file` (self-contained body; allocated criteria renumbered from R1 in the NEW spec), remove the moved criteria from the source spec's write-back, and record edges via `spec add-dep`. **Renumbering guard:** criteria a review cycle has already judged are never moved or renumbered — for those, keep them in place and record the proposal in `## Decision Context` instead. Autonomous/receipt-driven runs never split — record the proposal in `## Decision Context` as `### Split proposal (unactioned)`.
+ When the person declines a feature as product judgment (we could build it and choose not to), read [declined-scope.md](../../references/declined-scope.md) and record it.
- ## NOT in scope (defer to /flow-next:plan)
+ Before the write-back on a spec (a task or a plain file never splits), when the refined criteria reach 8 or more or visibly serve more than one independently shippable outcome, read [references/split.md](references/split.md).
- - Research scouts (codebase analysis)
- - File/line references
- - Task creation (interview refines requirements, plan creates tasks)
- - Task sizing (S/M/L)
- - Dependency ordering
- - Phased implementation details
- - **Time estimates, deadlines, durations, sprint cadence, "ship before X" framing.** Agents can't estimate their own work and shouldn't push the user into time-based prioritization debates. If the user volunteers a deadline in answer to another question, acknowledge it without cascading into MVP-Scope or What-NOT-to-Build re-asks driven by the time pressure.
+ ## Write-back
- ## Write Refined Spec — templates loaded at completion
+ At completion, read [references/write-back.md](references/write-back.md) and run the branch for the input type (spec, task, or file). It holds the write pattern, the read-back approval, the source tags, and the flowctl call per branch.
- At the Completion step, **read [`references/write-back.md`](references/write-back.md)** for the spec-write template matching the input type — NEW IDEA (text, no Flow ID), EXISTING SPEC (`fn-N` with tasks), Flow Task (`fn-N.M`), or File Path — plus the shared `## Resolved via Codebase / Project Docs / Experiment`, `## Glossary/Strategy Conflicts`, and `## Open Questions` section templates. Only the one matching branch runs; the file is loaded once, at write-time, not held through the Q&A.
+ ## After the write-back
- ## Post-write-back options (tracker sync, mark ready)
+ Refine never changes readiness: a spec that was ready stays ready unless the person unmarks it (only `capture --rewrite` resets it).
- Both are conditional. Probe once after the write-back; each sentinel names the section to read.
+ For a spec or task input (not a file path), probe the two optional offers:
```bash
- # Tracker sync (opt-in): projects the enrichment to the linked issue and reconciles
- # two-way. Skip entirely for the file-input case — there is no flow spec yet.
- TRACKER_GATE=0
- LEAF_RAW="$(jq -ce 'if .probes.config.status == "ok" then {value: .value.tracker.perEvent.interview} else error("config probe") end' "${TMPDIR:-/tmp}/flow-refine-preflight-<suffix>.json" 2>/dev/null)" || TRACKER_GATE=1
- ACTIVE_RAW="$(jq -ce 'if .probes.tracker.status == "ok" then .probes.tracker.value else error("tracker probe") end' "${TMPDIR:-/tmp}/flow-refine-preflight-<suffix>.json" 2>/dev/null)" || TRACKER_GATE=1
- if [ "$TRACKER_GATE" = "0" ]; then
- LEAF="$(printf '%s' "$LEAF_RAW" | jq -r '.value' 2>/dev/null)" || TRACKER_GATE=1
- ACTIVE="$(printf '%s' "$ACTIVE_RAW" | jq -r '.active' 2>/dev/null)" || TRACKER_GATE=1
- fi
- if [ "$TRACKER_GATE" = "0" ] && [ "${ACTIVE:-false}" = "true" ] \
- && [ -n "${LEAF:-}" ] && [ "${LEAF:-null}" != "null" ] && [ "${LEAF:-off}" != "off" ]; then
- TRACKER_GATE=1
- fi
- if [ "$TRACKER_GATE" = "1" ]; then
- echo "TRACKER-SYNC GATE ACTIVE — STOP. Read references/post-write-back.md#tracker-sync before continuing."
- fi
-
- # Mark-ready offer (flow spec inputs only — task ids and file paths carry no spec readiness).
- READY_GATE=0
- READY_STATE_RAW="$(jq -ce 'if .probes.config.status == "ok" then {value: .value.tracker.readyState} else error("config probe") end' "${TMPDIR:-/tmp}/flow-refine-preflight-<suffix>.json" 2>/dev/null)" || READY_GATE=1
- SPECS_RAW="$("$FLOWCTL" specs --json 2>/dev/null)" || READY_GATE=1
- if [ "$READY_GATE" = "0" ]; then
- READY_STATE="$(printf '%s' "$READY_STATE_RAW" | jq -r '.value // empty' 2>/dev/null)" || READY_GATE=1
- READY_ADOPTED="$(printf '%s' "$SPECS_RAW" | jq '[.specs[] | select(.ready == true)] | length' 2>/dev/null)" || READY_GATE=1
- if [ "$READY_GATE" = "0" ] && [ "${READY_ADOPTED:-0}" -ge 1 ] && [ -z "${READY_STATE:-}" ]; then
- READY_GATE=1
- fi
- fi
- if [ "$READY_GATE" = "1" ]; then
+ REFINE_PREFLIGHT="${TMPDIR:-/tmp}/flow-refine-preflight-<suffix>.json" # the same literal path as Setup
+ # Tracker sync: bridge active and tracker.perEvent.interview set to anything but off. Fails open.
+ TRACKER="$(jq -er '
+ def v(p): if p.status == "ok" then p.value else null end;
+ if .probes.config.status != "ok" or v(.probes.tracker) == null
+ or (v(.probes.tracker).active == true and ((.value.tracker.perEvent.interview // "off") != "off"))
+ then "open" else "closed" end' "$REFINE_PREFLIGHT" 2>/dev/null)" || TRACKER=open
+ [ "$TRACKER" = open ] && echo "TRACKER-SYNC GATE ACTIVE — STOP. Read references/post-write-back.md#tracker-sync before continuing."
+ # Mark-ready: readiness adopted (a spec is already ready) and tracker.readyState unset. Fails open.
+ SPECS_RAW="$("$FLOWCTL" specs --json 2>/dev/null)" && READY_ADOPTED="$(printf '%s' "$SPECS_RAW" | jq '[.specs[] | select(.ready == true)] | length' 2>/dev/null)" || READY_ADOPTED=""
+ READY_STATE="$(jq -er 'if .probes.config.status == "ok" then (.value.tracker.readyState // "") else error("config probe") end' "$REFINE_PREFLIGHT" 2>/dev/null)" || READY_STATE="?"
+ if [ -z "$READY_ADOPTED" ] || [ "$READY_STATE" = "?" ] || { [ "$READY_ADOPTED" -ge 1 ] && [ -z "$READY_STATE" ]; }; then
echo "MARK-READY GATE ACTIVE — STOP. Read references/post-write-back.md#mark-ready-offer before continuing."
fi
```
- When a sentinel prints, STOP and Read the named section of [`references/post-write-back.md`](references/post-write-back.md) before any further step. With no tracker configured and readiness unadopted, neither fires and the interview behaves exactly as today.
-
- **Interview never auto-resets `ready` on refinement.** A run that leaves a previously-ready spec unready without the human unmarking it has broken this. The interview edits the spec in place — a previously-blessed spec stays ready unless the human unmarks it. Only `capture --rewrite` (a full re-authoring) resets readiness.
+ When a sentinel prints, read the named section of [references/post-write-back.md](references/post-write-back.md) before continuing. With no tracker and readiness not adopted, neither fires.
## Completion
- Show summary:
- - Number of questions asked — when it is zero, say "Nothing worth asking; the spec is clear enough to build."
- - Skipped questions (ONLY when ≥1): count + disposition from the write-back checkpoint (parked under `## Open Questions` / filled as `*(assumed — unconfirmed)*` / re-asked) — omit the line entirely when nothing was skipped
- - Key decisions captured
- - What was written (Flow ID updated / file rewritten)
- - Tracker sync: when active and the `tracker.perEvent.interview` leaf opted in (the leaf keeps its name; refine reads it), whether the spec body was pushed/pulled/reconciled to the linked issue (else a silent no-op)
- - Readiness (ONLY when the mark-ready offer fired): marked ready vs kept draft — omit the line entirely otherwise (no readiness noise for non-adopters)
- - **Sections changed**: every section this session wrote, and that the rest came back byte-for-byte; the lens, when one was given. Project-docs and experiment resolutions captured under `## Resolved via Project Docs` / `## Resolved via Experiment`, one line each with its decision. For `--scope=research`: the number of items written under `## Resolved via Research` with their sources, or the printed skip reason.
- - Doc-aware mode (when `DOC_AWARE=1` was active): glossary terms added/updated via `flowctl glossary add`, decision entries written via `flowctl memory add --track knowledge --category decisions`, glossary conflicts captured under `## Glossary Conflicts`
- - Strategy-aware mode (when `STRATEGY_AWARE=1` was active): strategy conflicts captured under `## Strategy Conflicts` (read-only — interview never edits STRATEGY.md)
+ Print a summary:
- Done when: every line above is either printed or absent because its stated ONLY-when condition did not hold — the question count and the sections-changed line are unconditional and always appear.
+ - **Questions asked.** At zero: "Nothing worth asking; the spec is clear enough to build."
+ - **Skipped** (only with skips): the count and the checkpoint's outcome (parked, filled as assumed, or re-asked).
+ - **Key decisions** captured.
+ - **Written:** the id updated or the file rewritten.
+ - **Sections changed:** every section this session wrote, and that the rest came back byte-for-byte; the lens, when one was given; each `Resolved via Project Docs` / `Resolved via Experiment` entry in one line with its decision. For `--scope=research`: the items written under `## Resolved via Research` with their sources, or the printed skip reason.
+ - **Tracker sync** (only when the gate fired): whether the spec was pushed, pulled, reconciled or commented.
+ - **Readiness** (only when the mark-ready offer fired): marked ready or kept draft.
+ - **Doc-aware** (only when active): glossary terms added (`flowctl glossary add`), decision entries written (`flowctl memory add --track knowledge --category decisions`), and entries under `## Glossary Conflicts` / `## Strategy Conflicts` (refine never edits `STRATEGY.md`).
- Suggest next step based on input type:
- - New idea / spec without tasks → recommend `$flow-next-work fn-N --no-plan` for a ready cohesive spec. Use `$flow-next-plan fn-N` when dependencies, ownership, staged delivery, or execution constraints make decomposition useful; use `$flow-next-plan-review fn-N` for independent design review. Risk or multiple files alone do not require decomposition.
- - Spec with tasks → `$flow-next-work fn-N` (or more interview on specific tasks)
- - Task → `$flow-next-work fn-N.M`
- - File → `$flow-next-capture` to turn the refined document into a spec
- - Any of the above → also offer a compact visual digest for reviewing the refined result at a glance — `$flow-next-visual fn-N` for a spec input, `$flow-next-visual fn-N.M` for a task input, `$flow-next-visual <file-path>` for the file input (an option the user picks, never run for them).
+ The question count and the sections-changed line always appear.
- **Host command form:** print every copy-pasteable flow-next command here in the spelling this host invokes — the flat `/flow-next-<name>` form when the resolved plugin root carries `.flow-next-opencode-manifest` (an OpenCode install — the same signal setup's host detection uses); on any other or indeterminate host, exactly as spelled here.
+ Next step by input:
+
+ - Spec without tasks → recommend `$flow-next-work fn-N --no-plan` for a ready, cohesive spec. Use `$flow-next-plan fn-N` when dependencies, ownership, staged delivery or execution constraints make decomposition useful; use `$flow-next-plan-review fn-N` for an independent design review. Risk or file count alone does not call for decomposition.
+ - Spec with tasks → `$flow-next-work fn-N` (or more refine on specific tasks).
+ - Task → `$flow-next-work fn-N.M`.
+ - File → `$flow-next-capture` to turn the refined document into a spec.
+ - Any of these → offer a compact digest of the result: `$flow-next-visual fn-N` for a spec input, `$flow-next-visual fn-N.M` for a task input, `$flow-next-visual <file-path>` for the file input (an option, never run for them).
+
+ Print each command in the spelling this host invokes: the flat `/flow-next-<name>` form when the plugin root carries `.flow-next-opencode-manifest` (an OpenCode install), otherwise exactly as written here.