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:
Kjell Tore Guttormsen 2026-05-29 13:01:24 +02:00
commit e69ea1f4c9
20 changed files with 2520 additions and 59 deletions

View file

@ -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**