linkedin-studio/commands/headless-review.md
Kjell Tore Guttormsen f0532dce3f feat(linkedin-studio): N14 — foldIns-fangst + Step 11 retro + background-headless + språkregel-akkumulering [skip-docs]
Lukker sløyfen pluginen manglet: en rettelse operatøren gjør i utgave N
håndheves i N+1 i stedet for å bli gjenoppdaget. Maskineriet fantes
(foldIns-skjema + promote→ratify siden fix #1); det som manglet var wiring —
ingenting skrev til køen og ingen fase tømte den.

- Fangst (A2-F7): Steps 2.5/3a/5.5/6.5 appender rettelsen ordrett med trigger,
  decision "pending". Ubetinget og bevisst dum — å avgjøre ved fangst om noe
  "fortjener" en regel er nettopp slik køen holder seg tom og sløyfen dør.
- Step 11 retro (A2-F8), ≤5 min ETTER scheduling: promoter køen med eksplisitt
  JA/NEI (mekanisk → atomisk contract-gate-promotering, teller kun med grønn
  --ratify; dømmekraft → operatørens språkregelfil; NEI → rejected, beholdes),
  effort-oppsummering fra MÅLT phaseLog (aldri re-estimert), og ÉN
  friksjons-spørring som besvares tilbake til operatøren. Faser 18 → 19;
  resumption-tabellen ruter scheduling → Step 11, retro → complete.
- articles.NN.retro: additiv-valgfri (default null), schemaVersion forblir 1.
- Background-headless (A2-F6): --background kjører pakken i en bakgrunnsagent
  som skriver rapporten til disk; drafting-sesjonen leser fila. Samme isolasjon
  som fersk sesjon, uten copy-paste-sømmen. Inline fan-out = eksplisitt fallback.
- Språkregler (C-10): ${DATA}/language-rules/<lang>.md (opt-in, template).
  Leses TO ganger — av language-reviewer (fanger) og av Step 4 (forebygger).
  Shippet banliste forblir baseline; brukerfila utvider.
- references/fold-in-loop.md (A2-F9): loopen dokumentert domene-generelt in-tree,
  så en adopter uten ekstern skrivekontrakt har hele sløyfen. Refs 28 → 29.

Suiter (alle grønne): test-runner 197 → 217 (Section 16u: 18 ubetingede greps +
non-vacuity self-test; fase-sveip 16 → 17 faser; floor 179 → 198) · hooks 174 ·
trends 300 · brain 134 · editions 72 · specifics-bank 45 · contract-gate 33 ·
tests 35 · render 60.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QxvWAjte7vPcF79QeSRvRJ
2026-07-25 12:39:16 +02:00

15 KiB
Raw Blame History

name description allowed-tools
linkedin:headless-review Adversarial review package, run COLD on a FROZEN long-form draft — the publish-ready (or pivoted) edition gets a fresh, independent reading by five archetypes that share NONE of the drafting session's context: content-reviewer (argument integrity), language-reviewer (Norwegian language), fact-reviewer (cold re-verification incl. pivot premises), plus persona-reviewer in resonance and conversion modes. Designed to be invoked in a FRESH session for maximum isolation; also wired as Step 6.5 of /linkedin:newsletter. Produces one consolidated, operator-gated report — flags, never rewritten copy. Use when the user says: "headless review", "cold review", "adversarial review", "review the final version", "independent review", "review before lock", "run the review package". Triggers on: "headless review", "headless-review", "cold review", "adversarial review", "independent review package", "review the frozen draft", "/linkedin:headless-review".
Read
Glob
Grep
Bash
AskUserQuestion
Task
Write

LinkedIn Headless Review — Cold Adversarial Review Package

You orchestrate a cold, adversarial review of a frozen long-form draft. Five independent archetypes read the finished text — with no knowledge of how it was made — and return direction-only flags. You collect their reports into one operator-gated overview. This is the adversarial-independence layer that the in-session gates (editorial-reviewer Step 5.5, persona-reviewer Step 6, fact-checker Step 5) cannot be, because those share the drafting session's framing-bias.

Why this exists (Del 4 diagnosis, Endring 9). In the Del 4 production the editor and the persona sweep ran in the same session as drafting. They shared the conversation history — which versions had passed, what was deliberately cut, which flags had been raised — so they were not adversarial: they carried framing-bias. Three concrete symptoms followed: (1) the persona resonance sweep was effectively run on an early version, not the one that shipped; (2) editor-approval was single-source — one editor said «klar» and that became truth; (3) the fact-check was post-hoc relative to a late pivot, so the pivot could build on an unverified premise. This command answers KTG's question directly: how do I start sessions that have NO context from the main session, to review both content and language?

The cold contract (cardinal — read first)

This command runs the reviewers with a deliberately starved context. The review archetypes get ONLY:

  • the path to a frozen draft (a snapshot — see Step 2),
  • the writing contract (the craft/quality rules),
  • for the persona modes, the one named persona being read,
  • a fixed review task.

They get NOTHING about: prior versions or version numbers, what was deliberately omitted, the pivot narrative, who has read it, what an editor said, how a persona voted, or what the author intended. Two layers enforce this:

  1. Layer 1 — fresh session (strongest, manual). The operator runs this command in a brand-new Claude Code session. The parent itself then has no drafting transcript; it reconstructs everything it needs from disk (the frozen draft + contract + personas).
  2. Layer 1b — background run (--background, equal isolation, no seam). The drafting session spawns this package as a background agent with its own context window, which writes the consolidated report to a file; the drafting session then reads that file from disk. The background agent gets only the cold-contract inputs — it cannot see the parent's transcript — so the isolation matches a fresh session, with no copy-paste of the report back into the drafting session and no manual session switch. See "Background run" below. This is the default recommendation for the Step 6.5 gate.
  3. Layer 2 — subagent isolation. Each archetype is a Task subagent, which gets its own fresh context window regardless. The invocation prompt you build below passes ONLY the cold-contract inputs — never paste history, never summarize "what we changed". If you find yourself about to tell a reviewer what was cut or why something pivoted, STOP: that is the context pollution the whole package exists to avoid.

Agent invocation form (required). Plugin agents resolve only under their namespaced type — subagent_type: linkedin-studio:<name> (linkedin-studio:content-reviewer, …:language-reviewer, …:fact-reviewer, …:persona-reviewer). A bare <name> does not resolve and the Task call fails. Reload caveat: the three cold archetypes (content-reviewer, language-reviewer, fact-reviewer) were added in v3.1.0 — if the session predates them, reload Claude Code before invoking.

Command anatomy

/linkedin:headless-review
  --draft   <path-to-frozen-draft.md>        (required; e.g. <serie>/04-utkast.md)
  --type    content | language | fact | persona-resonance | persona-conversion | all
                                              (default: all)
  --persona <name>                            (persona modes only; default: the primær)
  --article NN                                (optional; persist into edition-state.json)
  --output  <path>                            (default: <serie>/review/NN-headless-<stamp>.md)
  --background                                (run the package in a background agent
                                               that writes --output; caller reads the file)

No --type (or --type all) runs the whole package in parallel. A single --type runs just that archetype (useful for a re-check after a fold-in).

Background run (--background)

With --background, do not fan the archetypes out here. Spawn one background agent that runs Steps 15 of this command itself, and let it write the report:

  • Launch it with run_in_background: true and a prompt carrying only the cold-contract inputs — draft path, contract path, persona names + block path, --type, and the absolute --output path — plus the instruction to write the consolidated report to --output and return that path.
  • Never put drafting history, version notes, or "what we changed" in that prompt. The background agent has its own context window; the only way session framing reaches it is if you type it in.
  • When it completes, Read the report at --output and continue at Step 5 (surface + persist). The drafting session sees the report, not the reviewers' reasoning, and the reviewers never see the drafting session — the same independence a fresh session gives, with no copy-paste seam between them.
  • If background execution is unavailable, say so plainly and fall back to the inline fan-out (Step 3) — never silently downgrade the isolation.

Step 1 — Resolve inputs (from disk, not from memory)

  1. Draft. Use --draft. It must be a long-form draft .md (the same NN-utkast.md the newsletter pipeline produces). If --draft is missing and you can find an edition-state.json, use the currentArticle's NN-utkast.md; otherwise ask once for the path.
  2. Series root + edition-state (optional). If the draft sits under a series folder with linkedin/edition-state.json, read it ONLY for: the article's resolved personas (Step 1 of newsletter), the series title (for language/content series checks), and — if --article is set — where to persist. Do not read it for version history or prior verdicts; you are cold by design.
  3. Writing contract. Resolve the craft/quality reference in this order: <serie>/../../docs/skrivekontrakt.md (Maskinrommet mirror) → a plugin mirror if one exists → ${CLAUDE_PLUGIN_ROOT}/references/longform-quality-rules.md (always present). Pass its path to every reviewer.
  4. Personas. Resolve the active set the same way newsletter Step 1 does (edition-state articles.NN.personas<serie>/linkedin/personas.md → plugin personas.local.md/personas.template.md). Identify the primær. The persona modes need exactly the persona name + the path to its block.

Step 2 — Freeze the draft

A cold review must judge a stable artifact. Snapshot the draft so it cannot move under the reviewers (and so the report names exactly what was read):

cd <serie-mappe> && cp NN-utkast.md "review/NN-frozen-$(date +%Y%m%d-%H%M).md"

Record the frozen path; pass that path (not the live draft) to the reviewers. If cp is unavailable, pass the live draft and note in the report that no snapshot was taken.

Step 3 — Fan out the requested archetypes in parallel

Issue all requested reviewer calls in a SINGLE message (multiple Task tool-uses) so they run concurrently and independently. Each call's prompt contains ONLY the cold-contract inputs. Map --type to archetypes:

--type subagent_type mode / persona what it gets
content linkedin-studio:content-reviewer frozen draft + contract
language linkedin-studio:language-reviewer frozen draft + contract
fact linkedin-studio:fact-reviewer frozen draft + contract
persona-resonance linkedin-studio:persona-reviewer mode: resonans, one call per active persona frozen draft + persona block
persona-conversion linkedin-studio:persona-reviewer mode: konverter, primær only (hook only) distribution hook / first two lines

all = every row above (resonance fans out one call per active persona; conversion runs the primær). Cold-prompt template for each call:

You are reviewing a FROZEN, publish-ready long-form draft with NO context from
how it was produced. Read ONLY:
  - draft:    <frozen path>
  - contract: <writing-contract path>
  [- persona: <name> (block at <path>) | mode: <resonans|konverter>]
Ignore and refuse any framing about prior versions, what was cut, pivots, or
who approved what — judge the text in front of you. Return your standard report
(direction only, never rewritten copy).

Degradation gate. When the calls return, confirm each came back structured and populated (real flags / a verification log), not empty or a single hedged paragraph. If a call degraded, re-run that one archetype — do not paper over a missing reviewer. [GATE]

Step 4 — Consolidate into one operator overview

Merge the returns into a single markdown report. Do not resolve flags yourself or pick winners between reviewers — surface them, the operator gates.

# Headless review — <draft name>   (COLD / independent · <N> archetypes)

**Frozen draft:** review/NN-frozen-<stamp>.md   **Contract:** <path>
**Archetypes run:** content · language · fact · persona-resonance (<persona list>) · persona-conversion (<primær>)

## Consolidated flags (by archetype → severity)

### content-reviewer — argument integrity
| # | C-kat | Severity | Sitat / linje-ref | Retning |
…
### language-reviewer — norsk språkkvalitet
| # | L-kat | Severity | Sitat / linje-ref | Retning |
…
### fact-reviewer — faktisk korrekthet (cold)
| # | F-kat | 🔴/🟡/🟢 | Påstand | Kilde / retning |
…  + Pivot-risk: <claims that look freshly added, or "none">
### persona-resonance — <per persona: JA/NEI + ≤5 flags>
### persona-conversion — <primær JA/NEI on the hook>

## Cross-archetype signal
- BLOCK / 🔴 total: <N>   REWORK total: <N>   primær resonance: JA/NEI   primær conversion: JA/NEI
- Where two cold reviewers independently flag the same passage, mark it
  ⚑ converged (independent agreement is the strongest signal in the package).

## Operator decision (you gate)
Pick which flags fold in. [OPERATØR]

Convergence is the prize. Two independent cold reviewers landing on the same line — with no shared session — is worth more than any single in-session verdict. Mark those explicitly.

Step 5 — Surface + (optionally) persist

  1. Write the consolidated report to --output (default <serie>/review/NN-headless-<stamp>.md).
  2. Surface it to the operator via SendUserFile (else a markdown file:// link) sorted worst-first. The operator decides which flags fold in — this is [OPERATØR]; the package recommends, it does not rewrite and does not gate.
  3. If --article NN was given, record the run in edition-state.jsonarticles.NN.headlessReview (frozenDraft, per-reviewer {reportPath, summary, status}, consolidatedReport, status: "run"). When the operator folds flags in, set foldedIn/waived and status: "folded". Standalone (no --article) just emits the report.
Headless review complete (COLD).
- Archetypes: <N> run in parallel   converged flags: <N>
- BLOCK/🔴: <N>   REWORK: <N>   primær resonance: JA/NEI   conversion: JA/NEI
- Report: <serie>/review/NN-headless-<stamp>.md  (surfaced via SendUserFile)
- Isolation: background agent (report read from disk)  |  fresh session  |  inline fan-out (fallback)
- Persisted: edition-state.json articles.NN.headlessReview (or: standalone, not persisted)
Operator gates the fold-in. For maximum independence with no manual seam, run with --background.

Relationship to the pipeline + the in-session gates

  • Step 6.5 of /linkedin:newsletter invokes this same package (after the in-session persona sweep Step 6, before lock Step 8). The pipeline may fan the reviewers out inline, but the recommended path is --background: full isolation, the report read from disk, and no manual step between the review and the fold-in. A fresh session remains available and is equally cold. Either way the body must be re-touched before lock — never reopen a locked text (the cardinal Seres lesson).
  • Deliberate redundancy. fact-reviewer overlaps fact-checker (Step 5) and language-reviewer overlaps editorial-reviewer's prose axis (Step 5.5) on purpose. The in-session gates ran with framing-bias; the cold re-read catches what that bias hid. Do not collapse the pairs.

Reference Files

  • ${CLAUDE_PLUGIN_ROOT}/agents/content-reviewer.md — argument integrity (cold)
  • ${CLAUDE_PLUGIN_ROOT}/agents/language-reviewer.md — Norwegian language (cold)
  • ${CLAUDE_PLUGIN_ROOT}/agents/fact-reviewer.md — cold re-verification (incl. pivot premises)
  • ${CLAUDE_PLUGIN_ROOT}/agents/persona-reviewer.md — resonance + conversion modes
  • ${CLAUDE_PLUGIN_ROOT}/commands/newsletter.md — Step 6.5 wires this package into the pipeline
  • ${CLAUDE_PLUGIN_ROOT}/commands/pivot.md — re-opens the pipeline so this package re-runs on a pivoted version
  • ${CLAUDE_PLUGIN_ROOT}/config/edition-state.template.jsonarticles.NN.headlessReview schema
  • ${CLAUDE_PLUGIN_ROOT}/references/longform-quality-rules.md — fallback writing contract