---
type: brief
brief-id: <ticket-id>-<file-title>          # equals the filename stem
parent-id: self                              # always `self` at root; child briefs use parent's brief-id
ticket-id: <LIN-1234 | PROJ-42 | gh-repo-123 | notion-abcdef12 | "">
source-type: <file | linear | jira | github | notion | url | user-input>
task-group: <task-group>
depth: 0                                     # 0=parent/single, 1=child, 2=grandchild, ...
created: <YYYY-MM-DD>
generator: okstra-brief-gen
reporter-confirmations: <complete | partial | pending | skipped>  # set by Step 6.5
# codebase-scan variant frontmatter (omit for reporter-input briefs):
scope: <reporter-input | codebase>              # 'codebase' for codebase-scan variant; omit for reporter-input variant
priority-lenses: []                              # codebase-scan only: lens enum subset, size 1..4
scan-scope: []                                   # codebase-scan only: 1+ paths
out-of-scope: []                                 # codebase-scan only: optional
candidate-cap: 8                                 # codebase-scan only: 1..12, default 8
---

# Task Brief: <task_group>/<filename-without-ext>

> Generated: okstra-brief-gen · <YYYY-MM-DD>
> Source type: <file | linear | jira | github | notion | url | user-input>
> Tracker key (if any): <LIN-1234 | PROJ-42 | gh-repo-123 | notion-abcdef12>
> Parent brief (child briefs only): <relative path>
> Recommended next phase: <requirements-discovery | error-analysis | improvement-discovery>  ← from Step 6
> Handoff contract: see `prompts/profiles/_common-contract.md` § "Brief handoff contract"

## Source Material

<!-- author guidance — strip out at fill-in time:
Paste each source separately and as-is. No paraphrasing, summarizing, or
restructuring. Format conversion (e.g. Jira ADF → Markdown) is allowed and
must be annotated in the header meta. Heading was originally
"Source Material (verbatim — do not modify)" — the parenthetical is a
reviewer note, not body text.
-->

### Source 1 — <type: file | linear | jira | github | notion | url | user-input>

- ref: <abs file path | LIN-1234 | https://... | "conversation synthesis">
- fetched-via: <Read | mcp__linear__getIssue | mcp__notion__... | gh issue view | WebFetch | user-paste>
- fetched-at: <YYYY-MM-DD HH:MM>
- format: <as-is | "Jira ADF → Markdown (semantics preserved)" | "tool-truncated — missing body requested from reporter">

```
<Paste the raw source here without changing a single character.>
```

<!-- Repeat `### Source N — …` blocks as needed. -->

## Context

<Background / scope / why now. If self-evident from Source Material, quote
it briefly and stop. Use the blockquote below when augmentation is needed.>

> augmented: <label> — <Interpretation added by the skill or user.>

<!-- label MUST be one of: `evidence-link` / `format-conversion` /
`terminology-mapping` / `intent-inference`. Do NOT add any extra
interpretation outside the `> augmented:` blockquote. -->

## Problem / Symptom

<Current state. For bugs: repro / observed / expected. For greenfield: gap
between current and desired.>

<!-- Same source-quote + `> augmented:` rule as the Context section. -->

## Desired Outcome

<Shape of success.>

<!-- Do NOT prescribe a solution — that belongs to implementation-planning. -->

## Expected Behavior

<One bullet per observable runtime behaviour the finished work must exhibit.
Use _(none)_ when this work changes no runtime behaviour (a pure refactor).>

<!-- Format: `EB-NNN <observable condition> — verify: <command or observation point>`
The `— verify:` half is mandatory and stays English in every locale, because
downstream validators parse it. An item you cannot give an observation method
belongs in `## External Gates`, not here. `## Expected Behavior` and
`## Expected Outcome` must not both be empty. -->

- <EB-NNN observable condition — verify: command or observation point>

## Preserved Behavior

<One bullet per behaviour this work must NOT change. Use _(none)_ if none.>

<!-- This is the upper bound a refactor or improvement cannot express through
Expected Behavior alone. Same id and `— verify:` rule, with the `PB-` prefix.
codebase-scan variant: this is the ONLY end-state section. `## Expected
Behavior` and `## Expected Outcome` are rejected there, because the scan has
not run yet. -->

- <PB-NNN behaviour that must survive unchanged — verify: regression observation point>

## Expected Outcome

<One bullet per artifact-state the finished work must leave behind — a module
moved, a duplicate removed, a record written. Use _(none)_ if none.>

<!-- NOT `## Desired Outcome`. That section is prose: the shape of success, in
whatever words the reporter thinks in. This one is the checkable half — each
bullet is an `EO-NNN` id with an observation method, and it is what downstream
phases map against. Prose written here is rejected outright. An `EO-NNN` id
written up there is NOT: `## Desired Outcome` is checked only for a non-blank
body, so a misfiled id passes the brief and then leaves the run with nothing to
map at `endStateCoverage`. Check which section you are in before writing an id.

Same id and `— verify:` rule as the two sections above, with the `EO-` prefix.
Downstream phases treat Expected Behavior / Preserved Behavior / Expected
Outcome as the requirement set: every later phase maps each id to its own
deliverable, and `implementation-planning` builds one Requirement Coverage row
per id. -->

- <EO-NNN artifact state that must exist when the work is done — verify: command or observation point>

## External Gates

<Must-pass points owned by a person or by live infrastructure — peer review
sign-off, manual QA by a named person, staging/production validation,
dashboard or alert setup, ticket status transitions. Use _(none)_ if none.>

<!-- These are recorded so the reader knows the full release picture, and are
NOT requirements for any okstra phase: no phase plans a stage for them, no
phase gates on them, and they never become acceptance blockers. Ticket
templates routinely mix these with real criteria — split them here rather
than downstream. -->

- <gate>: <who or what owns it>

## Constraints

<Deadlines, compatibility, technical/operational limits. Use _(none)_ if
none.>

## Scan Scope

<!-- codebase-scan variant only — omit this section for reporter-input briefs. -->
<!-- Author guidance: one bullet per `scan-scope` path with a short description of what lives there. -->

- <path>: <one-line description of contents / responsibility>

## Priority Lenses

<!-- codebase-scan variant only — omit this section for reporter-input briefs. -->
<!-- Author guidance: one bullet per priority lens explaining why it is a priority for THIS scope. -->

- <lens>: <short rationale tying this lens to the scope's risk surface>

## Related Artifacts

- <file path / URL / issue / prior task-key>

## Related Task Graph

<!-- author guidance — strip out at fill-in time:
Use this section when the source ticket / reporter / split operation exposes
relationships between this task and other tasks. The table is copied into
every brief generated from the same split so each downstream phase can see
the whole topology from a single brief.

Columns:
- From / To: task key, brief id, tracker id, or URL. Direction is encoded by
  `From` → `To`.
- Relation: one of `parent-of`, `child-of`, `depends-on`, `blocks`,
  `blocked-by`, `follow-up-of`, `split-from`, `duplicates`, `related-to`.
- Direction: `directed` for ordering/parentage relations, `undirected` for
  `duplicates` / `related-to`.
- Source: where the edge came from (tracker linked issue, task-list checkbox,
  reporter statement, manual split, prior okstra task).
- Impact: what the next phase must preserve about this edge.

Use `_(none)_` when there are no known task relationships. Do not invent
edges from filename similarity or topic overlap.
-->

_(none)_

## Open Questions

<!-- author guidance — strip out at fill-in time:
Prefix every row with one of these signals so the next phase knows how to
handle it. Free-form rows are allowed only as `general:`.

Allowed signals:
- `general: <unresolved question the user flagged>`
- `terminology: <reporter word> — needs canonical resolution against
  <PROJECT_ROOT>/.okstra/glossary.md`
- `intent-check: <restated inference> — confirm with reporter`
  (auto-paired with every `intent-inference` augmentation)
- `conversion-block: <reporter statement> — could not be mapped to project
  vocabulary; reporter query required`
- `adr-candidate: <topic>` — signal only; `implementation-planning`
  evaluates and, if accepted, drafts a decision file at
  `<PROJECT_ROOT>/.okstra/decisions/<NNNN>-<slug>.md`.

Use `_(none)_` only if every signal is empty. `intent-check:` and
`conversion-block:` rows that are answered in Step 6.5 are NOT removed
from this list — they receive a `[CONFIRMED <YYYY-MM-DD> → RC-N]`
marker that links to the corresponding entry under
`## Reporter Confirmations`.
-->

- <fill in one row per signal, or replace with `_(none)_`>

## Reporter Confirmations

<!-- Populated by Step 6.5. Each subsection records one reporter answer
verbatim, with a link back to the originating `Open Questions` row. -->

_(none — pending or skipped)_

<!-- when populated, the shape is:
### RC-1 — <intent-check: or conversion-block: row id / topic>
- asked: <YYYY-MM-DD HH:MM>
- linked-row: `<exact Open Questions row text>`
- answer (verbatim):

  > <reporter's answer, byte-for-byte>
-->

## Augmentation

<!-- author guidance — strip out at fill-in time:
Cross-references / interpretation / context added by the user or skill that
is not in the original source. May be empty. Keep this section visually
separated from Source Material — never inline it inside Source Material.

Every entry below must start with one of the four labels:
`evidence-link` / `format-conversion` / `terminology-mapping` /
`intent-inference`. Unlabelled entries are forbidden.
-->

### Domain alignment

<!-- author guidance — strip out at fill-in time:
Observations from Step 3b and the outcome of Step 4.5 (glossary applied
vs. skipped). The actual glossary edits live in
`<PROJECT_ROOT>/.okstra/glossary.md` when applied; this
section records what happened. Decision candidates are NOT recorded here —
they flow through `Open Questions` as `adr-candidate:` rows for
`implementation-planning` to evaluate (and, if accepted, draft into
`<PROJECT_ROOT>/.okstra/decisions/`).

Allowed entry shapes:
- `terminology-mapping: <reporter word> → <okstra glossary canonical>` —
  routine glossary alignment, paired with `terminology:` in Open Questions
  when unresolved.
- `terminology-mapping: applied glossary: <term> → <PROJECT_ROOT>/.okstra/glossary.md`
- `terminology-mapping: skipped glossary: <term> = <definition>` —
  Step 4.5 outcomes.
Use `_(none)_` if every alignment entry is empty.
-->

- <fill in one entry per alignment, or replace with `_(none)_`>

### Evidence links (file / symbol resolution)

<!-- Allowed entry shapes:
`evidence-link: <reporter phrase> → <relative path>:<line>` or
`evidence-link: <reporter phrase> → <symbol> in <relative path>`.
Use `_(none)_` if none. -->

- <fill in one entry per link, or replace with `_(none)_`>

### Intent inferences

<!-- Every entry here is an unverified hypothesis. Each one MUST have a
paired `intent-check:` row under Open Questions.

Allowed entry shape:
`intent-inference: <reporter phrase> → <qualitative restatement>`
(qualitative only — never invent numeric thresholds).
Use `_(none)_` if none. -->

- <fill in one entry per inference, or replace with `_(none)_`>

### Format conversions

<!-- Allowed entry shape:
`format-conversion: <ref> — <e.g. Jira ADF → Markdown, semantics preserved>`.
Use `_(none)_` if none. -->

- <fill in one entry per conversion, or replace with `_(none)_`>
