feat(linkedin): v2.2.0 — harden longform gates from 2nd production run

Implements the 6-change spec from the Seres-serien production
(linkedin-plugin-endringsspec.md). All acceptance criteria met.

1. Avoid-patterns (modell-/navne-katalog, completeness-over-reader-action,
   self-referential overhead openings) → longform-quality-rules.md (rule 1+3)
   + user-profile.template.md.
2. Persona gate now BLOCKING with explicit hard-fail list (primær mistet meg /
   doesn't own action / sjargong-mur / modell-navne-katalog → BLOCK;
   "JA med store forbehold" = NEI) → persona-reviewer.md + personas.template.md.
3. Fact-check declared orthogonal to narrative strength + post-cutoff
   web-search mandate + high-frequency-error checklist → fact-checker.md.
4. NEW agent voice-scrubber.md (Opus) — de-AI scrub + Norwegian-chronicle
   voice-drift; gold standard = approved Norwegian editions, NOT the English
   post corpus. Wired into newsletter.md Step 4.
5. Operator gates = render+annotate rounds (build-html.mjs to file://) as
   primary flow, AskUserQuestion as receipt/fallback → newsletter.md 2.5+3a.
6. Edition state reconciled with STATE.md (ONE-system). edition-HANDOVER
   template deleted; narrative to <serie>/STATE.md, machine data
   (factcheckLog, personaSweep, immutableRules) to edition-state.json.

Agents 14 to 15; commands unchanged (24). Backward-compatible (additive
state-shape only). Docs updated across all three levels + CHANGELOG.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-05-28 20:50:56 +02:00
commit 4ed9717627
15 changed files with 494 additions and 152 deletions

View file

@ -38,8 +38,20 @@ This command is **fundamentally different** from the short-form commands:
ships the *schema* (`config/edition-state.template.json`) and this command;
the edition's actual state + drafts live with the series.
- **Multi-session by design.** A single edition spans several sessions. Every
phase transition rewrites `edition-state.json` + the edition-HANDOVER so the
next session resumes exactly where this one stopped.
phase transition rewrites two files: **machine state**
`edition-state.json` (currentPhase, per-article status, fact-check log,
persona verdicts), and **narrative state**`<serie>/STATE.md` (overwritten,
not appended — where we are + the one next step). The next session resumes from
these exactly where this one stopped.
> **No edition-HANDOVER (ONE-system).** This command does **not** use a separate
> `edition-HANDOVER.md`. Per the global continuity rule, the cwd-nearest
> `STATE.md` (auto-injected by the `session-start` hook) is the authoritative
> narrative state-bearer; a plugin may not invent its own handover mechanism.
> Narrative status lives in `<serie>/STATE.md` (overwrite each phase); machine
> state lives in `edition-state.json`. There is no `§4`/`§5`/`§6` handover —
> those records moved into `edition-state.json` (fact-check log, persona
> verdicts) and `STATE.md` (next-step pointer).
## Architecture principle — all orchestration runs in the FOREGROUND from this command layer
@ -68,13 +80,13 @@ single most important corrections from the Seres process (plan §0.4, principle
| Step | Phase | What | Tools |
|------|-------|------|-------|
| 0 | **Load context** | edition-state/HANDOVER, voice profile, persona library, series brief | `Read` |
| 0 | **Load context** | edition-state + `<serie>/STATE.md`, voice profile, persona library, series brief | `Read` |
| 1 | **Brief + calibration** | angle, voice, audience personas (mark primær), key points, tone, leader-takeaway. ≤3 questions | `AskUserQuestion` |
| 2 | **Research** | parallel scoped mandates → verified notes; triangulation | **`Task` fan-out (foreground)** |
| 2.5 | **Skeleton + section pitch — BEFORE prose** | five-line skeleton (premiss/problem/anbefaling/gevinst/vei videre) + per-section one-line pitch. Operator-gate JA/NEI/REVIDER. Persona-skjelett-sweep before any prose is written. | `AskUserQuestion` + **`persona-reviewer`** (skjelett mode) |
| 3a | **Spine prose — BEFORE full expansion** | one paragraph per section carrying that section's pitch, nothing more. ~2030 % of final length. Operator-gate on whether the axis is right now that there is prose on it. | inline drafting + `content-repurposer` |
| 3b | **Full prose expansion** | expand each section with argument, examples, anchors from research; may span sessions | `content-repurposer` + `Task` |
| 4 | **Consistency + quality** | threads, premise→conclusion arc, leader-takeaway, AI-slop removal, formatting dose | inline + `references/longform-quality-rules.md` |
| 4 | **Consistency + quality** | threads, premise→conclusion arc, leader-takeaway, AI-slop removal, de-AI/voice scrub, formatting dose | inline + `references/longform-quality-rules.md` + **`voice-scrubber`** |
| 5 | **Fact-check sweep** | risk-sorted (🔴/🟡/🟢), guilty-until-disproven, verification log | **`fact-checker` (parallel)** |
| 6 | **Persona sweep — BEFORE lock** | reader jury, primær wins, convergence to clean YES | **`persona-reviewer`** (resonance mode) |
| 7 | **Annotation (optional)** | render annotatable review HTML for a manual pass | `render/build-html.mjs` |
@ -88,8 +100,8 @@ single most important corrections from the Seres process (plan §0.4, principle
> BEFORE prose)** → **spine prose (operator gate BEFORE full expansion)**
> full prose draft → consistency/quality → fact-check sweep → pre-lock persona
> sweep → optional annotation → LOCK/delivery → post-lock hook gate →
> scheduling, persisting each phase to `edition-state.json` and the HANDOVER
> and stopping cleanly between sessions.
> scheduling, persisting each phase to `edition-state.json` (machine) and
> `<serie>/STATE.md` (narrative) and stopping cleanly between sessions.
> **Why two gates BEFORE prose (v2.1).** Spine errors are the dearest failure
> mode in long-form: catching one at the skeleton stage costs 515 min, at the
@ -126,13 +138,17 @@ the edition left off before doing anything.
`${CLAUDE_PLUGIN_ROOT}/config/edition-state.template.json` (read it if you are
initializing a new edition). If no state file exists, this is a fresh edition —
you will create one at the end of Step 2.
3. **Read the edition-HANDOVER** (`<serie>/HANDOVER.md` or
`<serie>/linkedin/edition-HANDOVER.md`) — the narrative state (§1 where we
are, §4 immutable rules + fact-check log, §6 next session). The structure is
defined by `${CLAUDE_PLUGIN_ROOT}/config/edition-HANDOVER.template.md` (copy +
fill it when starting a new edition). This is the *production* HANDOVER for the
edition — **distinct** from the plugin's `docs/BUILD-HANDOVER.local.md`, which
governs building the plugin itself. Do not confuse or merge them.
3. **Read `<serie>/STATE.md`** — the narrative production state (where we are +
the one next step). The `session-start` hook auto-injects the cwd-nearest
`STATE.md`, so when the session was started in the series folder it is already
in context; otherwise read it explicitly. This is the authoritative
narrative bearer (ONE-system) — there is no `edition-HANDOVER.md`. The durable
records that used to live in the handover now live in `edition-state.json`
(immutable rules, fact-check log, persona verdicts). If `<serie>/STATE.md`
does not exist yet, this is a fresh edition — you will write it at the end of
Step 2. Do not confuse `<serie>/STATE.md` (this edition's production state)
with the plugin's own `STATE.md` / `docs/BUILD-HANDOVER.local.md` (which govern
building the plugin itself).
4. **Read the voice profile**`assets/voice-samples/authentic-voice-samples.md`
and anything else under `assets/voice-samples/`. Long-form must match the
author's voice; this is the reference for every drafting and review phase.
@ -140,8 +156,8 @@ the edition left off before doing anything.
if it exists, else `${CLAUDE_PLUGIN_ROOT}/config/personas.template.md`. You
will select the active personas + mark the primær in Step 1.
6. **Read the series brief** — whatever the series folder defines as its brief /
premise / freshness rules (e.g. `<serie>/brief.md` or the HANDOVER §3§5).
This anchors angle and scope.
premise / freshness rules (e.g. `<serie>/brief.md`, or the resolved brief
recorded in `edition-state.json`). This anchors angle and scope.
### Deterministic resumption — `currentPhase` → resume step
@ -174,16 +190,16 @@ Look up `edition-state.json` → `articles.<currentArticle>` (and the top-level
The phase identifiers are the canonical ones defined in
`${CLAUDE_PLUGIN_ROOT}/config/edition-state.template.json` (`_doc.phases`); the
Steps below write exactly these strings. If `currentPhase` is missing or
unrecognized, do NOT guess — read the edition-HANDOVER §6 next-session pointer and
unrecognized, do NOT guess — read the next-step pointer in `<serie>/STATE.md` and
confirm with the operator before proceeding.
**Draft-cursor note (Step 3b only).** `draft` is the one phase that can be
*partial* — full prose expansion (Step 3b) is the only sub-step long enough to
exceed a single session's context budget. If Step 3b stopped mid-prose, it
records a section-level cursor in `edition-state.json` and a "draft resumes at
section <X>" pointer in HANDOVER §6. On resume with `currentPhase: "draft"`,
section <X>" line in `<serie>/STATE.md`. On resume with `currentPhase: "draft"`,
check for that cursor first — if present, re-enter **Step 3b** at the cursor and
finish the prose expansion before Step 4; only when the HANDOVER records "draft
finish the prose expansion before Step 4; only when `STATE.md` records "draft
complete" (no open cursor) do you resume at **Step 4**.
Step 3a (spine prose) is short enough that it does NOT need a cursor: if 3a
@ -212,7 +228,7 @@ do not fabricate either.
## Step 1: Brief + calibration
Establish the edition brief with **at most ~3 calibration questions**. Infer
everything you can from Step 0 (series brief, HANDOVER, prior edition); only ask
everything you can from Step 0 (series brief, STATE.md, prior edition); only ask
what genuinely changes the work.
Settle these dimensions (most should come from context, not questions):
@ -296,8 +312,8 @@ Edition brief
5. **Persist + checkpoint state.** Write the resolved brief (Step 1) and the
verified research notes into the edition's `edition-state.json`
(`currentPhase: "research"`, article status `in-progress`) and append a
"research complete → next: skeleton + section pitch (BEFORE prose)" pointer to
the edition-HANDOVER §6. If this is a fresh edition, initialize
"research complete → next: skeleton + section pitch (BEFORE prose)" next-step
line to `<serie>/STATE.md` (overwrite). If this is a fresh edition, initialize
`edition-state.json` from the template schema first. Stop cleanly here if
context budget is tight — Step 2.5 begins in the next session; otherwise
Step 2.5 may run inline (it is short and operator-interactive).
@ -370,15 +386,33 @@ Next: Step 2.5 — Skeleton + section pitch (operator + persona gate BEFORE pros
2. …
```
4. **Operator-gate (first round).** Present the skeleton + pitches to the
operator with `AskUserQuestion`. Three options:
4. **Operator-gate (render + annotate — primary flow).** The operator review is
**HTML annotation**, not a multiple-choice prompt — and this holds for *every*
write deliverable, the skeleton included, not just the final POST.html. Render
the skeleton to an annotatable page and let the operator annotate in the browser:
- **JA** — skeleton is right, proceed to the persona-skjelett-sweep (step 5).
- **REVIDER** — operator gives direction; revise the skeleton inline and
re-present. Loop until JA or NEI.
- **NEI** — the skeleton is wrong at a load-bearing level (premise unsound,
argument-line incoherent). Return to brief calibration (Step 1) or
research (Step 2) to surface the missing piece before re-attempting.
1. The skeleton is already at `<serie>/NN-skjelett.md` (step 3).
2. Render it to review HTML with the plugin-owned renderer (cwd = series folder):
```bash
cd <serie-mappe> && node "${CLAUDE_PLUGIN_ROOT}/render/build-html.mjs" NN-skjelett.md
```
Check the exit code (N3 — non-zero = no HTML produced) and confirm
`<serie-mappe>/review/NN-skjelett.html` exists before handing it off.
3. Surface `<serie-mappe>/review/NN-skjelett.html` to the operator as a
`file://` link (use `SendUserFile` if available, else a markdown `file://`
link) for the annotation pass.
4. The operator annotates in the browser and pastes the annotated markdown
back. Fold the notes into `<serie>/NN-skjelett.md` by tightening (rule 6).
5. **Receipt, not gate.** After folding in the annotations, use
`AskUserQuestion` only as a *receipt* — «skeleton revised per your notes —
JA proceed, or another round?». `AskUserQuestion` (JA / REVIDER / NEI) is
also the **fallback** gate when rendering is unavailable; it is not the
primary flow:
- **JA** — proceed to the persona-skjelett-sweep (step 5).
- **REVIDER** — another annotation round; revise and re-render.
- **NEI** — the skeleton is wrong at a load-bearing level (premise unsound,
argument-line incoherent). Return to brief calibration (Step 1) or
research (Step 2) to surface the missing piece.
Do not proceed past this gate without an explicit JA. The pipeline may not
advance to Step 3a (spine prose) until both this operator-gate AND the
@ -430,7 +464,7 @@ Next: Step 2.5 — Skeleton + section pitch (operator + persona gate BEFORE pros
- `currentPhase: "skeleton-pitch"` in `edition-state.json` (the marker that
Step 2.5 is complete and the gate has passed).
- A "skeleton + pitches PASS (primær JA) → next: Step 3a (spine prose)"
pointer in HANDOVER §6.
next-step line in `<serie>/STATE.md` (overwrite).
```
Skeleton + section pitch (BEFORE prose) — complete.
@ -490,19 +524,30 @@ Typically ~2030 % of the edition's final length.
review HTML and Step 8's POST.html require `currentPhase: "draft"` — i.e.
Step 3b complete).
4. **Operator-gate.** Present the spine draft to the operator with
`AskUserQuestion`. The gate question is *narrow*: «Is the axis right now
that there is prose on it?» Three options:
4. **Operator-gate (render + annotate — primary flow).** Render the spine draft
and let the operator annotate it in the browser. The gate question stays
*narrow*: «Is the axis right now that there is prose on it?»
- **JA** — the axis lands as prose; proceed to Step 3b (full expansion).
- **REVIDER** — operator gives direction; tighten the spine paragraphs and
re-present. Stay in 3a; do NOT slip into expansion. (Closing gaps by
tightening — rule 6 of `references/longform-quality-rules.md` — applies
here just as it does in Steps 49.)
- **NEI** — the axis still fails as prose. Return to Step 2.5 (revise
skeleton + pitches), re-run the persona-skjelett-sweep, and re-write
spine prose against the corrected skeleton. Do not paper over a NEI by
pressing forward into expansion.
1. Spine prose is written to `<serie>/NN-utkast.md` (step 3). Render it to a
review page (cwd = series folder):
```bash
cd <serie-mappe> && node "${CLAUDE_PLUGIN_ROOT}/render/build-html.mjs" NN-utkast.md
```
Check the exit code and confirm `<serie-mappe>/review/NN-utkast.html` exists.
2. Surface the `file://` link (`SendUserFile` if available, else a markdown
`file://` link).
3. The operator annotates and pastes back; fold the notes in by tightening
(rule 6 of `references/longform-quality-rules.md`).
4. **Receipt, not gate.** `AskUserQuestion` as a receipt — «spine revised per
your notes — JA proceed to expansion, or another round?» (also the fallback
gate when rendering is unavailable):
- **JA** — the axis lands as prose; proceed to Step 3b (full expansion).
- **REVIDER** — tighten the spine paragraphs and re-render. Stay in 3a; do
NOT slip into expansion.
- **NEI** — the axis still fails as prose. Return to Step 2.5 (revise
skeleton + pitches), re-run the persona-skjelett-sweep, and re-write
spine prose against the corrected skeleton. Do not paper over a NEI by
pressing forward into expansion.
The pipeline may not advance to Step 3b without an explicit JA. `[OPERATØR]`
@ -512,8 +557,8 @@ Typically ~2030 % of the edition's final length.
with the expanded prose).
- `currentPhase: "spine-prose"` in `edition-state.json` (the marker that 3a
is complete and the gate has passed).
- A "spine prose JA → next: Step 3b (full prose expansion)" pointer in
HANDOVER §6.
- A "spine prose JA → next: Step 3b (full prose expansion)" next-step line in
`<serie>/STATE.md` (overwrite).
```
Spine prose (BEFORE full expansion) — complete.
@ -538,8 +583,8 @@ turning-points the spine already named.
> single session's context budget. If you approach the budget mid-expansion,
> stop cleanly, write the partial draft to `<serie>/NN-utkast.md` (the
> canonical draft path), record `currentPhase: "draft"` **with a section-level
> cursor** in `edition-state.json`, and append a precise "draft resumes at
> section <X>" pointer to the edition-HANDOVER §6. The next session re-reads
> cursor** in `edition-state.json`, and write a precise "draft resumes at
> section <X>" line to `<serie>/STATE.md` (overwrite). The next session re-reads
> Step 0, picks up the cursor, and continues. Never start the consistency
> pass (Step 4) on a half-written expansion. (Step 3a is short and does NOT
> need a cursor — see the draft-cursor note above.)
@ -581,8 +626,8 @@ turning-points the spine already named.
spine-prose state — this is the SAME canonical filename Steps 7 and 8
render from; `render/build-html.mjs` and `render/build-linkedin.mjs`
silently skip any draft without an `NN` prefix). Set
`currentPhase: "draft"` in `edition-state.json`, and append a "draft
complete → next: consistency/quality" pointer to the HANDOVER §6.
`currentPhase: "draft"` in `edition-state.json`, and write a "draft
complete → next: consistency/quality" line to `<serie>/STATE.md` (overwrite).
```
Full prose expansion — complete (or: partial — resumes at section <X>).
@ -629,9 +674,25 @@ checklist (full detail + pass/flag criteria in the reference file):
7. **Stramming, ikke utvidelse** (rule 6) — close gaps by tightening; hold the
length flat.
**De-AI / voice scrub (sub-pass — `voice-scrubber`).** After the rule pass, run
the draft through `voice-scrubber` (Opus) — `Task`, `subagent_type:
linkedin-thought-leadership:voice-scrubber`, from THIS command layer in the
foreground (principle 4). Pass it the draft path AND the paths to the **approved
Norwegian editions** as the gold standard (e.g. earlier parts' locked
`linkedin/NN/POST.html` or their approved `NN-utkast.md`). **Do NOT** point it at
`assets/voice-samples/authentic-voice-samples.md` — that corpus is English
short-form and forbids the em-dash; using it as the gold standard would degrade
the Norwegian chronicle voice. The scrubber runs two passes: Pass 1 strips
AI-tells (objective — «la meg være ærlig», reflex rule-of-three, em-dash-spam,
self-referential overhead, modell-/navne-katalog), Pass 2 corrects drift toward
the chronicle voice (calibrated to the gold standard). Fold its scrubbed draft +
change log back **by tightening**; route its flagged items (intentional evolution,
modell-/navne-katalog collapse) to the operator. Voice-MATCH remains
non-self-certified — that verdict stays with the Step 6 persona sweep / operator.
After the pass, set `currentPhase: "consistency-quality"` in `edition-state.json`
and append a "quality pass complete → next: fact-check sweep" pointer to the
HANDOVER §6.
and write a "quality pass complete → next: fact-check sweep" line to
`<serie>/STATE.md` (overwrite).
```
Consistency + quality pass complete.
@ -703,18 +764,18 @@ because it "feels" right or because it sits in your own research notes.
**freshness flag** to re-verify on publish day — a checklist item, not a text
weakness.
6. **Persist + checkpoint state.** Write the merged verification log into the
edition-HANDOVER §4 (immutable rules + fact-check log — the durable record of
what was checked), set `currentPhase: "factcheck-sweep"` in `edition-state.json`,
and append a "fact-check complete → next: persona sweep (BEFORE lock)" pointer
to the HANDOVER §6.
6. **Persist + checkpoint state.** Write the merged verification log into
`edition-state.json``articles.NN.factcheckLog` (the durable, machine-readable
record of what was checked — this is where the old HANDOVER §4 log now lives),
set `currentPhase: "factcheck-sweep"`, and write a "fact-check complete → next:
persona sweep (BEFORE lock)" line to `<serie>/STATE.md` (overwrite).
```
Fact-check sweep complete.
- Claims checked: <N> across <N> parallel blocks
- 🔴 High risk: <N> → all resolved (sourced/softened/cut)
- 🟡 Unverified: <N> → <resolved / framed as opinion>
- 🟢 Verified: <N> (sources logged to HANDOVER §4)
- 🟢 Verified: <N> (sources logged to edition-state.json factcheckLog)
- Freshness flags (re-verify on publish day): <N or none>
Gate: [PASS — zero unresolved 🔴] (else REWORK/BLOCK with the open claims)
Next: Step 6 — Persona sweep (reader jury, BEFORE lock).
@ -769,9 +830,10 @@ reopening locked texts — the biggest single process error of the series (plan
the personas whose verdicts are still open.
5. **Persist + checkpoint state.** Record the final per-persona verdicts and the
resolved flags in the edition-HANDOVER §5 (method / persona calibration), set
`currentPhase: "persona-sweep-prelock"` in `edition-state.json`, and append a "persona sweep
PASS (primær JA) → next: lock/delivery" pointer to the HANDOVER §6.
resolved flags in `edition-state.json``articles.NN.personaSweep.resonance`
(where the old HANDOVER §5 calibration now lives), set
`currentPhase: "persona-sweep-prelock"`, and write a "persona sweep
PASS (primær JA) → next: lock/delivery" line to `<serie>/STATE.md` (overwrite).
```
Persona sweep complete (BEFORE lock).
@ -821,8 +883,8 @@ editor is satisfied with the in-session draft. It does not gate lock.
substantive, re-run the affected sweep (Step 5 or 6) before proceeding.
4. **Persist.** Set `currentPhase: "annotation"` in `edition-state.json` and
append an "annotation rendered (optional) → next: lock/delivery" pointer to
the HANDOVER §6. If skipped, note "annotation skipped" and move on.
write an "annotation rendered (optional) → next: lock/delivery" line to
`<serie>/STATE.md` (overwrite). If skipped, note "annotation skipped" and move on.
```
Annotation (optional).
@ -939,7 +1001,7 @@ the post-lock conversion sweep, distinct from the pre-lock resonance sweep
conversion check. Loop until JA. `[GATE]`
4. **Persist.** Record the conversion verdict in
`edition-state.json``articles.NN.personaSweep.conversion` (and HANDOVER §5),
`edition-state.json``articles.NN.personaSweep.conversion`,
and set `currentPhase: "hook-conversion-gate"`.
```
@ -984,9 +1046,9 @@ now a first-class scheduled post.
3. **Persist + close the edition.** Set the article's `status: "scheduled"`,
`scheduled: "<YYYY-MM-DD HH:MM>"`, and `currentPhase: "scheduling"` in
`edition-state.json`. Append a closing "edition scheduled → mark live via
`/linkedin:calendar` on <date>" pointer to the HANDOVER §6. The pipeline is
complete.
`edition-state.json`. Write a closing "edition scheduled → mark live via
`/linkedin:calendar` on <date>" line to `<serie>/STATE.md` (overwrite). The
pipeline is complete.
```
Scheduling.
@ -1003,10 +1065,10 @@ Edition complete. Visible in /linkedin:calendar; mark live via /linkedin:calenda
- `${CLAUDE_PLUGIN_ROOT}/config/edition-state.template.json` — edition-state schema (13 phases including v2.1 skeleton + spine-prose gates)
- `${CLAUDE_PLUGIN_ROOT}/config/edition-config.template.json` — static delivery metadata schema (calendar, freshness, credit, captions) — Step 8
- `${CLAUDE_PLUGIN_ROOT}/config/edition-delingstekst.template.md` — distribution-copy grammar (`## Del N —` / `## Samle`) — Steps 8/9
- `${CLAUDE_PLUGIN_ROOT}/config/edition-HANDOVER.template.md` — narrative production-state structure (§1§6) — Step 0
- `${CLAUDE_PLUGIN_ROOT}/config/personas.template.md` — reusable reader personas + "primær trumfer" rule
- `${CLAUDE_PLUGIN_ROOT}/agents/fact-checker.md` — Step 5 fact-check agent (risk-sorted, guilty-until-disproven)
- `${CLAUDE_PLUGIN_ROOT}/agents/persona-reviewer.md` — Step 2.5/6/9 reader jury (skeleton + resonance + conversion modes)
- `${CLAUDE_PLUGIN_ROOT}/agents/voice-scrubber.md` — Step 4 de-AI / Norwegian-chronicle voice scrub (gold standard = approved Norwegian editions, NOT the English post corpus)
- `${CLAUDE_PLUGIN_ROOT}/commands/react.md` — multi-source synthesis discipline (reused in Step 2)
- `${CLAUDE_PLUGIN_ROOT}/assets/voice-samples/authentic-voice-samples.md` — voice matching
- `${CLAUDE_PLUGIN_ROOT}/references/longform-quality-rules.md` — canonical long-form rules (Steps 2.5, 3a, 3b, 49 all reference)