# okstra-inspect facet — recap

Loaded lazily by the dispatch table in `SKILL.md` (core). Shared rules — Step 0 preflight, the standard task-key resolution rule (0/1/N), the no-task fallback, and Output Rules — live in the core file and still apply here.

## recap

Trigger phrases: "okstra recap", "recap", "work summary", "summarize this task", "before/after summary", "explain this work", "task question".

On top of the `.okstra` artifacts accumulated for a single task-id — or for every task of one task-group — (a) produce a before/after summary and (b) answer free-form questions about that work. By default it reads only the `.okstra/` subtree (artifact mode). It expands to code mode only when the user explicitly asks to look at the code changes too. This sub-command performs the `recap-log.jsonl` append, the `notes/` note authoring (recap.5), and the group-context reconciliation that note triggers (recap.6); it never mutates `task-manifest.json` / catalog / timeline, and it touches `group-context.md` only in the authored sections above the `<!-- okstra:task-memory:begin -->` marker.

### recap.1 — Resolve target

Two scopes. Decide the scope before resolving anything:

- **Task scope** — the same three forms as `cost` / `errors`: ① full task-key, ② bare token — the standard task-key resolution rule in `SKILL.md` (core), ③ task-root path.
- **Group scope** — the user names a task-group ("recap the cache group", "how far is the `cache` group", "group progress") or the bare token resolves with every match `Matched via: taskGroup`. Do **not** drop to the N-match picker in that case; carry the group name as `<task-group>` and follow recap.2g / recap.4g below. A group-scope request still takes the one-task path when the user picks a single task from it.

If the user asks for a recap without naming a task or a group (e.g. "summarize this work"), apply the core no-task fallback as-is — do not list only a placeholder form like `<task-group>` and ask back.

### recap.2 — Assemble the before/after summary

When `Direct work record` is present, read that work record and report its summary, evidence,
limitations, and current `Work status`, including when `Run count` is zero. Direct work records
are JSON work artifacts, not final reports; do not send them to `render-final-report`. In group
output, `Memory source: direct` identifies these records even when `Memory run` is empty.

Use the CLI output as the source of truth:

```bash
okstra model-io recap-input --project-root <projectRoot> --task-ref <resolved-target>
```

Read the fixed-text `Run count` and repeated `Transition` blocks. Narrate each block's `From phase → To phase`, `Status`, `Last completed phase`, `Next phase`, and `Report` in the emitted chronological order. `Status`, `Last completed phase`, and `Next phase` are each run's end state from its own run-manifest, so a `prepared` transition is a run that was prepared and never ran, and it carries no `Report`. If `Run count: 0` and `Direct work record` is absent, report that the task has no recorded runs alongside its current work status.

`Next phase` is already a fixed scalar projection. Narrate it when non-empty, and otherwise use `Next phase status`: `pending` means that run did not settle the route, `blocked` means it stopped on something outside the run, and `terminal` means the lifecycle ended there.

For a transition that has a `Report`, run `okstra render-final-report <Report>` and read the rendered Markdown only when the user wants a deeper summary. Do not open the report data JSON directly and do not render every report automatically.

### recap.2g — Assemble the group status (group scope)

```bash
okstra model-io recap-input --project-root <projectRoot> --task-group <task-group>
```

The projection joins three sources and is the only place to read them from — do not re-derive the queue from the brief directory, the catalog, or `group-context.md` by hand:

- the group's briefs give the start order (brief ordinal) and the `waits for` edges;
- the catalog / each `task-manifest.json` gives the real `Status` (`done` / `in progress` / `not started`), `Progress` (`<phase> (<state>)`), run count, next phase, and report path;
- the group document's Task Memory gives each recorded task's `Headline`, `Decision N`, `Watch out N`, `Follow-up N`. A task with `Memory run: -` finished before group memory existed — its conclusion lives only in its `Report`.

Read the head lines (`Brief count`, `Task count`, `Next in group`), then the repeated `Queue entry` blocks in order, then the repeated `Task` blocks. Narrate the group as: how many briefs, how many started, which are done, which is next (`Next in group` — `-` means every brief has started), and any `Waits for` that names a ticket not yet done. `Human sections: absent` means the group has no authored `group-context.md` context yet (only okstra's memory region) — say so once when the user asks why the group exists; do not offer to write it here (that is `okstra group-context init` via okstra-brief-gen).

Numbers beyond run count (CPU, wall clock, error totals) are okstra-rollup's; if the user asks for them, point to `/okstra-rollup --task-group <task-group>` instead of summing anything here.

### recap.3 — Free-form Q&A loop

After the summary output, take the user's free-form questions.

- **artifact mode (default)**: answer only from `.okstra/` artifacts (timeline, task-manifest, that run's final-report; in group scope also `.okstra/briefs/<task-group>/group-context.md` and each member task's artifacts). Every factual claim is accompanied by a `path:line` citation to the `.okstra` file.
- **code mode (opt-in)**: only when the user **explicitly asks** — "look at the code changes / the diff too" — additionally read `git diff` · `git log` from that task's worktree/branch and answer at the code level. Entering recap never by itself switches to code mode.

### recap.4 — Persist each turn

Log one summary and each Q&A answer (append-only):

```bash
okstra recap record <resolved-target> --project-root <projectRoot> \
  --kind <summary|qa> --mode <artifact|code> \
  --question "<question or omit>" --answer "<one or two line summary>" \
  --citation "<path:line>" --citation "<path:line>"
```

Put a one-or-two-line summary in `--answer`, not the full answer transcript. If there are multiple citations, repeat `--citation`. Do not silently swallow a recording failure (abnormal exit) — tell the user.

### recap.4g — Persist each turn (group scope)

Same flags, but the group replaces the target and the log lands at `.okstra/tasks/<task-group>/.recap/recap-log.jsonl`:

```bash
okstra recap record --task-group <task-group> --project-root <projectRoot> \
  --kind <summary|qa> --mode <artifact|code> \
  --question "<question or omit>" --answer "<one or two line summary>" \
  --citation "<path:line>"
```

`recap note` has no group form — a note belongs to the task whose next run will carry it, so write it against that task-key.

### recap — Output template

```markdown
## okstra Recap — <task-key>

Before/after summary (runs: <N>):

| # | when | task-type | from → to | status | next |
|---|---|---|---|---|---|
| 1 | <ts> | requirements-discovery | (start) → requirements-discovery | done | error-analysis |

<Free-form questions follow. To include code changes, ask "also show me the diff".>
```

Group scope:

```markdown
## okstra Recap — task-group <task-group> (briefs: <Brief count>, started: <Task count>)

| # | task | status | progress | waits for | latest conclusion |
|---|---|---|---|---|---|
| 1 | dev-10626-1-… | done | release-handoff (completed) | — | <Headline, or "report only" when Memory run is -> |
| 2 | dev-10627-2-… | in progress | implementation-option-selection (prepared) | DEV-10642 | <Headline> |
| 3 | dev-10628-3-… | not started | — | — | — |

Next in group: <Next in group or "every brief has started">

<Free-form questions follow.>
```

### recap.5 — Agent-authored notes (`notes/`)

Leave something in `notes/` only when, during recap, you produced an artifact **for the okstra task** — verification evidence, a design/decision draft, an analysis note — that may serve as grounding for future runs, and whose content is **neither a rendered report nor a user decision**.

**Route by ownership.** First determine which of the following the thing you are about to write belongs to:

| Content | Lane (path) | Author |
|---|---|---|
| final report body | `runs/<type>/reports/*.md` (rendered from `*.data.json`) | okstra renderer — never hand-edit |
| user's answer to a clarification | `runs/<type>/user-responses/*.md` (`created-by: user`) | user only |
| finalized ADR | `.okstra/decisions/NNNN-*.md` | promoted / managed |
| **Agent evidence / design draft / analysis** | **`.okstra/tasks/<group>/<id>/notes/`** | you (the AI) |

If it is **your own grounding/draft** — not a rendered artifact, not a user decision — it goes to `notes/`. Do not hand-stamp the note; write it via the CLI — code guarantees the path/frontmatter/date and prints the argument to pass into the next run:

```bash
okstra recap note <resolved-target> --project-root <projectRoot> \
  --kind <verification-evidence|decision-draft|analysis-note> \
  --slug <short-topic-slug> \
  --purpose "<one line — what it is and which run/decision it feeds>" \
  --scope-note "<one line — what it is NOT, e.g. not a user decision on C-00x>" \
  --body-file <note-body markdown path>
```

Write the body to the scratchpad as markdown first, then pass it with `--body-file` (if short, an inline `--body "<md>"` also works). The CLI creates `.okstra/tasks/<group>/<id>/notes/<slug>-<YYYY-MM-DD>.md` and returns `notePath` and `clarificationResponseArg` as stdout JSON.

**self-check rules (there is no validator, so you keep them yourself):**

1. **Do not hand-edit a rendered report** (`*.md` / `*.data.json` / `*.html` under `runs/*/reports/`). Report assembly regenerates those artifacts, so write findings to `notes/` instead.
2. **Do not author a `user-responses/` file or apply `created-by: user`.** That is the user's decision, and writing it for them forges a decision the user never made. If your evidence supports a particular answer, write that in `notes/` and leave the decision to the user. The one exception is the echo-back confirmation flow of the `okstra-user-response` skill — there the user makes the decision in-session and the CLI is merely a transcription channel, so recording a `created-by: user` sidecar with `write` is legitimate. This exception holds only after the user has explicitly confirmed "correct", and only for verbatim input.
3. **Do not write to okstra-managed directories** (`runs/`, `instruction-set/`, `history/`, `recap/`, `.okstra/decisions/`). `notes/` is the only agent-owned lane. `recap/recap-log.jsonl` is the exception — write it, but not by hand; only via the `okstra recap record` CLI.
4. **`notes/` is inert to okstra** — no run reads it automatically. After writing, relay the `clarificationResponseArg` the CLI printed (e.g. `--clarification-response <notePath>`) to the user verbatim, telling them it only takes effect when the next run is executed with that argument.

**Guardrail:** `.okstra/` is gitignored — treat `notes/` as local scratch and never `git add` it. Creating a new note is easy to undo (delete the file), so always prefer it over editing a generated or user-owned file.

### recap.6 — Reconcile the task-group context (required whenever recap.5 writes a note)

A group's shared context does not stay true while its tasks run. Figures get re-measured, a success signal turns out to be satisfiable without a fix, a constraint names the wrong place. `group-context.md` states in its own header that okstra copies it into each run's `instruction-set/task-group-context.md` and carries it in the analysis packet's `## Task-Group Context` section, **ahead of the brief extract** — so a stale sentence there outranks a corrected brief for every task in the group.

**After writing a note, read `<PROJECT_ROOT>/.okstra/briefs/<task-group>/group-context.md` if it exists.** If anything the note establishes touches its Definition of Better figures, success signals, Group-Wide Constraints, Ticket Relations, or its statement of what is executable from the project root, update those sections **in the same response that wrote the note**. A note written without that check is an incomplete deliverable, the same way a `.project-docs/` document without its index row is.

Three rules for the edit:

1. **Only above the marker.** Edit the authored sections above `<!-- okstra:task-memory:begin -->`. The region below is okstra's projection — start order, per-task status, recorded runs — and it is redrawn from the task manifests at every `report-finalize`, at `okstra set-work-status`, and before each run copies the file. Anything you write there is overwritten without warning.
2. **Qualify a diverged figure; do not delete it.** An audit number is the baseline for the window it was measured in, not a current reading. Where a direct measurement contradicts it, say so with the measurement's date and method, and keep both. Deleting the old figure destroys the reason the group exists.
3. **Say which task and note the correction came from.** The next reader needs to get from the sentence back to its evidence.

If the group has no `group-context.md`, do not create one here — `okstra group-context init` (via okstra-brief-gen) owns that skeleton, and creating an empty one pre-empts the sections a human meant to author.

The same exposure applies to any other edit that supersedes group-wide facts, a brief rewrite most of all. Treat this check as belonging to the fact, not to this sub-command.
