feat(linkedin): v2.1.0 — skeleton + spine-prose gates BEFORE prose in /linkedin:newsletter

Two new pipeline phases gate the spine before any prose is written:

- Step 2.5 — Skeleton + section pitch: writes <serie>/NN-skjelett.md with
  the five-line spine (premiss / problem / anbefaling / gevinst / vei
  videre) + one-line section pitches. Operator-gate (JA / REVIDER / NEI)
  AND parallel persona-skjelett-sweep must both return JA before the
  pipeline can advance.
- Step 3a — Spine prose: one paragraph per section against the gated
  skeleton, ~20-30% of final edition length. Operator-gate on whether the
  axis lands now that there is prose on it. Old Step 3 (Draft) split into
  3a (spine) and 3b (full expansion); 3b owns the multi-session
  draft-cursor logic.

Third persona-reviewer mode added: skjelett (alongside resonans + konverter).
Five spine axes scored HOLDER / TVILER / MANGLER, max 3 direction-only flags,
per-pitch section-pay-in check. Reads the skeleton + pitches only.

Pipeline grows from 11 to 13 phases; commands (24) and agents (14) counts
unchanged. Encodes the Maskinrommet writing-contract section A discipline
(premiss / problem / anbefaling / gevinst / vei videre) into the pipeline.

Empirically motivated by the Seres-serien Del 3 + Del 4 production:
a spine error caught at the skeleton stage costs 5-15 min, the same
error caught at Step 6 (resonance) costs 4-12 h, post-lock it costs a
day of cascading rework (delingstekst, hooks, carousel, doc refs).

Backward-compatible: existing editions stop at currentPhase: "research"
and now resume at Step 2.5 instead of Step 3 — an intended deterministic
improvement, never a contract break. Steps 1, 2, 4-10 bit-for-bit
unchanged. Renderers (build-html.mjs, build-linkedin.mjs) untouched.

New phase strings in edition-state.template.json _doc.phases:
- skeleton-pitch (between research and draft)
- spine-prose (between skeleton-pitch and draft)

Files changed (10):
- plugin.json: 2.0.0 -> 2.1.0
- CHANGELOG.md: new [2.1.0] entry
- CLAUDE.md (plugin + marketplace): pipeline 11->13 phases noted
- README.md (plugin + marketplace): What's New v2.1.0 + version row
- agents/persona-reviewer.md: third mode skjelett added; resonans + konverter unchanged
- commands/newsletter.md: Step 2.5 + 3a + 3b sections, resumption + pipeline tables
- config/edition-state.template.json: 11 -> 13 phases in _doc.phases
- references/longform-quality-rules.md: Rule 8 (Skjelett foer prosa)

Verification: 9/9 criteria PASS pre-commit. Phase strings consistent
across template + command + resumption table. Renderer files git-untouched.
All 11 original step headings preserved (Step 0/1/2/4-10).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-05-28 10:09:47 +02:00
commit 2a27a7cd6a
10 changed files with 615 additions and 141 deletions

View file

@ -59,17 +59,21 @@ delegate the fan-out to a nested background agent.
> only layer that can reliably spawn parallel sub-agents. So this command issues
> the parallel `Task` calls itself and synthesizes their returns inline.
## Pipeline overview (11 phases)
## Pipeline overview (13 phases)
The phase order is fixed. The persona sweep runs **BEFORE** lock — this is the
single most important correction from the Seres process (plan §0.4, principle 5).
The phase order is fixed. Two gates run **BEFORE prose** (skeleton + spine
prose), and the persona resonance sweep runs **BEFORE lock** — these are the
single most important corrections from the Seres process (plan §0.4, principle
5; v2.1 brief §1 on spine-error cost).
| Step | Phase | What | Tools |
|------|-------|------|-------|
| 0 | **Load context** | edition-state/HANDOVER, 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)** |
| 3 | **Draft** | dramaturgical order, voice-matched; may span sessions | `content-repurposer` + `Task` |
| 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` |
| 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) |
@ -78,12 +82,23 @@ single most important correction from the Seres process (plan §0.4, principle 5
| 9 | **Hook / conversion gate** | persona gate on the distribution text post-lock: "would YOU click?" | **`persona-reviewer`** (conversion mode) |
| 10 | **Scheduling** | register the edition in the plugin queue/state for native scheduling | `hooks/scripts/queue-manager.mjs` |
> **Build status:** all 11 phases (Steps 010) are implemented below. This
> command takes an edition end-to-end: load → calibration → verified research →
> 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.
> **Build status:** all 13 phases (Steps 02.5, 3a, 3b, 410) are implemented
> below. This command takes an edition end-to-end: load → calibration →
> verified research → **skeleton + section pitch (operator + persona gate
> 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.
> **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
> spine-prose stage 3060 min, at the resonance stage (Step 6) 412 h, and
> post-lock a whole day of cascading rework (delingstekst, hooks, carousel,
> doc references). Steps 2.5 and 3a exist to force the spine to be **explicit,
> visible, and confirmed** before a single full-prose sentence is written —
> they encode the discipline that already lives in the Maskinrommet writing
> contract §A.
---
@ -144,7 +159,9 @@ Look up `edition-state.json` → `articles.<currentArticle>` (and the top-level
| *(no state file)* | **NEW edition** → Step 1 (init state at end of Step 2) |
| `load-context` | Step 1 — Brief + calibration |
| `brief-calibration` | Step 2 — Research |
| `research` | Step 3 — Draft |
| `research` | Step 2.5 — Skeleton + section pitch *(v2.1 — skeleton gate BEFORE prose)* |
| `skeleton-pitch` | Step 3a — Spine prose *(v2.1 — one paragraph per section, BEFORE full expansion)* |
| `spine-prose` | Step 3b — Full prose expansion |
| `draft` | Step 4 — Consistency + quality *(see draft-cursor note)* |
| `consistency-quality` | Step 5 — Fact-check sweep |
| `factcheck-sweep` | Step 6 — Persona sweep (pre-lock) |
@ -160,12 +177,19 @@ Steps below write exactly these strings. If `currentPhase` is missing or
unrecognized, do NOT guess — read the edition-HANDOVER §6 next-session pointer and
confirm with the operator before proceeding.
**Draft-cursor note (Step 3 only).** `draft` is the one phase that can be
*partial*: if Step 3 stopped mid-draft 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"`, check for that cursor first — if present,
re-enter **Step 3** at the cursor and finish the draft before Step 4; only when the
HANDOVER records "draft complete" do you resume at **Step 4**.
**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"`,
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
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
is interrupted, `currentPhase` stays at `skeleton-pitch` and the resume point
is "Step 3a — restart from section 1" (one short paragraph per section against
the gated skeleton — typically minutes, not session-length work).
> **Resumption is the deterministic test (plan §10, archetype E).** Abort after
> Step 6 → `currentPhase` is `persona-sweep-prelock` → re-run → the table resumes
@ -272,9 +296,11 @@ 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: draft" pointer to the edition-HANDOVER §6. If this
is a fresh edition, initialize `edition-state.json` from the template schema
first. Then stop cleanly — drafting (Step 3) begins in the next session.
"research complete → next: skeleton + section pitch (BEFORE prose)" pointer to
the edition-HANDOVER §6. 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).
```
Research phase complete.
@ -282,64 +308,289 @@ Research phase complete.
- Verified notes: <N> by key point
- Carried to fact-check (🟡 unverified): <N>
State written: <serie>/linkedin/edition-state.json (phase: research)
Next session: Step 3 — Draft.
Next: Step 2.5 — Skeleton + section pitch (operator + persona gate BEFORE prose).
```
---
## Step 3: Draft — dramaturgical order, voice-matched
## Step 2.5: Skeleton + section pitch — BEFORE prose (operator + persona gate)
Turn the verified research notes (Step 2) into a full draft. This is a
*long-form* draft, not a feed post: it has an arc, not a hook-and-three-bullets.
> **This is the cheapest gate in the pipeline (v2.1 brief §6).** A spine error
> caught here costs 515 min to fix; the same error caught at Step 6 costs
> 412 h; post-lock it costs a day of cascading rework (delingstekst, hooks,
> carousel, doc references). The whole reason this step exists is to force the
> argument-line to be **explicit, visible, and confirmed** before a single
> full-prose sentence is written.
> **This phase may span multiple sessions.** A long edition can exceed a single
> session's context budget. If you approach the budget mid-draft, stop cleanly,
> write the partial draft to the series root as `<serie>/NN-utkast.md` (the
> canonical draft path — see step 4), 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 Step 0, picks up the cursor, and continues. Never start the
> consistency pass (Step 4) on a half-written draft.
> **Order assertion (enforced).** Step 2.5 runs AFTER research (Step 2) and
> BEFORE any prose (Step 3a). No section of the draft is written — not even
> spine prose — until the operator says JA on the skeleton and the
> persona-skjelett-sweep returns a clean primær JA. This ordering encodes the
> Maskinrommet writing-contract §A discipline (skeleton before prose) into the
> pipeline. `[GATE]`
**Procedure:**
1. **Re-read the voice profile** (`assets/voice-samples/`) before writing a single
sentence — this is the existing LTL rule and it is not optional for long-form.
The draft must read as the author, not as generic LinkedIn prose.
1. **Propose the five-line skeleton.** Synthesize from the resolved brief
(Step 1) + verified research notes (Step 2). The format is fixed — five
lines, one per slot, each one sentence:
2. **Lay out the dramaturgical order** from the brief (Step 1) and notes (Step 2):
- **Ingress + first paragraph** establish ONE clear premise (this is the front
half of the premise→conclusion arc enforced in Step 4).
- **Body** develops the 24 key points in the order that builds tension, each
anchored to a verified note. Carry each note's source marker inline as a
comment so the Step 5 fact-check sweep can find it.
- **Conclusion** grips the premise concretely and twists it forward (direction +
one concrete grip) — it does not merely summarize.
- **Premiss** — what must the reader accept for the rest to land?
- **Problem** — what stands in the way, concretely named?
- **Anbefaling** — what should the reader think or do differently?
- **Gevinst** — what do they win?
- **Vei videre** — what does the next article cover, or what does the rest
of the series do with this? (N/A for standalone editions — say so
explicitly.)
3. **Draft with the `content-repurposer` muscle.** Reuse `agents/content-repurposer.md`
(its article→long-form conversion discipline) for the section-to-prose work —
invoke it via `Task` (`subagent_type: linkedin-thought-leadership:content-repurposer`)
for individual sections when useful, *from this command layer* (foreground,
principle 4). The command owns assembly and voice; the
agent assists with conversion. The draft is voice-matched by THIS session, not
self-certified for voice — voice-match remains an `[OPERATØR]` / `[GATE:
voice-trainer]` judgment, never auto-passed (plan §10.0).
2. **Propose section pitches — one line per section.** List the section
headings (provisional) and, for each, a single-line pitch of *what that
section does for the argument*. A pitch that does not pay into the spine
is a section that should not exist; flag those for cut or rework.
4. **Write the draft** to the **series root** as `<serie>/NN-utkast.md` (NN =
zero-padded edition number — the SAME filename Steps 7 and 8 render from).
This is the single canonical draft path: `render/build-html.mjs` (Step 7) and
`render/build-linkedin.mjs` (Step 8) both consume `NN-utkast.md` from cwd, and
the renderer **silently skips** any draft without an `NN` prefix. Do NOT write
to `linkedin/<article>.draft.md` — that path is skipped at render. Set
`currentPhase: "draft"` in `edition-state.json`, and append a "draft complete →
next: consistency/quality" pointer to the HANDOVER §6.
3. **Write the skeleton + pitches to `<serie>/NN-skjelett.md`** (NN = the same
zero-padded edition number used by `NN-utkast.md`, new suffix). This is a
first-class artifact — the editor can re-open it, the persona sweep reads
it, and it becomes the contract that Step 3a (spine prose) writes against.
Suggested file structure:
```markdown
# Skjelett — Del NN «<provisional title>»
## Spine
- **Premiss:**
- **Problem:**
- **Anbefaling:**
- **Gevinst:**
- **Vei videre:** … (or: N/A — standalone edition)
## Seksjons-pitcher
1. <heading> — <one-line pitch>
2. …
```
4. **Operator-gate (first round).** Present the skeleton + pitches to the
operator with `AskUserQuestion`. Three options:
- **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.
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
persona-skjelett-sweep below return JA. `[OPERATØR]`
5. **Persona-skjelett-sweep — fan out `persona-reviewer` in skjelett-mode.**
Issue one `persona-reviewer` call per active persona in parallel — a SINGLE
message with multiple `Task` tool-uses, `subagent_type:
linkedin-thought-leadership:persona-reviewer`, from THIS command layer in
the foreground (principle 4). Pass each call the persona name, the path to
`<serie>/NN-skjelett.md`, and **`mode: skjelett`** (the before-prose mode —
five spine axes, ≤3 flags as direction, HOLDER/TVILER/MANGLER scoring).
This is NOT resonans mode (Step 6 — that runs on full prose) and NOT
konverter mode (Step 9 — that judges the hook only).
6. **Collect skjelett verdicts and gate.** Each call returns per-axis flags
(HOLDER/TVILER/MANGLER), ≤3 direction-only flags, a section-pitch check
(any pitch that does not pay in), a per-persona verdict (JA/NEI), and a
gate decision. Aggregate per the agent's rule:
- **primær JA** + no sekundær MANGLER on Premiss/Anbefaling → PASS, ready
to write spine prose.
- **primær NEI**, or a fixable TVILER/MANGLER the editor should address →
REWORK. Revise the skeleton + pitches; re-run the sweep on the revision.
- **primær MANGLER on Premiss or Anbefaling** → BLOCK. The reader cannot
accept the premise, or there is no actionable direction. Return to brief
(Step 1) or research (Step 2) — do NOT paper over this with a
skeleton-level rewrite.
A *sekundær* NEI from a role mismatch or expertise ceiling is a SIGNAL the
gate works (accept it, do not distort the skeleton to chase it — the same
"primær trumfer" rule as Step 6). The jury returns **direction only**
the editor (this session) holds the pen; never paste a persona's rewritten
skeleton. `[GATE]`
7. **Convergence loop.** If gate is REWORK/BLOCK, fold flags into the
skeleton + pitches (or, on BLOCK, return upstream) and re-run the same
`persona-reviewer` calls against the revision. Loop until the primær
returns a clean JA. This loop is **cheap and frequent at this stage**
every round saved here is hours saved at the prose stage.
8. **Persist + checkpoint state.** Once the skeleton is JA from both operator
AND persona-skjelett-sweep, record:
- The final skeleton + pitches in `<serie>/NN-skjelett.md` (already written
in step 3, with any in-loop revisions applied).
- Per-persona skjelett verdicts in
`edition-state.json``articles.NN.personaSweep.skeleton` (or alongside
resonance/conversion under the same `personaSweep` object).
- `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.
```
Draft complete (or: partial — resumes at section <X>).
- Premise established: <one line>
- Key points drafted: <N>/<N>
Skeleton + section pitch (BEFORE prose) — complete.
- Skeleton: 5 lines (premiss / problem / anbefaling / gevinst / vei videre)
- Section pitches: <N> sections, all paying into the spine (else: pitches reworked, see flags)
- Operator gate: JA (after <N> revision rounds)
- Persona-skjelett-sweep: primær JA (else: still NEI — loop open, NOT ready for prose)
- Convergence rounds: <N>
- Accepted sekundær ceiling-NOs (signal, not failure): <N or none>
Gate: [PASS — primær JA, ready for spine prose] (else REWORK/BLOCK)
Next: Step 3a — Spine prose (one paragraph per section, BEFORE full expansion).
```
---
## Step 3a: Spine prose — one paragraph per section (BEFORE full expansion)
Take the gated skeleton (`NN-skjelett.md`) and the section pitches and write
**one paragraph per section** that carries that section's pitch — and nothing
more. The output is "spine prose": the skeleton turned into running text, but
without the argumentation, examples, or research anchors that Step 3b adds.
Typically ~2030 % of the edition's final length.
> **Order assertion (enforced).** Step 3a runs AFTER the Step 2.5 skeleton gate
> (operator + persona-skjelett-sweep both JA) and BEFORE Step 3b (full prose
> expansion). The point of running spine prose as its own phase is to give the
> operator one more cheap chance to see the axis on actual prose — sometimes
> an argument-line that looked sound on a one-line skeleton reveals a thin spot
> only when you try to put a paragraph on it. `[GATE]`
**Procedure:**
1. **Re-read the voice profile** (`assets/voice-samples/`) before writing a
single sentence — this is the existing LTL rule and it is not optional for
long-form. Voice match starts at the spine, not at expansion.
2. **For each section in `NN-skjelett.md`, write ONE paragraph that delivers
that section's pitch.** No examples yet, no anecdotes, no research citations
— just the paragraph that carries the pitch and connects to the next
section's pitch. Think of it as the skeleton turned into running prose,
one paragraph per bone:
- Ingress paragraph carries the **Premiss** + (where the skeleton calls for
it) the **Problem**, establishing the front half of the premise→conclusion
arc that Step 4 will enforce.
- Each body paragraph carries one section pitch (one pitch = one paragraph).
- Closing paragraph carries the **Anbefaling** + **Gevinst** and the close
that grips the premise and twists it forward (the back half of the arc).
- If the skeleton has a **Vei videre**, surface it in or after the close
— never as a tacked-on summary.
3. **Write the spine draft** to `<serie>/NN-utkast.md` (the canonical draft
path — Steps 7 and 8 render this exact file). This is the same `NN-utkast.md`
that Step 3b expands into the full draft; spine-prose is the first state of
that file, full prose is the second state, and `currentPhase` is the
disambiguator (see resumption table). Do NOT render in this state (Step 7's
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:
- **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.
The pipeline may not advance to Step 3b without an explicit JA. `[OPERATØR]`
5. **Persist + checkpoint state.** Once the operator says JA:
- `NN-utkast.md` holds the spine-prose draft (will be overwritten by Step 3b
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.
```
Spine prose (BEFORE full expansion) — complete.
- Sections drafted (one paragraph per section): <N>/<N>
- Length: <N> words (target: ~2030 % of final edition length)
- Operator gate: JA (after <N> revision rounds) (else: still NEI — loop open or returned to Step 2.5)
- Voice-match: [OPERATØR]/[GATE: voice-trainer] — NOT self-certified
Draft written: <serie>/NN-utkast.md (series root, NN-prefixed — Steps 7/8 render this exact file)
Draft written: <serie>/NN-utkast.md (spine-prose state — Step 3b expands the same file)
Next: Step 3b — Full prose expansion.
```
---
## Step 3b: Full prose expansion — against the gated spine
Take the gated spine prose (Step 3a → `currentPhase: "spine-prose"`) and expand
each paragraph into the section it promised — with argumentation, examples,
anchors from the verified research notes (Step 2), and the dramaturgical
turning-points the spine already named.
> **This phase may span multiple sessions.** A long edition can exceed a
> 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
> 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.)
**Procedure:**
1. **Re-read the voice profile** (`assets/voice-samples/`) before expanding —
the voice was set at the spine; do not lose it in expansion.
2. **Expand section by section, against the spine.** Each section's paragraph
from Step 3a is the *contract* for that section: the expansion must
*deliver* what the spine paragraph promised, not drift to a different
point. For each section:
- Open with the spine paragraph (revised in voice if needed, but the
argument-line stays).
- Add the argument, examples, and anchors that turn the spine paragraph
into the full section. Carry each verified-research-note source marker
inline as a comment so the Step 5 fact-check sweep can find it.
- Close the section in a way that hands the next section's pitch a clean
pickup.
Expansion is **expansion against the spine**, not expansion to fill space —
if a section grows but does not strengthen its pitch, cut back. (Rule 6 of
`references/longform-quality-rules.md`, applied during writing rather than
only afterward.)
3. **Expand with the `content-repurposer` muscle.** Reuse
`agents/content-repurposer.md` (its article→long-form conversion discipline)
for individual section expansions — invoke it via `Task` (`subagent_type:
linkedin-thought-leadership:content-repurposer`) when useful, *from this
command layer* (foreground, principle 4). The command owns assembly and
voice; the agent assists with conversion. The draft is voice-matched by
THIS session, not self-certified for voice — voice-match remains an
`[OPERATØR]` / `[GATE: voice-trainer]` judgment, never auto-passed (plan
§10.0).
4. **Write the expanded draft** to `<serie>/NN-utkast.md` (overwriting the
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.
```
Full prose expansion — complete (or: partial — resumes at section <X>).
- Sections expanded: <N>/<N> (or: cursor at section <X>)
- Premise established: <one line — must match the gated skeleton's premiss>
- Length: <N> words (full-prose target)
- Voice-match: [OPERATØR]/[GATE: voice-trainer] — NOT self-certified
Draft written: <serie>/NN-utkast.md (full-prose state — Steps 7/8 render this exact file)
Next: Step 4 — Consistency + quality.
```
@ -749,14 +1000,15 @@ Edition complete. Visible in /linkedin:calendar; mark live via /linkedin:calenda
## Reference Files
- `${CLAUDE_PLUGIN_ROOT}/config/edition-state.template.json` — edition-state schema (11 phases)
- `${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 6/9 reader jury (resonance + conversion modes)
- `${CLAUDE_PLUGIN_ROOT}/agents/persona-reviewer.md` — Step 2.5/6/9 reader jury (skeleton + resonance + conversion modes)
- `${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)
- `${CLAUDE_PLUGIN_ROOT}/render/build-linkedin.mjs` — POST.html delivery (Step 8)
- `${CLAUDE_PLUGIN_ROOT}/render/build-html.mjs` — annotatable review renderer (Step 7)