Use when a project needs a named finish line on the tracker — creating it, deciding which issues belong to it, and reading what is still open before it is reached. It files the first round of work as plain placeholder tickets that carry no readiness marker, so nothing it creates can be picked up by a background agent until a person sharpens it, and its status pass only reports — it never declares the finish line reached. Triggers on "cut a goal", "what is left before <goal>", "add this to the...
Installs into .claude/skills of the current project.
Are you the author of Goal?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/formtrieb-goal)
---
name: goal
description: Use when a project needs a named finish line on the tracker — creating it, deciding which issues belong to it, and reading what is still open before it is reached. It files the first round of work as plain placeholder tickets that carry no readiness marker, so nothing it creates can be picked up by a background agent until a person sharpens it, and its status pass only reports — it never declares the finish line reached. Triggers on "cut a goal", "what is left before <goal>", "add this to the goal", "goal status".
---
# goal
A **Goal** is a named finish line: a set of **direct members** living in **one container on your tracker** — a GitHub Milestone, a Linear Project, a Linear Initiative, or a file on the local markdown store — plus its **Frontier**, the derived remainder of members that are not finished yet. **The member kind follows the container, never your choice at call time**: an issue under a Milestone, a Project, or the markdown goal file; a **project** under a Linear Initiative, because an initiative holds projects, not issues. This station is the fourth planning station, beside `triage`, `to-prd` and `to-issues`, and it runs in four passes:
| Pass | Writes? | What it does |
|---|---|---|
| **cut** | yes | mints the container and files its opening frontier as **bare** direct members — title, prose, provenance line — with the dependencies you already know drawn between them, natively, at mint |
| **curation** | yes | joins a direct member to the goal, naming its kind as it does, including the handoff when a placeholder outgrows itself and its slices join in its place |
| **status** | no | reports the five-state frontier — the native project state alongside it, under an initiative binding — and stops |
| **mirror** | yes | publishes the Frontier as derived accounting to the bound container's own native update surface — a session-drafted, Operator-confirmed narrative above an engine-rendered anchor it can neither supply, edit, nor omit |
Your job is the **judgment** — what the finish line is, what its opening frontier contains, which issue belongs to it, what the report means, and — at the mirror pass — what belongs in the narrative and whether a health value has a real source behind it. The engine is the guardrail: it owns the container binding, the bare filing shape, the frontier derivation, and the mirror's own accounting render, and it deliberately exposes no verb for dispatching or for declaring a goal finished. So this skill stays on the judgment; the CLI invocation detail lives in [reference/goal-mechanics.md](reference/goal-mechanics.md) and the report's own shape in [reference/frontier-report.md](reference/frontier-report.md) — reach for them once a pass is confirmed. You never write a tracker directly; every read and write goes through the engine CLI (`{{wave-cli}}`), which selects the configured store.
## When to Use
- A release, a launch, or any other finish line needs naming, and the first round of work it implies needs to exist before anyone can say what it is.
- An issue should join an existing finish line, or a placeholder has been sliced and its slices should join in its place.
- Someone asks "what is still open before we get there?"
- The finish line's current accounting should live on the tracker's own timeline, for readers who never open this skill at all.
Do **not** use this skill to make a member ready for a background agent — `triage` decides *whether* it is ready and `to-issues` writes the planning header it needs. Do not use it to capture a design as a PRD (`to-prd`) or to choose what runs next (`wave-plan`). And do not use it to run anything: this station dispatches nothing, ever — publishing a mirror update is not an exception to that; the pass reports, even when it writes.
## THE FLOTILLA BOUNDARY — sight, never permission
**Goal membership informs planning and authorizes nothing.** This is the one rule that makes the station safe to hand a planning agent, and every clause below is structural rather than a promise:
- **The station never stamps eligibility.** Cut files **bare** issues — no planning header, no readiness marker — so nothing it creates can be drawn into a wave on its own. Sharpening bare → ready stays where it lives: `triage`'s answerability test and `to-issues` decorate-mode. If you find yourself reaching for `issue-store annotate` here, **stop** — that is `to-issues`' job.
- **The station never dispatches.** The Goal facet has no dispatch verb and never will, so there is nothing here to reach for. An issue enters a wave because it is *eligible and passes the readiness gate* — never because it is in a Goal.
- **Downstream, membership is display only.** `wave-plan` may read the facet for a read-only goal panel or filter, exactly as it surfaces PRDs today. Every execution skill from `wave-create` onward is blind to the facet by design; do not teach one to read it.
- **The station never declares the finish line reached — not even from the pass that writes.** There is no close verb on the facet, on any of its four passes. Status reports that the frontier is empty; the mirror pass may **publish** that same report to the tracker's own timeline, and publishing accounting is not the same act as declaring a release — the anchor says so in its own words: on an empty frontier it names closing the container as **your** act, not something this pass did on your behalf. The station owes the accounting, never the declaration.
- **A second way to write is fenced exactly like the first one was.** Every field the mirror pass's caller could steer — the narrative, an operator's note, a health value — passes the Operator's own confirm before the call is ever made (see "Pass 4 — mirror" below); the accounting half is rendered by the engine from a read it takes fresh, at write time, and can be neither supplied, nor edited, nor omitted by the skill or by the person driving it. So the one durable artifact this facet can now produce is not a channel for a self-issued release authorization: nothing reaches it unconfirmed, and the one part of it that could assert a release is the one part nobody here can touch.
## Per-pass human yes
**Every writing pass previews its writes and takes an explicit confirm, and no pass inherits an earlier pass's approval.** A confirmed cut authorizes exactly the container and the members it previewed; a curation pass run five minutes later previews and asks again. Present the preview as the concrete list of writes — the container's name, each member's title, each dependency edge, each membership join — and wait for a yes before the first call. The status pass is read-only and needs no confirm.
**A cut and its first curation may fold into one preview under one confirm, when they are genuinely one operator decision made in the same sitting — this is sanctioned, not merely tolerated.** A mature-pool cut routinely needs both in the same breath: new placeholders filed, existing work joined. Asking twice for one decision would be ceremony, not extra safety. The fold carries one condition: the preview still lists both write sets **by name and kind** — which members are newly-minted placeholders (the cut) and which are joins of work that already existed (the curation) — so the single yes is knowingly a yes to two different kinds of write, never a blurred list that reads as one. This is not a standing exemption for curation in general: a curation pass run later, in a separate sitting, still previews and asks on its own. The fold applies only to a cut's own first curation, decided in the same breath as the cut itself.
**The mirror pass never folds with anything, cut-and-curation exception included.** That fold is about *membership*, decided once, in one sitting; the mirror's preview is about *accounting* that keeps moving on the tracker whether or not you touch this skill again — folding it into an earlier pass's confirm would be a yes given to a read that is already aging. Every mirror run gets its own preview, on its own fresh read, with its own confirm — what that preview must show is in "Pass 4 — mirror" below.
## The container binding
Which native container a Goal is realized as is a **setup-time config fact**, `store.goal.container` in `wave.config.json` — never a choice made at call time and never one this skill makes for you. GitHub defaults to its Milestone, the only native container with direct issue membership; the markdown store defaults to its goal file; **Linear has no default at all** and refuses loudly, because live consumer conventions disagree about what a Linear project — or a Linear initiative — means. Linear realizes both roles it declares: `project` (direct issue members) and `initiative` (direct **project** members, minted under `store.team`, the consumer's config-bound team). A refusal names the config key and the roles the store ships — read it, fix the config, re-run. Never work around it by reaching for a tracker CLI. Two of the four roles — the two Linear ones — additionally carry a native **update surface**, the target the mirror pass (Pass 4) publishes to; the other two have none, and the mirror refuses there rather than substituting one. Full binding detail, the container-role table, the update-surface column, and the refusal shapes: [reference/goal-mechanics.md](reference/goal-mechanics.md).
## Pass 1 — cut
**Existence first — for whatever is genuinely new.** At a cut you know *that* a workstream must exist long before anyone can say *what* it is, so a newly-drafted member is filed bare and sharpened later — bare **issues** under the three issue-direct bindings, bare **projects** under an initiative binding. A Linear project is *born* bare (a name, prose, a `backlog` status carry no eligibility semantics at all), so there is no bare invariant to protect there the way there is for an issue — but the same "existence first, sharpen later" judgment applies to both kinds.
**A cut over a mature pool is mostly curation, and that is the more common shape, not an edge case.** The greenfield picture above — every member freshly minted bare — describes a finish line cut over nothing. Cut a finish line over a pool that already has work in it, and most of what the finish line needs already exists: triaged, some of it dispatch-ready. The goal then acts as a **collecting lens** over that pool — most of the cut's job is naming the finish line and joining the work that already answers it (Pass 2, curation), and only the genuinely-unspecifiable remainder gets filed bare (this pass). **A release cut is the archetype of this shape**: the release itself is new, but most of what it ships was triaged and moving before anyone thought to name the release as a goal. Both shapes are the same pass and the same judgment — what belongs, what still needs writing up — so the steps below still apply; they just file fewer bare members when the pool is mature. Whether the cut's first curation may share the cut's own preview and confirm is answered in "Per-pass human yes" below.
1. **Name the finish line.** One title a stranger can read, plus a short prose description of what being finished means. Do not encode a date, a status, or a checklist in it — completion is a query over the members, not a sentence in the container.
2. **Draft the opening frontier.** One placeholder per workstream that must exist. Each carries a title, a paragraph of prose saying what the workstream is *for*, and a **provenance line** naming where the cut came from (the session, the design record, the conversation). Draw a dependency where you already know one — a placeholder may depend on another placeholder even while neither is specifiable yet. Under an initiative binding, a placeholder is a **project** rather than an issue: the same judgment (what workstream, what it's for) still applies, and the file below it becomes a project's description rather than an issue body.
3. **Preview and confirm.** Print the container, every member title, its kind (issue or project), every dependency edge, and stop. **Do not file anything until the person says yes.**
4. **File, blockers first.** Mint the container, then file each member — one engine-CLI call both files the bare member and joins it to the container, so there is no separate join step in this pass. Blocker-before-dependent, so a dependent can name a real id. Under an initiative binding each member files as a bare project under `store.team`, the config-bound team — no other team choice is made here, and moving the finished project to whichever team will run the work is a tracker-UI act afterward, outside this station. Capture every printed id — they are opaque; never reconstruct one from a title. Commands, input shapes, and the id-inversion step: [reference/goal-mechanics.md](reference/goal-mechanics.md).
5. **Report.** Name the goal, its members, and the next step for each: every one of them is a placeholder, and none of them can be picked up until it is sharpened — for an issue member, `triage` then `to-issues`; for a project member, sharpening means triaging and decorating the issues filed *inside* it, since the project itself carries no eligibility marker to sharpen.
> **The bare dependency is realized natively.** A dependency between two bare members becomes a real tracker relation — a GitHub issue dependency, a Linear issue relation, or (under an initiative binding) a Linear **project** relation — and writes no header line, so the members stay bare. The local markdown store cannot represent it and **refuses** rather than faking it; on that store, either file the member without the edge and record the dependency when it is sharpened, or file it decorated through `to-issues` in the first place.
>
> **The ship-member pattern — filing a release's own act as a member, with a dependency edge on every content member it waits on — is sanctioned.** A release finish line's own act (the version decision, the CHANGELOG, the publish, the post-publish closes) needs a home like any other workstream, and a "ship" member beside the content members it ships is a natural shape for a release-goal specifically. Draw a native dependency edge from the ship member to every content member it waits on — the same mechanism step 2 already uses between ordinary placeholders — and its `blocked` reading then names exactly what the release is waiting on: sharper, per-member sight than reading the goal's aggregate open remainder and inferring the same thing. **The duty this buys is real, and it falls on you, not on the station**: a member that joins the goal later by curation is invisible to the ship member until its edge is drawn. Once the ship member is decorated on an issue-direct binding (milestone, project or goal-file), draw that edge with `issue-store block <ship> --by <member>` — the engine writer for exactly this edge (ADR-0054). While the ship member is still bare, or under an initiative binding (project members, where `block` does not apply), the edge stays hand-drawn: `goal-create-member`'s native `blockedBy` only fires at mint time, and curation's `goal-assign` (Pass 2) never touches an edge, so nothing re-derives the ship member's blocker list as the pool grows. Record that duty in the ship member's own body, in its own prose — "redraw this edge whenever a member joins by curation" — so it outlives the person who filed it, and re-check the ship member's edges any time a curation pass adds a member this release should wait on.
>
> **The first live read-back happened on 2026-08-16, both pinned values were wrong, and the repair has landed — read-back AND correction are both done.** The confirmation this note used to be pending — draw one dependency on an initiative-bound goal against a live Linear workspace, then read the two constants back — has now happened. Neither pinned value held: `type: "blocks"` must be `"dependency"`, and `anchorType`/`relatedAnchorType: "project"` must be one of `start`/`end`/`milestone` rather than a whole-project anchor. Both were corrected in the engine, so **a native project-relation write under an initiative binding now sends the measured values and Linear accepts them** — the same probe created the relation, read it back verbatim and confirmed it surfaces on the blocked project's `inverseRelations`. There is no symmetric anchor to correct to: the whole-project anchor is a finish-to-start pair, the blocker's `end` onto the blocked project's `start`. The engine still surfaces any rejection loudly, naming the minted member, so a workspace that ever disagrees is visible rather than silently lossy — but that is now the exception path, not the expected one. Full detail: [reference/goal-mechanics.md](reference/goal-mechanics.md).
## Pass 2 — curation
**The frontier is deliberately editable, and every edit is a human act.**
- **Joining.** One call joins one direct member to one goal — an issue under the three issue-direct bindings, a **project** under an initiative binding. It is idempotent, and it touches membership only — never the claim marker, never the triage state, never eligibility, never open/closed. Any member may join: one you filed at the cut, one that already existed, a slice someone wrote last month. **Name the member's kind in the preview** — "the project '…'" or "the issue '…'" — so the confirm is never ambiguous about what is about to enter the container. Under an initiative binding, an issue-shaped id is refused before any write rather than silently joined: "add this issue to the goal" is the one confusion this kind check exists to catch, because an initiative holds the projects issues live in, never the issues themselves — if you meant an issue, name the project it lives in instead.
- **The slicing handoff.** When a bare member outgrows its placeholder, it becomes a PRD (`to-prd`) whose slices (`to-issues`) join the goal by curation — **the slices join, the PRD does not**. A PRD is consumed rather than finished, so it has no completion state to query and can never be a member; it belongs to the goal derivedly, through its slices. The superseded placeholder then closes — and closing it is your act in the tracker, or `triage`'s won't-fix route where that is the honest verdict. This station names the placeholder and hands it over; it does not close it. Under an initiative binding the superseded placeholder is a project, and its slices are still issues filed inside whichever project now carries the work.
- **Leaving.** There is no leave verb. A member leaves by being removed from the container in the tracker, which is where you do it; the station reads the result on the next status pass.
- **Preview and confirm, per pass.** List each join, each handoff, and what the frontier will look like afterwards. Then ask. A yes given to a cut is not a yes to a curation pass.
> **Pending first live run.** The join call tells an issue id from a project id by shape — an uppercase team key followed by a number (`EX-123`). No document states every Linear workspace's team keys are uppercase-only; a lowercase-keyed workspace would fail this shape check and fall through to a plainer, less-well-taught refusal rather than the typed one above. That direction is benign — the join still refuses, just with a less specific message — so this is a confirm-at-first-live-run note, not a blocker: check the actual team-key casing the first initiative-bound live pass encounters.
## Pass 3 — status
Read-only, free, and the pass most runs will be. Ask the engine for the frontier and render it; derive nothing yourself and write nothing at all.
Each member reads as exactly one of five states — one finished bookend and four open ones — whatever its kind:
| Reading | What it means | Who moves it |
|---|---|---|
| `done` | closed on the tracker | nobody; it is finished |
| `in-motion` | a wave has claimed it, or (for a project member) the project itself is natively `started`/`paused` | the wave that holds it, or whoever moved the project |
| `actionable` | ready, unblocked, unclaimed | a wave could pick it up now |
| `blocked` | waiting on a dependency nothing has resolved | whatever it waits on |
| `unready` | carries no eligibility marker at all — an issue with no planning header, or a project holding no eligible issue (an empty project reads this way too) | for an issue: `triage`, then `to-issues`. For a project: triage and decorate an issue inside it |
**Under an initiative binding, render the native project state beside the reading — that is what keeps `in-motion` honest.** The frontier's `in-motion` folds two different native facts into one word: a project a person moved to `started` or `paused`, or a project still `backlog`/`planned` that merely has a wave-claimed issue inside it. Say which, when you know it — the two carry different next steps for the reader (a project a person is actively driving, versus one only a wave row inside it is touching) — and never let one word imply a false precision the tracker itself doesn't show. `completed`/`canceled` collapse to `done`; `backlog`/`planned` on their own contribute nothing to the reading — the reading then rests on whatever is happening to the issues inside. Full mapping and worked rendering: [reference/frontier-report.md](reference/frontier-report.md).
Render the distribution, then name names: **who is `unready`** (and which of the two sharpening skills each one needs), **who is `blocked` and on what**, and who is moving. A blocker the store could not resolve counts as unresolved, never as clear — say so rather than presenting the member as free. Report shape, the operator translations for each reading, and the worked example: [reference/frontier-report.md](reference/frontier-report.md).
**Report an empty membership distinctly from completion.** A goal with zero members and a goal whose every member is done both derive `complete: true` — an empty remainder is empty either way — but they mean different things to the reader, so say which one you are looking at: "this goal has no members yet" is not "every member of this goal is finished." Only in the second case is the remaining step yours to take.
**On completion (every member done), report it and stop.** Say that every member is finished and that the remaining step is yours: **close the container in the tracker.** Do not close it, do not write a release marker, do not file a note beside it — there is deliberately nowhere to write one.
End every pass with the operator block: what happened → where it lives → what you do next.
## Pass 4 — mirror
**The mirror pass writes; the status pass above stays read-only, in exactly the words it always has.** Mirror publishes the Frontier — the same reading status already reports — as **derived accounting** to the bound container's own native update surface: a Linear Project Update under a `project` binding, a Linear Initiative Update under `initiative`. Under `milestone` or `goal-file` there is no such surface, and the pass refuses rather than inventing one (see "The container binding" above and [reference/goal-mechanics.md](reference/goal-mechanics.md#pass-4--mirror) for the refusal shape).
One engine call makes the whole write. You may contribute exactly three things, and nothing else reaches the tracker:
- a **narrative** — Operator prose, in the consumer's own house form, saying what happened and why it matters;
- a **health** value — transcribed or proposed, never derived (below), or nothing at all;
- an **operator's note** — a short aside about the pass itself, attributed and kept apart from the narrative.
Everything else in the published body — the frontier, each member's state, its native state, its own health, its unresolved blockers, the distribution, the provenance line — is rendered by the **engine**, fresh, at the moment of writing, through one shared renderer every store calls. There is no field on this call for a body, a frontier, or a member list: the mirror cannot lie about the frontier because it is never told what it is — the same class of guarantee the triage facet gives the claim ledger, one seam over.
1. **Draft the narrative, sentence by sentence, in the consumer's own house form.** flotilla pins no template here — read whatever this consumer's own lived update style already is (a per-project update skill, a past initiative update, a standing convention) and write in it. **Every sentence goes to the Operator for a yes before it counts as final** — one sentence at a time, never one lump approval at the end: that confirm is what makes the prose the Operator's rather than the agent's. An absent narrative publishes an anchor-only update, which is a complete and honest artifact, not a degraded one — do not pad it just to have something to show.
2. **Run the health-proposal round, or skip it — never invent a third source.**
- **Transcribe.** The Operator states or confirms a value directly; write exactly what they said.
- **Propose.** Only as a **source-attributed aggregation of the members' own human-authored healths** — never a reading taken from the frontier. State it with one sentence of reasoning ("atRisk — inherited from *\<member\>*, whose own health reads atRisk") and get an explicit confirmation before it goes anywhere near the call.
- **Never** compute a health from the frontier's own classification — not from the counts, not from `blocked > 0`, not from any reading. That is the station judging a human's call, and it is the one thing this round exists to prevent.
- With no Operator value and no member health to aggregate, publish with none. Absence is a complete answer, not a gap to fill.
3. **Preview the whole body, verbatim, plus the target and the health — then stop.** Read the frontier fresh (`goal-frontier`) immediately before you preview — not a status report from earlier in the session — and render the anchor using the engine's own wording (the exact vocabulary and shape are in [reference/goal-mechanics.md](reference/goal-mechanics.md#pass-4--mirror)), so what the Operator sees is worded exactly as the engine's own render would word it for that frontier. Show, in full: the narrative text, the rendered anchor, the health value or its explicit absence, the operator's note if any, and the container the update publishes to. **No fold with any other pass, including a cut's own curation fold** — the mirror always previews and confirms on its own (see "Per-pass human yes" above). **If the fresh read shows zero members, say so before anything else.** The engine's own anchor already keeps a genuinely empty goal from reading as a release signal: `renderGoalUpdateBody` publishes only "this goal has no members yet" there, never "every member of this goal is closed" beside it (the render gates that sentence on the goal having at least one member). Naming the empty membership in your own preview is now belt-and-suspenders rather than the only guard — worth doing anyway, because an Operator publishing an update for a goal with nothing in it yet is a judgment call you should still surface, not skip past.
4. **State the freshness caveat at the preview, not after it.** The engine re-derives the frontier a second time, fresh, inside the write itself — not the read your preview used. If the tracker moved between that read and the write, what publishes can differ from what you just showed the Operator. Say this plainly: the preview promises what YOU are contributing — the narrative, the health, the note — never the exact bytes of the accounting, because neither you nor the engine knows those until the write actually happens.
5. **Publish, once confirmed.** One call. Input shape, the CLI invocation, and the receipt shape: [reference/goal-mechanics.md](reference/goal-mechanics.md#pass-4--mirror).
6. **Report from the receipt, not from the preview.** The receipt carries the exact body that was published and the frontier it was derived from — read those back rather than assuming the write matched what you showed. Report the published url when the tracker gave one, the health that went out (or that none did), and where the update now lives.
> **When every member is done (not when there are none), the anchor carries the engine's own sentence, published verbatim:** *"Every member of this goal is closed. The remaining step — closing the container itself — is the Operator’s act in the tracker: this pass reports the finish line has been reached and does not declare it reached."* You do not compose this sentence and you do not reword it in your preview — quote it exactly, because it is the one line most likely to be misread as a release if it is paraphrased. A goal with zero members is `complete` too, but the render does not publish this sentence there — see "Mirroring a still-empty goal without flagging it" below.
**The pass's working name from the design session, "health write-mirror," is retired.** What this pass carries is the **Frontier** — health only ever travels through it as a transcribed or source-attributed human judgment, never as the thing being mirrored. If that name turns up anywhere else, it names this same pass.
## Common Mistakes
- **Stamping readiness at the cut.** A bare member has no planning header and no readiness marker on purpose — existence is recorded, wave-readiness is not implied. Decorating it here collapses two separate decisions into one and puts unsharpened work in front of a background agent.
- **Treating membership as candidacy.** A goal is a planning artifact; the readiness gate is the only thing that lets work into a wave. A member that is in the goal and not eligible stays out, and that is the design working.
- **Closing the container.** The station reports an empty frontier and stops. The declaration is a human act in the tracker; there is no verb here for it and adding one would hand an agent its own release authorization.
- **Making a PRD a member.** A PRD is consumed, never done, so it has no completion state to query. Its slices are the members; the PRD belongs to the goal only through them.
- **Riding an earlier approval.** Each writing pass previews and asks for itself. A cut approved this morning authorizes nothing this afternoon.
- **Filing members through a tracker CLI.** Every write goes through the engine CLI, which resolves credentials and selects the configured store. Reaching past it is the defect class the triage facet already retired once.
- **Spelling a dependency reference by hand.** Ids are opaque. Ask the engine to invert one; never split an id on a separator or rebuild it from a title or a filing hint.
- **Picking a container when the config does not name one.** A store that binds no default refuses on purpose. Set the key in the config; do not choose a container on the consumer's behalf.
- **Reading a goal panel as a wave plan.** Membership is a display column. It never orders, ranks, or qualifies candidates.
- **Passing the wrong id kind under an initiative binding.** A member id's kind follows the container, not your intent — an issue id where the binding wants a project (or the reverse) is a category error, not a typo. The engine refuses it before any write; naming the member's kind in your own preview is what stops you from hitting that refusal in the first place.
- **Letting a ship member's edges go stale.** A ship member's `blockedBy` list is drawn once — at mint, or afterward with `issue-store block` once the ship member is decorated on an issue-direct binding (still hand-drawn for a bare ship member or under an initiative binding) — and nothing re-derives it: curation's `goal-assign` never touches an edge. A member joined by curation after the edges were drawn is invisible to the ship member's own blocked reading until someone redraws it. State that duty in the ship member's own body; do not trust memory to carry it.
- **Hand-composing the anchor.** The accounting half of a mirror update is the engine's own render of a fresh read, not prose you draft. Draft only the narrative and, if you have one, the operator's note — anything that looks like a member list or a distribution count belongs to the engine, never to your own sentence.
- **Deriving a health value from the frontier.** `blocked > 0 → atRisk` is exactly the formula this round exists to forbid (ADR-0046). A health value comes from the Operator, or from a source-attributed aggregation of the members' own healths — never from the reading a member happens to have right now.
- **Mirroring on a stale read.** A status report shown five minutes ago is not what the mirror publishes. Read the frontier again immediately before you preview, and say plainly that what actually publishes can still differ if the tracker moves once more before the write itself runs.
- **Reading a published mirror update as a release marker.** The mirror pass writes a durable artifact for the first time on this facet — but the artifact is accounting, worded by the engine, and its own empty-frontier sentence names closing the container as your act. Publishing it is not that act.
- **Mirroring a still-empty goal without flagging it.** The engine's anchor gates the "every member of this goal is closed" sentence on the goal having at least one member, so a zero-member goal's published body carries only "this goal has no members yet" — the render itself no longer confuses the two the way it once did. Check the member count before you preview and say so anyway: the guard now belongs to the engine, but an Operator deciding whether to publish an update for a goal with nothing in it yet is still a call worth surfacing, not skipping past.
## Provenance
- **[ADR-0044](../../../docs/adr/0044-a-goal-binds-a-native-container-and-derives-its-frontier.md)** — the decision this station carries: bare frontier tickets at the cut, the goal as an issue-set boundary orthogonal to PRDs, the facet on the store, the config-bound container role, the derived-never-written frontier, and *sight, never permission*. The file is `docs/adr/0044-a-goal-binds-a-native-container-and-derives-its-frontier.md`, beside the other decision records.
- **[ADR-0045](../../../docs/adr/0045-a-goals-members-are-the-containers-direct-native-members.md)** — the initiative realization: a goal's direct members follow the binding's own kind (issues, or projects under a Linear initiative), one frontier vocabulary at every member granularity, the member-kind-generic write verbs (`assignToGoal`, `createGoalMember` with its native `blockedBy` arm), and workspace-wide `listGoals` under `initiative`. The file is `docs/adr/0045-a-goals-members-are-the-containers-direct-native-members.md`.
- **[ADR-0046](../../../docs/adr/0046-the-mirror-pass-publishes-derived-accounting-to-the-containers-native-update-surface.md)** — the mirror pass itself: the fourth pass and its own preview/confirm, the engine-derives-fresh guarantee, the two-layer body (Operator narrative above an engine-owned anchor), the two sanctioned health sources and the one prohibition, and the surface-follows-binding rule. The ticket's own working name for this pass, "health write-mirror," is retired — what is mirrored is the **Frontier**, never health on its own. The file is `docs/adr/0046-the-mirror-pass-publishes-derived-accounting-to-the-containers-native-update-surface.md`.
- The five readings and the classification ladder are the engine's, in `tools/wave/src/goal-frontier.ts` — this skill renders them and never re-derives them.
- The mirror pass's renderer and its fixed wording — `renderGoalUpdateBody`, `GOAL_MEMBER_STATE_PROSE`, `GOAL_UPDATE_EMPTY_FRONTIER_SENTENCE`, `GOAL_UPDATE_PROVENANCE_LINE` — are engine code too, in `tools/wave/src/adapters/issue-store.ts`, root-exported specifically so a preview can show the same words the write will emit.
- The requirements arrived as counter-examples from an evaluation of a third-party planning-map tool: a planning/execution boundary that was only prose, an agent that wrote itself a release authorization into a map's free-prose notes, a planning-to-execution seam that never became typed, and remote writes against a tracker nobody had consented to. Each is closed structurally above rather than by instruction.
## Operator register (Convention 16)
**Everything you print for the person at this session is operator-directed output, and it holds one register.** Plain language, direct address ("du"/"you"), self-explaining. Translate every internal reference — a decision-record number, a convention number, a finding id, a wave slug, a retro path — into the one-line consequence it carries for them, instead of naming it. Introduce a domain term with a half-sentence the first time it appears in a session, then use it freely. End the run with an operator block: what happened → where it lives → what you do next. Operator-directed text follows the operator's own language; the artifacts you write — issues, PRs, decision records, spine entries — stay English. **Installed form is strict** — no internal token reaches the operator. **Source form**, flotilla's own repo, may append one compact reference pointer after the plain text. Full clause text, the operator mini-glossary, and the mistakes it closes: [wave-shared/reference/convention-16-operator-register.md](../wave-shared/reference/convention-16-operator-register.md), read as a file beside this skill's own directory — no skill invocation, no namespace to guess.