From 9df3de795c279029ea343b42d6acee5354b3c38a Mon Sep 17 00:00:00 2001 From: Kjell Tore Guttormsen Date: Fri, 29 May 2026 06:17:50 +0200 Subject: [PATCH] =?UTF-8?q?feat(linkedin):=20v2.4.0=20=E2=80=94=20editoria?= =?UTF-8?q?l-reviewer=20agent=20+=20Step=205.5=20craft=20gate=20in=20/link?= =?UTF-8?q?edin:newsletter?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Endring 8 from the change spec (Del 4 production, Maskinrommet). The persona resonance sweep measures reader-response (does it land?); nothing measured prose craft or narrative architecture (is it well-made?). In Del 4 every persona reported PASS, yet the editor found 8 fresh editorial points on first reading — ~6/8 craft/architecture blind spots no agent could see. v2.4.0 adds the missing editor role. New Step 5.5 (editorial-review) runs between fact-check (Step 5) and the persona sweep (Step 6): a new editorial-reviewer agent (Opus) judges two axes — prosa-handverk (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). Returns <=10 flags as direction (never copy), each BLOCK/REWORK/NICE, operator-gated via SendUserFile. Runs before the persona sweep so the personas measure resonance instead of stumbling on craft noise. Mirrors the Maskinrommet writing-contract section C2 (bidirectional mirror rule). - agents/editorial-reviewer.md (NEW, Opus, orange) + fasit fixture (editorial-reviewer-cases.md: Del 4 v5 gold standard, 8 points -> 2 axes + severities, 3 BLOCK / 5 REWORK, 6/8 blind spots) + structural lint (7 tests). - Step 5.5 wired into commands/newsletter.md; pipeline 14 -> 15 phases. - editorial-review phase + additive editorialReview state in config/edition-state.template.json; resumption: factcheck-sweep -> Step 5.5, editorial-review -> Step 6 (spec said fact-check; canonical key is factcheck-sweep). - persona-reviewer contract unchanged: editorial-reviewer is supplementary (one measures craft, one measures response). - All doc levels synced (plugin + root README/CLAUDE.md, CHANGELOG, plugin.json 2.3.0 -> 2.4.0; agents 15 -> 16). 94 tests green. Acceptance-criterion #8 (live run on Del 4 v5) delivered as fasit fixture: a live run needs a session reload (new agent not invokable until then) + read access to the Del 4 v5 draft in Maskinrommet. Co-Authored-By: Claude Opus 4.8 (1M context) --- CLAUDE.md | 2 +- README.md | 5 +- .../.claude-plugin/plugin.json | 4 +- .../linkedin-thought-leadership/CHANGELOG.md | 24 ++ plugins/linkedin-thought-leadership/CLAUDE.md | 9 +- plugins/linkedin-thought-leadership/README.md | 28 +- .../editorial-reviewer-fixture.test.mjs | 87 ++++++ .../agents/editorial-reviewer.md | 277 ++++++++++++++++++ .../fixtures/editorial-reviewer-cases.md | 157 ++++++++++ .../commands/newsletter.md | 146 ++++++++- .../config/edition-state.template.json | 3 + 11 files changed, 714 insertions(+), 28 deletions(-) create mode 100644 plugins/linkedin-thought-leadership/agents/__tests__/editorial-reviewer-fixture.test.mjs create mode 100644 plugins/linkedin-thought-leadership/agents/editorial-reviewer.md create mode 100644 plugins/linkedin-thought-leadership/agents/fixtures/editorial-reviewer-cases.md diff --git a/CLAUDE.md b/CLAUDE.md index 2bbb150..f009d5c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -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-thought-leadership/ v2.3.0 — Full-spectrum LinkedIn content engine (short-form feed + long-form newsletter). 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 adds **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, doc/orchestration-only (no new code). Commands unchanged (24); agents 15. Render pipeline self-hosted (OFL-1.1 fonts). + linkedin-thought-leadership/ v2.4.0 — Full-spectrum LinkedIn content engine (short-form feed + long-form newsletter). 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 diff --git a/README.md b/README.md index be66f0f..1b7400b 100644 --- a/README.md +++ b/README.md @@ -206,12 +206,13 @@ Key commands: `/architect`, `/architect:ros`, `/architect:security`, `/architect --- -### [LinkedIn Thought Leadership](plugins/linkedin-thought-leadership/) `v2.3.0` +### [LinkedIn Thought Leadership](plugins/linkedin-thought-leadership/) `v2.4.0` Build authentic LinkedIn authority through algorithmic understanding, strategic consistency, and AI-assisted content creation. -v2.3.0 makes **visual assets an explicit pipeline phase** in `/linkedin:newsletter`: new **Step 7.5 (visual-assets)** between annotation (Step 7) and lock (Step 8). 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**, so `render/build-linkedin.mjs` picks up `cover.png` + the edition-config credit/caption at lock without a post-lock re-render. Pipeline 13 → 14 phases; new `config/image-credit-caption.template.md` + additive `visualAssets` state; doc/orchestration-only (no new code). v2.2.0 **hardened the longform gates** with the lessons from the second production run (Seres-serien): the persona gate is **blocking with an explicit hard-fail list** (primær «mistet meg» / doesn't own the action / sjargong-mur / modell-/navne-katalog → BLOCK); fact-check is **orthogonal to narrative strength** with a **post-cutoff web-search mandate**; a **`voice-scrubber`** agent (Opus) does de-AI scrub + Norwegian-chronicle voice-drift correction; operator gates became **render+annotate** rounds; and per-edition state was **reconciled with the global STATE.md** continuity system (`edition-HANDOVER.md` removed). Commands unchanged (24); 15 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. +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`. - **Blocking persona hard-fails (v2.2)** — `persona-reviewer` + `personas.template.md` make primær «mistet meg», doesn't-own-the-action, sjargong-mur, and modell-/navne-katalog BLOCK-level rewrites, not annotations. The bar is the primær reader's *clean* JA. - **Fact-check orthogonal to polish (v2.2)** — `fact-checker` web-searches every post-cutoff claim (never confirms from memory) and runs an explicit checklist for person titles, org-varying "standards", over-credited studies, source scope, and founding/release years. diff --git a/plugins/linkedin-thought-leadership/.claude-plugin/plugin.json b/plugins/linkedin-thought-leadership/.claude-plugin/plugin.json index c501492..5231899 100644 --- a/plugins/linkedin-thought-leadership/.claude-plugin/plugin.json +++ b/plugins/linkedin-thought-leadership/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "linkedin-thought-leadership", - "version": "2.3.0", - "description": "Full-spectrum LinkedIn content engine — feed posts, carousels, video scripts, and long-form newsletter editions — with the January 2026 360Brew algorithm baked in. v2.3 adds Step 7.5 (visual assets) to /linkedin:newsletter: cover + inline figures or carousel deck, generated and operator-gated BEFORE lock (pipeline 13→14 phases). v2.2 hardened the longform gates: blocking persona hard-fails, post-cutoff fact-check mandate, a Norwegian-chronicle de-AI voice-scrubber, render+annotate operator gates, and STATE.md-reconciled edition state.", + "version": "2.4.0", + "description": "Full-spectrum LinkedIn content engine — feed posts, carousels, video scripts, and long-form newsletter editions — with the January 2026 360Brew algorithm baked in. v2.4 adds Step 5.5 (editorial review) to /linkedin:newsletter: a new editorial-reviewer agent (Opus) judges craft — prose-craft + narrative-architecture — between fact-check (Step 5) and the persona sweep (Step 6), operator-gated via SendUserFile, mirroring the Maskinrommet writing-contract §C2 (pipeline 14→15 phases, agents 15→16). v2.3 added Step 7.5 (visual assets): cover + inline figures or carousel deck, generated and operator-gated BEFORE lock. v2.2 hardened the longform gates: blocking persona hard-fails, post-cutoff fact-check mandate, a Norwegian-chronicle de-AI voice-scrubber, render+annotate operator gates, and STATE.md-reconciled edition state.", "author": { "name": "Kjell Tore Guttormsen" }, diff --git a/plugins/linkedin-thought-leadership/CHANGELOG.md b/plugins/linkedin-thought-leadership/CHANGELOG.md index 1ddb9de..8731b6e 100644 --- a/plugins/linkedin-thought-leadership/CHANGELOG.md +++ b/plugins/linkedin-thought-leadership/CHANGELOG.md @@ -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). +## [2.4.0] - 2026-05-29 + +### Summary +An **editor's craft gate** becomes an explicit pipeline phase in `/linkedin:newsletter`. The Del 4 production run (Maskinrommet, 2026-05-28) exposed a gap: the persona resonance sweep returned 15 flags across three personas and *every persona reported PASS / ready-to-publish* — yet the editor (KTG) found **eight fresh editorial points on first reading**, and only ~25 % overlapped anything the personas had touched. The other six — a missing theory anchor (SDT), a broken series-title link, a stranded small-business addressee, verbatim repetitions, em-dash over-density, an internal contradiction — were **craft and narrative-architecture blind spots no agent measured.** `persona-reviewer` measures *reader response* (does it land?); it does not measure *prose craft* or *narrative architecture* (is it well-made?). Two different roles; only one existed. A persona PASS was mis-reporting "ready for the editor's reading", costing an extra editorial round per article. v2.4.0 adds **Step 5.5 — Editorial review**, between fact-check (Step 5) and the persona sweep (Step 6), and a new **`editorial-reviewer` agent** (Opus) that mirrors the Maskinrommet writing-contract §C2. Pipeline 14 → 15 phases; 15 → 16 agents. Backward-compatible: the only state-shape change is additive (`editorialReview`), and existing editions resume by `currentPhase` (`factcheck-sweep` now resumes at Step 5.5 instead of Step 6 — an intended deterministic improvement). Doc/orchestration-only for the pipeline wiring; the new agent + its fasit fixture + structural lint test are the only new files. + +### Added +- **`agents/editorial-reviewer.md`** (new, Opus, orange) — an **editor**, not a reader. Judges two axes: **prosa-håndverk** (P1 em-dash density · P2 verbatim repetition · P3 postulated numbers without source/hedge · P4 internal contradiction · P5 versal-tic — mostly grep-able) and **narrativ-arkitektur** (A1 concrete instantiation · A2 theory-anchored hypotheses · A3 series-title symmetry · A4 equally-usable action per addressee · A5 un-overloaded conclusion — evaluative). Returns **≤10 flags** as direction (never rewritten copy — the jury judges, the writer writes), each with a quote/line-ref and a **severity: BLOCK / REWORK / NICE**. Tools `Read` + `Grep`. The checklist is the operationalized mirror of the **Maskinrommet skrivekontrakt §C2** (bidirectional mirror rule: §C2 is the source of truth). *New agent — requires a session reload before it is invokable.* +- **Step 5.5 — Editorial review** in `commands/newsletter.md`, between Step 5 (fact-check) and Step 6 (persona sweep). Runs a single foreground `editorial-reviewer` `Task` call, writes the report to `/NN-editorial-review.md`, surfaces it to the operator via **`SendUserFile`** (the Endring-5 / Step-7.5 operator-gate pattern), folds approved flags in **by tightening** (rule 6) → v(n+1), and optionally re-runs the agent on the cleaned version. **Why before the persona sweep:** the personas measure response — if the prose is locally messy the persona flags become noise; clean the craft first so Step 6 measures what it was built to measure. +- **`editorial-review` phase string** + **`articles.NN.editorialReview` schema** + **`_doc.editorialReview` note** in `config/edition-state.template.json` `_doc.phases` (14 → 15 phases). Additive; `editorialReview: null` until Step 5.5 runs. The craft companion to `factcheckLog` (truth) and `personaSweep` (response). +- **`agents/fixtures/editorial-reviewer-cases.md`** (new) — fasit fixture: the Del 4 v5 gold standard. KTG's eight editorial points mapped to the two axes + severities (3 BLOCK / 5 REWORK), with the persona-overlap column showing 6/8 were editorial-only blind spots. The calibration target for acceptance-criterion #8 (a live run needs a session reload + Maskinrommet read access; until then the fixture is the gold-standard of record). +- **`agents/__tests__/editorial-reviewer-fixture.test.mjs`** (new) — structural lint mirroring the persona-reviewer / fact-checker fixture tests: asserts both axes, all ten checks (P1–P5 + A1–A5), the three severities, the eight Del 4 cases, the §C2 tie, the direction-not-copy boundary, and the blind-spot rationale. 7 tests, green. + +### Changed +- **`/linkedin:newsletter` pipeline overview** — 14 → 15 phases; the overview table, build-status note, and reference-file list reflect Step 5.5. +- **Resumption table** in `commands/newsletter.md` — `currentPhase: "factcheck-sweep"` now resumes at **Step 5.5** (was Step 6); new `editorial-review` row resumes at Step 6. (Spec said `currentPhase: "fact-check"`; the canonical key in this plugin is `factcheck-sweep` — wired to the real key.) +- **Step 5 hand-off + ordering note** — fact-check now hands off to Step 5.5; the BEFORE-lock note names editorial review (5.5) and the persona sweep (6) as the two gates the fact-check precedes. +- **Step 6 intro** — now reads on the "editorially-cleaned, fact-checked draft"; the persona sweep judges response, not craft (that was 5.5). +- README, CLAUDE.md, root README, root CLAUDE.md, plugin.json version + descriptions. + +### Not changed (explicit non-deltas) +- **`persona-reviewer` contract** — bit-for-bit unchanged. Editorial review is *supplementary*: one agent measures craft (5.5), one measures response (6). The role boundary is sharp — `editorial-reviewer` never flags "this won't resonate", `persona-reviewer` never flags em-dash density. +- **Steps 0–5, 6 body, 7, 7.5, 8–10** — contract unchanged apart from the Step 5→5.5→6 wiring and the Step 6 intro line. +- **Renderers, hooks, scripts, command count (24)** — all unchanged. No new `.mjs` runtime code (the only new code is the fixture lint test). + ## [2.3.0] - 2026-05-28 ### Summary diff --git a/plugins/linkedin-thought-leadership/CLAUDE.md b/plugins/linkedin-thought-leadership/CLAUDE.md index 0ff05dc..3694e9c 100644 --- a/plugins/linkedin-thought-leadership/CLAUDE.md +++ b/plugins/linkedin-thought-leadership/CLAUDE.md @@ -1,6 +1,6 @@ -# LinkedIn Thought Leadership Plugin (v2.3.0) +# LinkedIn Thought Leadership Plugin (v2.4.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** makes **visual assets an explicit pipeline phase** — new **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. Pipeline 13 → 14 phases; new `config/image-credit-caption.template.md`; additive `visualAssets` state. Doc/orchestration-only — no new code. Agents unchanged (15); 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). ## Architecture @@ -46,7 +46,7 @@ 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 14-phase pipeline with **skeleton + spine-prose gates BEFORE prose (v2.1)**, 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 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: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 +63,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 (15) +## Agents (16) | Agent | Model | Color | Responsibility | |-------|-------|-------|----------------| @@ -80,6 +80,7 @@ All content commands (post, quick, react, pipeline, first-post, video, multiplat | `post-feedback-monitor` | Haiku | Lime | Post-publish 48h monitoring | | `video-scripter` | Sonnet | Violet | Video script creation with pacing | | `fact-checker` | Opus | Brown | Factual-claim verification against primary sources, post-cutoff web-search mandate (longform) | +| `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) | diff --git a/plugins/linkedin-thought-leadership/README.md b/plugins/linkedin-thought-leadership/README.md index ab2724d..875149c 100644 --- a/plugins/linkedin-thought-leadership/README.md +++ b/plugins/linkedin-thought-leadership/README.md @@ -6,20 +6,21 @@ *AI-generated: all code produced by Claude Code through dialog-driven development. [Full disclosure →](../../README.md#ai-generated-code-disclosure)* -![Version](https://img.shields.io/badge/version-2.3.0-blue) +![Version](https://img.shields.io/badge/version-2.4.0-blue) ![Platform](https://img.shields.io/badge/platform-Claude_Code_Plugin-purple) ![Commands](https://img.shields.io/badge/commands-24-green) -![Agents](https://img.shields.io/badge/agents-15-orange) +![Agents](https://img.shields.io/badge/agents-16-orange) ![Hooks](https://img.shields.io/badge/hooks-9-red) ![Reference Docs](https://img.shields.io/badge/reference_docs-24-teal) ![License](https://img.shields.io/badge/license-MIT-lightgrey) -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 — new **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 (pipeline 13 → 14 phases). 24 slash commands, 15 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). 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. --- ## Table of Contents +- [What's New in v2.4.0](#whats-new-in-v240) - [What's New in v2.3.0](#whats-new-in-v230) - [What's New in v2.2.0](#whats-new-in-v220) - [What's New in v2.1.0](#whats-new-in-v210) @@ -42,6 +43,21 @@ A comprehensive Claude Code plugin that turns LinkedIn from a chore into a full- --- +## What's New in v2.4.0 + +**An editor's craft gate becomes an explicit pipeline phase.** The Del 4 production run exposed a gap the existing gates could not see: the persona resonance sweep returned 15 flags across three personas and *every persona reported PASS / ready-to-publish* — yet the editor (KTG) found **eight fresh editorial points on first reading**, and only ~25 % overlapped anything the personas had touched. The other six were **craft and narrative-architecture blind spots** no agent measured. `persona-reviewer` measures *reader response* (does it land?); nothing measured *prose craft* or *narrative architecture* (is it well-made?). v2.4.0 adds the missing role. + +- **New `editorial-reviewer` agent** (Opus, orange) — an **editor**, not a reader. Two axes: **prosa-håndverk** (em-dash density, verbatim repetition, postulated numbers without source/hedge, internal contradictions, versal-tic — mostly grep-able) and **narrativ-arkitektur** (concrete instantiation, theory-anchored hypotheses, series-title symmetry, equally-usable action per addressee, an un-overloaded conclusion). Returns **≤10 flags** as *direction* — never rewritten copy (the jury judges, the writer writes) — each with a quote/line-ref and a **severity: BLOCK / REWORK / NICE**. The checklist is the operationalized mirror of the **Maskinrommet writing-contract §C2**. *(New agent — requires a session reload before it is invokable.)* +- **New Step 5.5 — Editorial review** (`commands/newsletter.md`), between fact-check (Step 5) and the persona sweep (Step 6). Runs a single foreground `editorial-reviewer` call, surfaces the report to the operator via **`SendUserFile`** (the same operator-gate pattern as Steps 2.5/3a/7.5), folds approved flags in *by tightening* → v(n+1), and optionally re-runs on the cleaned version. +- **Why before the persona sweep, not after** — the personas measure *response*. If the prose is locally messy (an em-dash thicket, a postulated number, a repeated phrase) the persona flags become *noise* — the reader stumbles on the craft defect instead of judging mobilization. Clean the craft first, and Step 6 measures what it was built to measure. +- **Supplementary, not a replacement** — `persona-reviewer` is unchanged. One agent measures craft (5.5), one measures response (6); the role boundary is sharp (`editorial-reviewer` never flags "this won't resonate"; `persona-reviewer` never flags em-dash density). +- **`editorial-review` phase + additive `editorialReview` state** in `config/edition-state.template.json`. Pipeline grows 14 → 15 phases; resumption stays deterministic (`factcheck-sweep` now resumes at Step 5.5). +- **Fasit fixture + structural lint** — `agents/fixtures/editorial-reviewer-cases.md` encodes the Del 4 v5 gold standard (KTG's eight points mapped to the two axes + severities; 6/8 editorial-only blind spots), with `agents/__tests__/editorial-reviewer-fixture.test.mjs` asserting its shape (7 tests, green). The calibration target for a live run (which needs a session reload + the Del 4 v5 draft). + +Doc/orchestration-only for the wiring — the new agent, its fasit fixture, and the lint test are the only new files; **no new runtime code**. 16 agents (was 15). Commands (24) unchanged. Backward-compatible: the only state-shape change is additive. + +--- + ## What's New in v2.3.0 **Visual assets become an explicit pipeline phase.** Until now, images (cover + inline figures) were produced ad-hoc *outside* the `/linkedin:newsletter` pipeline and referenced by hand — even though a cover is mandatory and has to coordinate with the text. v2.3.0 adds **Step 7.5 — Visual assets** between annotation (Step 7) and lock (Step 8), so visuals are resolved *before* the edition locks. @@ -232,7 +248,7 @@ All 24 commands use colon notation: `/linkedin:post`, `/linkedin:quick`, etc. ## Agent Architecture -The plugin delegates specialized work to 15 purpose-built agents. Each agent has its own model assignment, color identity, and focused responsibility. +The plugin delegates specialized work to 16 purpose-built agents. Each agent has its own model assignment, color identity, and focused responsibility. | Agent | Model | Color | Primary Responsibility | |-------|-------|-------|----------------------| @@ -249,6 +265,7 @@ The plugin delegates specialized work to 15 purpose-built agents. Each agent has | `post-feedback-monitor` | Haiku | Lime | Post-publish 48h monitoring and real-time interventions | | `video-scripter` | Sonnet | Violet | Video script creation with pacing and visual cues | | `fact-checker` | Opus | Brown | Factual-claim verification against primary/credible sources, post-cutoff web-search mandate (longform) | +| `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) | @@ -268,7 +285,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) → `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) → `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-thought-leadership:`, never the bare name. And a @@ -578,6 +595,7 @@ Scheduled posts are tracked in `assets/drafts/queue.json`: | Version | Date | Highlights | |---------|------|-----------| +| **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-kandidat.png` / `cover-raw.png` / `fig.png`). Pipeline 13 → 14 phases. Doc/orchestration-only (no new code); commands (24) + agents (15) unchanged. | | **2.2.0** | 2026-05-28 | Longform gates hardened (2nd production run). Persona gate blocking with explicit hard-fail list (primær mistet meg / doesn't own action / sjargong-mur / modell-navne-katalog → BLOCK; «JA med forbehold» = NEI). Fact-check post-cutoff web-search mandate + high-frequency-error checklist. New `voice-scrubber` agent (Opus): de-AI scrub + Norwegian-chronicle voice-drift, gold standard = approved Norwegian editions (NOT the English post corpus). Render+annotate operator gates (Steps 2.5/3a). Edition state reconciled with STATE.md (ONE-system); `edition-HANDOVER.template.md` deleted. 14 → 15 agents; commands unchanged (24). | | **2.1.0** | 2026-05-28 | Skeleton gate BEFORE prose in `/linkedin:newsletter`. New Step 2.5 (skeleton + section pitch, operator-gate + persona-skjelett-sweep) and Step 3a (spine prose, operator-gate) split the old Step 3 into pre-prose stages with their own gates. New `persona-reviewer` mode (`skjelett`). Pipeline grows 11 → 13 phases; commands and agents unchanged in count (24, 14). Encodes the Maskinrommet writing-contract §A discipline (premiss / problem / anbefaling / gevinst / vei videre) into the pipeline. Empirically motivated by the Seres-serien Del 3 + Del 4 spine-rework cost. | diff --git a/plugins/linkedin-thought-leadership/agents/__tests__/editorial-reviewer-fixture.test.mjs b/plugins/linkedin-thought-leadership/agents/__tests__/editorial-reviewer-fixture.test.mjs new file mode 100644 index 0000000..ba39674 --- /dev/null +++ b/plugins/linkedin-thought-leadership/agents/__tests__/editorial-reviewer-fixture.test.mjs @@ -0,0 +1,87 @@ +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 editorial-reviewer fasit fixture. +// Mirrors the structure-only discipline of persona-reviewer-fixture.test.mjs and +// fact-checker-fixture.test.mjs: this test asserts the SHAPE of the fixture — +// the two judging axes, all ten checks (P1–P5 + A1–A5), the three severities, +// and the eight Del 4 cases that form the gold standard. 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/editorial-reviewer-cases.md', import.meta.url) +); + +const fixture = readFileSync(FIXTURE_PATH, 'utf8'); + +// The ten checks: five prose-craft (P1–P5) + five narrative-architecture (A1–A5). +const PROSE_CHECKS = ['P1', 'P2', 'P3', 'P4', 'P5']; +const ARCH_CHECKS = ['A1', 'A2', 'A3', 'A4', 'A5']; + +// The two axis names (Norwegian, as the agent and the writing contract use them). +const AXES = ['prosa-håndverk', 'narrativ-arkitektur']; + +// The three-rung severity scale. +const SEVERITIES = ['BLOCK', 'REWORK', 'NICE']; + +describe('editorial-reviewer fixture structure', () => { + test('names both judging axes', () => { + for (const axis of AXES) { + assert.ok( + new RegExp(axis, 'i').test(fixture), + `fixture must name the axis "${axis}"` + ); + } + }); + + test('documents all ten checks (P1–P5 + A1–A5)', () => { + for (const check of [...PROSE_CHECKS, ...ARCH_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 eight Del 4 cases', () => { + const cases = fixture.match(/^###\s+Case\s+\d+\b/gim) || []; + assert.equal( + cases.length, + 8, + `fixture must document exactly 8 Del 4 cases (found ${cases.length})` + ); + }); + + test('ties the checklist to the Maskinrommet §C2 truth source', () => { + assert.ok( + /§C2|C2/.test(fixture), + 'fixture must reference the §C2 writing-contract truth source' + ); + }); + + 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('records the persona-blindspot rationale (≈6/8 editorial-only)', () => { + assert.ok( + /blindsone/i.test(fixture) && /6\/8/.test(fixture), + 'fixture must record why the gate exists (blind spots, ~6/8 editorial-only)' + ); + }); +}); diff --git a/plugins/linkedin-thought-leadership/agents/editorial-reviewer.md b/plugins/linkedin-thought-leadership/agents/editorial-reviewer.md new file mode 100644 index 0000000..d6284c7 --- /dev/null +++ b/plugins/linkedin-thought-leadership/agents/editorial-reviewer.md @@ -0,0 +1,277 @@ +--- +name: editorial-reviewer +description: | + Read a near-final long-form draft as an EDITOR and judge its craft, not its + reader-response. Two axes: prose craft (em-dash density, verbatim repetition, + postulated numbers, internal contradictions, uppercase tics) and narrative + architecture (concrete instantiation, theory-anchored hypotheses, series-title + symmetry, equally-usable action per addressee, an un-overloaded conclusion). + Returns ≤10 flags as direction — never rewritten copy — each tagged + BLOCK / REWORK / NICE. Mirrors the Maskinrommet writing-contract §C2. + + Use when the user says: + - "editorial review", "redaktør-pass", "editor pass on this draft" + - "check the prose craft", "is the prose clean?", "craft check" + - "does the architecture hold?", "are the hypotheses anchored?" + - "did I instantiate the abstract figures?", "is the conclusion overloaded?" + - "before the persona sweep, run the editor", "pre-persona craft gate" + + Triggers on: "editorial review", "redaktør-pass", "editor pass", "craft check", + "prose craft", "narrative architecture", "editorial-reviewer", "§C2", + "pre-persona gate", "C2-sjekk". +model: opus +color: orange +tools: ["Read", "Grep"] +--- + +# Editorial Reviewer Agent + +You are an **editor**. You read a near-final long-form draft and judge whether the +**prose is clean** and the **narrative architecture holds** — the craft layer a +reader never names but always feels. You are the pass a human editor (KTG) makes +on first reading, operationalized as an automated pre-persona gate. + +You run at **Step 5.5** of the `/linkedin:newsletter` pipeline — *after* the +fact-check sweep (Step 5) and *before* the persona resonance sweep (Step 6). + +## Your Mission + +Catch the editorial defects that survive every other gate. In the Del 4 +production (Maskinrommet, 2026-05-28) the persona resonance sweep returned 15 +flags across three personas and every persona reported PASS / ready-to-publish. +The editor then found **8 fresh editorial points on first reading** — and only +~25 % of them were anything the personas had touched. The other six were +*blind spots*: a missing theory anchor, a broken series-title link, a missing +small-business rule of thumb, verbatim repetitions, em-dash over-density, and an +internal contradiction. None of these are reader-response failures; they are +**craft and architecture failures**, and no agent in the pipeline measured them. +You are that agent. + +Core principle: **the jury judges; the editor directs — but the writer writes.** +Like `persona-reviewer`, you return **direction, never rewritten copy.** "Figure +in §3 is abstract — instantiate it with one concrete case" is your job. Supplying +the new sentence is not. If you ever hand back edited prose, you have failed the +role. + +## What you are NOT (boundary with the other gates) + +You are one of four longform gate agents, and the boundaries are sharp: + +| Agent | Measures | Question | +|-------|----------|----------| +| `fact-checker` (Step 5) | factual correctness | *Is it true?* | +| **`editorial-reviewer` (Step 5.5 — this agent)** | **prose craft + narrative architecture** | ***Is it well-made?*** | +| `persona-reviewer` (Step 6) | reader response | *Does it land for this reader?* | +| `voice-scrubber` (Step 4) | de-AI + voice drift | *Does it sound like the author?* | + +- You do **not** judge whether a claim is true (that is `fact-checker`). +- You do **not** judge whether the text lands for a reader, mobilizes them, or + holds their attention (that is `persona-reviewer` — it measures *response*; you + measure *craft*). A persona stumbling on an em-dash thicket or a postulated + number is the persona measuring noise instead of resonance — your gate runs + first precisely to remove that noise so the persona sweep measures what it was + built to measure. +- You do **not** strip AI-tells or correct voice drift (that is `voice-scrubber`). + Where you overlap (a reflex rule-of-three is both an AI-tell and a craft nit), + defer the AI-tell framing to `voice-scrubber` and flag only the *craft* face of + it (e.g. the verbatim repetition, not "this sounds like a machine"). + +Two different roles, both necessary, neither sufficient alone. A persona PASS is +**not** "ready for the editor" — it is "lands for the reader." This gate exists +because those are not the same thing. + +## Truth source — the Maskinrommet writing-contract §C2 + +The checklist below is the **operationalized mirror of Maskinrommet +skrivekontrakt §C2.** §C2 documents the rule-set at the article-production level +(what a human editor checks); this agent operationalizes it as the automated +pre-persona gate inside the plugin. + +> **Mirror rule (bidirectional, cardinal).** §C2 is the source of truth. A change +> on either side MUST be mirrored to the other: if §C2 gains, drops, or reworks +> a check, this agent's checklist follows, and vice-versa. The two must never +> drift. This is the same relationship `references/longform-quality-rules.md` +> rule 8 has with §A (skeleton-before-prose) — the pipeline satisfies the +> writing contract *by construction*, and §C2 is the craft half of that contract. + +If you are run with access to the live §C2 text, read it and reconcile any drift +before judging; if not, the two axes below are the faithful transcription of §C2 +as of the agent's authorship (v2.4.0) and you judge against them. + +## The Two Axes + +You judge on exactly **two axes**. Axis 1 is mechanical — most of it can be +`grep`'d. Axis 2 is evaluative — it requires reading the draft as an editor. + +### Axis 1 — Prosa-håndverk (prose craft — mechanical, grep-able) + +| # | Check | What flags it | How to find it | +|---|-------|---------------|----------------| +| P1 | **Tankestrek-tetthet** (em-dash density) | More than ~1 em-dash per 50 words, or a cluster of em-dashes inside a single paragraph. The em-dash is a tool, not a tic. | Count `—` occurrences; divide by word count; flag paragraphs above the local rate. | +| P2 | **Ordrette gjentakelser** (verbatim repetition) | The same distinctive phrase appears **>2 times**, or a sentence-opening pattern repeats mechanically. | `grep` for repeated 3–6-word phrases across the draft. | +| P3 | **Postulerte tall uten kilde eller hedge** (postulated numbers) | A specific figure («40 %», «tre av fire», «dobbelt så») stated as fact with neither a source marker nor a hedge. Fact-check (Step 5) verifies numbers that *have* a provenance; you flag numbers that arrive with *none* — postulated out of thin air. | Scan for digits / quantity words not carrying an inline source comment or a hedge ("anslagsvis", "trolig"). | +| P4 | **Indre spenninger / selvmotsigelser** (internal contradictions) | Two passages that cannot both be true, or a claim the conclusion silently reverses. | Read for assertion vs. later qualification; cross-check the premise against the close. | +| P5 | **Versal-tic midt i prosa** (uppercase tic mid-sentence) | ALL-CAPS or Title-Cased emphasis dropped into running prose for stress («det er IKKE slik»). One is a choice; a pattern is a tic. | `grep` for runs of ≥2 consecutive uppercase letters mid-line; flag the pattern, not the acronym. | + +P1, P2, P5 are countable — report the count. P3, P4 need a read but are still +crisp yes/no findings. + +### Axis 2 — Narrativ-arkitektur (narrative architecture — evaluative, needs a read) + +| # | Check | What flags it | +|---|-------|---------------| +| A1 | **Konkret instansiering** (abstract figures instantiated) | An abstract figure, role, or scenario ("en leder", "en virksomhet") that never lands on **one concrete case** the reader can picture. Choose one verifiable (preferably Norwegian) case over an exhaustive list — abstraction that is never instantiated reads as filler. | +| A2 | **Teori-anker for hypoteser** (theory-anchored hypotheses) | A causal or psychological hypothesis ("tillit øker når…") asserted with neither a **theory anchor** (a named model — e.g. SDT for motivation/trust) nor an **explicit hedge** ("hypotesen er…"). A hypothesis dressed as a finding is an architecture defect. | +| A3 | **Serietittel-symmetri** (series-title symmetry) | The article does not bind back to the **series premise / its own title** — the part floats free of the whole. (N/A for a standalone edition; record N/A and move on.) | +| A4 | **Like-brukbar handling per adressat** (equally-usable action per addressee) | The text addresses more than one reader (e.g. a line manager *and* a small-business owner) but the **actionable takeaway only serves one** — the other addressee leaves with nothing they can do (e.g. a missing small-business rule of thumb). | +| A5 | **Konklusjon ikke overlastet** (un-overloaded conclusion) | The conclusion tries to land **too many blows at once** — it carries several competing takeaways instead of ONE clear takeaway + ONE action (cf. `longform-quality-rules.md` rule 1). Overload buries the lede the reader should leave with. | + +A3, A4, A5 are exactly the blind spots the Del 4 persona sweep missed — they are +architecture, not response, and they are the reason this gate exists. + +## Severity scale — BLOCK / REWORK / NICE + +Every flag carries exactly one severity. Use them consistently: + +- **BLOCK** — a defect that **misrepresents the piece or loses the reader's + takeaway**: an internal contradiction (P4), a hypothesis postulated as + established fact with no anchor and no hedge (A2), a conclusion so overloaded + the one takeaway is lost (A5), an addressee left with no usable action (A4). + Your strong recommendation: fix before Step 6. (The pipeline gate is the + operator's — see below — but BLOCK means *you* judge it must not pass as-is.) +- **REWORK** — a real craft or architecture weakness that should be fixed but is + not load-bearing-fatal: verbatim repetition (P2), em-dash over-density (P1), an + abstract figure never instantiated (A1), a broken series-title link (A3), a + postulated number that should be sourced or hedged (P3). +- **NICE** — minor polish, fold in if cheap: a single uppercase tic (P5), one + slightly-high em-dash cluster, one mild repetition. Not worth a revision round + on its own. + +Sort flags **BLOCK before REWORK before NICE.** If there are more than ten +findings, surface the ten highest-severity and say how many you suppressed — do +not silently truncate. + +## Review Process + +### Step 1 — Read the whole draft as an editor + +Read top to bottom, once, the way an editor reads a near-final piece: not for +truth (that was Step 5), not as a target reader (that is Step 6), but for **how +it is made**. Note the premise the ingress sets and the takeaway the conclusion +lands — you will need both for P4 and A5. + +### Step 2 — Run Axis 1 (mechanical) — grep first, then read + +For P1, P2, P5, use `Grep` to get counts, then read the hits in context (a count +alone over- or under-flags). For P3, P4, scan with a read. Record each finding +with its **exact quote or line reference** and a count where the check is +countable. + +### Step 3 — Run Axis 2 (evaluative) — read for architecture + +For A1–A5, judge the draft's *structure*: does every abstract figure land on a +case, is every hypothesis anchored or hedged, does the part bind to the series, +does each addressee get a usable action, does the conclusion carry exactly one +takeaway. Record each finding with the quote/section 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]`). After fold-in, the editor (the command session) +produces v(n+1) and **may re-run you** on the cleaned version before Step 6. + +## Output Format + +``` +## Editorial Review — Del NN «» + +**Pass:** Step 5.5 (pre-persona craft gate) · **Axes:** prosa-håndverk + narrativ-arkitektur +**Read:** <N> words · em-dash rate <X>/1000 words · checks run: 10 (P1–P5, A1–A5) + +### Flags (≤10 — direction only, NO rewritten copy) + +| # | Kategori | Severity | Sitat / linje-ref | Foreslått retning | +|---|----------|----------|-------------------|-------------------| +| 1 | P4 (prosa) | BLOCK | "<quote>" (§3) | <direction — where it contradicts + which way to resolve> | +| 2 | A2 (arkitektur) | BLOCK | "<quote>" (§2) | <direction — anchor in a named model OR hedge as hypothesis> | +| 3 | P1 (prosa) | REWORK | §4 (6 em-dashes / 180 words) | <direction — thin the em-dashes to ~1/50 words> | +| … | … | … | … | … | + +### Suppressed +<N> further findings below the top ten (severities: …) (or: none) + +### Per-axis summary +- **Prosa-håndverk:** P1 <flag/clean> · P2 <…> · P3 <…> · P4 <…> · P5 <…> +- **Narrativ-arkitektur:** A1 <…> · A2 <…> · A3 <…/N·A> · A4 <…> · A5 <…> + +### Recommendation (operator gates) +<N> BLOCK / <N> REWORK / <N> NICE. Strong recommendation: fix the BLOCK flags +before the Step 6 persona sweep. 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 `persona-reviewer`). +2. **Craft, not response.** You measure whether the text is *well-made*, not + whether it *lands*. Never reach for "this won't resonate" — that is the + persona sweep's verdict, and it runs after you. +3. **Two axes, ten checks, no more.** P1–P5 (prose craft) + A1–A5 (narrative + architecture). Do not invent an eleventh check or fold in a fact-check / + persona / voice concern — route those to the agent that owns them. +4. **Every flag carries a quote or a line reference.** "Vague" is not a flag. + "§3, 'en leder bør…' — abstract figure, never instantiated" is. +5. **Severity is consistent and worst-first.** BLOCK = misrepresents or loses the + takeaway; REWORK = real weakness; NICE = cheap polish. Sort BLOCK→REWORK→NICE. +6. **Cap at ten; never truncate silently.** If you suppressed findings, say how + many and of what severity (`no silent caps`). +7. **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]`. +8. **§C2 is the source of truth.** If §C2 and this checklist disagree, §C2 wins + and the checklist must be reconciled. Flag the drift; do not judge against a + stale checklist. + +## Anti-Patterns + +- Rewrite the draft or hand back replacement copy (that is the writer's pen) +- Score factual accuracy (wrong agent — `fact-checker`), reader resonance (wrong + agent — `persona-reviewer`), or AI-tells / voice drift (wrong agent — + `voice-scrubber`) +- Flag "this won't land" / "the reader will disengage" — that is response, not + craft; it belongs to Step 6 +- Give a flag with no quote and no line reference +- Exceed ten flags, or silently drop findings past the cap +- Invent an eleventh check or an axis beyond the two +- Treat a postulated number (P3) as a fact-check finding — you flag the *absence + of a source or hedge*; `fact-checker` verifies numbers that have a provenance +- Soften a BLOCK (P4 contradiction, A2 unanchored hypothesis, A4 stranded + addressee, A5 overloaded conclusion) to REWORK to be agreeable +- Judge against a checklist you know has drifted from §C2 without flagging the + drift + +## References + +Read these for the contract and the pipeline position: +- **Maskinrommet skrivekontrakt §C2** — the source of truth this checklist + mirrors (craft + architecture half of the writing contract; §A is the + skeleton-before-prose half codified in `longform-quality-rules.md` rule 8). +- `${CLAUDE_PLUGIN_ROOT}/references/longform-quality-rules.md` — the broad Step 4 + quality pass; this agent is the *finer* craft+architecture gate that runs after + it (rule 1 ≈ A5 overload; rule 3 ≈ some prose nits — defer the AI-tell face to + `voice-scrubber`). +- `${CLAUDE_PLUGIN_ROOT}/agents/persona-reviewer.md` — the reader jury (Step 6), + the gate that runs *after* this one; the role boundary is craft vs. response. +- `${CLAUDE_PLUGIN_ROOT}/agents/fact-checker.md` — the Step 5 sweep (truth); + this agent runs *after* it on the fact-checked draft. +- `${CLAUDE_PLUGIN_ROOT}/agents/fixtures/editorial-reviewer-cases.md` — fasit + fixture: the Del 4 v5 gold-standard (KTG's eight editorial points mapped to the + two axes + severities). diff --git a/plugins/linkedin-thought-leadership/agents/fixtures/editorial-reviewer-cases.md b/plugins/linkedin-thought-leadership/agents/fixtures/editorial-reviewer-cases.md new file mode 100644 index 0000000..f846a94 --- /dev/null +++ b/plugins/linkedin-thought-leadership/agents/fixtures/editorial-reviewer-cases.md @@ -0,0 +1,157 @@ +# Editorial-Reviewer Fasit Fixture + +The Del 4 production round (Maskinrommet, 2026-05-28) as the gold standard for the +`editorial-reviewer` agent. The persona resonance sweep returned 15 flags across +three personas (Linjeleder C primær + KI-seksjon B sekundær + IT-direktør A +sekundær) and **every persona reported PASS / ready-to-publish**. KTG then found +**eight editorial points on first reading** — and only ~25 % of them overlapped +anything the personas had touched. The other six were craft/architecture blind +spots. Those eight points are the fasit below: a correct `editorial-reviewer` run +on Del 4 v5 should surface **comparable flags**, mapped to the two axes with +consistent severities. + +This file is a *fasit*, not a test harness. The structural lint lives in +`agents/__tests__/editorial-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.** A persona PASS measures *reader response*, not *craft*. +> Six of these eight points were invisible to the persona sweep because they are +> architecture and prose-craft defects, not resonance defects. The numbers tell +> the story: persona overlap ≈ 2/8; editorial-only ≈ 6/8. + +--- + +## The two axes (the agent judges on exactly these) + +Both axes are the operationalized mirror of the **Maskinrommet skrivekontrakt +§C2** — §C2 is the source of truth; this fixture and the agent's checklist follow +it. (§C2 is the craft half of the writing contract; §A — skeleton-before-prose — +is codified in `references/longform-quality-rules.md` rule 8.) + + +- **Prosa-håndverk** (mechanical, grep-able): P1 tankestrek-tetthet · P2 ordrette + gjentakelser · P3 postulerte tall uten kilde/hedge · P4 indre selvmotsigelse · + P5 versal-tic. +- **Narrativ-arkitektur** (evaluative): A1 konkret instansiering · A2 teori-anker + for hypoteser · A3 serietittel-symmetri · A4 like-brukbar handling per adressat · + A5 konklusjon ikke overlastet. + +## Severity (every flag carries exactly one) + +- **BLOCK** — misrepresents the piece or loses the takeaway. +- **REWORK** — a real craft/architecture weakness, not load-bearing-fatal. +- **NICE** — cheap polish, fold in if convenient. + +--- + +## The eight Del 4 editorial points (fasit) + +Each case states the point KTG raised, the axis it belongs to, the expected +severity, and the direction a correct agent run returns. The persona-overlap +column records whether the persona sweep had already (partially) touched it — +the whole reason the gate is needed is the rows marked **blindsone**. + +### Case 1 — manglende konkret eksempel (abstract figure never instantiated) + +- **Axis:** A1 (arkitektur) · **Severity:** REWORK +- **Persona overlap:** delvis (KI-seksjon B brushed it) — *not* a pure blind spot. +- **Fasit / direction:** An abstract figure carries the section but never lands on + one concrete case the reader can picture. Direction: instantiate with a single + verifiable (preferably Norwegian) case — do not list several. The agent flags + the *absence of instantiation*; it does not supply the case. + +### Case 2 — postulert tall uten kilde eller hedge (postulated number) + +- **Axis:** P3 (prosa) · **Severity:** REWORK +- **Persona overlap:** delvis (IT-direktør A brushed it). +- **Fasit / direction:** A specific figure is stated as fact with neither an inline + source marker nor a hedge. This is distinct from a fact-check finding — Step 5 + verifies numbers that *have* a provenance; here the provenance is simply + **absent**. Direction: source it or hedge it ("anslagsvis"); else cut. + +### Case 3 — manglende SDT-anker for tillit-effekt (unanchored hypothesis) — BLINDSONE + +- **Axis:** A2 (arkitektur) · **Severity:** BLOCK +- **Persona overlap:** none — pure blind spot. +- **Fasit / direction:** A psychological hypothesis about a trust effect is asserted + as if established, with no named theory anchor (e.g. Self-Determination Theory) + and no explicit hedge. A hypothesis dressed as a finding is an architecture + defect. Direction: anchor in a named model OR mark it explicitly as hypothesis. + +### Case 4 — brutt serietittel-kobling (broken series-title symmetry) — BLINDSONE + +- **Axis:** A3 (arkitektur) · **Severity:** REWORK +- **Persona overlap:** none — pure blind spot. +- **Fasit / direction:** The part does not bind back to the series premise / its own + title — it floats free of the whole. Direction: tie the part's argument back to + the series title so the reader feels the part-of-a-whole. (N/A only for a + standalone edition; Del 4 is part of a series, so it applies.) + +### Case 5 — manglende småbedrifts-tommelfingerregel (stranded addressee) — BLINDSONE + +- **Axis:** A4 (arkitektur) · **Severity:** BLOCK +- **Persona overlap:** none — pure blind spot. +- **Fasit / direction:** The text addresses more than one reader but the actionable + takeaway only serves one; the small-business reader leaves with nothing they can + do. Direction: add a small-business rule of thumb so each addressee gets an + equally-usable action. (Stranding an addressee = BLOCK: that reader has no + takeaway at all.) + +### Case 6 — ordrette gjentakelser (verbatim repetition) — BLINDSONE + +- **Axis:** P2 (prosa) · **Severity:** REWORK +- **Persona overlap:** none — pure blind spot. +- **Fasit / direction:** A distinctive phrase recurs more than twice. Direction: + vary or cut the repeats; keep at most the one load-bearing use. `grep`-findable. + +### Case 7 — tankestrek-tetthet (em-dash over-density) — BLINDSONE + +- **Axis:** P1 (prosa) · **Severity:** REWORK +- **Persona overlap:** none — pure blind spot. +- **Fasit / direction:** Em-dashes run above ~1 per 50 words (clusters within + paragraphs). Direction: thin them to the local target; the em-dash is a tool, + not a tic. Report the count. `grep`-findable. + +### Case 8 — indre selvmotsigelse (internal contradiction) — BLINDSONE + +- **Axis:** P4 (prosa) · **Severity:** BLOCK +- **Persona overlap:** none — pure blind spot. +- **Fasit / direction:** Two passages cannot both be true (an assertion the + conclusion silently reverses). Direction: name the contradiction and resolve one + side — a contradiction misrepresents the piece, so BLOCK. + +--- + +## Expected aggregate (what a correct run looks like) + +- **Total flags:** 8 (well within the ≤10 cap — no suppression needed). +- **By axis:** prosa-håndverk = 4 (P1, P2, P3, P4) · narrativ-arkitektur = 4 (A1, + A2, A3, A4). A5 (overloaded conclusion) and P5 (versal-tic) did **not** flag on + Del 4 v5 — record them clean. +- **By severity:** BLOCK = 3 (A2, A4, P4) · REWORK = 5 (A1, P3, A3, P2, P1) · + NICE = 0. +- **Persona overlap:** 2/8 (Cases 1 + 2, both delvis) · editorial-only blind + spots: 6/8 (Cases 3–8). This 6/8 is the quantified case for the gate. + +A run that reproduces ~these eight directions, on ~these axes, with ~these +severities, is **comparable** to KTG's actual editorial round — the bar +acceptance-criterion #8 sets. 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 `persona-reviewer-cases.md` and `fact-checker-cases.md` are fasits +for their agents. + +> **Live-run note.** A live run on Del 4 v5 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 Del 4 v5 draft in the +> Maskinrommet series folder. Until both hold, this fixture is the gold-standard +> of record. diff --git a/plugins/linkedin-thought-leadership/commands/newsletter.md b/plugins/linkedin-thought-leadership/commands/newsletter.md index d44352d..198dc10 100644 --- a/plugins/linkedin-thought-leadership/commands/newsletter.md +++ b/plugins/linkedin-thought-leadership/commands/newsletter.md @@ -71,12 +71,13 @@ 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 (14 phases) +## Pipeline overview (15 phases) The phase order is fixed. Two gates run **BEFORE prose** (skeleton + spine -prose), and the persona resonance sweep runs **BEFORE lock** — these are the -single most important corrections from the Seres process (plan §0.4, principle -5; v2.1 brief §1 on spine-error cost). +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). | Step | Phase | What | Tools | |------|-------|------|-------| @@ -88,6 +89,7 @@ single most important corrections from the Seres process (plan §0.4, principle | 3b | **Full prose expansion** | expand each section with argument, examples, anchors from research; may span sessions | `content-repurposer` + `Task` | | 4 | **Consistency + quality** | threads, premise→conclusion arc, leader-takeaway, AI-slop removal, de-AI/voice scrub, formatting dose | inline + `references/longform-quality-rules.md` + **`voice-scrubber`** | | 5 | **Fact-check sweep** | risk-sorted (🔴/🟡/🟢), guilty-until-disproven, verification log | **`fact-checker` (parallel)** | +| 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) | | 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` | @@ -95,11 +97,12 @@ single most important corrections from the Seres process (plan §0.4, principle | 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 14 phases (Steps 0–2.5, 3a, 3b, 4–7, 7.5, 8–10) are -> implemented below. This command takes an edition end-to-end: load → +> **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 + > 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 @@ -182,7 +185,8 @@ Look up `edition-state.json` → `articles.<currentArticle>` (and the top-level | `spine-prose` | Step 3b — Full prose expansion | | `draft` | Step 4 — Consistency + quality *(see draft-cursor note)* | | `consistency-quality` | Step 5 — Fact-check sweep | -| `factcheck-sweep` | Step 6 — Persona sweep (pre-lock) | +| `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 | | `annotation` | Step 7.5 — Visual assets *(cover/figures or carousel deck, BEFORE lock)* | | `visual-assets` | Step 8 — LOCK → delivery | @@ -720,9 +724,10 @@ was in fact the prime contractor — nearly a counter-example). Never trust a cl because it "feels" right or because it sits in your own research notes. > **This sweep runs BEFORE lock.** No edition is locked (Step 8) with an -> unresolved 🔴 claim. Fact-check precedes the persona sweep (Step 6), which in -> turn precedes lock — fixing facts can move text, and the text must settle -> before the reader jury judges resonance. +> unresolved 🔴 claim. Fact-check precedes the editorial review (Step 5.5) and the +> persona sweep (Step 6), which in turn precede lock — fixing facts can move text, +> and the text must settle before the editor judges craft and the reader jury +> judges resonance. **Procedure:** @@ -781,14 +786,126 @@ Fact-check sweep complete. - 🟢 Verified: <N> (sources logged to edition-state.json factcheckLog) - Freshness flags (re-verify on publish day): <N or none> Gate: [PASS — zero unresolved 🔴] (else REWORK/BLOCK with the open claims) +Next: Step 5.5 — Editorial review (craft gate, BEFORE the persona sweep). +``` + +## Step 5.5: Editorial review — craft gate, BEFORE the persona sweep + +The fact-checked draft now faces the **editor**: a single `editorial-reviewer` +pass that judges **craft**, not reader-response. It asks *is this well-made?* — +clean prose and sound narrative architecture — where Step 6 asks *does this land +for this reader?* Two different roles; both necessary, neither sufficient alone. + +> **Why this step exists (Del 4 diagnosis, v2.4).** In the Del 4 production the +> persona resonance sweep returned 15 flags across three personas and **every +> persona reported PASS / ready-to-publish**. The editor then found **eight fresh +> editorial points on first reading**, and only ~25 % overlapped anything the +> personas had touched. The other six — a missing theory anchor, a broken +> series-title link, a stranded small-business addressee, verbatim repetitions, +> em-dash over-density, an internal contradiction — were **craft and architecture +> blind spots** no agent measured. A persona PASS was mis-reporting "ready for the +> editor's reading"; it only ever meant "lands for the reader." That gap cost an +> extra editorial round per article. Step 5.5 closes it. + +> **Why BEFORE the persona sweep, not after (enforced).** The personas measure +> *response*. If the prose is locally messy — em-dash thickets, postulated +> numbers, a repeated phrase — the persona flags become **noise**: the reader +> stumbles on the craft defect instead of judging mobilization. Clean the craft +> first (here), and the Step 6 sweep measures exactly what it was built to +> measure. So editorial review runs after fact-check (Step 5) and before the +> persona sweep (Step 6). `[GATE]` + +**Relationship to `persona-reviewer` (unchanged).** This step does **not** alter +the persona sweep. `editorial-reviewer` is *supplementary*: one agent measures +craft (this step), one measures reader-response (Step 6). The role boundary is +sharp — `editorial-reviewer` never flags "this won't resonate" (that is Step 6) +and `persona-reviewer` never flags em-dash density (that is this step). + +> **Truth source — §C2.** The agent's two-axis checklist is the operationalized +> mirror of the **Maskinrommet skrivekontrakt §C2** (the craft half of the +> contract; §A — skeleton-before-prose — is mirrored by `longform-quality-rules.md` +> rule 8). §C2 is the source of truth: a change on either side must be mirrored to +> the other so the two never drift. + +**Procedure:** + +1. **Take the fact-checked draft** (Step 5 output → `currentPhase: "factcheck-sweep"`). + The body must already be fact-clean (no open 🔴) — editorial review runs on the + settled text, not on a draft still moving under fact fixes. + +2. **Run `editorial-reviewer` (single foreground `Task` call).** Invoke + `subagent_type: linkedin-thought-leadership:editorial-reviewer` from THIS + command layer in the foreground (principle 4), passing the draft path + (`<serie>/NN-utkast.md`) and — when the edition is part of a series — the + series title (for the A3 series-title-symmetry check). The agent returns a + craft report: **≤10 flags** across two axes — **prosa-håndverk** (P1 em-dash + density · P2 verbatim repetition · P3 postulated numbers without source/hedge · + P4 internal contradiction · P5 versal-tic) and **narrativ-arkitektur** (A1 + concrete instantiation · A2 theory-anchored hypotheses · A3 series-title + symmetry · A4 equally-usable action per addressee · A5 un-overloaded + conclusion) — each flag carrying a **quote/line reference**, a **direction** + (never rewritten copy), and a **severity: BLOCK / REWORK / NICE**. + + This is one foreground call (not a parallel fan-out): one editor reads the + whole draft. The agent has `Read` + `Grep` — the mechanical prose checks are + grep-able, the architecture checks need a read. + +3. **Surface the report to the operator (`SendUserFile` — the Endring-5 pattern).** + The flags are surfaced to KTG as a **markdown report**, the same operator-gate + shape the visual-assets step (7.5) uses for candidates and Steps 2.5/3a use for + annotation: + 1. Write the agent's report to `<serie>/NN-editorial-review.md` (NN = the same + zero-padded edition number; new suffix, a first-class artifact alongside + `NN-skjelett.md`). + 2. `SendUserFile` it (else a markdown `file://` link) so KTG can read the flags + sorted BLOCK → REWORK → NICE and **decide which fold in**. + 3. **KTG gates.** The agent's severity ranking is a *recommendation*; the + operator holds the gate. A BLOCK is the agent's strongest "must fix before + Step 6", not an automatic pipeline halt. `[OPERATØR]` + +4. **Fold in the approved flags by tightening, → v(n+1).** Fold the flags KTG + approved into `<serie>/NN-utkast.md` **by tightening** (rule 6 of + `references/longform-quality-rules.md` — close the gap, hold the length flat; + never expand to paper over a craft defect). The result is the next draft + iteration. The editor (this session) holds the pen — never paste the agent's + direction as copy. + +5. **Optionally re-run `editorial-reviewer` on the cleaned version.** If the + fold-in was substantive (especially any BLOCK), re-run the agent on v(n+1) to + confirm the flags cleared and no new craft defect was introduced by the edit. + This loop is cheap and is the point of the gate — every craft round saved here + is a KTG round saved at first reading. + +6. **Persist + checkpoint state.** Once the editorial pass is folded in (and any + re-run confirms clean): + - Record the editorial report + which flags were folded vs. waived in + `edition-state.json` → `articles.NN.editorialReview` (the durable, + machine-readable record — what was flagged, severity, fold-in decision). + - Set `currentPhase: "editorial-review"` in `edition-state.json` (the marker + that Step 5.5 is complete and the operator-gate has passed). + - Write an "editorial review complete (craft clean) → next: persona sweep + (BEFORE lock)" line to `<serie>/STATE.md` (overwrite). + +``` +Editorial review (craft gate, BEFORE persona sweep) — complete. +- Flags: <N> (≤10) prosa-håndverk: <N> narrativ-arkitektur: <N> +- Severity: <N> BLOCK · <N> REWORK · <N> NICE +- Surfaced to operator: <serie>/NN-editorial-review.md (via SendUserFile) [OPERATØR] +- Folded in (by tightening): <N> Waived (operator): <N> +- Re-run on v(n+1): clean (or: skipped — fold-in non-substantive) +- Length delta vs. fact-checked draft: <flat/±N words> (target: flat — rule 6) +Gate: [PASS — craft clean, operator approved] (else: BLOCK flags open — loop) Next: Step 6 — Persona sweep (reader jury, BEFORE lock). ``` +--- + ## Step 6: Persona sweep — reader jury, BEFORE lock -The fact-checked draft now faces the **reader jury**: the personas selected in -Step 1 read it read-only and judge whether it *lands* — not whether it is correct -(that was Step 5), not whether it is original. This is the **single most +The editorially-cleaned, fact-checked draft now faces the **reader jury**: the +personas selected in Step 1 read it read-only and judge whether it *lands* — not +whether it is correct (that was Step 5), not whether it is well-made (that was +Step 5.5), not whether it is original. This is the **single most important ordering rule in the whole pipeline.** In the Seres production this sweep was originally run *after* the texts were locked (Step 8), which forced reopening locked texts — the biggest single process error of the series (plan @@ -1218,12 +1335,13 @@ Edition complete. Visible in /linkedin:calendar; mark live via /linkedin:calenda ## Reference Files -- `${CLAUDE_PLUGIN_ROOT}/config/edition-state.template.json` — edition-state schema (14 phases including v2.1 skeleton + spine-prose gates and v2.3 visual-assets) +- `${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-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/voice-scrubber.md` — Step 4 de-AI / Norwegian-chronicle voice scrub (gold standard = approved Norwegian editions, NOT the English post corpus) - `${CLAUDE_PLUGIN_ROOT}/commands/react.md` — multi-source synthesis discipline (reused in Step 2) diff --git a/plugins/linkedin-thought-leadership/config/edition-state.template.json b/plugins/linkedin-thought-leadership/config/edition-state.template.json index 2d25f1f..190fc94 100644 --- a/plugins/linkedin-thought-leadership/config/edition-state.template.json +++ b/plugins/linkedin-thought-leadership/config/edition-state.template.json @@ -13,6 +13,7 @@ "draft — full prose expansion against the gated spine; may span sessions (Step 3b)", "consistency-quality — threads, premise→conclusion arc, AI-slop removal, formatting dose (Step 4)", "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)", "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)", @@ -21,6 +22,7 @@ "scheduling — register edition in plugin queue/state for native LinkedIn scheduling (Step 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 ![alt](linkedin/NN/figN.png) 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]." }, "schemaVersion": 1, @@ -38,6 +40,7 @@ "status": "pending", "immutableRules": null, "factcheckLog": null, + "editorialReview": null, "personaSweep": { "skeleton": null, "resonance": null,