feat(linkedin-studio): v3.1.0 — Endring 9 adversarial review-pakke + per-artefakt personas
Cold, adversarial review package for the long-form pipeline + configurable per-edition personas. Motivated by Del 4 (Security Champions pivot): the in-session editor + persona sweep shared the drafting session's framing-bias, so the shipped version was never independently re-reviewed. Headless package (9a/9b): - New Step 6.5 (headless-review) in /linkedin:newsletter, after the persona sweep, before lock — the independence layer the in-session gates can't be. - New standalone /linkedin:headless-review command (run in a fresh session for maximum isolation; reconstructs frozen draft + contract + personas from disk). - 3 new Opus archetypes, each with a cardinal context-isolation block that refuses drafting-session framing as "context pollution": - content-reviewer (argument integrity C1–C5, ≤8 flags) - language-reviewer (Norwegian language L1–L5, ≤10 flags) - fact-reviewer (cold re-verification F1–F4, risk-sort + pivot-risk, WebSearch) - Deliberate redundancy with fact-checker / editorial-reviewer documented so the pairs are never de-duplicated. Pivot-reopen (9c): - New /linkedin:pivot command: logs articles.NN.pivots[], resets currentPhase, un-locks, marks gates to re-run. - Pivot-detection gate in Step 8 lock precondition (>20% word-count change or >2 new sections re-opens cleared gates). Del 4 v8→v11 worked example. Per-artifact personas (new requirement): - articles.NN.personas with resolution order (edition-state → series file → plugin library → interactive). One or more readers configurable per edition. Schema/docs: - edition-state.template.json: additive personas[], pivots[], headlessReview, headless-review phase (16 phases); personaSweep.resonance.wordCount baseline. - 3 fasit fixtures + 3 structural lint tests (Del 4 worked cases). - Counts: 24→26 commands, 16→19 agents, 15→16 newsletter phases. - README + CLAUDE.md (plugin + root) + CHANGELOG synced. Verification: 35 agent-fixture + 59 hook + 20 render tests green. Backward- compatible (additive state); reload required before the 3 new agents resolve. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
e162cdce38
commit
e69ea1f4c9
20 changed files with 2520 additions and 59 deletions
|
|
@ -9,7 +9,7 @@ plugins/
|
|||
ai-psychosis/ v1.0.0 — Interaction awareness (sycophancy, reinforcement loops)
|
||||
config-audit/ v3.1.0 — Configuration intelligence (health, opportunities, auto-fix, whats-active)
|
||||
graceful-handoff/ v2.1.0 — Auto-trigger handoff via Stop hook (skill + JSON pipeline + 4-step model-aware context resolution)
|
||||
linkedin-studio/ v3.0.0 — Full-spectrum LinkedIn content engine (short-form feed + long-form newsletter). **v3.0.0 renamed from `linkedin-thought-leadership`** (LinkedIn Thought Leadership → LinkedIn Studio): slug + agent namespace (`linkedin-studio:<agent>`) + runtime state path (`~/.claude/linkedin-studio.local.md`) all change; the `/linkedin:*` commands are unchanged (frontmatter-namespaced, slug-independent). Breaking — reinstall required; functionality byte-identical to v2.4.0. v2.0.0 consolidated surface (27→24 commands, 16→14 agents) + added `/linkedin:newsletter` orchestrator with fact-check + persona-sweep gates BEFORE lock. v2.1.0 added skeleton-gate BEFORE prose (Step 2.5 + Step 3a) + third `persona-reviewer` mode (`skjelett`); pipeline 11→13 phases. v2.2.0 hardened the longform gates (2nd production run): blocking persona hard-fails, fact-check post-cutoff web-search mandate + orthogonal-to-narrative rule, new `voice-scrubber` agent (Opus, de-AI + Norwegian-chronicle voice; gold standard = approved Norwegian editions NOT English post corpus), render+annotate operator gates (2.5/3a), edition-state reconciled with STATE.md (`edition-HANDOVER.md` deleted); agents 14→15. v2.3.0 added **Step 7.5 (visual-assets)** to `/linkedin:newsletter` — cover (+ inline figures) or carousel deck, generated (default mcp-image; external `cover-raw.png` accepted) + operator-gated via `SendUserFile` BEFORE lock so `build-linkedin.mjs` picks up `cover.png` without a post-lock re-render; pipeline 13→14 phases, new `config/image-credit-caption.template.md`, additive `visualAssets` state. v2.4.0 adds **Step 5.5 (editorial-review)** to `/linkedin:newsletter` — new `editorial-reviewer` agent (Opus) judging craft (prosa-håndverk + narrativ-arkitektur), not reader-response, ≤10 flags BLOCK/REWORK/NICE as direction, operator-gated via `SendUserFile` between fact-check (5) and persona-sweep (6), mirroring Maskinrommet skrivekontrakt §C2; motivated by Del 4 (every persona PASS yet 8 fresh editor points, ~6/8 craft/architecture blind spots). Pipeline 14→15 phases; agents 15→16; additive `editorialReview` state; doc/orchestration-only (new agent + fasit fixture + lint test the only new files). Commands unchanged (24); agents 16. Render pipeline self-hosted (OFL-1.1 fonts).
|
||||
linkedin-studio/ v3.1.0 — Full-spectrum LinkedIn content engine (short-form feed + long-form newsletter). **v3.1.0 adds a cold adversarial review package (Endring 9)** to the long-form pipeline: three new headless archetypes (all Opus) — `content-reviewer` (argument integrity C1–C5, ≤8 flags), `language-reviewer` (Norwegian L1–L5, ≤10 flags), `fact-reviewer` (cold re-verification F1–F4 + pivot-risk, web search) — that re-review a frozen draft with NO drafting-session context (each refuses drafting framing as "context pollution"); new **Step 6.5 (headless-review)** in `/linkedin:newsletter` after the persona sweep, before lock (the independence layer the in-session gates can't be); standalone **`/linkedin:headless-review`** command (run in a fresh session for max isolation); **`/linkedin:pivot`** command + pivot-detection gate (>20 % word-count / >2 new sections re-opens cleared gates before lock); **per-artifact personas** (`articles.NN.personas`). Motivated by Del 4 (Security Champions pivot): the in-session editor + persona sweep shared the drafting session's framing-bias, so the shipped version was never independently re-reviewed. Pipeline 15→16 phases; 24→26 commands; 16→19 agents; additive `personas`/`pivots`/`headlessReview` state; backward-compatible, reload required for the new agents. **v3.0.0 renamed from `linkedin-thought-leadership`** (LinkedIn Thought Leadership → LinkedIn Studio): slug + agent namespace (`linkedin-studio:<agent>`) + runtime state path (`~/.claude/linkedin-studio.local.md`) all change; the `/linkedin:*` commands are unchanged (frontmatter-namespaced, slug-independent). Breaking — reinstall required; functionality byte-identical to v2.4.0. v2.0.0 consolidated surface (27→24 commands, 16→14 agents) + added `/linkedin:newsletter` orchestrator with fact-check + persona-sweep gates BEFORE lock. v2.1.0 added skeleton-gate BEFORE prose (Step 2.5 + Step 3a) + third `persona-reviewer` mode (`skjelett`); pipeline 11→13 phases. v2.2.0 hardened the longform gates (2nd production run): blocking persona hard-fails, fact-check post-cutoff web-search mandate + orthogonal-to-narrative rule, new `voice-scrubber` agent (Opus, de-AI + Norwegian-chronicle voice; gold standard = approved Norwegian editions NOT English post corpus), render+annotate operator gates (2.5/3a), edition-state reconciled with STATE.md (`edition-HANDOVER.md` deleted); agents 14→15. v2.3.0 added **Step 7.5 (visual-assets)** to `/linkedin:newsletter` — cover (+ inline figures) or carousel deck, generated (default mcp-image; external `cover-raw.png` accepted) + operator-gated via `SendUserFile` BEFORE lock so `build-linkedin.mjs` picks up `cover.png` without a post-lock re-render; pipeline 13→14 phases, new `config/image-credit-caption.template.md`, additive `visualAssets` state. v2.4.0 adds **Step 5.5 (editorial-review)** to `/linkedin:newsletter` — new `editorial-reviewer` agent (Opus) judging craft (prosa-håndverk + narrativ-arkitektur), not reader-response, ≤10 flags BLOCK/REWORK/NICE as direction, operator-gated via `SendUserFile` between fact-check (5) and persona-sweep (6), mirroring Maskinrommet skrivekontrakt §C2; motivated by Del 4 (every persona PASS yet 8 fresh editor points, ~6/8 craft/architecture blind spots). Pipeline 14→15 phases; agents 15→16; additive `editorialReview` state; doc/orchestration-only (new agent + fasit fixture + lint test the only new files). Commands unchanged (24); agents 16. Render pipeline self-hosted (OFL-1.1 fonts).
|
||||
llm-security/ v7.7.2 — Security scanning, auditing, threat modeling. HTML report output for all 18 skill commands (render-report CLI + canonical ESM module mirrored bit-identical into the playground). v7.7.2 translated the remaining Norwegian surface text in the playground UI, the canonical renderer, the agent prompts, and the README/CLAUDE.md state sections to English. v7.7.1 stripped the playground to the catalog as the only routable surface.
|
||||
ms-ai-architect/ v1.15.0 — Microsoft AI architecture (Cosmo Skyberg persona) + manual KB-refresh slash command + v3 project-view (sidebar med 17 artifacts + main + import-modal overlay, v2-surface fjernet i v1.15.0)
|
||||
okr/ v1.0.0 — OKR guidance for Norwegian public sector
|
||||
|
|
|
|||
|
|
@ -206,11 +206,11 @@ Key commands: `/architect`, `/architect:ros`, `/architect:security`, `/architect
|
|||
|
||||
---
|
||||
|
||||
### [LinkedIn Studio](plugins/linkedin-studio/) `v3.0.0`
|
||||
### [LinkedIn Studio](plugins/linkedin-studio/) `v3.1.0`
|
||||
|
||||
Build authentic LinkedIn authority through algorithmic understanding, strategic consistency, and AI-assisted content creation.
|
||||
|
||||
**v3.0.0 renames the plugin to LinkedIn Studio** (was `linkedin-thought-leadership`): the slug, agent namespace, and runtime state-file path are now `linkedin-studio` — the `/linkedin:*` commands are unchanged. Breaking: reinstall required and the state file moves to `~/.claude/linkedin-studio.local.md`. Functionality is identical to v2.4.0. v2.4.0 adds an **editor's craft gate as an explicit pipeline phase** in `/linkedin:newsletter`: a new **`editorial-reviewer` agent** (Opus) + **Step 5.5 (editorial-review)** between fact-check (Step 5) and the persona sweep (Step 6). It judges **craft** — **prosa-håndverk** (em-dash density, verbatim repetition, postulated numbers, contradictions, versal-tic) + **narrativ-arkitektur** (concrete instantiation, theory-anchored hypotheses, series-title symmetry, equal action per addressee, un-overloaded conclusion) — not reader-response, returning **≤10 flags** (BLOCK / REWORK / NICE) as *direction* (never copy), operator-gated via `SendUserFile`, mirroring the Maskinrommet writing-contract §C2. Motivated by the Del 4 run, where **every persona reported PASS yet the editor found 8 fresh points on first reading, ~6/8 of them craft/architecture blind spots no agent measured.** Pipeline 14 → 15 phases; 15 → 16 agents; additive `editorialReview` state. v2.3.0 made **visual assets an explicit pipeline phase** (Step 7.5, between annotation and lock): the cover (+ optional inline figures) or a carousel deck is generated (default `mcp-image`; external `cover-raw.png` accepted) and operator-gated via `SendUserFile` **before lock**. v2.2.0 **hardened the longform gates** (blocking persona hard-fails, post-cutoff fact-check mandate, a Norwegian-chronicle `voice-scrubber`, render+annotate operator gates, STATE.md-reconciled edition state). Commands unchanged (24); 16 agents. v2.1.0's skeleton-gate-before-prose and v2.0.0's full-spectrum surface are preserved. Updated for the January 2026 360Brew algorithm change, which validates your creator profile before distributing content.
|
||||
**v3.1.0 adds a cold adversarial review package to the long-form pipeline (Endring 9)** — three new headless archetypes (`content-reviewer` argument, `language-reviewer` Norwegian, `fact-reviewer` cold re-verification + pivot-risk), all Opus, that re-review a frozen draft with NO drafting-session context; a new **Step 6.5 (headless-review)** in `/linkedin:newsletter` after the persona sweep and before lock; a standalone **`/linkedin:headless-review`** command (run in a fresh session for maximum isolation); a **`/linkedin:pivot`** command + pivot-detection gate (> 20 % word-count / > 2 new sections re-opens cleared gates before lock); and **per-artifact personas** configurable per edition. Motivated by the Del 4 Security Champions pivot, where the in-session editor + persona sweep shared the drafting session's framing-bias so the shipped version was never independently re-reviewed. Pipeline 15 → 16 phases; 24 → 26 commands; 16 → 19 agents; backward-compatible (additive state); reload required for the new agents. **v3.0.0 renames the plugin to LinkedIn Studio** (was `linkedin-thought-leadership`): the slug, agent namespace, and runtime state-file path are now `linkedin-studio` — the `/linkedin:*` commands are unchanged. Breaking: reinstall required and the state file moves to `~/.claude/linkedin-studio.local.md`. Functionality is identical to v2.4.0. v2.4.0 adds an **editor's craft gate as an explicit pipeline phase** in `/linkedin:newsletter`: a new **`editorial-reviewer` agent** (Opus) + **Step 5.5 (editorial-review)** between fact-check (Step 5) and the persona sweep (Step 6). It judges **craft** — **prosa-håndverk** (em-dash density, verbatim repetition, postulated numbers, contradictions, versal-tic) + **narrativ-arkitektur** (concrete instantiation, theory-anchored hypotheses, series-title symmetry, equal action per addressee, un-overloaded conclusion) — not reader-response, returning **≤10 flags** (BLOCK / REWORK / NICE) as *direction* (never copy), operator-gated via `SendUserFile`, mirroring the Maskinrommet writing-contract §C2. Motivated by the Del 4 run, where **every persona reported PASS yet the editor found 8 fresh points on first reading, ~6/8 of them craft/architecture blind spots no agent measured.** Pipeline 14 → 15 phases; 15 → 16 agents; additive `editorialReview` state. v2.3.0 made **visual assets an explicit pipeline phase** (Step 7.5, between annotation and lock): the cover (+ optional inline figures) or a carousel deck is generated (default `mcp-image`; external `cover-raw.png` accepted) and operator-gated via `SendUserFile` **before lock**. v2.2.0 **hardened the longform gates** (blocking persona hard-fails, post-cutoff fact-check mandate, a Norwegian-chronicle `voice-scrubber`, render+annotate operator gates, STATE.md-reconciled edition state). Commands unchanged (24); 16 agents. v2.1.0's skeleton-gate-before-prose and v2.0.0's full-spectrum surface are preserved. Updated for the January 2026 360Brew algorithm change, which validates your creator profile before distributing content.
|
||||
|
||||
- **Editorial-review craft gate BEFORE the persona sweep (v2.4)** — Step 5.5 runs the new `editorial-reviewer` (Opus) on the fact-checked draft, two axes (prosa-håndverk + narrativ-arkitektur), ≤10 flags severity-ranked BLOCK/REWORK/NICE, surfaced to the operator via `SendUserFile`. It runs *before* the persona sweep so the personas measure resonance instead of stumbling on craft noise; `persona-reviewer` is unchanged (one measures craft, one measures response). Mirrors Maskinrommet §C2.
|
||||
- **Visual-assets gate BEFORE lock (v2.3)** — Step 7.5 decides image needs from the article type (method-heavy → 1–2 inline figures; diagnosis-heavy → cover only), briefs each image, generates via mcp-image or an external `cover-raw.png`, surfaces candidates with `SendUserFile`, and copies the approved one to the fixed `cover.png` name. Explicit `format: "carousel"` branch reusing `build-carousel.mjs`.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "linkedin-studio",
|
||||
"version": "3.0.0",
|
||||
"description": "LinkedIn Studio — full-spectrum LinkedIn content engine: feed posts, carousels, video scripts, and long-form newsletter editions, with the January 2026 360Brew algorithm baked in. v3.0.0 renames the plugin (was `linkedin-thought-leadership`): the slug, agent namespace, and runtime state-file path are now `linkedin-studio` — the `/linkedin:*` commands are unchanged. Breaking: reinstall required and the state file moves to `~/.claude/linkedin-studio.local.md`.",
|
||||
"version": "3.1.0",
|
||||
"description": "LinkedIn Studio — full-spectrum LinkedIn content engine: feed posts, carousels, video scripts, and long-form newsletter editions, with the January 2026 360Brew algorithm baked in. v3.1.0 (Endring 9) adds a cold adversarial review package to `/linkedin:newsletter` — Step 6.5 + the standalone `/linkedin:headless-review` command run three new headless archetypes (content-reviewer, language-reviewer, fact-reviewer) plus the persona reviewer with NO drafting-session context — a `/linkedin:pivot` command that re-opens cleared gates after a late change, and per-artifact personas (one or more readers configurable per edition). v3.0.0 renamed the plugin (was `linkedin-thought-leadership`): slug, agent namespace, and state-file path are `linkedin-studio`; the `/linkedin:*` commands are unchanged.",
|
||||
"author": {
|
||||
"name": "Kjell Tore Guttormsen"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -5,6 +5,30 @@ All notable changes to this project will be documented in this file.
|
|||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [3.1.0] - 2026-05-29
|
||||
|
||||
### Summary
|
||||
**An adversarial review package becomes part of the long-form pipeline (Endring 9).** The Del 4 production run (Maskinrommet, 2026-05-29 — the Security Champions pivot, v8 → v11) shipped a high-quality article, but its quality assurance leaned on **one good editor + KTG's availability to read it several times** — it did not scale. The root cause: the editor and the persona sweep ran *in the same session as drafting*, sharing the conversation history (which versions passed, what was deliberately cut, which flags had been raised). They were therefore **not adversarial** — they carried framing-bias. Three concrete symptoms: (1) the persona resonance sweep effectively judged an early version, not the one that shipped; (2) editor-approval was single-source; (3) the fact-check was post-hoc relative to the late pivot, so the pivot could build on an unverified premise. v3.1.0 answers KTG's explicit question — *how do I start sessions with no context from the main session, to review both content and language?* — and makes per-artifact personas a first-class input.
|
||||
|
||||
### Added
|
||||
- **`/linkedin:headless-review` command** — runs the cold adversarial review package on a FROZEN draft. Designed to be invoked in a **fresh session** for maximum isolation (the parent then has no drafting transcript); reconstructs everything from disk (frozen draft + writing contract + personas). Flags `--draft`, `--type {content|language|fact|persona-resonance|persona-conversion|all}`, `--persona`, `--article`, `--output`.
|
||||
- **Three new headless review archetypes** (all Opus, each with an explicit cardinal context-isolation block that refuses drafting-session framing as "context pollution"):
|
||||
- **`content-reviewer`** (color maroon, Read+Grep) — argument integrity: C1 logical holes · C2 unsupported assumptions · C3 argument-level contradiction · C4 missing concretization · C5 unanswered «what about X?». ≤8 flags BLOCK/REWORK/NICE.
|
||||
- **`language-reviewer`** (navy, Read+Grep) — Norwegian language: L1 verbatim repetition · L2 anglicisms · L3 stiff bureaucratic register · L4 language-level self-contradiction · L5 clang/rhythm. ≤10 flags. Deliberate cold re-take of `editorial-reviewer`'s prose axis.
|
||||
- **`fact-reviewer`** (gold, Read+WebSearch) — cold re-verification on the frozen/pivoted version: F1 verifiable claims · F2 quote precision · F3 number attribution · F4 source quality. Carries over `fact-checker`'s 5-dimension scoring + 🔴/🟡/🟢 sort + contradiction sweep + post-cutoff mandate, adds a **pivot-risk** subsection. Deliberate redundancy with `fact-checker` to catch a pivot premise that arrived after Step 5.
|
||||
- **Step 6.5 (headless-review)** in `/linkedin:newsletter` — fans the package out in parallel after the in-session persona sweep (Step 6), on a frozen draft snapshot, BEFORE lock; consolidated report surfaced via `SendUserFile`; converged flags (two independent cold reviewers agreeing) marked as the strongest signal. Pipeline 15 → 16 phases.
|
||||
- **`/linkedin:pivot` command** + **pivot-detection gate** — a pivot re-opens the pipeline so the cleared gates (fact-check 5 → editorial 5.5 → persona 6 → headless 6.5) re-run on the changed version before lock. Heuristic: a draft that drifted **> 20 % in word count OR gained > 2 sections** since Step 6 cleared triggers the gate (enforced as a Step 8 lock precondition). Worked example: the Del 4 v8→v11 run (+42 %, 2 new sections) would have fired the gate and forced the re-sweep.
|
||||
- **Per-artifact personas** — `articles.NN.personas` in `edition-state.json`: one or more readers configurable **per edition**, resolved in Step 1 in order (edition-state → `<serie>/linkedin/personas.md` per-series file → plugin `personas.local.md`/template → interactive definition). Feeds both the Step 6 sweep and the Step 6.5 package. `config/personas.template.md` documents the resolution order.
|
||||
- **Three fasit fixtures + three structural lint tests** for the new agents (Del 4 / Security Champions worked cases), mirroring the `editorial-reviewer` fixture discipline. All 35 agent-fixture assertions green.
|
||||
|
||||
### Changed
|
||||
- `config/edition-state.template.json` — additive: per-article `personas[]`, `pivots[]`, `headlessReview` object; new `headless-review` phase string (16 phases total); `personaSweep.resonance.wordCount` recorded at Step 6 as the pivot-detection baseline.
|
||||
- `commands/newsletter.md` — Step 0/1 persona resolution reworked to per-artifact; new Step 6.5; Step 8 lock preconditions add the headless gate + pivot-detection gate; pipeline + resumption tables updated (`persona-sweep-prelock` → resume at Step 6.5; new `headless-review` → Step 7).
|
||||
- Counts: 24 → 26 commands; 16 → 19 agents; 15 → 16 newsletter phases.
|
||||
|
||||
### Compatibility
|
||||
Backward-compatible: every state-shape change is additive (existing editions resume by `currentPhase`; `persona-sweep-prelock` now resumes at Step 6.5 — an intended deterministic improvement). **Reload required** before the three new agents resolve (the plugin agent set is built at session start). No new runtime code beyond the agents/commands/fixtures; the render pipeline, hooks, and short-form surface are untouched.
|
||||
|
||||
## [3.0.0] - 2026-05-29
|
||||
|
||||
### Summary
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# LinkedIn Studio Plugin (v2.4.0)
|
||||
# LinkedIn Studio Plugin (v3.1.0)
|
||||
|
||||
Full-spectrum LinkedIn content engine — short-form feed posts, carousels, video scripts, and long-form newsletter editions — with the January 2026 360Brew algorithm baked in. v2.0.0 consolidated the surface (27 commands → 24, 16 agents → 14) while adding the long-form `/linkedin:newsletter` orchestrator + two longform-quality gate agents (`fact-checker`, `persona-reviewer`). v2.1.0 added two gates BEFORE prose (Step 2.5 skeleton + Step 3a spine prose) + a third `persona-reviewer` mode (`skjelett`). v2.2.0 hardened the longform gates with the lessons from the second production run (Seres-serien): blocking persona hard-fails, a post-cutoff fact-check mandate, a `voice-scrubber` agent, render+annotate operator gates, and STATE.md-reconciled edition state. v2.3.0 made **visual assets an explicit pipeline phase** — Step 7.5 (visual-assets) between annotation (Step 7) and lock (Step 8): cover (+ optional inline figures) or a carousel deck, generated (default `mcp-image`, external `cover-raw.png` accepted) and operator-gated BEFORE lock so `render/build-linkedin.mjs` picks up `cover.png` at lock without a post-lock re-render. **v2.4.0** makes an **editor's craft gate an explicit pipeline phase** — new **Step 5.5 (editorial-review)** between fact-check (Step 5) and the persona sweep (Step 6): a new **`editorial-reviewer` agent** (Opus) judges **craft** (prosa-håndverk + narrativ-arkitektur), not reader-response, returning ≤10 flags (BLOCK/REWORK/NICE) as direction, **operator-gated via `SendUserFile` BEFORE the persona sweep** so the personas measure resonance instead of stumbling on craft noise. Motivated by Del 4: every persona reported PASS, yet the editor found 8 fresh points on first reading, ~6/8 of them craft/architecture blind spots no agent measured. Mirrors the Maskinrommet writing-contract §C2. Pipeline 14 → 15 phases; agents 15 → 16; additive `editorialReview` state. Doc/orchestration-only for the wiring (the new agent + its fasit fixture + lint test are the only new files); commands unchanged (24).
|
||||
Full-spectrum LinkedIn content engine — short-form feed posts, carousels, video scripts, and long-form newsletter editions — with the January 2026 360Brew algorithm baked in. v2.0.0 consolidated the surface (27 commands → 24, 16 agents → 14) while adding the long-form `/linkedin:newsletter` orchestrator + two longform-quality gate agents (`fact-checker`, `persona-reviewer`). v2.1.0 added two gates BEFORE prose (Step 2.5 skeleton + Step 3a spine prose) + a third `persona-reviewer` mode (`skjelett`). v2.2.0 hardened the longform gates with the lessons from the second production run (Seres-serien): blocking persona hard-fails, a post-cutoff fact-check mandate, a `voice-scrubber` agent, render+annotate operator gates, and STATE.md-reconciled edition state. v2.3.0 made **visual assets an explicit pipeline phase** — Step 7.5 (visual-assets) between annotation (Step 7) and lock (Step 8): cover (+ optional inline figures) or a carousel deck, generated (default `mcp-image`, external `cover-raw.png` accepted) and operator-gated BEFORE lock so `render/build-linkedin.mjs` picks up `cover.png` at lock without a post-lock re-render. **v2.4.0** makes an **editor's craft gate an explicit pipeline phase** — new **Step 5.5 (editorial-review)** between fact-check (Step 5) and the persona sweep (Step 6): a new **`editorial-reviewer` agent** (Opus) judges **craft** (prosa-håndverk + narrativ-arkitektur), not reader-response, returning ≤10 flags (BLOCK/REWORK/NICE) as direction, **operator-gated via `SendUserFile` BEFORE the persona sweep** so the personas measure resonance instead of stumbling on craft noise. Motivated by Del 4: every persona reported PASS, yet the editor found 8 fresh points on first reading, ~6/8 of them craft/architecture blind spots no agent measured. Mirrors the Maskinrommet writing-contract §C2. Pipeline 14 → 15 phases; agents 15 → 16; additive `editorialReview` state. Doc/orchestration-only for the wiring (the new agent + its fasit fixture + lint test are the only new files); commands unchanged (24). **v3.1.0 (Endring 9)** adds an **adversarial review package** run COLD on a frozen draft — new **Step 6.5 (headless-review)** between the persona sweep (Step 6) and lock, plus a standalone **`/linkedin:headless-review`** command (run in a fresh session for maximum isolation): three new headless archetypes — **`content-reviewer`** (argument integrity), **`language-reviewer`** (Norwegian language), **`fact-reviewer`** (cold re-verification incl. claims a late pivot bolted on) — plus `persona-reviewer` in resonance + conversion modes, all with NO drafting-session context (the independence layer the in-session gates structurally cannot be). v3.1.0 also adds **`/linkedin:pivot`** (re-opens cleared gates after a late change + a >20 %/>2-section pivot-detection gate at lock) and **per-artifact personas** (`articles.NN.personas` — one or more readers configurable per edition, resolved edition-state → series file → plugin library → interactive). Pipeline 15 → 16 phases; agents 16 → 19; commands 24 → 26; additive `personas` / `pivots` / `headlessReview` state. Motivated by Del 4: the in-session editor + persona sweep shared the drafting session's framing-bias, so the version that shipped was never independently re-reviewed.
|
||||
|
||||
## Architecture
|
||||
|
||||
|
|
@ -32,9 +32,9 @@ Full-spectrum LinkedIn content engine — short-form feed posts, carousels, vide
|
|||
|
||||
**Hook editing:** Edit `hooks/hooks.template.json` + `hooks/prompts/*.md`, then run `python3 hooks/scripts/compile-hooks.py`. Do not edit `hooks.json` directly. Prompts are loaded at runtime by gatekeeper scripts; the compile step is only needed when adding `type: prompt` hooks.
|
||||
|
||||
## Commands (24)
|
||||
## Commands (26)
|
||||
|
||||
All content commands (post, quick, react, pipeline, first-post, video, multiplatform, carousel, newsletter) auto-copy output to clipboard via `clipboard-helper.mjs`. Interactive steps are minimized — angle, format, and post type are inferred from context, with max 2 questions per post. **v2.0.0 net change:** 5 commands removed (`templates`, `publish`, `authority`, `collab`, `speaking` — absorbed into `quick`, `calendar`, `strategy`, `outreach` respectively) + 2 commands added (`newsletter`, `outreach`) = 27 → 24.
|
||||
All content commands (post, quick, react, pipeline, first-post, video, multiplatform, carousel, newsletter) auto-copy output to clipboard via `clipboard-helper.mjs`. Interactive steps are minimized — angle, format, and post type are inferred from context, with max 2 questions per post. **v2.0.0 net change:** 5 commands removed (`templates`, `publish`, `authority`, `collab`, `speaking` — absorbed into `quick`, `calendar`, `strategy`, `outreach` respectively) + 2 commands added (`newsletter`, `outreach`) = 27 → 24. **v3.1.0** adds 2 longform companions (`headless-review`, `pivot`) = 24 → 26.
|
||||
|
||||
| Command | Purpose |
|
||||
|---------|---------|
|
||||
|
|
@ -46,7 +46,9 @@ All content commands (post, quick, react, pipeline, first-post, video, multiplat
|
|||
| `/linkedin:post` | Full post creation (10-15 min) |
|
||||
| `/linkedin:quick` | 5-minute quick post (3-line formula) + 8 post-type templates |
|
||||
| `/linkedin:pipeline` | Full end-to-end content pipeline |
|
||||
| `/linkedin:newsletter` | Long-form orchestrator: newsletter edition / essay / series article — multi-session 15-phase pipeline with **skeleton + spine-prose gates BEFORE prose (v2.1)**, **editorial-review craft gate BEFORE the persona sweep (Step 5.5, v2.4)**, fact-check + persona-sweep BEFORE lock, and **visual-assets gate BEFORE lock (Step 7.5, v2.3)** |
|
||||
| `/linkedin:newsletter` | Long-form orchestrator: newsletter edition / essay / series article — multi-session 16-phase pipeline with **skeleton + spine-prose gates BEFORE prose (v2.1)**, **editorial-review craft gate BEFORE the persona sweep (Step 5.5, v2.4)**, fact-check + persona-sweep BEFORE lock, **headless adversarial review BEFORE lock (Step 6.5, v3.1)**, and **visual-assets gate BEFORE lock (Step 7.5, v2.3)** |
|
||||
| `/linkedin:headless-review` | **(v3.1)** Cold adversarial review package — run the 3 headless archetypes (`content-reviewer`, `language-reviewer`, `fact-reviewer`) + `persona-reviewer` (resonance/conversion) on a FROZEN draft with no drafting-session context; consolidated, operator-gated report. Step 6.5's standalone surface (run in a fresh session for maximum isolation) |
|
||||
| `/linkedin:pivot` | **(v3.1)** Re-open a long-form edition after a late substantive change so cleared gates (fact-check → editorial → persona → headless) re-run before lock; logs `pivots[]`, resets `currentPhase`, un-locks if needed (pivot heuristic: >20 % word-count change or >2 new sections) |
|
||||
| `/linkedin:batch` | Create a full week of content |
|
||||
| `/linkedin:calendar` | View/manage post scheduling queue + publish action (mark scheduled posts as published) |
|
||||
| `/linkedin:carousel` | Structured multi-slide carousel generator |
|
||||
|
|
@ -63,7 +65,7 @@ All content commands (post, quick, react, pipeline, first-post, video, multiplat
|
|||
| `/linkedin:outreach` | Outreach orchestrator — collaborations + speaking opportunities (unlocks at ~1K followers) |
|
||||
| `/linkedin:profile` | 360Brew profile optimization |
|
||||
|
||||
## Agents (16)
|
||||
## Agents (19)
|
||||
|
||||
| Agent | Model | Color | Responsibility |
|
||||
|-------|-------|-------|----------------|
|
||||
|
|
@ -83,6 +85,9 @@ All content commands (post, quick, react, pipeline, first-post, video, multiplat
|
|||
| `editorial-reviewer` | Opus | Orange | Editor's craft gate (v2.4, Step 5.5, before persona sweep): prosa-håndverk + narrativ-arkitektur, ≤10 flags BLOCK/REWORK/NICE as direction, operator-gated via `SendUserFile`; mirrors Maskinrommet §C2 (longform) |
|
||||
| `persona-reviewer` | Opus | Olive | Reader-persona skeleton (v2.1, before prose) + resonance (before lock) + hook-conversion (after lock) gate, blocking hard-fail list (longform) |
|
||||
| `voice-scrubber` | Opus | Red | De-AI scrub + Norwegian-chronicle voice-drift correction; gold standard = approved Norwegian editions, not the English post corpus (longform, v2.2) |
|
||||
| `content-reviewer` | Opus | Maroon | **(v3.1, Step 6.5 — cold/headless)** Argument-integrity review on a frozen draft: C1 logical holes · C2 unsupported assumptions · C3 argument contradiction · C4 missing concretization · C5 unanswered objection. ≤8 flags BLOCK/REWORK/NICE as direction; refuses drafting-session framing as context pollution (longform) |
|
||||
| `language-reviewer` | Opus | Navy | **(v3.1, Step 6.5 — cold/headless)** Norwegian-language review on a frozen draft: L1 verbatim repetition · L2 anglicisms · L3 stiff bureaucratic register · L4 language-level self-contradiction · L5 clang/rhythm. ≤10 flags BLOCK/REWORK/NICE; deliberate cold re-take of editorial's prose axis (longform) |
|
||||
| `fact-reviewer` | Opus | Gold | **(v3.1, Step 6.5 — cold/headless)** Cold re-verification on the frozen/pivoted version (web search): F1 verifiable claims · F2 quote precision · F3 number attribution · F4 source quality. 🔴/🟡/🟢 + pivot-risk subsection; deliberate redundancy with `fact-checker` to catch a pivot premise that arrived after Step 5 (longform) |
|
||||
|
||||
**Rule:** Always read `assets/voice-samples/` before generating content.
|
||||
|
||||
|
|
|
|||
|
|
@ -6,20 +6,21 @@
|
|||
|
||||
*AI-generated: all code produced by Claude Code through dialog-driven development. [Full disclosure →](../../README.md#ai-generated-code-disclosure)*
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
A comprehensive Claude Code plugin that turns LinkedIn from a chore into a full-spectrum content engine — short-form feed posts, carousels, video scripts, and long-form newsletter editions. v2.0.0 consolidated the surface (27 → 24 commands, 16 → 14 agents) and added `/linkedin:newsletter` as a multi-session long-form orchestrator with fact-check + persona-sweep gates BEFORE lock. **v2.1.0** adds two more gates BEFORE prose to `/linkedin:newsletter` — a skeleton gate (Step 2.5) and a spine-prose gate (Step 3a) — encoding the Maskinrommet writing-contract §A discipline (premiss / problem / anbefaling / gevinst / vei videre) into the pipeline itself, so spine errors get caught in minutes at the skeleton stage instead of hours at the resonance stage or a full day post-lock. v2.2.0 hardened the longform gates with the lessons from the next production run: blocking persona hard-fails (primær «mistet meg» / doesn't own the action / jargon wall / model-name catalog → BLOCK), a post-cutoff fact-check mandate, a new Norwegian-chronicle de-AI voice-scrubber agent, render+annotate operator gates, and edition state reconciled with the global STATE.md continuity system. v2.3.0 makes visual assets an explicit pipeline phase — **Step 7.5 (visual-assets)** between annotation and lock: the cover (+ optional inline figures) or a carousel deck is generated and operator-gated *before* lock, so the renderer picks up `cover.png` without a post-lock re-render. **v2.4.0** adds an **editor's craft gate** — new **Step 5.5 (editorial-review)** between fact-check and the persona sweep: a new `editorial-reviewer` agent (Opus) judges *craft* (prose-craft + narrative-architecture), not reader-response, returning ≤10 flags (BLOCK / REWORK / NICE) operator-gated via `SendUserFile` so the personas measure resonance instead of stumbling on craft noise (pipeline 14 → 15 phases). 24 slash commands, 16 specialized agents, 9 automated hooks, and a 24-document knowledge base grounded in LinkedIn's actual algorithm signals. Updated for the January 2026 **360Brew** algorithm change, where LinkedIn now validates your profile before distributing content.
|
||||
A comprehensive Claude Code plugin that turns LinkedIn from a chore into a full-spectrum content engine — short-form feed posts, carousels, video scripts, and long-form newsletter editions. v2.0.0 consolidated the surface (27 → 24 commands, 16 → 14 agents) and added `/linkedin:newsletter` as a multi-session long-form orchestrator with fact-check + persona-sweep gates BEFORE lock. **v2.1.0** adds two more gates BEFORE prose to `/linkedin:newsletter` — a skeleton gate (Step 2.5) and a spine-prose gate (Step 3a) — encoding the Maskinrommet writing-contract §A discipline (premiss / problem / anbefaling / gevinst / vei videre) into the pipeline itself, so spine errors get caught in minutes at the skeleton stage instead of hours at the resonance stage or a full day post-lock. v2.2.0 hardened the longform gates with the lessons from the next production run: blocking persona hard-fails (primær «mistet meg» / doesn't own the action / jargon wall / model-name catalog → BLOCK), a post-cutoff fact-check mandate, a new Norwegian-chronicle de-AI voice-scrubber agent, render+annotate operator gates, and edition state reconciled with the global STATE.md continuity system. v2.3.0 makes visual assets an explicit pipeline phase — **Step 7.5 (visual-assets)** between annotation and lock: the cover (+ optional inline figures) or a carousel deck is generated and operator-gated *before* lock, so the renderer picks up `cover.png` without a post-lock re-render. **v2.4.0** adds an **editor's craft gate** — new **Step 5.5 (editorial-review)** between fact-check and the persona sweep: a new `editorial-reviewer` agent (Opus) judges *craft* (prose-craft + narrative-architecture), not reader-response, returning ≤10 flags (BLOCK / REWORK / NICE) operator-gated via `SendUserFile` so the personas measure resonance instead of stumbling on craft noise (pipeline 14 → 15 phases). **v3.1.0** adds a **cold adversarial review package** as **Step 6.5 (headless-review)** in `/linkedin:newsletter` — three new headless archetypes (`content-reviewer`, `language-reviewer`, `fact-reviewer`) that re-review a frozen draft with NO drafting-session context, surfaced standalone via the new `/linkedin:headless-review` command (run in a fresh session for maximum isolation), plus a `/linkedin:pivot` command + pivot-detection gate that re-opens cleared gates after a late change, and per-artifact personas configurable per edition (pipeline 15 → 16 phases). 26 slash commands, 19 specialized agents, 9 automated hooks, and a 24-document knowledge base grounded in LinkedIn's actual algorithm signals. Updated for the January 2026 **360Brew** algorithm change, where LinkedIn now validates your profile before distributing content.
|
||||
|
||||
---
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [What's New in v3.1.0](#whats-new-in-v310)
|
||||
- [What's New in v3.0.0](#whats-new-in-v300)
|
||||
- [What's New in v2.4.0](#whats-new-in-v240)
|
||||
- [What's New in v2.3.0](#whats-new-in-v230)
|
||||
|
|
@ -44,6 +45,20 @@ A comprehensive Claude Code plugin that turns LinkedIn from a chore into a full-
|
|||
|
||||
---
|
||||
|
||||
## What's New in v3.1.0
|
||||
|
||||
**An adversarial review package becomes part of the long-form pipeline (Endring 9).** The Del 4 production run (the Security Champions pivot) shipped a high-quality article, but its quality assurance leaned on one good editor plus the operator's availability to re-read it several times — it did not scale. The root cause: the editor (Step 5.5) and the persona sweep (Step 6) ran *in the same session as drafting*, sharing the conversation history (which versions passed, what was cut, which flags were raised). They carried the drafting session's **framing-bias** and were therefore not independent. Three symptoms followed: the resonance sweep effectively judged an early version rather than the one that shipped, editor-approval was single-source, and the fact-check was post-hoc relative to a late pivot — so the pivot could build on an unverified premise.
|
||||
|
||||
v3.1.0 answers the operator's explicit question — *how do I start sessions with no context from the main session, to review both content and language?* — with a **cold review package** that reconstructs everything from disk and refuses the drafting session's framing as "context pollution".
|
||||
|
||||
- **Three new headless review archetypes** (all Opus, cold/headless): **`content-reviewer`** (maroon — argument integrity: C1 logical holes · C2 unsupported assumptions · C3 argument contradiction · C4 missing concretization · C5 unanswered objection; ≤8 flags), **`language-reviewer`** (navy — Norwegian language: L1 verbatim repetition · L2 anglicisms · L3 stiff bureaucratic register · L4 language-level self-contradiction · L5 clang/rhythm; ≤10 flags; a deliberate cold re-take of the editorial prose axis), and **`fact-reviewer`** (gold — cold re-verification on the frozen/pivoted version via web search: F1 verifiable claims · F2 quote precision · F3 number attribution · F4 source quality; 🔴/🟡/🟢 + a pivot-risk subsection; deliberate redundancy with `fact-checker` to catch a pivot premise that arrived after Step 5).
|
||||
- **New `/linkedin:headless-review` command** — runs the cold package on a FROZEN draft, designed to be invoked in a **fresh session** for maximum isolation (the parent then has no drafting transcript) and reconstructs the draft + writing contract + personas from disk.
|
||||
- **New Step 6.5 (headless-review)** in `/linkedin:newsletter` — fans the package out in parallel after the in-session persona sweep (Step 6), on a frozen draft snapshot, BEFORE lock; the independence layer the in-session gates cannot be. Converged flags (two independent cold reviewers agreeing) are the strongest signal.
|
||||
- **New `/linkedin:pivot` command + pivot-detection gate** — a late change re-opens the cleared gates (fact-check → editorial → persona → headless) so they re-run on the changed version before lock. Heuristic: a draft that drifted **> 20 % in word count OR gained > 2 sections** since Step 6 cleared fires the gate (enforced as a Step 8 lock precondition).
|
||||
- **Per-artifact personas** (`articles.NN.personas`) — one or more readers configurable **per edition**, resolved in order (edition-state → `<serie>/linkedin/personas.md` per-series file → plugin library/template → interactive definition); feeds both the Step 6 sweep and the Step 6.5 package.
|
||||
|
||||
Counts: 24 → 26 commands; 16 → 19 agents; newsletter pipeline 15 → 16 phases. **Backward-compatible** — every state-shape change is additive (`personas`/`pivots`/`headlessReview`); existing editions resume by `currentPhase`. **Reload required** before the three new agents resolve (the plugin agent set is built at session start).
|
||||
|
||||
## What's New in v3.0.0
|
||||
|
||||
**The plugin is renamed `linkedin-thought-leadership` → `linkedin-studio` ("LinkedIn Thought Leadership" → LinkedIn Studio).** The old display title read as pompous; the new name is plain and matches how the plugin already describes itself — a *LinkedIn content engine*. This is a **breaking** release because the identity changes at three levels, but **no functionality changes** — v3.0.0 is byte-for-byte v2.4.0 under a new name.
|
||||
|
|
@ -203,7 +218,7 @@ The wizard handles everything: 360Brew profile checklist, voice and user profile
|
|||
|
||||
## Commands
|
||||
|
||||
All 24 commands use colon notation: `/linkedin:post`, `/linkedin:quick`, etc.
|
||||
All 26 commands use colon notation: `/linkedin:post`, `/linkedin:quick`, etc.
|
||||
|
||||
### Onboarding
|
||||
|
||||
|
|
@ -257,7 +272,7 @@ All 24 commands use colon notation: `/linkedin:post`, `/linkedin:quick`, etc.
|
|||
|
||||
## Agent Architecture
|
||||
|
||||
The plugin delegates specialized work to 16 purpose-built agents. Each agent has its own model assignment, color identity, and focused responsibility.
|
||||
The plugin delegates specialized work to 19 purpose-built agents. Each agent has its own model assignment, color identity, and focused responsibility.
|
||||
|
||||
| Agent | Model | Color | Primary Responsibility |
|
||||
|-------|-------|-------|----------------------|
|
||||
|
|
@ -277,6 +292,9 @@ The plugin delegates specialized work to 16 purpose-built agents. Each agent has
|
|||
| `editorial-reviewer` | Opus | Orange | Editor's craft gate (v2.4, Step 5.5, before persona sweep): **prosa-håndverk** + **narrativ-arkitektur**, ≤10 flags BLOCK/REWORK/NICE as direction, operator-gated via `SendUserFile`; mirrors Maskinrommet §C2 (longform) |
|
||||
| `persona-reviewer` | Opus | Olive | Reader-persona **skeleton** (v2.1, before prose) + **resonance** (before lock) + **hook-conversion** (after lock) gate, blocking hard-fail list (longform) |
|
||||
| `voice-scrubber` | Opus | Red | De-AI scrub + Norwegian-chronicle voice-drift correction; gold standard = approved Norwegian editions, not the English post corpus (longform, v2.2) |
|
||||
| `content-reviewer` | Opus | Maroon | (v3.1, Step 6.5 — cold/headless) Argument integrity: C1 logical holes · C2 unsupported assumptions · C3 argument contradiction · C4 missing concretization · C5 unanswered objection; ≤8 flags BLOCK/REWORK/NICE; refuses drafting-session framing as context pollution (longform) |
|
||||
| `language-reviewer` | Opus | Navy | (v3.1, Step 6.5 — cold/headless) Norwegian language: L1 verbatim repetition · L2 anglicisms · L3 stiff bureaucratic register · L4 language-level self-contradiction · L5 clang/rhythm; ≤10 flags; deliberate cold re-take of editorial's prose axis (longform) |
|
||||
| `fact-reviewer` | Opus | Gold | (v3.1, Step 6.5 — cold/headless) Cold re-verification on the frozen/pivoted version (web search): F1 verifiable claims · F2 quote precision · F3 number attribution · F4 source quality; 🔴/🟡/🟢 + pivot-risk; deliberate redundancy with `fact-checker` to catch a pivot premise that arrived after Step 5 (longform) |
|
||||
|
||||
### Content Pipeline
|
||||
|
||||
|
|
@ -294,7 +312,7 @@ trend-spotter --> content-planner --> differentiation-checker --> content-optimi
|
|||
|
||||
Parallel support agents: `strategy-advisor`, `analytics-interpreter`, `network-builder`, `content-repurposer`, `video-scripter`.
|
||||
|
||||
Longform quality gates (newsletter): **`persona-reviewer` (skjelett) run BEFORE prose** (v2.1, Step 2.5) → `voice-scrubber` de-AI / chronicle-voice scrub (v2.2, Step 4) → `fact-checker` (Step 5) → **`editorial-reviewer` craft gate run BEFORE the persona sweep** (v2.4, Step 5.5) → `persona-reviewer` (resonance) run BEFORE lock (Step 6) → `persona-reviewer` (conversion) run AFTER lock on the hook (Step 9).
|
||||
Longform quality gates (newsletter): **`persona-reviewer` (skjelett) run BEFORE prose** (v2.1, Step 2.5) → `voice-scrubber` de-AI / chronicle-voice scrub (v2.2, Step 4) → `fact-checker` (Step 5) → **`editorial-reviewer` craft gate run BEFORE the persona sweep** (v2.4, Step 5.5) → `persona-reviewer` (resonance) run BEFORE lock (Step 6) → **headless adversarial review package run COLD BEFORE lock** (v3.1, Step 6.5: `content-reviewer` + `language-reviewer` + `fact-reviewer` + `persona-reviewer`) → `persona-reviewer` (conversion) run AFTER lock on the hook (Step 9).
|
||||
|
||||
> **Note (agent invocation + reload):** Commands invoke agents by their **namespaced**
|
||||
> type — `subagent_type: linkedin-studio:<name>`, never the bare name. And a
|
||||
|
|
@ -604,6 +622,7 @@ Scheduled posts are tracked in `assets/drafts/queue.json`:
|
|||
|
||||
| Version | Date | Highlights |
|
||||
|---------|------|-----------|
|
||||
| **3.1.0** | 2026-05-29 | Adversarial review package (Endring 9). New **`/linkedin:headless-review`** command + **Step 6.5 (headless-review)** in `/linkedin:newsletter`: three cold/headless archetypes — **`content-reviewer`** (argument), **`language-reviewer`** (Norwegian), **`fact-reviewer`** (cold re-verification + pivot-risk) — plus `persona-reviewer` (resonance/conversion), all with NO drafting-session context. New **`/linkedin:pivot`** command + pivot-detection gate (> 20 % word-count / > 2 new sections re-opens cleared gates before lock). **Per-artifact personas** (`articles.NN.personas`). Pipeline 15 → 16 phases; 24 → 26 commands; 16 → 19 agents; additive `personas`/`pivots`/`headlessReview` state. Backward-compatible; reload required for the new agents. |
|
||||
| **3.0.0** | 2026-05-29 | **Renamed** `linkedin-thought-leadership` → `linkedin-studio` ("LinkedIn Thought Leadership" → **LinkedIn Studio**). Breaking (slug + agent namespace `linkedin-studio:<agent>` + runtime state path `~/.claude/linkedin-studio.local.md` all change; reinstall required, state migrated in place), but **functionality byte-identical to v2.4.0**. The `/linkedin:*` commands are unchanged (frontmatter-namespaced, slug-independent). Catch-all skill dir renamed to match (`skills/linkedin-studio/`); the five functional skills unchanged. |
|
||||
| **2.4.0** | 2026-05-29 | Editor's craft gate as an explicit pipeline phase. New **`editorial-reviewer` agent** (Opus) + **Step 5.5 — Editorial review** in `/linkedin:newsletter` (between fact-check and the persona sweep): two axes — **prosa-håndverk** (em-dash density, verbatim repetition, postulated numbers, contradictions, versal-tic) + **narrativ-arkitektur** (concrete instantiation, theory-anchored hypotheses, series-title symmetry, equal action per addressee, un-overloaded conclusion); ≤10 flags BLOCK/REWORK/NICE as direction; operator-gated via `SendUserFile`; mirrors Maskinrommet §C2. Motivated by Del 4 (every persona PASS, yet 8 fresh editor points, ~6/8 craft/architecture blind spots). `editorial-review` phase + additive `editorialReview` state. Pipeline 14 → 15 phases; 15 → 16 agents. New agent + fasit fixture + lint test the only new files; commands (24) unchanged. |
|
||||
| **2.3.0** | 2026-05-28 | Visual assets as an explicit pipeline phase. New **Step 7.5 — Visual assets** in `/linkedin:newsletter` (between annotation and lock): cover (+ optional inline figures) or carousel deck, generated (default `mcp-image`; external `cover-raw.png` accepted) and operator-gated via `SendUserFile` BEFORE lock so `build-linkedin.mjs` picks up `cover.png` without a post-lock re-render. Explicit `format: "carousel"` branch reusing `build-carousel.mjs`. New `config/image-credit-caption.template.md`; additive `visualAssets` state + naming convention (`cover.png` / `cover-v<N>-kandidat.png` / `cover-raw.png` / `fig<N>.png`). Pipeline 13 → 14 phases. Doc/orchestration-only (no new code); commands (24) + agents (15) unchanged. |
|
||||
|
|
|
|||
|
|
@ -0,0 +1,82 @@
|
|||
import { describe, test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
// Lint-test for the content-reviewer fasit fixture.
|
||||
// Mirrors the structure-only discipline of editorial-reviewer-fixture.test.mjs,
|
||||
// persona-reviewer-fixture.test.mjs, and fact-checker-fixture.test.mjs: this test
|
||||
// asserts the SHAPE of the fixture — the one judging axis (argument-integritet),
|
||||
// all five checks (C1–C5), the three severities, the six Del 4 cases, the
|
||||
// direction-not-copy boundary, and the cold-reader / context-isolation rationale.
|
||||
// Whether the agent's live flags actually reproduce the fasit directions is
|
||||
// [GATE]/[OPERATØR], never self-certified here.
|
||||
|
||||
const FIXTURE_PATH = fileURLToPath(
|
||||
new URL('../fixtures/content-reviewer-cases.md', import.meta.url)
|
||||
);
|
||||
|
||||
const fixture = readFileSync(FIXTURE_PATH, 'utf8');
|
||||
|
||||
// The five argument-integrity checks.
|
||||
const CHECKS = ['C1', 'C2', 'C3', 'C4', 'C5'];
|
||||
|
||||
// The single judging axis (Norwegian, as the agent uses it).
|
||||
const AXIS = 'argument-integritet';
|
||||
|
||||
// The three-rung severity scale.
|
||||
const SEVERITIES = ['BLOCK', 'REWORK', 'NICE'];
|
||||
|
||||
describe('content-reviewer fixture structure', () => {
|
||||
test('names the argument-integritet axis', () => {
|
||||
assert.ok(
|
||||
new RegExp(AXIS, 'i').test(fixture),
|
||||
`fixture must name the axis "${AXIS}"`
|
||||
);
|
||||
});
|
||||
|
||||
test('documents all five checks (C1–C5)', () => {
|
||||
for (const check of CHECKS) {
|
||||
assert.ok(
|
||||
fixture.includes(check),
|
||||
`fixture must reference the check "${check}"`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test('defines the three-rung severity scale', () => {
|
||||
for (const sev of SEVERITIES) {
|
||||
assert.ok(
|
||||
fixture.includes(sev),
|
||||
`fixture must define the severity "${sev}"`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test('documents exactly six Del 4 cases', () => {
|
||||
const cases = fixture.match(/^###\s+Case\s+\d+\b/gim) || [];
|
||||
assert.equal(
|
||||
cases.length,
|
||||
6,
|
||||
`fixture must document exactly 6 Del 4 cases (found ${cases.length})`
|
||||
);
|
||||
});
|
||||
|
||||
test('keeps the jury-judges-writer-writes boundary (direction, not copy)', () => {
|
||||
assert.ok(
|
||||
/direction, not rewritten copy/i.test(fixture),
|
||||
'fixture must state the direction-not-copy boundary'
|
||||
);
|
||||
});
|
||||
|
||||
test('documents the cold-reader / context-isolation rationale', () => {
|
||||
assert.ok(
|
||||
/context pollution/i.test(fixture),
|
||||
'fixture must document the context-isolation principle (context pollution)'
|
||||
);
|
||||
assert.ok(
|
||||
/cold/i.test(fixture),
|
||||
'fixture must describe the agent as a cold reader'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
import { describe, test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
// Lint-test for the fact-reviewer fasit fixture.
|
||||
// Mirrors the structure-only discipline of fact-checker-fixture.test.mjs and
|
||||
// editorial-reviewer-fixture.test.mjs: this test asserts the SHAPE of the
|
||||
// fixture — the single axis (faktisk-korrekthet), the four checks (F1–F4), the
|
||||
// 🔴/🟡/🟢 risk sort, the six Del 4 (Security Champions) cases, the
|
||||
// direction-not-copy boundary, and the cold-reader / pivot-risk rationale.
|
||||
// Whether the agent's live verdicts actually reproduce the fasit is
|
||||
// [GATE]/[OPERATØR], never self-certified here.
|
||||
|
||||
const FIXTURE_PATH = fileURLToPath(
|
||||
new URL('../fixtures/fact-reviewer-cases.md', import.meta.url)
|
||||
);
|
||||
|
||||
const fixture = readFileSync(FIXTURE_PATH, 'utf8');
|
||||
|
||||
// The four checks: F1 verifiable claims · F2 quote precision · F3 number
|
||||
// attribution · F4 source quality.
|
||||
const CHECKS = ['F1', 'F2', 'F3', 'F4'];
|
||||
|
||||
// The 🔴/🟡/🟢 risk sort (the emoji are the safest assertion).
|
||||
const VERDICTS = ['🔴', '🟡', '🟢'];
|
||||
|
||||
describe('fact-reviewer fixture structure', () => {
|
||||
test('names the axis "faktisk-korrekthet"', () => {
|
||||
assert.ok(
|
||||
/faktisk-korrekthet/i.test(fixture),
|
||||
'fixture must name the axis "faktisk-korrekthet"'
|
||||
);
|
||||
});
|
||||
|
||||
test('documents all four checks (F1–F4)', () => {
|
||||
for (const check of CHECKS) {
|
||||
assert.ok(
|
||||
fixture.includes(check),
|
||||
`fixture must reference the check "${check}"`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test('references the 🔴/🟡/🟢 risk sort', () => {
|
||||
for (const v of VERDICTS) {
|
||||
assert.ok(
|
||||
fixture.includes(v),
|
||||
`fixture must reference the risk verdict "${v}"`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test('references the PASS/REWORK/BLOCK gate', () => {
|
||||
for (const gate of ['PASS', 'REWORK', 'BLOCK']) {
|
||||
assert.ok(
|
||||
fixture.includes(gate),
|
||||
`fixture must reference the gate decision "${gate}"`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test('documents exactly 6 Del 4 cases', () => {
|
||||
const cases = fixture.match(/^###\s+Case\s+\d+\b/gim) || [];
|
||||
assert.equal(
|
||||
cases.length,
|
||||
6,
|
||||
`fixture must document exactly 6 Del 4 cases (found ${cases.length})`
|
||||
);
|
||||
});
|
||||
|
||||
test('states the direction-not-copy boundary', () => {
|
||||
assert.ok(
|
||||
/direction, not rewritten copy/i.test(fixture),
|
||||
'fixture must state the direction-not-copy boundary'
|
||||
);
|
||||
});
|
||||
|
||||
test('documents the cold-reader / context-pollution principle', () => {
|
||||
assert.ok(
|
||||
/context pollution/i.test(fixture) && /framing-bias/i.test(fixture),
|
||||
'fixture must document the cold-reader / context-pollution / framing-bias principle'
|
||||
);
|
||||
});
|
||||
|
||||
test('records the pivot-premise-risk rationale', () => {
|
||||
assert.ok(
|
||||
/pivot/i.test(fixture),
|
||||
'fixture must record why the gate exists (pivot premise never met Step 5)'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
import { describe, test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
// Lint-test for the language-reviewer fasit fixture.
|
||||
// Mirrors the structure-only discipline of editorial-reviewer-fixture.test.mjs,
|
||||
// persona-reviewer-fixture.test.mjs and fact-checker-fixture.test.mjs: this test
|
||||
// asserts the SHAPE of the fixture — the one judging axis (norsk-språkkvalitet),
|
||||
// all five checks (L1–L5), the three severities, the six Del 4 cases that form
|
||||
// the gold standard, the direction-not-copy boundary, and the cold-reader /
|
||||
// context-isolation principle. Whether the agent's live flags actually reproduce
|
||||
// the fasit directions is [GATE]/[OPERATØR], never self-certified here.
|
||||
|
||||
const FIXTURE_PATH = fileURLToPath(
|
||||
new URL('../fixtures/language-reviewer-cases.md', import.meta.url)
|
||||
);
|
||||
|
||||
const fixture = readFileSync(FIXTURE_PATH, 'utf8');
|
||||
|
||||
// The five checks of the one axis.
|
||||
const CHECKS = ['L1', 'L2', 'L3', 'L4', 'L5'];
|
||||
|
||||
// The single axis name (Norwegian, as the agent and the writing contract use it).
|
||||
const AXIS = 'norsk-språkkvalitet';
|
||||
|
||||
// The three-rung severity scale.
|
||||
const SEVERITIES = ['BLOCK', 'REWORK', 'NICE'];
|
||||
|
||||
describe('language-reviewer fixture structure', () => {
|
||||
test('names the judging axis (norsk-språkkvalitet)', () => {
|
||||
assert.ok(
|
||||
new RegExp(AXIS, 'i').test(fixture),
|
||||
`fixture must name the axis "${AXIS}"`
|
||||
);
|
||||
});
|
||||
|
||||
test('documents all five checks (L1–L5)', () => {
|
||||
for (const check of CHECKS) {
|
||||
assert.ok(
|
||||
fixture.includes(check),
|
||||
`fixture must reference the check "${check}"`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test('defines the three-rung severity scale', () => {
|
||||
for (const sev of SEVERITIES) {
|
||||
assert.ok(
|
||||
fixture.includes(sev),
|
||||
`fixture must define the severity "${sev}"`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test('documents the six Del 4 cases', () => {
|
||||
const cases = fixture.match(/^###\s+Case\s+\d+\b/gim) || [];
|
||||
assert.equal(
|
||||
cases.length,
|
||||
6,
|
||||
`fixture must document exactly 6 Del 4 cases (found ${cases.length})`
|
||||
);
|
||||
});
|
||||
|
||||
test('keeps the jury-judges-writer-writes boundary (direction, not copy)', () => {
|
||||
assert.ok(
|
||||
/direction, not rewritten copy/i.test(fixture),
|
||||
'fixture must state the direction-not-copy boundary'
|
||||
);
|
||||
});
|
||||
|
||||
test('documents the cold-reader / context-isolation principle', () => {
|
||||
assert.ok(
|
||||
/cold/i.test(fixture) &&
|
||||
/(context pollution|framing-bias)/i.test(fixture),
|
||||
'fixture must document the cold-reader / context-isolation principle ' +
|
||||
'(context pollution / framing-bias)'
|
||||
);
|
||||
});
|
||||
});
|
||||
286
plugins/linkedin-studio/agents/content-reviewer.md
Normal file
286
plugins/linkedin-studio/agents/content-reviewer.md
Normal file
|
|
@ -0,0 +1,286 @@
|
|||
---
|
||||
name: content-reviewer
|
||||
description: |
|
||||
Read a frozen, publish-ready long-form draft as an ADVERSARIAL, independent
|
||||
reviewer in a COLD context and judge whether the ARGUMENT holds — not whether
|
||||
it is well-made (editorial), true (fact), clean Norwegian (language), or
|
||||
resonant (persona). Catches logical holes, premises asserted without support,
|
||||
argument-level contradictions, load-bearing claims left abstract where a
|
||||
skeptic needs a concrete instance, and the obvious "what about X?" the text
|
||||
never answers. Returns ≤8 flags as direction — never rewritten copy — each
|
||||
tagged BLOCK / REWORK / NICE. One archetype of the Step 6.5 headless package.
|
||||
|
||||
Use when the user says:
|
||||
- "content review", "argument check", "headless review"
|
||||
- "does the argument hold?", "is the reasoning sound?"
|
||||
- "find the logical holes", "where does the logic jump?"
|
||||
- "what about X — did the text answer it?", "the obvious objection"
|
||||
- "what's asserted without support?", "is this load-bearing claim grounded?"
|
||||
- "run the cold reviewer", "read this as a first-time skeptic"
|
||||
|
||||
Triggers on: "content review", "does the argument hold", "logical holes",
|
||||
"argument check", "what about X", "is the reasoning sound", "headless review",
|
||||
"cold reader", "argument integrity", "unanswered objection".
|
||||
model: opus
|
||||
color: maroon
|
||||
tools: ["Read", "Grep"]
|
||||
---
|
||||
|
||||
# Content Reviewer Agent
|
||||
|
||||
You are an **adversarial, independent reviewer**. You read a **frozen,
|
||||
publish-ready** long-form draft and judge whether the **argument holds** — the
|
||||
logical and argumentative integrity a reader feels as "this convinced me" or
|
||||
"wait, that doesn't follow." You are the skeptic the in-session gates could not
|
||||
be, because they shared the drafting session's framing.
|
||||
|
||||
You run at **Step 6.5** of the `/linkedin:newsletter` pipeline — *after* the
|
||||
in-session persona resonance sweep (Step 6), on a **FROZEN draft**, and *before*
|
||||
lock (Step 8). You are also invocable standalone via `/linkedin:headless-review`.
|
||||
|
||||
## Your Mission
|
||||
|
||||
Catch the argument defects that survive every in-session gate. The gates inside
|
||||
the drafting session (fact-check, editorial, persona) all read the draft through
|
||||
the framing the session built — what was intended, what was deliberately scoped
|
||||
out, why the pivot happened. That framing is exactly what hides a logical hole:
|
||||
the author *knows* the missing step, so the gate's reader supplies it for free.
|
||||
You do not get that for free. You read the frozen page as a first-time reader
|
||||
who was handed nothing but the page, and you ask the only question that matters:
|
||||
**does the reasoning actually hold?**
|
||||
|
||||
Core principle: **the jury judges; the writer writes.** Like `editorial-reviewer`
|
||||
and `persona-reviewer`, you return **direction, never rewritten copy.** "§4 jumps
|
||||
from 'Champions exist' to 'judgment is preserved' with no connecting step —
|
||||
supply the step or hedge the claim" is your job. Supplying the connecting
|
||||
sentence is not. If you ever hand back edited prose, you have failed the role.
|
||||
|
||||
## Context isolation — you are a COLD reader (cardinal)
|
||||
|
||||
> You are an **adversarial, independent** reviewer, run in a **cold context**.
|
||||
> Your entire input is: this prompt, the path to a **frozen draft**, and the
|
||||
> writing contract. You have **no** access to — and must **refuse to act on** —
|
||||
> any of:
|
||||
> - the drafting session's conversation history;
|
||||
> - prior versions, version numbers, or a changelog;
|
||||
> - a "deliberately omitted" / "out of scope" list;
|
||||
> - a pivot narrative or the reason for any pivot;
|
||||
> - who has read the draft, what an editor said, or how a persona voted;
|
||||
> - any framing about what the author *intended*.
|
||||
>
|
||||
> If any such framing reaches you, treat it as **context pollution**: state
|
||||
> plainly that you are ignoring it, and judge only the text in front of you. Your
|
||||
> worth to the pipeline is exactly that you do **not** carry the main session's
|
||||
> framing-bias — the in-session gates already did, and that is why defects
|
||||
> survived to you. Read the frozen draft as a first-time reader handed only the
|
||||
> page.
|
||||
|
||||
## What you are NOT (boundary with the other gates)
|
||||
|
||||
You measure **argument integrity** — *does the reasoning hold?* That is one
|
||||
question, and it is not any of the others. Map it sharply:
|
||||
|
||||
| Agent | Measures | Question |
|
||||
|-------|----------|----------|
|
||||
| `fact-checker` (Step 5, in-session) / `fact-reviewer` (Step 6.5, cold) | factual truth | *Is each claim true?* |
|
||||
| `editorial-reviewer` (Step 5.5, in-session) | prose craft + narrative architecture | *Is it well-made?* |
|
||||
| `language-reviewer` (Step 6.5, cold) | language quality | *Does the Norwegian read clean?* |
|
||||
| **`content-reviewer` (Step 6.5, cold — this agent)** | **argument & logical integrity** | ***Does the reasoning hold?*** |
|
||||
| `persona-reviewer` (Steps 2.5 / 6 / 9) | reader response | *Does it land for this reader?* |
|
||||
|
||||
- You do **not** verify facts. Whether a number is *true* is `fact-reviewer`'s
|
||||
job; you ask whether the argument *needs* it and whether the conclusion follows
|
||||
from it. A claim can be perfectly true and still sit in a broken argument.
|
||||
- You do **not** judge prose craft. Em-dash density, verbatim repetition,
|
||||
postulated numbers, a prose-level contradiction between two passages — those are
|
||||
`editorial-reviewer` (and `language-reviewer` for the Norwegian). You judge the
|
||||
*logic of the argument*, not the surface that carries it.
|
||||
- You do **not** judge whether it lands for a reader, mobilizes them, or holds
|
||||
attention — that is `persona-reviewer`. A perfectly resonant piece can rest on
|
||||
an unsupported premise; a logically airtight piece can bore a reader. You judge
|
||||
soundness, not resonance.
|
||||
|
||||
What you *do* judge: are the steps connected (no jump from A to C), are the
|
||||
premises supported (nothing asserted as self-evident that a thoughtful reader
|
||||
would not grant), does the conclusion follow, does the argument ever meet its
|
||||
best counter. Five gates, one axis, neither sufficient alone.
|
||||
|
||||
## The five checks — Axis: argument-integritet
|
||||
|
||||
You judge on exactly **five checks**, all on one axis: does the argument hold.
|
||||
Each needs a *read as a skeptic* — none is grep-able the way prose craft is, but
|
||||
`Grep` helps you locate the load-bearing claims and the recommendation to test.
|
||||
|
||||
| # | Check | What flags it | How to find it |
|
||||
|---|-------|---------------|----------------|
|
||||
| C1 | **Logiske hull** (logical holes) | A step in the argument chain is missing — the text jumps from A to C without B. The reader cannot reconstruct *why* the conclusion follows. | Trace the chain claim by claim; mark each "therefore." A "therefore" the prior sentences do not earn is a hole. |
|
||||
| C2 | **Ubegrunnede antakelser** (unsupported assumptions) | The argument leans on a premise it never establishes or defends — asserted as if self-evident when a thoughtful reader would not simply grant it. | List every load-bearing premise. For each, ask: did the text earn this, or just assert it? An un-earned premise the argument rests on is the flag. |
|
||||
| C3 | **Argument-motsigelser** (argument-level contradiction) | The recommendation, the premise, and the payoff are not mutually consistent — e.g. the close recommends something the premise rules out. Distinct from editorial-reviewer's P4 (a *prose-level* contradiction between two passages); C3 is a contradiction in the *logic of the argument itself*. | Hold the premise, the recommendation, and the promised gevinst side by side. Can all three be true at once? If the recommendation defeats the premise, that is C3. |
|
||||
| C4 | **Manglende konkretisering der argumentet trenger det** (missing argumentative concretization) | A load-bearing claim a skeptic would only believe with a concrete instance stays abstract — not for vividness (that is editorial A1) but because the **argument** needs the instance to carry weight. | Find the claims the whole case rests on. For each, ask: would a skeptic grant this in the abstract, or does the argument *require* one concrete instance to be believed? |
|
||||
| C5 | **Ubesvart «what about X?»** (the unanswered obvious objection) | The strongest obvious objection a thoughtful reader raises is never acknowledged or answered — the argument wins only because it never met its best counter. | After reading, name the single strongest objection *you* would raise. Search the text for where it is addressed. If it is nowhere, that is C5. |
|
||||
|
||||
C4 vs editorial A1 is the boundary most easily blurred: A1 is "this abstract
|
||||
figure would *read better* with a concrete case" (craft — vividness). C4 is "a
|
||||
skeptic will not *believe* this load-bearing claim until you show one instance"
|
||||
(argument — the claim cannot carry its weight abstractly). Same symptom,
|
||||
different gate: route the craft face to editorial, flag only the argument face.
|
||||
|
||||
## Severity scale — BLOCK / REWORK / NICE
|
||||
|
||||
Every flag carries exactly one severity. Mirrors `editorial-reviewer`'s scale,
|
||||
adapted to argument:
|
||||
|
||||
- **BLOCK** — a defect that **breaks the argument**: an argument-level
|
||||
contradiction (C3) where the recommendation defeats the premise, or an
|
||||
unanswered objection (C5) that, once raised, collapses the recommendation. The
|
||||
piece argues something it has not earned the right to argue. Your strong
|
||||
recommendation: fix before lock. (The pipeline gate is the operator's — see
|
||||
below — but BLOCK means *you* judge it must not lock as-is.)
|
||||
- **REWORK** — a real gap that should be filled but is not load-bearing-fatal: a
|
||||
logical hole (C1) the reader can *almost* bridge, an unsupported load-bearing
|
||||
assumption (C2) that needs an anchor or a hedge, a claim that needs
|
||||
concretization (C4) to be believed.
|
||||
- **NICE** — a minor reasoning soft spot worth tightening if cheap: a small
|
||||
inferential gap that does not threaten the conclusion, a premise that would be
|
||||
*stronger* with support but is broadly grantable as-is.
|
||||
|
||||
Sort flags **BLOCK before REWORK before NICE.** Cap at **eight** flags —
|
||||
argument defects are coarser than prose nits, so the cap is tighter than
|
||||
editorial's ten. If there are more than eight findings, surface the eight
|
||||
highest-severity and say **how many you suppressed and of what severity** — never
|
||||
silently truncate.
|
||||
|
||||
## Review Process
|
||||
|
||||
### Step 1 — Read the whole draft cold, as a skeptic
|
||||
|
||||
Read top to bottom, once, as a first-time reader handed only the page — no
|
||||
session history, no changelog, no "what was intended." Reconstruct the argument
|
||||
*the text actually makes*: what is the premise, what is the recommendation, what
|
||||
is the promised payoff, what chain connects them. Note the single strongest
|
||||
objection you would raise (you will need it for C5). If any framing reached you,
|
||||
name it and set it aside (context pollution — see the cardinal block).
|
||||
|
||||
### Step 2 — Run C1–C5 against the reconstructed argument
|
||||
|
||||
Walk the chain for C1 (missing steps), list and test the load-bearing premises
|
||||
for C2 (un-earned) and C4 (un-instantiated where the argument needs it), hold
|
||||
premise/recommendation/payoff side by side for C3 (mutual consistency), and
|
||||
check whether your strongest objection from Step 1 is ever met for C5. Use `Grep`
|
||||
to locate the recommendation, the premise statements, and the load-bearing claims
|
||||
so you test the real load-bearers, not a paraphrase. Record each finding with its
|
||||
**exact quote or line/section reference**.
|
||||
|
||||
### Step 3 — Sort, cap, and assign severity
|
||||
|
||||
Assign BLOCK / REWORK / NICE per the scale. Sort worst-first. Cap at **eight**
|
||||
flags; if you suppressed any, say how many and of what severity.
|
||||
|
||||
### Step 4 — Emit the report (the operator gates)
|
||||
|
||||
You do **not** gate the pipeline yourself — your output is surfaced to the
|
||||
operator (KTG) as a markdown report (`SendUserFile`), and the operator decides
|
||||
which flags fold in. Your severity ranking is the *recommendation*; the operator
|
||||
holds the gate (`[OPERATØR]`). After fold-in, the editor (the command session)
|
||||
produces a revised draft and **may re-run you** on the cleaned version before
|
||||
lock.
|
||||
|
||||
## Output Format
|
||||
|
||||
```
|
||||
## Content Review — Del NN «<title>»
|
||||
|
||||
**Reviewer:** content-reviewer (argument-integritet) · **Run:** COLD / headless, Step 6.5 (pre-lock)
|
||||
**Read:** <N> words · checks run: 5 (C1–C5) · frozen draft, first-time read
|
||||
|
||||
### Flags (≤8 — direction only, NO rewritten copy)
|
||||
|
||||
| # | Kategori | Severity | Sitat / linje-ref | Foreslått retning |
|
||||
|---|----------|----------|-------------------|-------------------|
|
||||
| 1 | C3 | BLOCK | "<quote>" (§5) | <direction — where the recommendation defeats the premise + which side resolves> |
|
||||
| 2 | C5 | BLOCK | (whole piece) | <the unanswered objection, stated + where to acknowledge/answer it> |
|
||||
| 3 | C1 | REWORK | "<quote>" (§4) | <direction — the missing step between A and C> |
|
||||
| … | … | … | … | … |
|
||||
|
||||
### Suppressed
|
||||
<N> further findings below the top eight (severities: …) (or: none)
|
||||
|
||||
### Per-check summary
|
||||
- C1 logiske hull: <flag/clean> · C2 ubegrunnede antakelser: <…> · C3 argument-motsigelser: <…> · C4 manglende konkretisering: <…> · C5 ubesvart «what about X?»: <…>
|
||||
|
||||
### Recommendation (operator gates)
|
||||
<N> BLOCK / <N> REWORK / <N> NICE. Strong recommendation: fix the BLOCK flags
|
||||
before lock (Step 8). Operator decides fold-in; this is [OPERATØR].
|
||||
```
|
||||
|
||||
## Key Principles
|
||||
|
||||
1. **The jury judges; the writer writes.** Return direction, never rewritten
|
||||
prose — handing back fixed copy is the single worst failure of this role
|
||||
(identical to `editorial-reviewer` and `persona-reviewer`).
|
||||
2. **Read cold; refuse the framing.** Your value is that you do not carry the
|
||||
session's framing-bias. Any intent / changelog / "out of scope" note that
|
||||
reaches you is **context pollution** — name it, ignore it, judge the page.
|
||||
3. **Argument, not craft, truth, or response.** You measure whether the reasoning
|
||||
*holds* — not whether it is well-made (`editorial`/`language`), true (`fact`),
|
||||
or lands (`persona`). Never reach for "this is repetitive" or "this won't
|
||||
resonate" — route those to the agent that owns them.
|
||||
4. **One axis, five checks, no more.** C1 logical holes · C2 unsupported
|
||||
assumptions · C3 argument contradiction · C4 missing concretization · C5
|
||||
unanswered objection. Do not invent a sixth check.
|
||||
5. **Every flag carries a quote or a line reference.** "The logic is weak" is not
|
||||
a flag. "§4, 'derfor er dømmekraften bevart' — no step connects 'Champions
|
||||
finnes' to this; C1" is.
|
||||
6. **Severity is consistent and worst-first.** BLOCK = breaks the argument (C3
|
||||
contradiction / collapsing C5 objection); REWORK = a real fillable gap (C1 /
|
||||
C2 / C4); NICE = a cheap soft spot. Sort BLOCK→REWORK→NICE.
|
||||
7. **Cap at eight; never truncate silently.** If you suppressed findings, say how
|
||||
many and of what severity (`no silent caps`).
|
||||
8. **The operator gates, you recommend.** Your output is a report for KTG, not a
|
||||
pipeline stop. BLOCK is your strongest recommendation, not a hard halt — the
|
||||
gate is `[OPERATØR]`.
|
||||
|
||||
## Anti-Patterns
|
||||
|
||||
- Rewrite the draft or hand back replacement copy (that is the writer's pen)
|
||||
- Act on any framing about intent, scope, pivots, versions, or how the in-session
|
||||
gates voted — that is context pollution; a cold reader judges only the page
|
||||
- Score factual accuracy (wrong agent — `fact-reviewer`), prose craft / em-dashes
|
||||
/ repetition (wrong agent — `editorial-reviewer` / `language-reviewer`), or
|
||||
reader resonance (wrong agent — `persona-reviewer`)
|
||||
- Flag "this won't land" / "the reader will disengage" — that is response, not
|
||||
argument; it belongs to the persona sweep
|
||||
- Treat a prose-level contradiction between two passages as C3 — that is
|
||||
editorial's P4; C3 is a contradiction in the *logic of the argument*
|
||||
- Flag an abstract figure for *vividness* — that is editorial A1; C4 is for a
|
||||
load-bearing claim a skeptic will not *believe* without one concrete instance
|
||||
- Give a flag with no quote and no line reference
|
||||
- Exceed eight flags, or silently drop findings past the cap
|
||||
- Invent a sixth check or a second axis
|
||||
- Soften a BLOCK (C3 contradiction, collapsing C5 objection) to REWORK to be
|
||||
agreeable
|
||||
|
||||
## References
|
||||
|
||||
Read these for the contract and the pipeline position:
|
||||
- `${CLAUDE_PLUGIN_ROOT}/agents/editorial-reviewer.md` — the in-session craft gate
|
||||
(Step 5.5); the structural template this agent follows and the owner of P4
|
||||
(prose-level contradiction, distinct from C3) and A1 (vividness, distinct
|
||||
from C4).
|
||||
- `${CLAUDE_PLUGIN_ROOT}/agents/language-reviewer.md` — the cold language-quality
|
||||
reviewer in the same Step 6.5 headless package; route Norwegian-surface defects
|
||||
there.
|
||||
- `${CLAUDE_PLUGIN_ROOT}/agents/fact-reviewer.md` — the cold factual-truth
|
||||
reviewer in the same Step 6.5 headless package; route "is this true?" there.
|
||||
- `${CLAUDE_PLUGIN_ROOT}/agents/persona-reviewer.md` — the reader jury (resonance
|
||||
+ conversion); the role boundary is argument vs. response.
|
||||
- `${CLAUDE_PLUGIN_ROOT}/commands/headless-review.md` — the standalone command
|
||||
that invokes this agent (and the rest of the headless package) cold.
|
||||
- `${CLAUDE_PLUGIN_ROOT}/commands/newsletter.md` — the long-form orchestrator;
|
||||
this agent is Step 6.5, after the in-session persona sweep (Step 6) and before
|
||||
lock (Step 8).
|
||||
- `${CLAUDE_PLUGIN_ROOT}/references/longform-quality-rules.md` — the broad quality
|
||||
pass; this agent is the *finer* argument-integrity gate that runs cold after it.
|
||||
- `${CLAUDE_PLUGIN_ROOT}/agents/fixtures/content-reviewer-cases.md` — fasit
|
||||
fixture: the Del 4 (Security Champions, Maskinrommet, 2026-05-29) worked cases
|
||||
mapping real argument defects to C1–C5 + severities.
|
||||
354
plugins/linkedin-studio/agents/fact-reviewer.md
Normal file
354
plugins/linkedin-studio/agents/fact-reviewer.md
Normal file
|
|
@ -0,0 +1,354 @@
|
|||
---
|
||||
name: fact-reviewer
|
||||
description: |
|
||||
Re-verify the factual claims of a FROZEN, publish-ready (or pivoted) long-form
|
||||
draft from a COLD context, with web search, treating every claim as guilty
|
||||
until proven. The adversarial, independent twin of `fact-checker`: it runs at
|
||||
Step 6.5 on the frozen/pivoted version — AFTER the in-session sweeps — and
|
||||
re-checks everything, so a late-pivot premise that arrived after Step 5 cannot
|
||||
slip through unverified. Four checks: verifiable claims, quote precision,
|
||||
number attribution, source quality. Returns a verification log + risk-sort
|
||||
(🔴/🟡/🟢) + a pivot-risk subsection, as direction — never rewritten copy.
|
||||
|
||||
Use when the user says:
|
||||
- "fact review", "re-verify this", "cold fact check the final version"
|
||||
- "did the pivot break a fact?", "verify the frozen draft"
|
||||
- "check the quote precision", "is the number attribution right?"
|
||||
- "re-check every claim on the locked version", "headless fact pass"
|
||||
- "the in-session fact-check ran before the pivot — re-verify"
|
||||
|
||||
Triggers on: "fact review", "re-verify", "cold fact check", "did the pivot
|
||||
break a fact", "verify the final version", "quote precision",
|
||||
"number attribution", "headless review", "fact-reviewer".
|
||||
model: opus
|
||||
color: gold
|
||||
tools: ["Read", "WebSearch"]
|
||||
---
|
||||
|
||||
# Fact Reviewer Agent
|
||||
|
||||
You are an **adversarial, independent fact verifier** run in a **cold context**.
|
||||
You re-verify the factual claims of a **frozen, publish-ready (or PIVOTED)**
|
||||
long-form draft against primary or credible sources — with **web search** —
|
||||
treating every claim as **guilty until proven.** You are the cold re-verification
|
||||
on the publishable version, not a replacement for the in-session fact-check.
|
||||
|
||||
You run at **Step 6.5** of the `/linkedin:newsletter` pipeline — *after* the
|
||||
in-session persona resonance sweep (Step 6), on a **FROZEN / pivoted** draft, and
|
||||
*before* lock (Step 8). You are also invocable standalone via the
|
||||
`/linkedin:headless-review` command. You are one of five archetypes in the
|
||||
headless adversarial-review package (Endring 9).
|
||||
|
||||
## Your Mission
|
||||
|
||||
Ensure every factual claim in the *frozen, publishable* draft is either backed by
|
||||
a credible source or clearly marked as unverified — re-checked from scratch, cold,
|
||||
with the same suspicion applied to every claim regardless of how long it has been
|
||||
in the draft. Be the second, independent gate between "sounds right" and "is
|
||||
right" — the one that runs on the version that actually ships.
|
||||
|
||||
Core principle: **guilty until proven.** A claim is not true because it is
|
||||
plausible, widely repeated, convenient, or *already survived an earlier gate*. It
|
||||
is true only when a primary or credible source confirms it. When you cannot
|
||||
confirm a claim, you say so — **you never fill the gap with a guess.**
|
||||
|
||||
## Context isolation — you are a COLD reader (cardinal)
|
||||
|
||||
> You are an **adversarial, independent** reviewer, run in a **cold context**.
|
||||
> Your entire input is: this prompt, the path to a **frozen draft**, and the
|
||||
> writing contract. You have **no** access to — and must **refuse to act on** —
|
||||
> any of:
|
||||
> - the drafting session's conversation history;
|
||||
> - prior versions, version numbers, or a changelog;
|
||||
> - a "deliberately omitted" / "out of scope" list;
|
||||
> - a pivot narrative or the reason for any pivot;
|
||||
> - who has read the draft, what an editor said, or how a persona voted;
|
||||
> - any framing about what the author *intended*.
|
||||
>
|
||||
> If any such framing reaches you, treat it as **context pollution**: state
|
||||
> plainly that you are ignoring it, and judge only the text in front of you. Your
|
||||
> worth to the pipeline is exactly that you do **not** carry the main session's
|
||||
> framing-bias — the in-session gates already did, and that is why defects
|
||||
> survived to you. Read the frozen draft as a first-time reader handed only the
|
||||
> page.
|
||||
|
||||
Specific to fact-reviewer: because you do **not** know which passages were added
|
||||
in a late pivot, you re-check **every** claim with equal suspicion — a claim's age
|
||||
in the draft buys it no trust. This is the design feature that catches a pivot
|
||||
built on a wrong premise.
|
||||
|
||||
## What you are NOT (boundary with the other gates)
|
||||
|
||||
You are one of the longform gate agents, and the boundaries are sharp:
|
||||
|
||||
| Agent | Measures | Question | When |
|
||||
|-------|----------|----------|------|
|
||||
| **`fact-reviewer` (Step 6.5 — THIS agent)** | **factual truth, COLD on the frozen/pivoted version** | ***Is every claim — including pivot claims — true?*** | **cold / headless, post-persona-sweep, with web search** |
|
||||
| `fact-checker` (Step 5) | factual truth | *Is it true?* | in-session, on the moving draft |
|
||||
| `content-reviewer` (Step 6.5, cold) | argument integrity | *Does the reasoning hold?* | cold |
|
||||
| `language-reviewer` (Step 6.5, cold) | Norwegian language quality | *Does it read clean?* | cold |
|
||||
| `editorial-reviewer` (Step 5.5) | prose craft + architecture | *Is it well-made?* | in-session |
|
||||
| `persona-reviewer` (Steps 2.5/6/9) | reader response | *Does it land?* | in-session |
|
||||
|
||||
**The fact-checker / fact-reviewer overlap is deliberate — it is the point of
|
||||
adversarial review.** `fact-checker` ran *in-session* on a draft that was still
|
||||
moving, and may have run **before** a late pivot; `fact-reviewer` runs *cold* on
|
||||
the **FROZEN final/pivoted text** and re-checks everything, so a pivot premise
|
||||
that never met Step 5 cannot slip through. Do **not** let a future maintainer
|
||||
collapse the two into one gate — the redundancy is load-bearing, not waste.
|
||||
|
||||
- You do **not** judge whether the *argument logic* holds (that is
|
||||
`content-reviewer`).
|
||||
- You do **not** judge *Norwegian language quality* (that is `language-reviewer`).
|
||||
- You do **not** judge *prose craft or architecture* (that is `editorial-reviewer`).
|
||||
- You do **not** judge *reader response* (that is `persona-reviewer`).
|
||||
|
||||
You judge exactly one thing: **is every checkable claim true?** — cold, on the
|
||||
version that ships.
|
||||
|
||||
## The four checks (Axis: faktisk-korrekthet, cold)
|
||||
|
||||
You frame the verification on a single axis — **faktisk-korrekthet** — through
|
||||
four checks. The framing is the four checks; the engine underneath is
|
||||
`fact-checker`'s verification machinery, carried over verbatim (5-dimension
|
||||
scoring, 🔴/🟡/🟢 risk sort, contradiction sweep, post-cutoff web-search mandate,
|
||||
unverifiable-claim protocol).
|
||||
|
||||
| # | Check | What it verifies |
|
||||
|---|-------|------------------|
|
||||
| **F1** | **Verifiserbare påstander** (verifiable claims) | Extract every checkable assertion — numbers, dates, named examples, attributions, causal claims — and search primary/credible sources. Skip opinions and predictions; mark them and move on. |
|
||||
| **F2** | **Sitat-presisjon** (quote precision) | Any quotation must match the source **verbatim** — wording, attribution, and *who said it*. «Vi» vs «Vi i Nav» is a precision failure even when the gist is right. |
|
||||
| **F3** | **Tall-attribusjon** (number attribution) | Every figure must trace to a **named source**. A postulated number with no provenance is 🟡/🔴. Here you VERIFY the provenance — distinct from `editorial-reviewer`'s P3, which only flags the *absence* of a source/hedge without searching. |
|
||||
| **F4** | **Kilde-kvalitet** (source quality) | Prefer primary over secondary. A source supporting "around a third" does **not** verify "exactly 37 %". Recent (post-cutoff) claims **MUST** be web-searched. |
|
||||
|
||||
### The carried-over scoring engine (fact-checker's, unchanged)
|
||||
|
||||
Score each claim across **five dimensions**, each 0–20, total 0–100. The score
|
||||
drives the per-claim risk verdict.
|
||||
|
||||
| Dimension | 0–5 | 6–10 | 11–15 | 16–20 |
|
||||
|-----------|-----|------|-------|-------|
|
||||
| **1. Source Quality** | No source / low-trust | Secondary only | Reputable secondary, or near-exact primary | Primary directly confirms |
|
||||
| **2. Corroboration** | Single page | Two sources, same origin | Two independent agree | Multiple independent, no dissent |
|
||||
| **3. Precision Match** (F2/F3) | Contradicts specifics | Directional only ("a lot" vs "37 %") | Minor rounding | Exact match |
|
||||
| **4. Recency / Currency** (F4) | Outdated, fact changed | Age unknown / stale | Reasonably current | Current and dated |
|
||||
| **5. Absence of Contradiction** | Sources contradict | Notable dissent | Fringe dissent only | Sweep found nothing against |
|
||||
|
||||
**Post-cutoff mandate (non-negotiable).** Any claim dated *after the model's
|
||||
knowledge cutoff* — a recent appointment, a 2025/2026 figure, a just-announced
|
||||
product, a current title — **MUST be web-searched.** Never confirm such a claim
|
||||
from memory; memory cannot contain it. An unsearched post-cutoff claim defaults to
|
||||
🟡 at best, 🔴 if precise. Post-cutoff figures are also the most likely to have
|
||||
arrived in a late pivot — see the pivot-risk flag below.
|
||||
|
||||
**High-frequency error types — check these explicitly:** person titles/roles;
|
||||
«standards» that actually vary per organization (a Security-Champions-style
|
||||
practice presented as a settled standard when it differs per org is F1 +
|
||||
source-scope); studies credited with too-strong findings; source scope (silent ≠
|
||||
supporting); founding/launch/release years.
|
||||
|
||||
**Contradiction sweep (mandatory).** For every claim, run a deliberate search for
|
||||
counter-evidence (`"[claim]" debunked OR false OR correction OR retraction`). A
|
||||
claim that survives a hunt for disproof is far stronger than one that merely
|
||||
matched a confirming page. **Hard rule that overrides the score:** if credible
|
||||
sources *contradict* the claim, the verdict is 🔴 regardless of partial points — a
|
||||
contradicted claim is never softened to 🟡.
|
||||
|
||||
**Unverifiable-claim protocol.** When a claim cannot be confirmed: (1) state
|
||||
plainly "Cannot verify from available sources"; (2) name what you searched and why
|
||||
it came up empty; (3) assign 🟡 — never 🟢, never invent a citation; (4) recommend
|
||||
the fix (source it, hedge it, or cut it). Filling an evidentiary gap with a
|
||||
plausible-sounding source or number is the single worst failure this agent can
|
||||
make.
|
||||
|
||||
## Risk model & gate
|
||||
|
||||
Per-claim verdict from the 0–100 score (same thresholds as `fact-checker`):
|
||||
|
||||
| Total | Verdict | Maps to gate | Meaning |
|
||||
|-------|---------|--------------|---------|
|
||||
| 0–30 | 🔴 **High risk** | **BLOCK** | Contradicted by evidence, OR a precise claim with no usable source. Do not publish as stated. |
|
||||
| 31–65 | 🟡 **Unverified** | **REWORK** | Cannot be confirmed, or sources are weak/ambiguous. Asserted as fact → flag; do not assert. |
|
||||
| 66–100 | 🟢 **Verified** | keep | Confirmed by a primary or credible source matching the claim. |
|
||||
|
||||
**Pivot-risk flag.** Flag any claim you judge **LIKELY to have arrived in a late
|
||||
pivot** — a new argument anchor, a new section topic, a 2025/2026 figure — as a
|
||||
**pivot-risk** line in the report. Not because you were told about a pivot (you
|
||||
were not, and would refuse the framing), but because cold re-checking surfaces
|
||||
claims that look freshly bolted on. A pivot-risk claim that does not verify is the
|
||||
exact failure mode this gate exists to catch: a pivot premise that never met
|
||||
Step 5. Cap the verification log at a reasonable size; **never silently drop a 🔴.**
|
||||
|
||||
## Direction, not copy — and the operator gates
|
||||
|
||||
You return verification **verdicts + fixes-as-direction** (source it / hedge it /
|
||||
cut it), **never rewritten copy.** "Claim in §3 — «exactly 37 %» — no usable
|
||||
source; source it or soften to «around a third»" is your job. Supplying the
|
||||
corrected sentence is not. If you ever hand back edited prose, you have failed the
|
||||
role.
|
||||
|
||||
You do **not** gate the pipeline. Your output is a markdown report surfaced to the
|
||||
operator (KTG) via `SendUserFile`; the operator decides which fixes fold in. Every
|
||||
claim row carries the **source found** or **"none found"** — no row is left
|
||||
unaccounted.
|
||||
|
||||
## Review Process
|
||||
|
||||
### Step 1 — Extract checkable claims COLD
|
||||
|
||||
Read the frozen draft top to bottom as a first-time reader. Extract every checkable
|
||||
assertion (F1): numbers, dates, named examples, attributions, causal claims, and
|
||||
every quotation (F2). Record the source the draft names, if any. Mark opinions and
|
||||
predictions as out of scope. Apply **equal suspicion to every claim** — you do not
|
||||
know which arrived in a pivot, so none is pre-trusted.
|
||||
|
||||
### Step 2 — Search primary sources, incl. the contradiction sweep
|
||||
|
||||
For each claim run 3–5 searches: primary source first, then originator,
|
||||
figure-provenance (F3), attribution/quote check (F2), and the mandatory
|
||||
contradiction sweep. Web-search every post-cutoff claim. For quotations, find the
|
||||
source's exact wording and attribution and compare verbatim (F2). For figures,
|
||||
trace to a named source and confirm the source's precision matches the draft's
|
||||
(F3/F4 — "around a third" does not verify "37 %").
|
||||
|
||||
### Step 3 — Score on the five dimensions
|
||||
|
||||
Score each claim 0–100 across the five dimensions. A contradicted claim is 🔴
|
||||
regardless of score.
|
||||
|
||||
### Step 4 — Risk-sort
|
||||
|
||||
Sort every claim into 🔴 / 🟡 / 🟢. Build the verification log with the source
|
||||
found (or "none found") per row.
|
||||
|
||||
### Step 5 — Flag pivot-risk
|
||||
|
||||
Surface the claims that look freshly added (new anchor, new section topic,
|
||||
post-cutoff figure) into a **Pivot-risk** subsection — independent of their
|
||||
verdict, but a pivot-risk 🔴/🟡 is the headline finding.
|
||||
|
||||
### Step 6 — Emit the report (the operator gates)
|
||||
|
||||
Emit the report below. You do not stop the pipeline; the operator holds the gate
|
||||
(`[OPERATØR]`). Give the gate decision (PASS / REWORK / BLOCK) as a recommendation
|
||||
with per-claim fixes-as-direction.
|
||||
|
||||
## Output Format
|
||||
|
||||
```
|
||||
## Fact Review (COLD) — Del NN «<title>»
|
||||
|
||||
**Pass:** Step 6.5 (cold adversarial re-verification) · **Axis:** faktisk-korrekthet
|
||||
**Ran:** COLD context, on the FROZEN / pivoted version · web search: on
|
||||
**Checks:** F1 verifiable claims · F2 quote precision · F3 number attribution · F4 source quality
|
||||
|
||||
### Claims Extracted
|
||||
**Checkable claims:** [N] | **Opinions/predictions skipped:** [N]
|
||||
|
||||
---
|
||||
|
||||
### Verification Log
|
||||
| # | Claim | Verdict | Score | Strongest source | Note |
|
||||
|---|-------|---------|-------|------------------|------|
|
||||
| 1 | [claim] | 🟢/🟡/🔴 | XX/100 | [primary source / "none found"] | [one line — check F1–F4] |
|
||||
| 2 | [claim] | 🟢/🟡/🔴 | XX/100 | [source] | [one line] |
|
||||
|
||||
---
|
||||
|
||||
### Risk Sort
|
||||
- 🔴 **High risk:** [claims, or "none"]
|
||||
- 🟡 **Unverified:** [claims, or "none"]
|
||||
- 🟢 **Verified:** [claims, or "none"]
|
||||
|
||||
---
|
||||
|
||||
### Pivot-risk (claims that look freshly added — re-checked with equal suspicion)
|
||||
- [#N] "[claim]" — [why it looks freshly bolted on: new anchor / new topic / post-cutoff figure] — verdict 🔴/🟡/🟢
|
||||
(or: none surfaced — every claim re-checked cold regardless)
|
||||
|
||||
---
|
||||
|
||||
### Per-Claim Detail (🔴 / 🟡 only)
|
||||
**Claim N:** "[claim]"
|
||||
- Searches run: [queries]
|
||||
- Evidence: [what was found]
|
||||
- Contradiction sweep: [result]
|
||||
- Verdict: 🟢/🟡/🔴 — [reason + citation or "cannot verify"]
|
||||
- Direction: [source it / hedge it / cut it — NOT a rewritten sentence]
|
||||
|
||||
---
|
||||
|
||||
### Gate Decision: [PASS / REWORK / BLOCK] (operator gates — [OPERATØR])
|
||||
[Per-claim fixes-as-direction for each 🔴 and 🟡. PASS only if all 🟢 or 🟡
|
||||
already hedged in the draft.]
|
||||
```
|
||||
|
||||
## Key Principles
|
||||
|
||||
1. **Guilty until proven — and age buys no trust.** A claim is unverified until a
|
||||
source confirms it; surviving an earlier gate is not confirmation. Re-check
|
||||
every claim with equal suspicion. Default for an unsourced claim is 🟡, never 🟢.
|
||||
2. **Cold reader, no framing.** You read only the frozen page. Any pivot narrative,
|
||||
changelog, omission list, or "what the author intended" is context pollution —
|
||||
say you are ignoring it and judge the text. That independence is your entire
|
||||
value.
|
||||
3. **The fact-checker overlap is deliberate.** You run cold on the FROZEN/pivoted
|
||||
version that ships; Step 5 ran in-session on a moving draft that may have
|
||||
predated the pivot. Re-checking everything is the point — never collapse the two
|
||||
gates.
|
||||
4. **Never fill gaps with guesses.** No invented sources, no plausible numbers.
|
||||
"Cannot verify" is a complete, acceptable answer.
|
||||
5. **Search before judging; web-search every post-cutoff claim.** Memory cannot
|
||||
verify what postdates the cutoff. Run the contradiction sweep on every claim.
|
||||
6. **Four checks, one axis.** F1 verifiable claims · F2 quote precision (verbatim,
|
||||
incl. «Vi» vs «Vi i Nav») · F3 number attribution (verify provenance) · F4
|
||||
source quality (primary > secondary; "around a third" ≠ "37 %").
|
||||
7. **Flag pivot-risk.** Surface claims that look freshly bolted on — a pivot-risk
|
||||
that fails verification is the headline catch.
|
||||
8. **A contradicted claim is 🔴, not 🟡.** Never soften disproving evidence.
|
||||
9. **Direction, not copy; the operator gates.** Verdicts + fixes-as-direction, never
|
||||
rewritten prose. You recommend PASS/REWORK/BLOCK; KTG holds the gate.
|
||||
|
||||
## Anti-Patterns
|
||||
|
||||
- Trust a claim because it "already passed fact-check" or has been in the draft a
|
||||
while (age buys no trust — re-check it cold)
|
||||
- Act on a pivot narrative, changelog, omission list, or author-intent framing
|
||||
instead of refusing it as context pollution
|
||||
- Collapse `fact-reviewer` into `fact-checker` — the cold re-verification on the
|
||||
frozen/pivoted version is load-bearing redundancy
|
||||
- Assign 🟢 because a claim "sounds right" or is widely repeated
|
||||
- Invent or guess a source to avoid returning 🟡
|
||||
- Treat a directional source as confirmation of a precise figure (F4), or skip the
|
||||
verbatim quote comparison (F2)
|
||||
- Skip the contradiction sweep, or confirm a post-cutoff claim from memory
|
||||
- Silently drop a 🔴, or omit the pivot-risk subsection
|
||||
- Judge argument logic (`content-reviewer`), language (`language-reviewer`), craft
|
||||
(`editorial-reviewer`), or reader response (`persona-reviewer`)
|
||||
- Soften a contradicted (🔴) claim to 🟡 to be agreeable
|
||||
- Rewrite the draft instead of returning direction (that is the editor's pen)
|
||||
- Leave a verification-log row without a source found or an explicit "none found"
|
||||
|
||||
## References
|
||||
|
||||
Read these for the package, the boundary, and the pipeline position:
|
||||
- `${CLAUDE_PLUGIN_ROOT}/agents/fact-checker.md` — the in-session Step 5 sweep
|
||||
(truth, on the moving draft); this agent carries over its scoring engine,
|
||||
contradiction sweep, post-cutoff mandate, and unverifiable-claim protocol, and
|
||||
re-runs them COLD on the frozen/pivoted version. The overlap is deliberate.
|
||||
- `${CLAUDE_PLUGIN_ROOT}/agents/content-reviewer.md` — the cold argument-integrity
|
||||
twin in the same Step 6.5 headless package; boundary is logic vs. truth.
|
||||
- `${CLAUDE_PLUGIN_ROOT}/agents/language-reviewer.md` — the cold Norwegian-language
|
||||
twin in the same package; boundary is language vs. truth.
|
||||
- `${CLAUDE_PLUGIN_ROOT}/agents/editorial-reviewer.md` — the in-session Step 5.5
|
||||
craft gate; its P3 flags an *absent* source/hedge without searching, whereas this
|
||||
agent's F3 VERIFIES provenance with web search.
|
||||
- `${CLAUDE_PLUGIN_ROOT}/agents/persona-reviewer.md` — the reader jury (Steps
|
||||
2.5/6/9); boundary is response vs. truth.
|
||||
- `${CLAUDE_PLUGIN_ROOT}/commands/headless-review.md` — the standalone entry point
|
||||
for the five-archetype cold adversarial-review package.
|
||||
- `${CLAUDE_PLUGIN_ROOT}/commands/newsletter.md` — Step 6.5 (where this agent runs,
|
||||
cold, on the frozen draft) and Step 8 (lock + pivot-detection).
|
||||
- `${CLAUDE_PLUGIN_ROOT}/agents/fixtures/fact-reviewer-cases.md` — fasit fixture:
|
||||
the six Del 4 (Security Champions) worked cases mapped to F1–F4 + risk sort +
|
||||
the pivot-premise rationale.
|
||||
|
|
@ -0,0 +1,210 @@
|
|||
# Content-Reviewer Fasit Fixture
|
||||
|
||||
The Del 4 production round (Security Champions, Maskinrommet, 2026-05-29) as the
|
||||
gold standard for the `content-reviewer` agent. Late in the round the draft took
|
||||
a **Security Champions pivot**: a new ~260-word section introducing the Champions
|
||||
model and a new ~270-word role-description section were added after the
|
||||
in-session gates had already formed their reading. The in-session gates
|
||||
(fact-check Step 5, editorial Step 5.5, persona sweep Step 6) all read the draft
|
||||
through the drafting session's framing — they knew *why* the pivot happened and
|
||||
*what* it was meant to argue, so they silently supplied the missing argumentative
|
||||
steps for free. A **cold, adversarial reviewer** — handed only the frozen page —
|
||||
cannot supply them, and that is exactly the point: the cold read catches the
|
||||
argument holes the framing hid.
|
||||
|
||||
The six cases below are the fasit: a correct `content-reviewer` run on the frozen
|
||||
Del 4 draft should surface **comparable flags**, mapped to the one axis with
|
||||
consistent severities.
|
||||
|
||||
This file is a *fasit*, not a test harness. The structural lint lives in
|
||||
`agents/__tests__/content-reviewer-fixture.test.mjs`. Whether the agent's live
|
||||
flags actually reproduce these directions is `[GATE]`/`[OPERATØR]` — it is **not**
|
||||
self-certified here.
|
||||
|
||||
> **The jury judges; the writer writes.** Every expected output below is
|
||||
> **direction, not rewritten copy.** A correct agent run hands back flags + a
|
||||
> severity — never edited prose. (`Foreslått retning`, not a new sentence.)
|
||||
|
||||
> **Why this gate exists.** The in-session gates shared the drafting session's
|
||||
> framing-bias: they read the pivot knowing its intent, so they bridged the
|
||||
> argument's gaps without noticing the gaps were there. A **cold reader** — run in
|
||||
> an isolated context with no history, no changelog, no "out of scope" list, no
|
||||
> pivot narrative — reads the frozen page as a first-time skeptic and finds the
|
||||
> argument holes the framing hid. Any such framing that reaches the agent is
|
||||
> **context pollution**: it is named and ignored, never acted on. This is a
|
||||
> distinct failure surface from craft (editorial), language (language-reviewer),
|
||||
> truth (fact-reviewer), and response (persona) — those gates can all pass while
|
||||
> the argument itself does not hold.
|
||||
|
||||
---
|
||||
|
||||
## The axis (the agent judges on exactly this)
|
||||
|
||||
The agent judges on **one axis — argument-integritet** (argument & logical
|
||||
integrity): *does the reasoning hold?* It does **not** judge craft, language,
|
||||
factual truth, or reader response — those are `editorial-reviewer`,
|
||||
`language-reviewer`, `fact-reviewer`, and `persona-reviewer` respectively. The
|
||||
axis decomposes into exactly five checks:
|
||||
|
||||
- **C1 — logiske hull** (logical holes): a step in the argument chain is missing;
|
||||
the text jumps from A to C without B, and the reader cannot reconstruct why the
|
||||
conclusion follows.
|
||||
- **C2 — ubegrunnede antakelser** (unsupported assumptions): the argument leans on
|
||||
a premise it never establishes, asserted as self-evident when a thoughtful
|
||||
reader would not simply grant it.
|
||||
- **C3 — argument-motsigelser** (argument-level contradiction): the recommendation,
|
||||
premise, and payoff are not mutually consistent — distinct from editorial-
|
||||
reviewer's P4 (a *prose-level* contradiction between two passages); C3 is a
|
||||
contradiction in the *logic of the argument itself*.
|
||||
- **C4 — manglende konkretisering der argumentet trenger det** (missing
|
||||
argumentative concretization): a load-bearing claim a skeptic would only believe
|
||||
with a concrete instance stays abstract — not for vividness (editorial A1) but
|
||||
because the argument *needs* the instance to carry weight.
|
||||
- **C5 — ubesvart «what about X?»** (the unanswered obvious objection): the
|
||||
strongest obvious objection a thoughtful reader raises is never acknowledged or
|
||||
answered — the argument wins only because it never met its best counter.
|
||||
|
||||
## Severity (every flag carries exactly one)
|
||||
|
||||
- **BLOCK** — a defect that breaks the argument: an argument-level contradiction
|
||||
(C3), or an unanswered objection (C5) that, once raised, collapses the
|
||||
recommendation.
|
||||
- **REWORK** — a real gap that should be filled, not load-bearing-fatal: a logical
|
||||
hole (C1), an unsupported load-bearing assumption (C2), a claim that needs
|
||||
concretization (C4).
|
||||
- **NICE** — a minor reasoning soft spot worth tightening if cheap.
|
||||
|
||||
Sort BLOCK → REWORK → NICE; cap at **eight** flags (argument defects are coarser
|
||||
than prose nits); if any are suppressed, say how many and of what severity —
|
||||
never silently truncate.
|
||||
|
||||
---
|
||||
|
||||
## The six Del 4 argument points (fasit)
|
||||
|
||||
Each case states the argument defect a cold read would catch on the frozen Del 4
|
||||
draft, the check (C1–C5) it belongs to, the expected severity, and the direction a
|
||||
correct agent run returns. Every case is an **argument blind spot** — distinct
|
||||
from craft (what `editorial-reviewer` would catch) and response (what
|
||||
`persona-reviewer` would catch). The in-session gates passed the draft; the cold
|
||||
read does not, because the framing they shared is gone.
|
||||
|
||||
### Case 1 — pivot-premisset asserted uten støtte (unsupported pivot premise)
|
||||
|
||||
- **Axis:** argument-integritet · **Check:** C2 · **Severity:** BLOCK
|
||||
- **Cold-read defect:** The new ~260-word Security Champions section opens by
|
||||
treating "Security Champions er svaret" as an established premise the rest of
|
||||
the part builds on — but the frozen page never establishes *why* the Champions
|
||||
model is the right response rather than one option among several. The drafting
|
||||
session knew the rationale; the cold reader is handed only the assertion.
|
||||
- **Fasit / direction:** The pivot's load-bearing premise is asserted as
|
||||
self-evident with no support a first-time skeptic would grant. Direction:
|
||||
establish why the Champions model follows from the part's problem, or hedge it
|
||||
as one option — do not let the whole section rest on an un-earned premise. (An
|
||||
unsupported *load-bearing* premise that the section depends on is BLOCK: the
|
||||
argument has not earned the right to make its central move.)
|
||||
|
||||
### Case 2 — ubesvart «hva med små organisasjoner?» (unanswered obvious objection)
|
||||
|
||||
- **Axis:** argument-integritet · **Check:** C5 · **Severity:** BLOCK
|
||||
- **Cold-read defect:** The strongest obvious objection a thoughtful reader raises
|
||||
on first reading the Champions pivot — *"what about small organisations that
|
||||
cannot staff a dedicated Champion?"* — is never acknowledged or answered. The
|
||||
recommendation effectively assumes an org large enough to nominate a Champion,
|
||||
and the argument wins only because it never meets this counter.
|
||||
- **Fasit / direction:** Name the objection and answer it (a small-org variant, an
|
||||
explicit scope boundary, or a rule of thumb) — an unanswered objection that, once
|
||||
raised, collapses the recommendation for a whole class of readers is BLOCK.
|
||||
Direction only; the agent does not write the answer.
|
||||
|
||||
### Case 3 — sprang fra «Champions finnes» til «dømmekraft bevart» (logical hole)
|
||||
|
||||
- **Axis:** argument-integritet · **Check:** C1 · **Severity:** REWORK
|
||||
- **Cold-read defect:** The text jumps from *"Security Champions finnes i
|
||||
organisasjonen"* (A) to *"dermed er dømmekraften bevart"* (C) with no connecting
|
||||
step (B): existence of a role does not on its own establish that judgment is
|
||||
preserved. The reader cannot reconstruct why the conclusion follows. The session
|
||||
carried the missing step in its head; the page does not state it.
|
||||
- **Fasit / direction:** Supply the missing step — *how* the Champion's presence
|
||||
translates into preserved judgment (mechanism, mandate, practice) — or soften the
|
||||
conclusion to a hypothesis. A bridgeable-but-unbridged jump on a supporting line
|
||||
is REWORK.
|
||||
|
||||
### Case 4 — rolle-seksjonen aldri forankret i én konkret org (missing concretization)
|
||||
|
||||
- **Axis:** argument-integritet · **Check:** C4 · **Severity:** REWORK
|
||||
- **Cold-read defect:** The new ~270-word role-description section describes what a
|
||||
Champion *does* entirely in the abstract and never grounds it in **one concrete
|
||||
organisation** where this role actually operates. This is not a vividness nit
|
||||
(that would be editorial A1) — the *argument* that the role works needs one real
|
||||
instance to be believed; a skeptic will not grant an abstract job description as
|
||||
evidence the model functions.
|
||||
- **Fasit / direction:** Anchor the role in a single concrete (preferably
|
||||
Norwegian) org where a Champion operates, so the load-bearing claim "this role
|
||||
works" carries weight. Flag the *absence of the argument-bearing instance*; do
|
||||
not supply the org. (Boundary: route any pure craft/vividness face to editorial
|
||||
A1; this flag is the argument face — the claim cannot be believed abstractly.)
|
||||
|
||||
### Case 5 — anbefaling delegerer den dømmekraften serien sier ikke kan settes ut (argument contradiction)
|
||||
|
||||
- **Axis:** argument-integritet · **Check:** C3 · **Severity:** BLOCK
|
||||
- **Cold-read defect:** The series premise is *"du kan ikke sette ut dømmekraft"*
|
||||
(you cannot outsource judgment). The Champions recommendation, read cold on the
|
||||
frozen page, effectively **delegates that judgment** to the Champion — the close
|
||||
recommends the very move the premise rules out. Premise, recommendation, and
|
||||
payoff are not mutually consistent. This is an argument-level contradiction (C3),
|
||||
not a prose-level one between two passages (that would be editorial P4): the
|
||||
*logic* defeats itself.
|
||||
- **Fasit / direction:** Hold premise, recommendation, and gevinst side by side and
|
||||
resolve one side — either reframe the Champion as *supporting* judgment that
|
||||
stays distributed (not a delegate it is outsourced to), or qualify the series
|
||||
premise. A recommendation that defeats the series premise is BLOCK.
|
||||
|
||||
### Case 6 — gevinst-leddet antar utbredt modenhet (unsupported assumption)
|
||||
|
||||
- **Axis:** argument-integritet · **Check:** C2 · **Severity:** REWORK
|
||||
- **Cold-read defect:** The promised payoff of the Champions model leans on an
|
||||
unstated assumption that the surrounding organisation is mature enough to use a
|
||||
Champion well (clear mandate, time allocation, leadership backing). The frozen
|
||||
page asserts the gevinst as if it follows automatically; the cold reader sees an
|
||||
un-earned premise standing between the model and its benefit.
|
||||
- **Fasit / direction:** Establish or hedge the maturity assumption the payoff
|
||||
depends on — name the conditions under which the gevinst holds, or mark it
|
||||
conditional. A load-bearing assumption left unstated under the payoff is REWORK
|
||||
(it weakens the case rather than defeating it outright).
|
||||
|
||||
---
|
||||
|
||||
## Expected aggregate (what a correct run looks like)
|
||||
|
||||
- **Total flags:** 6 (well within the ≤8 cap — no suppression needed).
|
||||
- **By check:** C1 = 1 (Case 3) · C2 = 2 (Cases 1, 6) · C3 = 1 (Case 5) ·
|
||||
C4 = 1 (Case 4) · C5 = 1 (Case 2).
|
||||
- **By severity:** BLOCK = 3 (Cases 1, 2, 5 — unsupported pivot premise,
|
||||
unanswered small-org objection, premise/recommendation contradiction) ·
|
||||
REWORK = 3 (Cases 3, 4, 6) · NICE = 0.
|
||||
- **All six are argument blind spots:** none is a craft defect (`editorial-
|
||||
reviewer`'s domain), a language defect (`language-reviewer`), a factual error
|
||||
(`fact-reviewer`), or a resonance miss (`persona-reviewer`). The in-session
|
||||
gates passed the draft on every one of those axes — and still the argument did
|
||||
not hold, because they read it through the session's framing. The cold read is
|
||||
the quantified case for the gate.
|
||||
|
||||
A run that reproduces ~these six directions, on the one argument-integritet axis,
|
||||
with ~these severities, is **comparable** to the cold adversarial read the gate is
|
||||
built to deliver. Exact wording is the editor's; the agent returns
|
||||
**direction, not rewritten copy.**
|
||||
|
||||
## Calibration boundary
|
||||
|
||||
Whether the agent's live flags truly match this fasit is judged by the operator
|
||||
(`[OPERATØR]`), not self-certified here. This fixture is the calibration target,
|
||||
the same way `editorial-reviewer-cases.md`, `persona-reviewer-cases.md`, and
|
||||
`fact-checker-cases.md` are fasits for their agents.
|
||||
|
||||
> **Live-run note.** A live run on the frozen Del 4 draft requires (a) a Claude
|
||||
> Code session reload — a freshly added agent is not invokable until the plugin
|
||||
> agent set is rebuilt at session start — and (b) a genuinely **cold** invocation
|
||||
> (an isolated context with no drafting-session history, changelog, scope list, or
|
||||
> pivot narrative reaching the agent). Until both hold, this fixture is the
|
||||
> gold-standard of record.
|
||||
196
plugins/linkedin-studio/agents/fixtures/fact-reviewer-cases.md
Normal file
196
plugins/linkedin-studio/agents/fixtures/fact-reviewer-cases.md
Normal file
|
|
@ -0,0 +1,196 @@
|
|||
# Fact-Reviewer Fasit Fixture
|
||||
|
||||
The Del 4 production round (Security Champions, Maskinrommet, 2026-05-29) as the
|
||||
gold standard for the `fact-reviewer` agent. The in-session `fact-checker`
|
||||
(Step 5) ran on a still-moving draft. A **late Security Champions pivot** — a new
|
||||
argument anchor — arrived **after** that Step 5 sweep, so the pivot's premise was
|
||||
**never fact-checked**. The pivot then went through the in-session persona sweep
|
||||
(Step 6) and reached the frozen, publish-ready version with an unverified premise
|
||||
intact. KTG's cold re-reading caught a misattribution, a quote-precision error, a
|
||||
postulated number with no provenance, a "settled standard" that actually varies,
|
||||
and a secondary source trusted for a precise figure — six points in all. Those six
|
||||
points are the fasit below: a correct `fact-reviewer` run on the frozen/pivoted Del
|
||||
4 should surface **comparable verdicts**, mapped to the four checks with consistent
|
||||
risk verdicts and the pivot-risk flag.
|
||||
|
||||
This file is a *fasit*, not a test harness. The structural lint lives in
|
||||
`agents/__tests__/fact-reviewer-fixture.test.mjs`. Whether the agent's live
|
||||
verdicts actually reproduce these is `[GATE]`/`[OPERATØR]` — it is **not**
|
||||
self-certified here.
|
||||
|
||||
> **The jury judges; the writer writes.** Every expected output below is
|
||||
> **direction, not rewritten copy.** A correct agent run hands back a verdict + a
|
||||
> source (or "none found") + a fix-as-direction (source it / hedge it / cut it) —
|
||||
> **never** edited prose.
|
||||
|
||||
> **Why this gate exists.** Fact-checking was **post-hoc relative to the pivot** in
|
||||
> Del 4: the in-session Step 5 sweep ran *before* the Security Champions pivot was
|
||||
> added, so the pivot premise never met it. A **cold re-verification on the
|
||||
> frozen/pivoted version** closes that gap — it re-checks every claim with equal
|
||||
> suspicion, with no knowledge of which passages were pivot-fresh, and so catches
|
||||
> exactly the premise Step 5 missed.
|
||||
|
||||
---
|
||||
|
||||
## The axis and the four checks (the agent judges on exactly these)
|
||||
|
||||
The single axis is **faktisk-korrekthet** — factual correctness, re-verified COLD
|
||||
on the frozen/pivoted version. It is checked through four lenses:
|
||||
|
||||
- **F1 — Verifiserbare påstander** (verifiable claims): every checkable assertion
|
||||
(numbers, dates, named examples, attributions, causal claims) searched against
|
||||
primary/credible sources; opinions and predictions skipped.
|
||||
- **F2 — Sitat-presisjon** (quote precision): any quotation must match the source
|
||||
verbatim — wording, attribution, and who said it. «Vi» vs «Vi i Nav» is a
|
||||
precision failure even when the gist is right.
|
||||
- **F3 — Tall-attribusjon** (number attribution): every figure must trace to a
|
||||
named source; a postulated number with no provenance is 🟡/🔴. Here provenance is
|
||||
VERIFIED (distinct from `editorial-reviewer`'s P3, which only flags the absence
|
||||
of a source/hedge without searching).
|
||||
- **F4 — Kilde-kvalitet** (source quality): primary over secondary; a source
|
||||
supporting "around a third" does not verify "exactly 37 %"; post-cutoff claims
|
||||
must be web-searched.
|
||||
|
||||
## Context isolation — cold reader (the agent's cardinal rule)
|
||||
|
||||
The agent runs in a **cold context**: its only input is this prompt, the frozen
|
||||
draft, and the writing contract. Any pivot narrative, changelog, omission list, or
|
||||
"what the author intended" is **context pollution** — the agent states it is
|
||||
ignoring it and judges only the text. That independence (no main-session
|
||||
**framing-bias**) is the whole reason a defect that survived the in-session gates
|
||||
can still be caught here.
|
||||
|
||||
**Pivot-premise risk (the design feature).** Because the agent does **not** know
|
||||
which passages were added in a late pivot, it re-checks **every** claim with equal
|
||||
suspicion — a claim's age in the draft buys it no trust. A claim that looks freshly
|
||||
bolted on (new anchor, new section topic, a 2025/2026 figure) is surfaced in a
|
||||
**pivot-risk** subsection. A pivot-risk claim that fails verification is the
|
||||
headline catch: the pivot premise that never met Step 5.
|
||||
|
||||
## Risk sort and gate (every claim carries exactly one verdict)
|
||||
|
||||
- 🔴 **høy risiko** (high risk) → **BLOCK** — contradicted by evidence, or a precise
|
||||
claim with no usable source.
|
||||
- 🟡 **uverifisert** (unverified) → **REWORK** — cannot be confirmed / weak sources;
|
||||
asserted as fact must be hedged, sourced, or cut.
|
||||
- 🟢 **verifisert** (verified) → keep — confirmed by a primary/credible source
|
||||
matching the claim.
|
||||
|
||||
The agent recommends PASS / REWORK / BLOCK; the operator (`[OPERATØR]`) holds the
|
||||
gate. Each case block below carries exactly one verdict emoji in its **Verdict**
|
||||
field; the surrounding prose deliberately avoids the emoji so the structural lint
|
||||
can read a single unambiguous verdict per case.
|
||||
|
||||
---
|
||||
|
||||
## The six Del 4 worked cases (fasit)
|
||||
|
||||
Each case states the point, the check it belongs to (F1–F4), the verdict, whether
|
||||
it is a pivot-risk claim, and the direction a correct cold run returns.
|
||||
|
||||
### Case 1 — pivot-premissen aldri faktasjekket (pivot premise never met Step 5) — PIVOT-RISK
|
||||
|
||||
- **Check:** F1 (verifiable claim — the pivot's anchor assertion) · **Verdict:** 🔴
|
||||
- **Pivot-risk:** YES — this is the late Security Champions pivot, added *after* the
|
||||
Step 5 fact-check; its premise was never verified in-session.
|
||||
- **Fasit / direction:** The Security Champions pivot rests on a premise asserted as
|
||||
established fact, but no primary source confirms it as stated. Because the pivot
|
||||
arrived after Step 5, the in-session sweep never touched it. The cold re-check
|
||||
— applying equal suspicion to a claim it does not know is pivot-fresh — searches
|
||||
primary sources, finds none that confirm the premise as worded, and returns high
|
||||
risk. **This is the exact catch the gate exists for:** the cold pass on the frozen
|
||||
version surfaces the pivot premise that Step 5 missed. Direction: source the
|
||||
premise to a primary record or recast it as a hedged hypothesis; do not assert.
|
||||
The agent returns the verdict + "none found", not a rewritten premise.
|
||||
|
||||
### Case 2 — feilattribusjon (misattribution) — editor caught on cold read
|
||||
|
||||
- **Check:** F1 (attribution) + F2 (who said it) · **Verdict:** 🔴
|
||||
- **Pivot-risk:** no.
|
||||
- **Fasit / direction:** A statement is attributed to the wrong source/originator —
|
||||
the named party is not who said or published it. Contradicted by the primary
|
||||
record, so high risk (a contradicted claim is 🔴 regardless of partial score).
|
||||
Direction: correct the attribution to the verified originator, or cut the
|
||||
attribution; the agent names the contradicting source, never invents one.
|
||||
|
||||
### Case 3 — sitat-presisjon «Vi» vs «Vi i Nav» (quote precision) — editor caught
|
||||
|
||||
- **Check:** F2 (quote precision) · **Verdict:** 🟡
|
||||
- **Pivot-risk:** no.
|
||||
- **Fasit / direction:** A quotation's gist is right but the wording/attribution is
|
||||
not verbatim: the source said «Vi i Nav», the draft renders «Vi». Changing who the
|
||||
«vi» refers to is a precision failure even though the meaning is close. The source
|
||||
exists, so this is unverified-as-worded rather than contradicted. Direction: match
|
||||
the source verbatim — restore «Vi i Nav» — or mark it as a paraphrase, not a
|
||||
quote. The agent flags the precision gap; it does not supply the corrected line.
|
||||
|
||||
### Case 4 — postulert tall uten proveniens (postulated number, no provenance)
|
||||
|
||||
- **Check:** F3 (number attribution) · **Verdict:** 🟡
|
||||
- **Pivot-risk:** plausible — a figure of this kind often arrives with a late anchor;
|
||||
surface it in the pivot-risk subsection if it reads freshly bolted on.
|
||||
- **Fasit / direction:** A specific figure is stated as fact with **no named
|
||||
source**. Distinct from `editorial-reviewer`'s P3, which would only flag the
|
||||
*absence* of a source/hedge: here the agent **searches for the provenance**, finds
|
||||
none that supports the exact figure, and returns unverified. Direction: trace it to
|
||||
a named source or hedge it ("anslagsvis"); else cut. The agent never invents a
|
||||
provenance to promote it to verified.
|
||||
|
||||
### Case 5 — «Security Champions» som settet standard (a settled standard that varies)
|
||||
|
||||
- **Check:** F1 (claim) + source-scope · **Verdict:** 🔴
|
||||
- **Pivot-risk:** YES — part of the same Security Champions pivot.
|
||||
- **Fasit / direction:** The "Security Champions" practice is presented as a settled,
|
||||
universal standard, but in reality it is a practice that **varies per
|
||||
organization** — implementations, scope, and definitions differ. A local
|
||||
convention dressed as a universal standard is a source-scope failure; asserting it
|
||||
as settled with no source that supports the universal framing is high risk.
|
||||
Direction: scope the claim to where it actually holds ("varies; in some orgs…") or
|
||||
source the universal framing to a standard that does establish it. The agent flags
|
||||
the over-broad scope; it does not rewrite the passage.
|
||||
|
||||
### Case 6 — sekundærkilde brukt for et presist tall (secondary source for a precise figure)
|
||||
|
||||
- **Check:** F4 (source quality) + F3 (number) · **Verdict:** 🟡
|
||||
- **Pivot-risk:** no.
|
||||
- **Fasit / direction:** A precise figure is backed only by a **secondary source**
|
||||
that summarizes the number — the primary record supports a *directional* claim
|
||||
("around a third"), not the precise figure ("37 %") the draft asserts. A source
|
||||
supporting "around a third" does not verify "exactly 37 %". Direction: trace to the
|
||||
primary source and confirm the exact figure, soften the draft to the directional
|
||||
claim the secondary source actually supports, or hedge. The agent records the
|
||||
secondary source found and the precision gap, not a corrected number.
|
||||
|
||||
---
|
||||
|
||||
## Expected aggregate (what a correct cold run looks like)
|
||||
|
||||
- **Total verdicts surfaced:** 6 (within a reasonable verification-log cap; no 🔴
|
||||
silently dropped).
|
||||
- **By check:** F1 = 3 (Cases 1, 2, 5) · F2 = 2 (Cases 2, 3) · F3 = 2 (Cases 4, 6) ·
|
||||
F4 = 1 (Case 6). (Cases overlap checks; the headline check is listed first.)
|
||||
- **By risk verdict:** 🔴 høy risiko = 3 (Cases 1, 2, 5 → BLOCK) · 🟡 uverifisert = 3
|
||||
(Cases 3, 4, 6 → REWORK) · 🟢 verifisert = 0 among the flagged points (the rest of
|
||||
the draft's claims verify clean and are not listed here).
|
||||
- **Pivot-risk:** Cases 1 and 5 are the Security Champions pivot; Case 4 is a
|
||||
plausible pivot-risk. **Case 1 is the headline catch** — the pivot premise that
|
||||
was never fact-checked in-session, caught only because the cold pass re-checks
|
||||
every claim with equal suspicion.
|
||||
|
||||
A run that reproduces ~these six verdicts, on ~these checks, with ~these risk
|
||||
levels — and that surfaces the Security Champions pivot premise as a pivot-risk 🔴
|
||||
— is **comparable** to KTG's actual cold re-reading. Exact wording is the editor's;
|
||||
the agent returns **direction, not rewritten copy**.
|
||||
|
||||
## Calibration boundary
|
||||
|
||||
Whether the agent's live verdicts truly match this fasit is judged by the operator
|
||||
(`[OPERATØR]`), not self-certified here. This fixture is the calibration target, the
|
||||
same way `fact-checker-cases.md`, `editorial-reviewer-cases.md`, and
|
||||
`persona-reviewer-cases.md` are fasits for their agents.
|
||||
|
||||
> **Live-run note.** A live cold run on the frozen Del 4 requires (a) a Claude Code
|
||||
> session reload — a freshly added agent is not invokable until the plugin agent set
|
||||
> is rebuilt at session start — and (b) the agent run in a genuinely cold context
|
||||
> (no drafting-session history, no pivot narrative) with read access to the frozen
|
||||
> draft and web search. Until both hold, this fixture is the gold-standard of record.
|
||||
|
|
@ -0,0 +1,194 @@
|
|||
# Language-Reviewer Fasit Fixture
|
||||
|
||||
The Del 4 production round (Security Champions, Maskinrommet, 2026-05-29) as the
|
||||
gold standard for the `language-reviewer` agent. By Step 6 the in-session persona
|
||||
resonance sweep had returned PASS across the personas and the in-session craft
|
||||
gate (`editorial-reviewer`, Step 5.5) had run — both *inside* the drafting session,
|
||||
both sharing its framing-bias. On a **cold, first-time reading of the frozen
|
||||
draft** (the F5 finding), the editor then caught Norwegian-language defects the
|
||||
in-session passes had all read straight past: a verbatim **quote error** («Vi»
|
||||
where the source said «Vi i Nav»), anglicisms, and verbatim repetitions across
|
||||
sections. Those are the fasit below: a correct `language-reviewer` run on the
|
||||
Del 4 frozen draft should surface **comparable flags**, mapped to the one axis
|
||||
with consistent severities.
|
||||
|
||||
This file is a *fasit*, not a test harness. The structural lint lives in
|
||||
`agents/__tests__/language-reviewer-fixture.test.mjs`. Whether the agent's live
|
||||
flags actually reproduce these directions is `[GATE]`/`[OPERATØR]` — it is **not**
|
||||
self-certified here.
|
||||
|
||||
> **The jury judges; the writer writes.** Every expected output below is
|
||||
> **direction, not rewritten copy.** A correct agent run hands back flags + a
|
||||
> severity — never edited prose. (`Foreslått retning`, not a new sentence.)
|
||||
|
||||
> **Why this gate exists — the cold re-read.** The in-session gates (fact-check,
|
||||
> craft, persona) all ran while the drafting session's framing-bias was still in
|
||||
> the room: the same blind spots that let the author miss «Vi» vs «Vi i Nav» let
|
||||
> those gates miss it too. `language-reviewer` is run in a **cold context** with
|
||||
> no access to version history, intent, pivots, or how any gate voted — exactly so
|
||||
> it carries none of that bias. Any such framing that reaches it is **context
|
||||
> pollution** to be named and ignored. A cold Norwegian re-read catches what the
|
||||
> bias hid. That is the F5 finding made into a gate.
|
||||
|
||||
---
|
||||
|
||||
## The axis (the agent judges on exactly this)
|
||||
|
||||
**Axis: norsk-språkkvalitet** (Norwegian language quality) — one axis, five
|
||||
checks. L1, L2, L5 start grep-able; L3, L4 need a read. The voice under judgment
|
||||
is a **personal chronicle**, not a saksframlegg.
|
||||
|
||||
- **L1 — Ordrette gjentakelser** (verbatim repetition): the same distinctive
|
||||
phrase or sentence-opening repeats mechanically across the draft (grep 3–6-word
|
||||
phrases, then read in context).
|
||||
- **L2 — Anglisismer** (anglicisms): English calques / loan-constructions where
|
||||
idiomatic Norwegian exists («adressere et problem», «på en daglig basis», «i
|
||||
terms av»). Flag the calque **and name the Norwegian idiom direction.**
|
||||
- **L3 — Stivt tjenesteskriftspråk** (stiff bureaucratic register): «kanselli-stil»
|
||||
— nominalisations, passive overload, «det vises til», agentless sentences that
|
||||
drain the chronicle voice.
|
||||
- **L4 — Indre språklige selvmotsigelser** (language-level self-contradiction): a
|
||||
sentence/phrase that undercuts itself, or two phrasings that cannot both be the
|
||||
intended register/meaning. The *wording* contradicting itself — **not** the
|
||||
argument-level logic (that is `content-reviewer`).
|
||||
- **L5 — Klang / rytme** (clang & rhythm): sentences that read badly aloud —
|
||||
monotone cadence, every sentence the same length, a jarring word, run-ons that
|
||||
lose the breath.
|
||||
|
||||
## Severity (every flag carries exactly one)
|
||||
|
||||
- **BLOCK** — misrepresents or embarrasses: a quote rendered wrong (a verbatim
|
||||
error inside a quotation — «Vi» vs «Vi i Nav»), or a self-contradicting phrasing
|
||||
(L4) that changes the meaning.
|
||||
- **REWORK** — a real language weakness a reader notices: a repeated phrase (L1),
|
||||
an anglicism (L2), a bureaucratic passage (L3), a rhythm stumble (L5).
|
||||
- **NICE** — cheap polish: a single mild repetition, one slightly stiff sentence.
|
||||
|
||||
## Direction, not copy (the boundary)
|
||||
|
||||
Every expected output is **direction, not rewritten copy**: "§3 'adressere' —
|
||||
anglicism; use the Norwegian idiom («ta tak i»)" is the agent's job; supplying the
|
||||
rewritten sentence is not. Each flag carries a **quote or line reference.**
|
||||
|
||||
---
|
||||
|
||||
## The six Del 4 language points (fasit)
|
||||
|
||||
Each case states the point the editor raised on the cold reading, the check it
|
||||
belongs to, the expected severity, and the direction a correct agent run returns.
|
||||
These are **language blind spots** — distinct from craft (`editorial-reviewer`),
|
||||
de-AI / voice (`voice-scrubber`), and reader response (`persona-reviewer`). They
|
||||
survived to the cold pass precisely because the in-session gates shared the
|
||||
author's framing-bias.
|
||||
|
||||
### Case 1 — sitat gjengitt feil: «Vi» i stedet for «Vi i Nav» (verbatim quote error)
|
||||
|
||||
- **Check:** L4 (language-level self-contradiction / verbatim quotation error)
|
||||
· **Severity:** BLOCK
|
||||
- **Cold-read finding:** A quotation in the chronicle is rendered «Vi …» where the
|
||||
source said «Vi i Nav …». The clipped quote changes who "vi" refers to — the
|
||||
wording now misrepresents the source. (Maps to L4 as a wording-level
|
||||
self-contradiction; the same defect could be filed under L1 as a near-verbatim
|
||||
repetition of the source gone wrong — the agent files it once, as the BLOCK it
|
||||
is.)
|
||||
- **Fasit / direction:** Quote misrenders «Vi i Nav» as «Vi»; restore the source
|
||||
wording. A misquote misrepresents the piece, so BLOCK. The agent flags the
|
||||
*wrong rendering*; it does not supply the corrected sentence.
|
||||
- **Why blind to the in-session gates:** the persona sweep measured whether the
|
||||
passage *landed* (it did — PASS); none of the in-session gates re-checked the
|
||||
quote against the source on a cold reading. This is the canonical F5 finding.
|
||||
|
||||
### Case 2 — anglisisme: «adressere problemet» (anglicism)
|
||||
|
||||
- **Check:** L2 (anglicisms) · **Severity:** REWORK
|
||||
- **Cold-read finding:** «adressere et problem» is an English calque (to *address*
|
||||
a problem) where idiomatic Norwegian reads «ta tak i / håndtere / ta opp».
|
||||
- **Fasit / direction:** Anglicism; use the Norwegian idiom («ta tak i» /
|
||||
«håndtere»). Name the idiom direction, do not write the sentence.
|
||||
- **Why blind:** an anglicism reads fluently to a reader inside the drafting
|
||||
session — the calque *sounds* like normal prose until a cold ear hits it.
|
||||
|
||||
### Case 3 — anglisisme: «på en daglig basis» (anglicism)
|
||||
|
||||
- **Check:** L2 (anglicisms) · **Severity:** REWORK
|
||||
- **Cold-read finding:** «på en daglig basis» is a calque of *on a daily basis*;
|
||||
idiomatic Norwegian is «daglig» / «til daglig».
|
||||
- **Fasit / direction:** Anglicism; collapse to the Norwegian adverb («daglig»).
|
||||
Direction only.
|
||||
- **Why blind:** same mechanism as Case 2 — a second calque the in-session passes
|
||||
read straight through. Two L2 flags is itself a signal the draft drifted into
|
||||
English construction.
|
||||
|
||||
### Case 4 — ordrette gjentakelser: samme frase 3× på tvers av seksjoner (verbatim repetition)
|
||||
|
||||
- **Check:** L1 (verbatim repetition) · **Severity:** REWORK
|
||||
- **Cold-read finding:** A distinctive phrase recurs three times across §1, §4 and
|
||||
§6 — mechanical, not load-bearing. `grep`-findable as a repeated 3–6-word
|
||||
string.
|
||||
- **Fasit / direction:** Vary or cut the repeats; keep at most the one
|
||||
load-bearing use. Report the count (3×).
|
||||
- **Why blind:** a reader inside the session sees each section in isolation; the
|
||||
repetition only shows when a cold reader takes the whole draft at once. This is
|
||||
the verbatim-repetition half of the F5 finding.
|
||||
|
||||
### Case 5 — stivt tjenesteskriftspråk: «det vises til»-passasje i en personlig krønike (stiff bureaucratic register)
|
||||
|
||||
- **Check:** L3 (stiff bureaucratic register / «kanselli-stil») · **Severity:**
|
||||
REWORK
|
||||
- **Cold-read finding:** A passage slides into saksframlegg register — «det vises
|
||||
til», nominalised, agentless, passive-stacked — inside a piece whose voice is a
|
||||
personal chronicle. The register break drains the chronicle voice.
|
||||
- **Fasit / direction:** Kanselli-stil in a personal chronicle; restore an agent
|
||||
and an active verb so the passage reads as the chronicle, not a memo. Direction
|
||||
only. (This is a *language-register* defect, distinct from `voice-scrubber`'s
|
||||
de-AI tells and from `editorial-reviewer`'s craft.)
|
||||
- **Why blind:** bureaucratic register is the author's professional default; inside
|
||||
the session it reads as "normal," and only a cold ear hears it clash with the
|
||||
chronicle voice.
|
||||
|
||||
### Case 6 — klang / rytme: fem like lange setninger på rad (monotone cadence)
|
||||
|
||||
- **Check:** L5 (clang & rhythm) · **Severity:** NICE
|
||||
- **Cold-read finding:** A run of five sentences shares the same length and a
|
||||
near-identical opening — a monotone cadence that reads flat aloud. Chronicle
|
||||
prose has a varied cadence; this passage loses it.
|
||||
- **Fasit / direction:** Break the monotone — vary one or two sentence lengths /
|
||||
openings so the passage breathes. NICE: noticeable on a read-aloud, not
|
||||
load-bearing. `grep`/scan-findable (same-length run, repeated opening).
|
||||
- **Why blind:** rhythm is heard, not seen; a silent in-session read past a fluent
|
||||
passage never trips on it. A cold read-aloud does.
|
||||
|
||||
---
|
||||
|
||||
## Expected aggregate (what a correct run looks like)
|
||||
|
||||
- **Total flags:** 6 (well within the ≤10 cap — no suppression needed).
|
||||
- **By check:** L1 = 1 (Case 4) · L2 = 2 (Cases 2 + 3) · L3 = 1 (Case 5) ·
|
||||
L4 = 1 (Case 1) · L5 = 1 (Case 6).
|
||||
- **By severity:** BLOCK = 1 (Case 1, the quote error) · REWORK = 4 (Cases 2, 3,
|
||||
4, 5) · NICE = 1 (Case 6).
|
||||
- **All six are language blind spots** — none is a craft defect (editorial), a
|
||||
de-AI / voice defect (voice-scrubber), an argument defect (content-reviewer), a
|
||||
factual defect (fact-reviewer), or a resonance defect (persona). They survived
|
||||
to the cold pass because the in-session gates shared the author's framing-bias;
|
||||
the cold Norwegian re-read is what caught them.
|
||||
|
||||
A run that reproduces ~these six directions, on ~these checks, with ~these
|
||||
severities, is **comparable** to the editor's actual cold reading of Del 4 — the
|
||||
acceptance bar. Exact wording is the editor's; the agent returns direction, never
|
||||
copy.
|
||||
|
||||
## Calibration boundary
|
||||
|
||||
Whether the agent's live flags truly match this fasit is judged by the operator
|
||||
(`[OPERATØR]`), not self-certified here. This fixture is the calibration target,
|
||||
the same way `editorial-reviewer-cases.md`, `persona-reviewer-cases.md` and
|
||||
`fact-checker-cases.md` are fasits for their agents.
|
||||
|
||||
> **Live-run note.** A live run on the Del 4 frozen draft requires (a) a Claude
|
||||
> Code session reload — a freshly added agent is not invokable until the plugin
|
||||
> agent set is rebuilt at session start — and (b) read access to the frozen Del 4
|
||||
> draft in the Maskinrommet series folder. Critically, the live run must be a
|
||||
> **cold context**: no session history, no version numbers, no intent narrative —
|
||||
> only the prompt, the frozen draft path, and the writing contract. Until both
|
||||
> hold, this fixture is the gold-standard of record.
|
||||
301
plugins/linkedin-studio/agents/language-reviewer.md
Normal file
301
plugins/linkedin-studio/agents/language-reviewer.md
Normal file
|
|
@ -0,0 +1,301 @@
|
|||
---
|
||||
name: language-reviewer
|
||||
description: |
|
||||
Read a frozen, publish-ready long-form Norwegian draft as an ADVERSARIAL,
|
||||
independent reviewer in a COLD context and judge its Norwegian language
|
||||
quality on one axis (norsk-språkkvalitet, five checks): verbatim repetition,
|
||||
anglicisms, stiff bureaucratic register («kanselli-stil»), language-level
|
||||
self-contradiction, and clang/rhythm. Carries none of the drafting session's
|
||||
framing-bias. Returns ≤10 flags as direction — never rewritten copy — each
|
||||
tagged BLOCK / REWORK / NICE.
|
||||
|
||||
Use when the user says:
|
||||
- "language review", "språkvask", "is the Norwegian clean?"
|
||||
- "check the anglicisms", "anglisismer", "any English calques?"
|
||||
- "find the repetitions", "gjentakelser", "ordrette gjentakelser"
|
||||
- "does it read well aloud?", "klang og rytme", "rhythm check"
|
||||
- "is the register too stiff?", "stivt språk", "kanselli-stil"
|
||||
- "run the cold language pass", "headless review", "Step 6.5"
|
||||
|
||||
Triggers on: "language review", "språkvask", "anglisismer", "gjentakelser",
|
||||
"klang og rytme", "stivt språk", "is the Norwegian clean", "headless review",
|
||||
"language-reviewer", "norsk-språkkvalitet", "cold reader".
|
||||
model: opus
|
||||
color: navy
|
||||
tools: ["Read", "Grep"]
|
||||
---
|
||||
|
||||
# Language Reviewer Agent
|
||||
|
||||
You are an **adversarial, independent language reviewer**. You read a frozen,
|
||||
publish-ready long-form Norwegian chronicle and judge whether the **Norwegian
|
||||
reads clean** — the language layer a reader feels in their ear before they can
|
||||
name it. You are run in a **cold context**, handed only the page, precisely so
|
||||
you do **not** carry the framing-bias the in-session gates shared with the
|
||||
author. That bias is why language defects survived to you.
|
||||
|
||||
You run at **Step 6.5** of the `/linkedin:newsletter` pipeline — *after* the
|
||||
in-session persona resonance sweep (Step 6), on a **frozen** draft, *before*
|
||||
lock — and you are invocable standalone via `/linkedin:headless-review`.
|
||||
|
||||
## Pipeline position
|
||||
|
||||
You are one of three **cold, headless re-readers** in the Step 6.5 package (with
|
||||
`content-reviewer` and `fact-reviewer`). The in-session gates (fact-check Step 5,
|
||||
editorial craft Step 5.5, persona sweep Step 6) all ran *inside* the drafting
|
||||
session and shared its framing-bias. You re-read the **finished** Norwegian on a
|
||||
**frozen version**, from cold, as a first-time reader — and you catch the
|
||||
language defects the in-session pass missed because it shared the author's blind
|
||||
spots. This is the Del 4 / F5 finding made into a gate: on first cold reading the
|
||||
editor caught a verbatim **quote error** («Vi» where the source said «Vi i Nav»),
|
||||
anglicisms, and verbatim repetitions that **every persona had reported PASS on**.
|
||||
|
||||
## Context isolation — you are a COLD reader (cardinal)
|
||||
|
||||
> You are an **adversarial, independent** reviewer, run in a **cold context**.
|
||||
> Your entire input is: this prompt, the path to a **frozen draft**, and the
|
||||
> writing contract. You have **no** access to — and must **refuse to act on** —
|
||||
> any of:
|
||||
> - the drafting session's conversation history;
|
||||
> - prior versions, version numbers, or a changelog;
|
||||
> - a "deliberately omitted" / "out of scope" list;
|
||||
> - a pivot narrative or the reason for any pivot;
|
||||
> - who has read the draft, what an editor said, or how a persona voted;
|
||||
> - any framing about what the author *intended*.
|
||||
>
|
||||
> If any such framing reaches you, treat it as **context pollution**: state
|
||||
> plainly that you are ignoring it, and judge only the text in front of you. Your
|
||||
> worth to the pipeline is exactly that you do **not** carry the main session's
|
||||
> framing-bias — the in-session gates already did, and that is why defects
|
||||
> survived to you. Read the frozen draft as a first-time reader handed only the
|
||||
> page.
|
||||
|
||||
## What you are NOT (boundary with the other gates) — read this carefully
|
||||
|
||||
You overlap two in-session gates **deliberately**. The overlap is the point — it
|
||||
is the *cold re-take*, not a duplicate checklist. The boundary below is explicit
|
||||
so no future maintainer "de-duplicates" these agents away:
|
||||
|
||||
| Agent | Measures | Question | When |
|
||||
|-------|----------|----------|------|
|
||||
| `editorial-reviewer` (Step 5.5) | prose craft + narrative architecture | *Is it well-made?* | in-session, pre-persona |
|
||||
| `voice-scrubber` (Step 4) | de-AI + Norwegian-chronicle voice drift | *Does it sound like the author?* | in-session |
|
||||
| **`language-reviewer` (Step 6.5 — this agent)** | **Norwegian language quality** | ***Does the Norwegian read clean?*** | **COLD / headless, post-persona-sweep, on the frozen version** |
|
||||
| `content-reviewer` (Step 6.5, cold) | argument integrity | *Does the reasoning hold?* | cold |
|
||||
| `fact-reviewer` (Step 6.5, cold) | factual truth | *Is it true?* | cold |
|
||||
| `persona-reviewer` (Steps 2.5/6/9) | reader response | *Does it land?* | in-session |
|
||||
|
||||
- **Versus `editorial-reviewer`** — editorial-reviewer is the **in-session** craft
|
||||
gate; it runs while the drafting session's framing-bias is still in the room.
|
||||
You are the **cold, independent, adversarial re-read of the FINISHED Norwegian
|
||||
on a frozen version.** Where your L1 (repetition) / L5 (rhythm) graze
|
||||
editorial's P1/P2: **defer the in-session framing to editorial.**
|
||||
language-reviewer's value is the *cold re-take* — the same defect surfaced by a
|
||||
reader who shares none of the author's blind spots — not a different checklist.
|
||||
- **Versus `voice-scrubber`** — voice-scrubber owns the **de-AI face** and
|
||||
Norwegian-chronicle *voice drift* (does it sound like the author / like a
|
||||
machine). You flag the **Norwegian language defect itself** — the anglicism, the
|
||||
repetition, the bureaucratic passage — **not** "this sounds like a machine."
|
||||
Defer the de-AI verdict to voice-scrubber.
|
||||
- You do **not** judge whether the reasoning holds (`content-reviewer`), whether a
|
||||
claim is true (`fact-reviewer`), or whether the text lands for a reader
|
||||
(`persona-reviewer`). You judge the **Norwegian**.
|
||||
|
||||
Three overlapping faces of the same page, all necessary, none sufficient alone. A
|
||||
persona PASS and an editorial PASS are **not** "the Norwegian is clean" — those
|
||||
are different questions, and the F5 finding is the proof that they miss this one.
|
||||
|
||||
## The five checks — Axis: norsk-språkkvalitet
|
||||
|
||||
You judge on exactly **one axis** and **five checks**. L1, L2, L5 start with
|
||||
`grep` (then a read in context); L3, L4 need a read. The voice is a **personal
|
||||
chronicle**, not a saksframlegg — judge against that register.
|
||||
|
||||
| # | Check | What flags it | How to find it |
|
||||
|---|-------|---------------|----------------|
|
||||
| L1 | **Ordrette gjentakelser** (verbatim repetition) | The same distinctive phrase or sentence-opening repeats mechanically across the draft. | `grep` for repeated 3–6-word phrases / sentence-openings; read the hits in context. |
|
||||
| L2 | **Anglisismer** (anglicisms) | English calques / loan-constructions where idiomatic Norwegian exists («adressere et problem», «på en daglig basis», «i terms av»). | Scan for calqued constructions; flag the calque **and name the Norwegian idiom direction** (e.g. «adressere» → «ta tak i / håndtere»). |
|
||||
| L3 | **Stivt tjenesteskriftspråk** (stiff bureaucratic register) | «Kanselli-stil»: nominalisations, passive overload, «det vises til», agentless sentences that drain the chronicle voice. The voice is a personal chronicle, not a saksframlegg. | Read for nominalised, agentless, passive-stacked passages; flag where the chronicle voice goes bureaucratic. |
|
||||
| L4 | **Indre språklige selvmotsigelser** (language-level self-contradiction) | A sentence or phrase that undercuts itself, or two phrasings that cannot both be the intended register/meaning. **Distinct from `content-reviewer`'s argument-level contradiction: L4 is the *wording* contradicting itself, not the *logic*.** | Read for a phrase that reverses its own sense, or a quote rendered against itself; cross-check wording, not argument. |
|
||||
| L5 | **Klang / rytme** (clang & rhythm) | Sentences that read badly aloud — monotone cadence, every sentence the same length, a jarring word that breaks the music, run-ons that lose the breath. Norwegian chronicle prose has a cadence. | `grep`/scan for runs of same-length sentences and repeated openings; read the passage aloud in your head and flag where it stumbles. |
|
||||
|
||||
L1, L2, L5 are partly countable — report the count where you have one. L3, L4
|
||||
need a read but are still crisp yes/no findings.
|
||||
|
||||
## Severity scale — BLOCK / REWORK / NICE
|
||||
|
||||
Every flag carries exactly one severity (mirrors `editorial-reviewer`, adapted to
|
||||
language):
|
||||
|
||||
- **BLOCK** — a language defect that **misrepresents or embarrasses**: a quote
|
||||
rendered wrong (a **verbatim error inside a quotation** — e.g. «Vi» where the
|
||||
source said «Vi i Nav»), or a self-contradicting phrasing (L4) that **changes
|
||||
the meaning**. Your strong recommendation: fix before lock.
|
||||
- **REWORK** — a real language weakness a reader notices: a repeated phrase (L1),
|
||||
an anglicism (L2), a bureaucratic passage (L3), or a rhythm stumble (L5).
|
||||
- **NICE** — minor polish: a single mild repetition, one slightly stiff sentence.
|
||||
|
||||
Sort flags **BLOCK before REWORK before NICE.** Cap at **ten flags**; if you
|
||||
suppress any, say how many and of what severity — **never silently truncate.**
|
||||
|
||||
## Direction, not copy
|
||||
|
||||
Return **direction**, never rewritten copy (identical to `editorial-reviewer` and
|
||||
`persona-reviewer`). "§3 'adressere' — anglicism; use the Norwegian idiom
|
||||
(«ta tak i»)" is your job; **supplying the rewritten sentence is not.** Every flag
|
||||
carries a **quote or line reference.** If you ever hand back edited prose, you
|
||||
have failed the role.
|
||||
|
||||
You do **not** gate the pipeline. Your output is a markdown report surfaced to the
|
||||
operator (KTG) via `SendUserFile`; the operator decides which flags fold in. Your
|
||||
severity ranking is the *recommendation*; the operator holds the gate
|
||||
(`[OPERATØR]`).
|
||||
|
||||
## Review Process
|
||||
|
||||
### Step 1 — Read the frozen draft cold, for language
|
||||
|
||||
Read top to bottom, once, as a first-time reader handed only the page — not for
|
||||
truth, not for argument, not as a target persona, but for **how the Norwegian
|
||||
sounds.** Carry no framing about prior versions, intent, or what any gate said
|
||||
(see Context isolation). If framing reached you, name it and ignore it.
|
||||
|
||||
### Step 2 — Run the grep-able checks (L1, L2, L5)
|
||||
|
||||
Use `Grep` to get candidates, then **read the hits in context** (a count alone
|
||||
over- or under-flags):
|
||||
- **L1** — repeated 3–6-word phrases and sentence-openings across the draft.
|
||||
- **L2** — calqued constructions; flag each with the Norwegian idiom direction.
|
||||
- **L5** — runs of same-length sentences / repeated openings; then read the
|
||||
passage for cadence.
|
||||
Record each finding with its **exact quote or line reference** and a count where
|
||||
the check is countable.
|
||||
|
||||
### Step 3 — Judge the read-only checks (L3, L4)
|
||||
|
||||
- **L3** — scan for nominalised, agentless, passive-stacked «kanselli-stil»
|
||||
passages that drain the chronicle voice.
|
||||
- **L4** — read for a phrasing that undercuts itself, or a **quote rendered wrong**
|
||||
(«Vi» vs «Vi i Nav»). This is *wording* contradicting itself — not the argument
|
||||
(that is `content-reviewer`).
|
||||
Record each finding with the quote/line it concerns.
|
||||
|
||||
### Step 4 — Sort, cap, and assign severity
|
||||
|
||||
Assign BLOCK / REWORK / NICE per the scale. Sort worst-first. Cap at **ten
|
||||
flags**; if you suppressed any, say how many and of what severity.
|
||||
|
||||
### Step 5 — Emit the report (the operator gates)
|
||||
|
||||
You do **not** gate the pipeline yourself — your output is surfaced to the
|
||||
operator (KTG) as a markdown report (`SendUserFile`), and the operator decides
|
||||
which flags fold in. Your severity ranking is the *recommendation*; the operator
|
||||
holds the gate (`[OPERATØR]`).
|
||||
|
||||
## Output Format
|
||||
|
||||
```
|
||||
## Language Review — Del NN «<title>»
|
||||
|
||||
**Ran:** COLD / headless · Step 6.5 (post-persona-sweep, on the frozen version)
|
||||
**Axis:** norsk-språkkvalitet · **Read:** <N> words · checks run: 5 (L1–L5)
|
||||
|
||||
### Flags (≤10 — direction only, NO rewritten copy)
|
||||
|
||||
| # | Kategori | Severity | Sitat / linje-ref | Foreslått retning |
|
||||
|---|----------|----------|-------------------|-------------------|
|
||||
| 1 | L4 (selvmotsigelse) | BLOCK | "Vi …" (§2 — sitat) | <direction — quote misrenders «Vi i Nav» as «Vi»; restore the source wording> |
|
||||
| 2 | L2 (anglisisme) | REWORK | "adressere problemet" (§3) | <direction — anglicism; use the Norwegian idiom («ta tak i / håndtere»)> |
|
||||
| 3 | L1 (gjentakelse) | REWORK | "<phrase>" (§1, §4, §6 — 3×) | <direction — vary or cut the repeats; keep at most one> |
|
||||
| … | … | … | … | … |
|
||||
|
||||
### Suppressed
|
||||
<N> further findings below the top ten (severities: …) (or: none)
|
||||
|
||||
### Per-check summary
|
||||
- **L1 ordrette gjentakelser:** <flag/clean — count>
|
||||
- **L2 anglisismer:** <…>
|
||||
- **L3 stivt tjenesteskriftspråk:** <…>
|
||||
- **L4 indre selvmotsigelser:** <…>
|
||||
- **L5 klang / rytme:** <…>
|
||||
|
||||
### Recommendation (operator gates)
|
||||
<N> BLOCK / <N> REWORK / <N> NICE. Strong recommendation: fix the BLOCK flags
|
||||
before lock. Operator decides fold-in; this is [OPERATØR].
|
||||
```
|
||||
|
||||
## Key Principles
|
||||
|
||||
1. **You are a cold, adversarial reader.** Your worth is that you carry none of
|
||||
the drafting session's framing-bias. Refuse any framing about versions, intent,
|
||||
pivots, or how a gate voted — name it as context pollution and ignore it.
|
||||
2. **The jury judges; the writer writes.** Return direction, never rewritten
|
||||
copy — handing back fixed prose is the single worst failure of this role
|
||||
(identical to `editorial-reviewer` / `persona-reviewer`).
|
||||
3. **Norwegian language, not craft, not voice.** You measure whether the Norwegian
|
||||
reads clean. Defer the in-session craft framing to `editorial-reviewer` and the
|
||||
de-AI verdict to `voice-scrubber`; you flag the *language defect*, never "this
|
||||
sounds like a machine."
|
||||
4. **One axis, five checks, no more.** L1 (gjentakelser), L2 (anglisismer), L3
|
||||
(stivt tjenesteskriftspråk), L4 (selvmotsigelser), L5 (klang/rytme). Do not
|
||||
invent a sixth check or route in a craft / argument / fact / persona concern.
|
||||
5. **Every flag carries a quote or a line reference.** "Stiff" is not a flag.
|
||||
"§4 'det vises til …' — kanselli-stil in a personal chronicle" is.
|
||||
6. **Severity is consistent and worst-first.** BLOCK = misrepresents/embarrasses
|
||||
(a wrong quote, a meaning-changing L4); REWORK = a real weakness; NICE = cheap
|
||||
polish. Sort BLOCK→REWORK→NICE.
|
||||
7. **Cap at ten; never truncate silently.** If you suppressed findings, say how
|
||||
many and of what severity.
|
||||
8. **The operator gates, you recommend.** Your output is a report for KTG via
|
||||
`SendUserFile`, not a pipeline stop. BLOCK is your strongest recommendation,
|
||||
not a hard halt — the gate is `[OPERATØR]`.
|
||||
|
||||
## Anti-Patterns
|
||||
|
||||
- Act on the drafting session's history, version numbers, a changelog, an
|
||||
out-of-scope list, a pivot narrative, or what an editor/persona said (it never
|
||||
reaches a true cold reader — if it does, name it and ignore it)
|
||||
- Rewrite the draft or hand back replacement copy (that is the writer's pen)
|
||||
- Flag "this sounds like a machine" (wrong agent — `voice-scrubber`), the prose
|
||||
craft / architecture (wrong agent — `editorial-reviewer`), the argument
|
||||
(`content-reviewer`), the facts (`fact-reviewer`), or reader resonance
|
||||
(`persona-reviewer`)
|
||||
- Treat L4 (wording contradicts itself) as an argument-level contradiction — that
|
||||
is `content-reviewer`'s axis; you judge the *wording*, not the *logic*
|
||||
- Give a flag with no quote and no line reference
|
||||
- Exceed ten flags, or silently drop findings past the cap
|
||||
- Invent a sixth check or a second axis
|
||||
- Soften a BLOCK (a verbatim quote error, a meaning-changing L4) to REWORK to be
|
||||
agreeable
|
||||
- "De-duplicate" yourself against `editorial-reviewer` — the overlap is the cold
|
||||
re-take, deliberately kept; the value is reading the FINISHED Norwegian without
|
||||
the author's blind spots
|
||||
|
||||
## References
|
||||
|
||||
Read these for the boundary and the pipeline position:
|
||||
- `${CLAUDE_PLUGIN_ROOT}/agents/editorial-reviewer.md` — the **in-session** craft
|
||||
gate (Step 5.5) that shares the drafting session's framing-bias; your L1/L5
|
||||
graze its P1/P2 — defer the in-session framing to it, your value is the cold
|
||||
re-take.
|
||||
- `${CLAUDE_PLUGIN_ROOT}/agents/voice-scrubber.md` — the de-AI / Norwegian-chronicle
|
||||
voice gate (Step 4); it owns "sounds like a machine / like the author" — you flag
|
||||
the *language defect*, not the de-AI face.
|
||||
- `${CLAUDE_PLUGIN_ROOT}/agents/content-reviewer.md` — the cold argument-integrity
|
||||
re-read (Step 6.5); it owns argument-level contradiction — your L4 is *wording*,
|
||||
not *logic*.
|
||||
- `${CLAUDE_PLUGIN_ROOT}/agents/fact-reviewer.md` — the cold factual-truth re-read
|
||||
(Step 6.5); it owns "is it true."
|
||||
- `${CLAUDE_PLUGIN_ROOT}/agents/persona-reviewer.md` — the in-session reader jury
|
||||
(Steps 2.5/6/9); it owns "does it land."
|
||||
- `${CLAUDE_PLUGIN_ROOT}/commands/headless-review.md` — the standalone command that
|
||||
runs this cold package.
|
||||
- `${CLAUDE_PLUGIN_ROOT}/commands/newsletter.md` — Step 6.5 in the long-form
|
||||
pipeline (the in-session sweep is Step 6; you run after it, on the frozen draft,
|
||||
before lock).
|
||||
- `${CLAUDE_PLUGIN_ROOT}/references/longform-quality-rules.md` — the broad quality
|
||||
pass; rule 3 (AI-slop ban-list) is `voice-scrubber`'s; your axis is the cold
|
||||
Norwegian-language re-read, not the de-AI ban-list.
|
||||
- `${CLAUDE_PLUGIN_ROOT}/agents/fixtures/language-reviewer-cases.md` — fasit
|
||||
fixture: the Del 4 / F5 language blind spots (the «Vi» vs «Vi i Nav» quote
|
||||
error, anglicisms, repetitions) mapped to L1–L5 + severities.
|
||||
248
plugins/linkedin-studio/commands/headless-review.md
Normal file
248
plugins/linkedin-studio/commands/headless-review.md
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
---
|
||||
name: linkedin:headless-review
|
||||
description: |
|
||||
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".
|
||||
allowed-tools:
|
||||
- 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).** For the publish-ready gate, 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). This is the recommended
|
||||
path and the one KTG asked for.
|
||||
2. **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)
|
||||
```
|
||||
|
||||
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).
|
||||
|
||||
## 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):
|
||||
|
||||
```bash
|
||||
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.
|
||||
|
||||
```markdown
|
||||
# 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.json` →
|
||||
`articles.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)
|
||||
- Persisted: edition-state.json articles.NN.headlessReview (or: standalone, not persisted)
|
||||
Operator gates the fold-in. For maximum independence, run this command in a FRESH session.
|
||||
```
|
||||
|
||||
## 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 **strongest** isolation is the operator running
|
||||
`/linkedin:headless-review` in a fresh session and pasting the consolidated
|
||||
report back. 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.json` — `articles.NN.headlessReview` schema
|
||||
- `${CLAUDE_PLUGIN_ROOT}/references/longform-quality-rules.md` — fallback writing contract
|
||||
|
|
@ -71,13 +71,15 @@ 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 (15 phases)
|
||||
## Pipeline overview (16 phases)
|
||||
|
||||
The phase order is fixed. Two gates run **BEFORE prose** (skeleton + spine
|
||||
prose), an **editorial craft gate** runs before the persona sweep, 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; v2.4 on the editor/persona role split).
|
||||
prose), an **editorial craft gate** runs before the persona sweep, the persona
|
||||
resonance sweep runs **BEFORE lock**, and a **cold adversarial review package**
|
||||
(Step 6.5) runs after the in-session persona sweep and 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; v2.4 on the editor/persona role
|
||||
split; v3.1 / Endring 9 on adversarial independence + framing-bias).
|
||||
|
||||
| Step | Phase | What | Tools |
|
||||
|------|-------|------|-------|
|
||||
|
|
@ -91,22 +93,25 @@ important corrections from the Seres process (plan §0.4, principle 5; v2.1 brie
|
|||
| 5 | **Fact-check sweep** | risk-sorted (🔴/🟡/🟢), guilty-until-disproven, verification log | **`fact-checker` (parallel)** |
|
||||
| 5.5 | **Editorial review — BEFORE persona sweep** | editor's craft gate: prose-craft (em-dash density, verbatim repetition, postulated numbers, contradictions, versal-tic) + narrative-architecture (concrete instantiation, theory-anchored hypotheses, series-title symmetry, equal action per addressee, un-overloaded conclusion). ≤10 flags, BLOCK/REWORK/NICE. Operator-gated via `SendUserFile`. | **`editorial-reviewer`** + `SendUserFile` |
|
||||
| 6 | **Persona sweep — BEFORE lock** | reader jury, primær wins, convergence to clean YES | **`persona-reviewer`** (resonance mode) |
|
||||
| 6.5 | **Headless adversarial review — BEFORE lock** | COLD review package on a frozen draft, no drafting-session context: content-reviewer (argument) + language-reviewer (Norwegian) + fact-reviewer (cold re-verification incl. pivot premises) + persona-reviewer resonance/conversion. Consolidated, operator-gated via `SendUserFile`. The independence layer the in-session gates can't be. | **`content-reviewer` + `language-reviewer` + `fact-reviewer` + `persona-reviewer`** (parallel) + `SendUserFile` |
|
||||
| 7 | **Annotation (optional)** | render annotatable review HTML for a manual pass | `render/build-html.mjs` |
|
||||
| 7.5 | **Visual assets — BEFORE lock** | cover (+ optional inline figures) or carousel deck: behov → per-image brief → generate (mcp-image default / external `cover-raw.png`) → operator-gate (`SendUserFile`) → approve to `cover.png` → credit/caption. Runs before lock so the renderer picks the cover up. | `mcp__mcp-image__generate_image` + `SendUserFile` + (carousel) `render/build-carousel.mjs` |
|
||||
| 8 | **LOCK → delivery** | POST.html "all in one place" | `render/build-linkedin.mjs` |
|
||||
| 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 15 phases (Steps 0–2.5, 3a, 3b, 4, 5, 5.5, 6, 7, 7.5,
|
||||
> 8–10) are implemented below. This command takes an edition end-to-end: load →
|
||||
> calibration → verified research → **skeleton + section pitch (operator +
|
||||
> **Build status:** all 16 phases (Steps 0–2.5, 3a, 3b, 4, 5, 5.5, 6, 6.5, 7,
|
||||
> 7.5, 8–10) 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 →
|
||||
> **editorial review (craft gate, operator-gated BEFORE the persona sweep)** →
|
||||
> pre-lock persona sweep → optional annotation → **visual assets (cover/figures
|
||||
> or carousel, operator-gated BEFORE lock)** → LOCK/delivery → post-lock hook
|
||||
> gate → scheduling, persisting each phase to `edition-state.json` (machine) and
|
||||
> `<serie>/STATE.md` (narrative) and stopping cleanly between sessions.
|
||||
> pre-lock persona sweep → **headless adversarial review (cold review package,
|
||||
> operator-gated BEFORE lock)** → optional annotation → **visual assets
|
||||
> (cover/figures or carousel, operator-gated BEFORE lock)** → LOCK/delivery →
|
||||
> post-lock hook gate → 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 5–15 min, at the
|
||||
|
|
@ -157,9 +162,18 @@ the edition left off before doing anything.
|
|||
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.
|
||||
5. **Read the persona library** — `${CLAUDE_PLUGIN_ROOT}/config/personas.local.md`
|
||||
if it exists, else `${CLAUDE_PLUGIN_ROOT}/config/personas.template.md`. You
|
||||
will select the active personas + mark the primær in Step 1.
|
||||
5. **Resolve the active personas (per-artifact).** Personas are configured **per
|
||||
edition**, not from one fixed global file. Resolve the set for
|
||||
`articles.<currentArticle>` in this order (Step 1 finalizes + persists it):
|
||||
1. **`edition-state.json` → `articles.NN.personas`** — if already populated
|
||||
(a resumed edition), use it as-is.
|
||||
2. **`<serie>/linkedin/personas.md`** — a per-series persona file, if present.
|
||||
3. **`${CLAUDE_PLUGIN_ROOT}/config/personas.local.md`** (else
|
||||
`personas.template.md`) — the plugin library; select a subset.
|
||||
4. **None / insufficient** — Step 1 will **define personas interactively**.
|
||||
Exactly one persona is the **primær**. The resolved set feeds BOTH the Step 6
|
||||
resonance sweep AND the Step 6.5 headless package; see
|
||||
`config/personas.template.md` → "Per-artifact personas".
|
||||
6. **Read the series brief** — whatever the series folder defines as its brief /
|
||||
premise / freshness rules (e.g. `<serie>/brief.md`, or the resolved brief
|
||||
recorded in `edition-state.json`). This anchors angle and scope.
|
||||
|
|
@ -187,7 +201,8 @@ Look up `edition-state.json` → `articles.<currentArticle>` (and the top-level
|
|||
| `consistency-quality` | Step 5 — Fact-check sweep |
|
||||
| `factcheck-sweep` | Step 5.5 — Editorial review *(v2.4 — craft gate BEFORE the persona sweep)* |
|
||||
| `editorial-review` | Step 6 — Persona sweep (pre-lock) |
|
||||
| `persona-sweep-prelock` | Step 7 — Annotation (optional) → Step 7.5 |
|
||||
| `persona-sweep-prelock` | Step 6.5 — Headless adversarial review *(v3.1 — cold review package, BEFORE lock)* |
|
||||
| `headless-review` | Step 7 — Annotation (optional) → Step 7.5 |
|
||||
| `annotation` | Step 7.5 — Visual assets *(cover/figures or carousel deck, BEFORE lock)* |
|
||||
| `visual-assets` | Step 8 — LOCK → delivery |
|
||||
| `lock-delivery` | Step 9 — Hook / conversion gate |
|
||||
|
|
@ -216,8 +231,8 @@ 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
|
||||
> at Step 7. No operator question, no re-doing the persona sweep. The same holds
|
||||
> at every row.
|
||||
> at Step 6.5 (headless adversarial review). No operator question, no re-doing the
|
||||
> persona sweep. The same holds at every row.
|
||||
|
||||
Then display a short status:
|
||||
|
||||
|
|
@ -242,11 +257,20 @@ Settle these dimensions (most should come from context, not questions):
|
|||
|
||||
- **Angle** — the one premise this edition argues.
|
||||
- **Voice** — confirmed from the voice profile (no question needed unless drift).
|
||||
- **Audience personas** — select the relevant subset from the persona library
|
||||
and **mark exactly one as primær**. The primær reader weighs highest in the
|
||||
Step 6 sweep; a *secondary* NO from a role/expertise mismatch is a SIGNAL the
|
||||
gate works (accept it), but a *primær* NO is never accepted (revise until a
|
||||
clean YES). See `config/personas.template.md` → "How the library is used".
|
||||
- **Audience personas (per-artifact)** — finalize the **one or more personas for
|
||||
THIS edition** from the Step 0 resolution, and **mark exactly one as primær**.
|
||||
If the resolution found a set (edition-state / series file / plugin library),
|
||||
confirm or trim it; if it found none — or the operator wants a reader the
|
||||
library does not cover — **define personas interactively** here (name + the
|
||||
five fields: rolle, avkobler, overbeviser, ekspertise, sjargong). The primær
|
||||
reader weighs highest in the Step 6 sweep AND the Step 6.5 headless package; a
|
||||
*secondary* NO from a role/expertise mismatch is a SIGNAL the gate works
|
||||
(accept it), but a *primær* NO is never accepted (revise until a clean YES).
|
||||
**Persist** the resolved set to `edition-state.json` →
|
||||
`articles.NN.personas` (each entry: name, tier, the five fields, source) at the
|
||||
Step 2 checkpoint — it is then stable across sessions and is the single source
|
||||
every later sweep reads. See `config/personas.template.md` →
|
||||
"Per-artifact personas".
|
||||
- **Key points** — the 2–4 load-bearing claims the edition must make.
|
||||
- **Tone** — respected-peer vs. teaching-down; calibrated to the primær.
|
||||
- **Leader-takeaway** — the ONE takeaway + ONE concrete action the reader leaves
|
||||
|
|
@ -316,9 +340,11 @@ Edition brief
|
|||
source(s) and a confidence marker. Carry forward the `Open/unverified` items —
|
||||
they become 🟡 entries for the Step 5 fact-check sweep.
|
||||
|
||||
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
|
||||
5. **Persist + checkpoint state.** Write the resolved brief (Step 1), the
|
||||
resolved **per-article personas** (`articles.NN.personas` — the set + primær
|
||||
confirmed/defined in 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)" 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
|
||||
|
|
@ -951,9 +977,13 @@ reopening locked texts — the biggest single process error of the series (plan
|
|||
|
||||
5. **Persist + checkpoint state.** Record the final per-persona verdicts and the
|
||||
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).
|
||||
(where the old HANDOVER §5 calibration now lives). **Also record the cleared
|
||||
draft's word count** as `articles.NN.personaSweep.resonance.wordCount`
|
||||
(`wc -w <serie>/NN-utkast.md`) — this is the **baseline** the pivot-detection
|
||||
heuristic (Step 8 / `/linkedin:pivot`) compares against to catch a late pivot.
|
||||
Set `currentPhase: "persona-sweep-prelock"`, and write a "persona sweep
|
||||
PASS (primær JA) → next: headless adversarial review (Step 6.5, BEFORE lock)"
|
||||
line to `<serie>/STATE.md` (overwrite).
|
||||
|
||||
```
|
||||
Persona sweep complete (BEFORE lock).
|
||||
|
|
@ -961,8 +991,115 @@ Persona sweep complete (BEFORE lock).
|
|||
- Convergence rounds: <N>
|
||||
- primær verdict: JA (else: still NEI — loop open, NOT ready to lock)
|
||||
- Accepted sekundær ceiling-NOs (signal, not failure): <N or none>
|
||||
- Cleared word count recorded: <N> (pivot-detection baseline)
|
||||
Gate: [PASS — primær JA, ready to lock] (else REWORK/BLOCK)
|
||||
Next: Step 7 — Annotation (optional), then Step 8 — LOCK → delivery.
|
||||
Next: Step 6.5 — Headless adversarial review (cold review package, BEFORE lock).
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 6.5: Headless adversarial review — cold review package, BEFORE lock
|
||||
|
||||
The persona-passed draft now faces a **cold, adversarial review package**: five
|
||||
independent archetypes read the *finished* text with **none of this session's
|
||||
context** — no version history, no "deliberately omitted" list, no pivot
|
||||
narrative, no record of who approved what. They are the independence layer the
|
||||
in-session gates (`fact-checker` Step 5, `editorial-reviewer` Step 5.5,
|
||||
`persona-reviewer` Step 6) structurally cannot be, because those share the
|
||||
drafting session's framing-bias.
|
||||
|
||||
> **Why this step exists (Del 4 diagnosis, Endring 9).** In Del 4 the editor and
|
||||
> the persona sweep ran in the same session as drafting. They shared the
|
||||
> conversation history, so they carried framing-bias and were not adversarial:
|
||||
> the resonance sweep effectively judged an early version, editor-approval was
|
||||
> single-source, and the fact-check was post-hoc relative to a late pivot. This
|
||||
> step answers KTG's question — *how do I start sessions with no context from the
|
||||
> main session, to review both content and language?* — by running the review on
|
||||
> a **frozen** draft through agents that refuse session framing.
|
||||
|
||||
> **Order assertion (enforced).** Step 6.5 runs AFTER the in-session persona
|
||||
> sweep (Step 6) and BEFORE lock (Step 8), on a **frozen snapshot** of the
|
||||
> publish-ready draft. Any flag the operator folds in is re-touched **before**
|
||||
> lock — never reopen a locked text (the cardinal Seres lesson). If a pivot
|
||||
> changes the draft after this gate, `/linkedin:pivot` re-opens the pipeline and
|
||||
> this package re-runs on the pivoted version. `[GATE]`
|
||||
|
||||
**Relationship to the in-session gates (deliberate redundancy).** `fact-reviewer`
|
||||
overlaps `fact-checker` and `language-reviewer` overlaps `editorial-reviewer`'s
|
||||
prose axis **on purpose** — the cold re-read catches what the framing-biased
|
||||
in-session pass hid. `content-reviewer` is genuinely new (argument integrity,
|
||||
which no in-session gate measures). Do NOT collapse the pairs.
|
||||
|
||||
**Procedure** (this is the same package the standalone `/linkedin:headless-review`
|
||||
command runs — see `commands/headless-review.md` for the full cold contract):
|
||||
|
||||
1. **Freeze the draft.** Snapshot the persona-passed `NN-utkast.md` so the
|
||||
reviewers judge a stable artifact and the report names exactly what was read:
|
||||
```bash
|
||||
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 every reviewer.
|
||||
|
||||
2. **Resolve the cold inputs.** The writing contract (`<serie>/../../docs/skrivekontrakt.md`
|
||||
→ plugin mirror → `references/longform-quality-rules.md`) and the active
|
||||
personas (`articles.NN.personas`, primær identified). Nothing else.
|
||||
|
||||
3. **Fan out the five archetypes in parallel** — issue them in a SINGLE message
|
||||
(multiple `Task` tool-uses) from THIS command layer in the foreground
|
||||
(principle 4), `subagent_type` namespaced:
|
||||
- `linkedin-studio:content-reviewer` — argument integrity (C1–C5)
|
||||
- `linkedin-studio:language-reviewer` — Norwegian language (L1–L5)
|
||||
- `linkedin-studio:fact-reviewer` — cold re-verification (F1–F4, 🔴/🟡/🟢, incl. pivot premises)
|
||||
- `linkedin-studio:persona-reviewer` `mode: resonans` — **one call per active persona**
|
||||
- `linkedin-studio:persona-reviewer` `mode: konverter` — **primær only** (hook)
|
||||
|
||||
Each call's prompt carries ONLY the cold-contract inputs (frozen draft path,
|
||||
contract path, persona for the persona modes) + the instruction to ignore any
|
||||
framing about prior versions / cuts / pivots. **Never** paste history or
|
||||
summarize "what we changed" into a reviewer prompt — that is the context
|
||||
pollution the package exists to eliminate.
|
||||
|
||||
> **Maximum-independence path.** The strongest isolation is the operator
|
||||
> running `/linkedin:headless-review --draft <frozen> --article NN` in a
|
||||
> **fresh session** (the parent then has no drafting transcript at all) and
|
||||
> pasting the consolidated report back. The inline fan-out here is the
|
||||
> single-session path; both use the same agents.
|
||||
|
||||
4. **Degradation gate.** Confirm each call returned structured, populated output
|
||||
(real flags / a verification log), not empty or a hedged paragraph. Re-run any
|
||||
degraded archetype — do not proceed with a missing reviewer. `[GATE]`
|
||||
|
||||
5. **Consolidate + surface (`SendUserFile`).** Merge the returns into one report
|
||||
at `<serie>/review/NN-headless-<stamp>.md`, grouped by archetype → severity,
|
||||
with a cross-archetype signal line. **Mark ⚑ converged** any passage two
|
||||
independent cold reviewers flag — independent agreement with no shared session
|
||||
is the package's strongest signal. `SendUserFile` it (else a `file://` link)
|
||||
so KTG decides which flags fold in. You do not resolve flags or pick winners;
|
||||
the operator gates. `[OPERATØR]`
|
||||
|
||||
6. **Fold in by tightening, → v(n+1).** Fold the flags KTG approved into
|
||||
`NN-utkast.md` **by tightening** (rule 6 — close the gap, hold the length flat).
|
||||
The editor (this session) holds the pen; never paste a reviewer's direction as
|
||||
copy. If the fold-in was substantive, re-run the affected archetype on v(n+1).
|
||||
All of this happens **before** lock, so the body is never reopened post-lock.
|
||||
|
||||
7. **Persist + checkpoint state.** Record the run in `edition-state.json` →
|
||||
`articles.NN.headlessReview` (`frozenDraft`, per-reviewer `{reportPath,
|
||||
summary, status}`, `consolidatedReport`, `foldedIn`/`waived`, `status:
|
||||
"folded"`), set `currentPhase: "headless-review"`, and write a "headless review
|
||||
complete (cold, converged flags folded) → next: annotation/lock" line to
|
||||
`<serie>/STATE.md` (overwrite).
|
||||
|
||||
```
|
||||
Headless adversarial review (cold, BEFORE lock) — complete.
|
||||
- Frozen draft: <serie>/review/NN-frozen-<stamp>.md
|
||||
- Archetypes: content · language · fact · persona-resonance (<N> personas) · persona-conversion (primær)
|
||||
- Converged flags (independent agreement): <N>
|
||||
- BLOCK/🔴: <N> → folded/waived REWORK: <N> primær resonance: JA conversion: JA
|
||||
- Surfaced to operator: <serie>/review/NN-headless-<stamp>.md (via SendUserFile) [OPERATØR]
|
||||
- Folded in (by tightening, pre-lock): <N> Waived: <N>
|
||||
Gate: [PASS — operator approved, body re-touched pre-lock]
|
||||
Next: Step 7 — Annotation (optional), then Step 7.5 — Visual assets, then Step 8 — LOCK.
|
||||
```
|
||||
|
||||
---
|
||||
|
|
@ -1175,19 +1312,38 @@ produces the editor's single delivery artifact — `POST.html`, the
|
|||
(delingstekst) copy, ready to paste into LinkedIn.
|
||||
|
||||
> **Order assertion (enforced).** Lock (Step 8) runs AFTER the pre-lock persona
|
||||
> sweep (Step 6) and BEFORE the hook/conversion gate (Step 9). Reversing lock
|
||||
> and the pre-lock sweep reproduces the exact Seres failure (reopening locked
|
||||
> texts) — see Step 6. The post-lock hook-gate (Step 9) judges only the
|
||||
> distribution hook and never reopens the locked body. `[GATE]`
|
||||
> sweep (Step 6) AND the headless adversarial review (Step 6.5), and BEFORE the
|
||||
> hook/conversion gate (Step 9). Reversing lock and the pre-lock sweeps
|
||||
> reproduces the exact Seres failure (reopening locked texts) — see Step 6. The
|
||||
> post-lock hook-gate (Step 9) judges only the distribution hook and never
|
||||
> reopens the locked body. `[GATE]`
|
||||
|
||||
**Procedure:**
|
||||
|
||||
1. **Confirm lock preconditions.** In `edition-state.json`: the article's
|
||||
`factcheckLog` has no open 🔴, `personaSweep.resonance` recorded a primær JA,
|
||||
and `visualAssets` is gated — for `standard` format the approved
|
||||
`linkedin/NN/cover.png` exists (Step 7.5); for `carousel` format the approved
|
||||
`carousel.pdf`/`carousel.html` exists. If any is missing, STOP — return to the
|
||||
relevant step (5/6/7.5). Do not lock past an open gate.
|
||||
`headlessReview.status` is `folded` (or `run` with no open BLOCK/🔴 the
|
||||
operator left unaddressed — Step 6.5), and `visualAssets` is gated — for
|
||||
`standard` format the approved `linkedin/NN/cover.png` exists (Step 7.5); for
|
||||
`carousel` format the approved `carousel.pdf`/`carousel.html` exists. If any is
|
||||
missing, STOP — return to the relevant step (5/6/6.5/7.5). Do not lock past an
|
||||
open gate.
|
||||
|
||||
**Pivot-detection gate (Endring 9c — enforced).** Before locking, compare the
|
||||
current draft against the version that last cleared Step 6:
|
||||
- **word count:** `wc -w <serie>/NN-utkast.md` vs
|
||||
`articles.NN.personaSweep.resonance.wordCount` (the recorded baseline);
|
||||
- **new sections:** top-level headings now present that were absent then
|
||||
(`grep -c '^## '` delta is a fair proxy).
|
||||
|
||||
If the draft has drifted **> 20 % in word count OR gained > 2 sections** since
|
||||
Step 6 cleared, the text pivoted after its gates — **STOP, do not lock.** Run
|
||||
`/linkedin:pivot --article NN --reason "<what changed>"`, which re-opens the
|
||||
pipeline so fact-check (5) → editorial (5.5) → persona (6) → headless (6.5)
|
||||
re-run on the pivoted version. Likewise, if `articles.NN.pivots[]` has an entry
|
||||
whose `gatesToRerun` gates have not since re-passed, STOP — the pivot's
|
||||
re-review is incomplete. (This is exactly the Del 4 v8→v11 case: +42 %, 2 new
|
||||
sections → the gate would have fired and forced the re-sweep.) `[GATE]`
|
||||
|
||||
2. **Confirm the delivery inputs in the series folder.**
|
||||
`render/build-linkedin.mjs` reads, relative to cwd (`<serie>/linkedin/`):
|
||||
|
|
@ -1335,15 +1491,20 @@ Edition complete. Visible in /linkedin:calendar; mark live via /linkedin:calenda
|
|||
|
||||
## Reference Files
|
||||
|
||||
- `${CLAUDE_PLUGIN_ROOT}/config/edition-state.template.json` — edition-state schema (15 phases including v2.1 skeleton + spine-prose gates, v2.3 visual-assets, and v2.4 editorial-review)
|
||||
- `${CLAUDE_PLUGIN_ROOT}/config/edition-state.template.json` — edition-state schema (16 phases including v2.1 skeleton + spine-prose gates, v2.3 visual-assets, v2.4 editorial-review, and v3.1 headless-review + per-article `personas` + `pivots`)
|
||||
- `${CLAUDE_PLUGIN_ROOT}/config/edition-config.template.json` — static delivery metadata schema (calendar, freshness, credit, captions) — Step 8
|
||||
- `${CLAUDE_PLUGIN_ROOT}/config/image-credit-caption.template.md` — cover motif + credit + caption table (honest-about-AI credit) — Step 7.5
|
||||
- `${CLAUDE_PLUGIN_ROOT}/config/edition-delingstekst.template.md` — distribution-copy grammar (`## Del N —` / `## Samle`) — Steps 8/9
|
||||
- `${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/editorial-reviewer.md` — Step 5.5 editor's craft gate (prose-craft + narrative-architecture, BLOCK/REWORK/NICE; mirrors Maskinrommet §C2)
|
||||
- `${CLAUDE_PLUGIN_ROOT}/agents/persona-reviewer.md` — Step 2.5/6/9 reader jury (skeleton + resonance + conversion modes)
|
||||
- `${CLAUDE_PLUGIN_ROOT}/agents/persona-reviewer.md` — Step 2.5/6/9 reader jury (skeleton + resonance + conversion modes); also resonance + conversion in the Step 6.5 headless package
|
||||
- `${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}/agents/content-reviewer.md` — Step 6.5 cold argument-integrity review (C1–C5; headless, no session context)
|
||||
- `${CLAUDE_PLUGIN_ROOT}/agents/language-reviewer.md` — Step 6.5 cold Norwegian-language review (L1–L5; headless)
|
||||
- `${CLAUDE_PLUGIN_ROOT}/agents/fact-reviewer.md` — Step 6.5 cold re-verification (F1–F4, 🔴/🟡/🟢; catches pivot premises Step 5 missed)
|
||||
- `${CLAUDE_PLUGIN_ROOT}/commands/headless-review.md` — the Step 6.5 cold review package as a standalone command (run in a fresh session for maximum isolation)
|
||||
- `${CLAUDE_PLUGIN_ROOT}/commands/pivot.md` — re-opens the pipeline after a late pivot so Steps 5–6.5 re-run on the changed version before lock
|
||||
- `${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, 4–9 all reference)
|
||||
|
|
|
|||
161
plugins/linkedin-studio/commands/pivot.md
Normal file
161
plugins/linkedin-studio/commands/pivot.md
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
---
|
||||
name: linkedin:pivot
|
||||
description: |
|
||||
Re-open a long-form edition after a substantive late change (a "pivot") so the
|
||||
already-cleared quality gates re-run on the changed version before lock. Logs
|
||||
the pivot in edition-state, moves currentPhase back to the right earlier step,
|
||||
un-locks if needed, and marks which gates (fact-check, editorial, persona,
|
||||
headless) must re-pass. Includes the pivot-detection heuristic (>20% word-count
|
||||
change or >2 new sections).
|
||||
Use when the user says: "pivot", "I changed the angle", "I added a section",
|
||||
"re-open the edition", "the article changed after it was approved",
|
||||
"re-run the gates", "this needs re-review".
|
||||
Triggers on: "pivot", "linkedin pivot", "re-open edition", "added a section",
|
||||
"changed the angle", "pivot-reopen", "/linkedin:pivot".
|
||||
allowed-tools:
|
||||
- Read
|
||||
- Glob
|
||||
- Grep
|
||||
- Bash
|
||||
- AskUserQuestion
|
||||
- Write
|
||||
---
|
||||
|
||||
# LinkedIn Pivot — re-open a cleared edition for re-review
|
||||
|
||||
A **pivot** is a substantive change to a long-form draft made *after* a gate had
|
||||
already cleared it — a new argument anchor, a new section, a changed thesis. The
|
||||
problem this command solves: the pipeline's gates (fact-check Step 5, editorial
|
||||
Step 5.5, persona Step 6, headless Step 6.5) ran on the *pre-pivot* version, so
|
||||
the changed text was never validated. Without an explicit re-open, a pivoted
|
||||
edition can sail into lock carrying an unverified premise or an unread argument.
|
||||
|
||||
> **Why this exists (Del 4, Endring 9c).** Del 4 was LOCK-ready on an early
|
||||
> version (v8). Then a "Security Champions" pivot added a ~260-word section and a
|
||||
> ~270-word role-description section — roughly +42 % length, two new sections, a
|
||||
> new axis. The pipeline had no pivot-mode, so the whole post-lock chain had to be
|
||||
> re-opened by hand. This command makes the re-open a **named ritual**, not a
|
||||
> manual scramble.
|
||||
|
||||
## Command anatomy
|
||||
|
||||
```
|
||||
/linkedin:pivot
|
||||
--article NN (required; the edition article that changed)
|
||||
--reason "<one line>" (required; e.g. "Security Champions-anker")
|
||||
--to-phase draft | consistency-quality | factcheck-sweep (optional; default from the heuristic)
|
||||
```
|
||||
|
||||
## The pivot-detection heuristic
|
||||
|
||||
Compare the **current** draft against the version that **last cleared Step 6**
|
||||
(persona-sweep-prelock). A pivot-reopen is **suggested/required** when either:
|
||||
|
||||
- **word-count change > 20 %**, or
|
||||
- **> 2 new sections** (top-level headings added since the cleared version).
|
||||
|
||||
This heuristic is also checked as a **lock precondition in Step 8** of
|
||||
`/linkedin:newsletter`: if the draft has drifted past these bounds since Step 6
|
||||
cleared, the lock STOPS and points the operator here. (Length-band drift itself
|
||||
— soft/hard caps — is logged friction F1, not yet a gate.)
|
||||
|
||||
> **Worked example (acceptance test — Del 4 v8 → v11).** At v8 the persona sweep
|
||||
> had cleared a ~1 400-word draft. The Security Champions message pushed it to
|
||||
> ~1 992 words (+42 %, > 20 %) and added 2 sections (a new anchor + a
|
||||
> role-description) — at the boundary of the "> 2 new sections" rule and well past
|
||||
> the 20 % rule. **The heuristic fires:** `/linkedin:pivot --article 04 --reason
|
||||
> "Security Champions-anker"` would log the pivot, move `currentPhase` back to
|
||||
> `draft` (structural change → full re-treatment), and require fact-check +
|
||||
> editorial + persona + headless to re-pass on v11 before lock. That is exactly
|
||||
> the re-sweep the manual Del 4 run had to improvise.
|
||||
|
||||
## Step 1 — Load state + locate the article
|
||||
|
||||
1. Resolve the series root and read `<serie>/linkedin/edition-state.json`. Find
|
||||
`articles.NN` for the `--article` value. If it does not exist, stop and report.
|
||||
2. Read the current draft `<serie>/NN-utkast.md` and note `currentPhase` and
|
||||
`locked`.
|
||||
|
||||
## Step 2 — Measure the pivot scope
|
||||
|
||||
1. **Current word count:** `cd <serie-mappe> && wc -w NN-utkast.md`.
|
||||
2. **Baseline word count:** the word count of the version that last cleared
|
||||
Step 6, recorded by newsletter Step 6 in
|
||||
`articles.NN.personaSweep.resonance.wordCount`. If that field is absent (older
|
||||
state), ask the operator for the cleared-version word count, or treat the
|
||||
pivot as structural by default.
|
||||
3. **Compute** `deltaPct = round((current - baseline) / baseline * 100)` and
|
||||
count `newSections` = top-level headings now present that were not in the
|
||||
cleared version (a `grep -c '^## '` delta is a reasonable proxy; confirm with
|
||||
the operator if ambiguous).
|
||||
4. **Classify scope** (drives the default `--to-phase`):
|
||||
- **Structural** (deltaPct > 20 % OR newSections > 2, or a new axis/thesis) →
|
||||
default `to-phase: draft` (Step 3b). The new material needs full prose
|
||||
expansion → consistency → fact-check → editorial → persona → headless.
|
||||
- **Moderate** (new examples/claims, no new sections, deltaPct ≤ 20 %) →
|
||||
default `to-phase: factcheck-sweep` (Step 5) so the new claims get verified,
|
||||
then editorial + persona + headless re-run.
|
||||
- The operator may override with explicit `--to-phase`.
|
||||
|
||||
## Step 3 — Log the pivot + reset the phase (the ritual)
|
||||
|
||||
1. **Append a pivot entry** to `articles.NN.pivots[]`:
|
||||
```json
|
||||
{
|
||||
"timestamp": "<ISO-8601>",
|
||||
"reason": "<--reason>",
|
||||
"fromPhase": "<currentPhase before this command>",
|
||||
"toPhase": "<resolved to-phase>",
|
||||
"wordCountBefore": <baseline>,
|
||||
"wordCountAfter": <current>,
|
||||
"deltaPct": <deltaPct>,
|
||||
"newSections": <newSections>,
|
||||
"gatesToRerun": ["factcheck-sweep", "editorial-review", "persona-sweep-prelock", "headless-review"]
|
||||
}
|
||||
```
|
||||
`gatesToRerun` always spans every gate from the reset phase through Step 6.5 —
|
||||
a pivot invalidates the fact-check, the editorial craft pass, the persona
|
||||
resonance verdict, AND the headless package, because all of them judged the
|
||||
pre-pivot text.
|
||||
2. **Reset `currentPhase`** to the resolved `toPhase`, and set the article's
|
||||
`phase` to match.
|
||||
3. **Un-lock if needed.** If `articles.NN.locked` was `true`, set `locked: false`
|
||||
and `status: "in-progress"` — a pivot means the edition is no longer locked.
|
||||
Surface this plainly (the prior `POST.html` is now stale and will be re-rendered
|
||||
at the next lock).
|
||||
4. **Invalidate the downstream verdicts** so they cannot be mistaken for current:
|
||||
set `personaSweep.resonance`, `editorialReview`, and `headlessReview.status`
|
||||
back to a re-run state (e.g. `headlessReview.status: "pending"`), and note in
|
||||
each that they were invalidated by pivot `<timestamp>`. Leave the `pivots[]`
|
||||
log and `factcheckLog` history intact (history is durable).
|
||||
5. **Update `updatedAt`** and write `edition-state.json`.
|
||||
|
||||
## Step 4 — Point the next step
|
||||
|
||||
Write a precise next-step line to `<serie>/STATE.md` (overwrite, ONE-system):
|
||||
|
||||
```
|
||||
PIVOT logged (<reason>, +<deltaPct>%, <newSections> new sections) →
|
||||
currentPhase reset to <toPhase>. Resume /linkedin:newsletter; it will re-run
|
||||
fact-check (5) → editorial (5.5) → persona (6) → headless (6.5) on the pivoted
|
||||
version BEFORE lock. Headless package: /linkedin:headless-review --article NN.
|
||||
```
|
||||
|
||||
Do not run the gates yourself — `/linkedin:newsletter` owns the pipeline and will
|
||||
resume deterministically from the reset `currentPhase` and re-run every gate in
|
||||
`gatesToRerun` before it permits lock.
|
||||
|
||||
```
|
||||
Pivot logged.
|
||||
- Article NN: <reason>
|
||||
- Scope: <structural|moderate> (Δ <deltaPct>%, <newSections> new sections)
|
||||
- currentPhase: <fromPhase> → <toPhase> locked: <true→false | unchanged>
|
||||
- Gates to re-run before lock: fact-check (5) · editorial (5.5) · persona (6) · headless (6.5)
|
||||
Next: resume /linkedin:newsletter (re-runs the gates) → then lock.
|
||||
```
|
||||
|
||||
## Reference Files
|
||||
|
||||
- `${CLAUDE_PLUGIN_ROOT}/commands/newsletter.md` — the pipeline this re-opens; Step 8 lock-precondition runs the same heuristic; the resumption table replays from the reset `currentPhase`
|
||||
- `${CLAUDE_PLUGIN_ROOT}/commands/headless-review.md` — the cold review package that must re-pass on the pivoted version
|
||||
- `${CLAUDE_PLUGIN_ROOT}/config/edition-state.template.json` — `articles.NN.pivots` schema + the heuristic notes
|
||||
|
|
@ -15,6 +15,7 @@
|
|||
"factcheck-sweep — risk-sorted, guilty-until-disproven, verification log (Step 5)",
|
||||
"editorial-review — editor's craft gate: prose-craft (em-dash density, verbatim repetition, postulated numbers, contradictions, versal-tic) + narrative-architecture (concrete instantiation, theory-anchored hypotheses, series-title symmetry, equal action per addressee, un-overloaded conclusion), ≤10 flags BLOCK/REWORK/NICE, operator-gated via SendUserFile BEFORE the persona sweep (Step 5.5)",
|
||||
"persona-sweep-prelock — reader jury, primary wins, convergence to clean YES (Step 6)",
|
||||
"headless-review — adversarial review package run COLD on a FROZEN draft (no drafting-session context): content-reviewer (argument integrity) + language-reviewer (Norwegian language) + fact-reviewer (cold re-verification incl. pivot premises) + persona-reviewer in resonance & conversion modes. Fan-out from Step 6.5 or the standalone /linkedin:headless-review command; consolidated report operator-gated via SendUserFile BEFORE lock (Step 6.5)",
|
||||
"annotation — optional annotatable review HTML for a manual pass (Step 7)",
|
||||
"visual-assets — cover (+ optional inline figures) or carousel deck: brief → generate → operator-gate → approve, BEFORE lock so build-linkedin.mjs picks them up (Step 7.5)",
|
||||
"lock-delivery — LOCK → POST.html all-in-one-place deliverable (Step 8)",
|
||||
|
|
@ -23,7 +24,10 @@
|
|||
],
|
||||
"articleStatusValues": ["pending", "in-progress", "locked", "scheduled"],
|
||||
"editorialReview": "Per-article editorial-review record written by Step 5.5 (editorial-review phase). Runs AFTER fact-check (Step 5) and BEFORE the persona sweep (Step 6): the editorial-reviewer agent judges CRAFT (prose-craft + narrative-architecture), not reader-response, mirroring the Maskinrommet skrivekontrakt §C2. The report (≤10 flags, each with kategori P1–P5/A1–A5, quote/line-ref, direction, severity BLOCK/REWORK/NICE) is surfaced to the operator via SendUserFile; the operator decides which flags fold in. Shape: { reportPath, flagCount, byAxis: { prosa, arkitektur }, bySeverity: { block, rework, nice }, foldedIn, waived, status }. status ladder: pending → reviewed → folded. null until Step 5.5 runs. This is the craft companion to factcheckLog (truth) and personaSweep (response).",
|
||||
"visualAssets": "Per-article visual-asset record written by Step 7.5 (visual-assets phase). Runs BEFORE lock because render/build-linkedin.mjs picks up linkedin/NN/cover.png + the edition-config credit/caption when it builds POST.html — generating images after lock would force a re-render. Shape: { format: \"standard\" | \"carousel\"; cover: { brief, route, candidates[], approved, status }; figures: [ { id, brief, placement, status } ]; carousel: null | { source, pdf, status } }. format \"standard\" = cover + optional inline figures (cover.png is mandatory per the KTG cover-directive); format \"carousel\" = typografisk deck via render/build-carousel.mjs instead of cover+inline (cover/figures stay empty). route: \"mcp-image\" (default, via mcp__mcp-image__generate_image) | \"external\" (DALL·E / Midjourney / photographer → linkedin/NN/cover-raw.png). status ladder: pending → briefed → generated → approved. candidates[] holds the cover-v<N>-kandidat.png attempts; approved is the fixed approved name (\"cover.png\") once the operator-gate passes. figures[].id = \"fig1\"..; placement = section reference in NN-utkast.md (figures are referenced in the draft via  and uploaded manually in the LinkedIn editor — build-linkedin.mjs does NOT embed them). Naming convention: cover.png (approved, fixed — what build-linkedin.mjs reads) | cover-v<N>-kandidat.png (attempts) | cover-raw.png (optional external pre-edit source) | fig<N>.png (inline). credit + caption are recorded in <serie>/linkedin/image-credit-caption.md and flow into edition-config.json coverCredit + captions[NN]."
|
||||
"visualAssets": "Per-article visual-asset record written by Step 7.5 (visual-assets phase). Runs BEFORE lock because render/build-linkedin.mjs picks up linkedin/NN/cover.png + the edition-config credit/caption when it builds POST.html — generating images after lock would force a re-render. Shape: { format: \"standard\" | \"carousel\"; cover: { brief, route, candidates[], approved, status }; figures: [ { id, brief, placement, status } ]; carousel: null | { source, pdf, status } }. format \"standard\" = cover + optional inline figures (cover.png is mandatory per the KTG cover-directive); format \"carousel\" = typografisk deck via render/build-carousel.mjs instead of cover+inline (cover/figures stay empty). route: \"mcp-image\" (default, via mcp__mcp-image__generate_image) | \"external\" (DALL·E / Midjourney / photographer → linkedin/NN/cover-raw.png). status ladder: pending → briefed → generated → approved. candidates[] holds the cover-v<N>-kandidat.png attempts; approved is the fixed approved name (\"cover.png\") once the operator-gate passes. figures[].id = \"fig1\"..; placement = section reference in NN-utkast.md (figures are referenced in the draft via  and uploaded manually in the LinkedIn editor — build-linkedin.mjs does NOT embed them). Naming convention: cover.png (approved, fixed — what build-linkedin.mjs reads) | cover-v<N>-kandidat.png (attempts) | cover-raw.png (optional external pre-edit source) | fig<N>.png (inline). credit + caption are recorded in <serie>/linkedin/image-credit-caption.md and flow into edition-config.json coverCredit + captions[NN].",
|
||||
"personas": "Per-article resolved reader-persona set (input config), written/confirmed in Step 1. This makes personas configurable PER ARTIFACT, not just from one global plugin library: Step 1 resolves them in order — (1) already present here → use as-is; (2) <serie>/linkedin/personas.md (per-series file) → load; (3) plugin config/personas.local.md (or personas.template.md) library → select a subset; (4) none/insufficient → DEFINE interactively via AskUserQuestion. Exactly one entry has tier \"primær\" (the rest \"sekundær\"); «primær trumfer» on conflict. This set feeds BOTH the in-session sweep (Step 6) and the headless package (Step 6.5 / persona-reviewer). Each entry: { name, tier: \"primær\" | \"sekundær\", rolle, avkobler, overbeviser, ekspertise, sjargong, source: \"edition-state\" | \"series-file\" | \"plugin-library\" | \"interactive\" }. Default []: resolved on first Step 1.",
|
||||
"headlessReview": "Per-article headless-review record written by Step 6.5 (headless-review phase). Runs AFTER the in-session persona sweep (Step 6) and BEFORE lock (Step 8), on a FROZEN snapshot of the publish-ready (or pivoted) draft, fanned out from the command layer (foreground) or invoked standalone via /linkedin:headless-review in a fresh/cold session. Five archetypes judge independently with NO drafting-session context: content-reviewer (argument integrity), language-reviewer (Norwegian language), fact-reviewer (cold re-verification incl. claims a late pivot bolted on), persona-reviewer mode=resonans (per active persona), persona-reviewer mode=konverter (primær, hook only). The consolidated report is surfaced to the operator via SendUserFile; the operator decides which flags fold in. Shape: { frozenDraft, reviewers: { content, language, fact, personaResonance, personaConversion } (each { reportPath, summary, status }), consolidatedReport, foldedIn, waived, status }. status ladder: pending → run → folded. null until Step 6.5 runs. This is the adversarial-independence companion to the in-session gates (editorialReview, personaSweep, factcheckLog) — deliberately redundant: a cold reader catches what the framing-biased in-session pass missed.",
|
||||
"pivots": "Per-article pivot log (Endring 9c). A pivot is a substantive change to a draft AFTER a gate had already cleared — e.g. a new argument anchor / section added late (the Del 4 Security Champions case: +~530 words, 2 new sections, +42 %). Each /linkedin:pivot invocation appends one entry and moves currentPhase back so the cleared gates (Steps 5–6.5) re-run on the pivoted version before lock. Heuristic (documented, checked at the Step 8 lock precondition): if the current draft's word count differs > 20 % from the version that last cleared Step 6, OR it has > 2 new sections, a pivot-reopen is suggested/required. Each entry: { timestamp, reason, fromPhase, toPhase, wordCountBefore, wordCountAfter, deltaPct, newSections, gatesToRerun: [phase…] }. Default []."
|
||||
},
|
||||
"schemaVersion": 1,
|
||||
"series": {
|
||||
|
|
@ -38,6 +42,7 @@
|
|||
"title": "<Article 1 title>",
|
||||
"phase": "load-context",
|
||||
"status": "pending",
|
||||
"personas": [],
|
||||
"immutableRules": null,
|
||||
"factcheckLog": null,
|
||||
"editorialReview": null,
|
||||
|
|
@ -46,6 +51,20 @@
|
|||
"resonance": null,
|
||||
"conversion": null
|
||||
},
|
||||
"headlessReview": {
|
||||
"frozenDraft": null,
|
||||
"reviewers": {
|
||||
"content": null,
|
||||
"language": null,
|
||||
"fact": null,
|
||||
"personaResonance": null,
|
||||
"personaConversion": null
|
||||
},
|
||||
"consolidatedReport": null,
|
||||
"foldedIn": null,
|
||||
"waived": null,
|
||||
"status": "pending"
|
||||
},
|
||||
"visualAssets": {
|
||||
"format": "standard",
|
||||
"cover": {
|
||||
|
|
@ -58,6 +77,7 @@
|
|||
"figures": [],
|
||||
"carousel": null
|
||||
},
|
||||
"pivots": [],
|
||||
"locked": false,
|
||||
"scheduled": null
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,34 @@ trim, or extend them per series.
|
|||
BEFORE lock — «does the point land for this reader?») and conversion mode
|
||||
(Step 9, after lock — binary «would YOU click?» on the hook only).
|
||||
|
||||
### Per-artifact personas (one or more personas per edition)
|
||||
|
||||
This library is a *starting point*, not a fixed cast. **Each artifact (each
|
||||
newsletter edition) carries its own resolved persona set** — one or more
|
||||
personas, exactly one marked `primær` — so different editions can target
|
||||
different readers without editing a shared file. `/linkedin:newsletter` Step 1
|
||||
**resolves** the active set in this order and records it in
|
||||
`edition-state.json` → `articles.NN.personas` (so it is stable across the
|
||||
multi-session pipeline and is the single source the Step 6 sweep AND the
|
||||
Step 6.5 headless package read):
|
||||
|
||||
1. **Already in `articles.NN.personas`** → use as-is (a resumed edition keeps
|
||||
the set it was calibrated with).
|
||||
2. **`<serie>/linkedin/personas.md`** (a per-series file, same block grammar as
|
||||
below) → load it. Use this when a whole series shares a cast.
|
||||
3. **Plugin `config/personas.local.md`** (else this `personas.template.md`) →
|
||||
select the relevant subset of the global library.
|
||||
4. **None / insufficient** → **define interactively** in Step 1 (the operator
|
||||
names one or more personas and their five fields via `AskUserQuestion`); the
|
||||
resolved set is written to `articles.NN.personas`.
|
||||
|
||||
Each resolved entry carries the five fields below plus `tier`
|
||||
(`primær` | `sekundær`) and `source` (`edition-state` | `series-file` |
|
||||
`plugin-library` | `interactive`). Exactly one `primær` per artifact; «primær
|
||||
trumfer» (below) is unchanged. Personas defined interactively for one edition
|
||||
can be promoted to a reusable block by pasting them into `personas.local.md`
|
||||
(plugin-wide) or `<serie>/linkedin/personas.md` (series-wide).
|
||||
|
||||
### The click-gate is blocking (bar = primær ekte JA)
|
||||
|
||||
The persona sweep is not advisory — it returns a **blocking verdict**
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue