feat(linkedin-studio): v3.1.0 — Endring 9 adversarial review-pakke + per-artefakt personas
Cold, adversarial review package for the long-form pipeline + configurable per-edition personas. Motivated by Del 4 (Security Champions pivot): the in-session editor + persona sweep shared the drafting session's framing-bias, so the shipped version was never independently re-reviewed. Headless package (9a/9b): - New Step 6.5 (headless-review) in /linkedin:newsletter, after the persona sweep, before lock — the independence layer the in-session gates can't be. - New standalone /linkedin:headless-review command (run in a fresh session for maximum isolation; reconstructs frozen draft + contract + personas from disk). - 3 new Opus archetypes, each with a cardinal context-isolation block that refuses drafting-session framing as "context pollution": - content-reviewer (argument integrity C1–C5, ≤8 flags) - language-reviewer (Norwegian language L1–L5, ≤10 flags) - fact-reviewer (cold re-verification F1–F4, risk-sort + pivot-risk, WebSearch) - Deliberate redundancy with fact-checker / editorial-reviewer documented so the pairs are never de-duplicated. Pivot-reopen (9c): - New /linkedin:pivot command: logs articles.NN.pivots[], resets currentPhase, un-locks, marks gates to re-run. - Pivot-detection gate in Step 8 lock precondition (>20% word-count change or >2 new sections re-opens cleared gates). Del 4 v8→v11 worked example. Per-artifact personas (new requirement): - articles.NN.personas with resolution order (edition-state → series file → plugin library → interactive). One or more readers configurable per edition. Schema/docs: - edition-state.template.json: additive personas[], pivots[], headlessReview, headless-review phase (16 phases); personaSweep.resonance.wordCount baseline. - 3 fasit fixtures + 3 structural lint tests (Del 4 worked cases). - Counts: 24→26 commands, 16→19 agents, 15→16 newsletter phases. - README + CLAUDE.md (plugin + root) + CHANGELOG synced. Verification: 35 agent-fixture + 59 hook + 20 render tests green. Backward- compatible (additive state); reload required before the 3 new agents resolve. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
e162cdce38
commit
e69ea1f4c9
20 changed files with 2520 additions and 59 deletions
161
plugins/linkedin-studio/commands/pivot.md
Normal file
161
plugins/linkedin-studio/commands/pivot.md
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
---
|
||||
name: linkedin:pivot
|
||||
description: |
|
||||
Re-open a long-form edition after a substantive late change (a "pivot") so the
|
||||
already-cleared quality gates re-run on the changed version before lock. Logs
|
||||
the pivot in edition-state, moves currentPhase back to the right earlier step,
|
||||
un-locks if needed, and marks which gates (fact-check, editorial, persona,
|
||||
headless) must re-pass. Includes the pivot-detection heuristic (>20% word-count
|
||||
change or >2 new sections).
|
||||
Use when the user says: "pivot", "I changed the angle", "I added a section",
|
||||
"re-open the edition", "the article changed after it was approved",
|
||||
"re-run the gates", "this needs re-review".
|
||||
Triggers on: "pivot", "linkedin pivot", "re-open edition", "added a section",
|
||||
"changed the angle", "pivot-reopen", "/linkedin:pivot".
|
||||
allowed-tools:
|
||||
- Read
|
||||
- Glob
|
||||
- Grep
|
||||
- Bash
|
||||
- AskUserQuestion
|
||||
- Write
|
||||
---
|
||||
|
||||
# LinkedIn Pivot — re-open a cleared edition for re-review
|
||||
|
||||
A **pivot** is a substantive change to a long-form draft made *after* a gate had
|
||||
already cleared it — a new argument anchor, a new section, a changed thesis. The
|
||||
problem this command solves: the pipeline's gates (fact-check Step 5, editorial
|
||||
Step 5.5, persona Step 6, headless Step 6.5) ran on the *pre-pivot* version, so
|
||||
the changed text was never validated. Without an explicit re-open, a pivoted
|
||||
edition can sail into lock carrying an unverified premise or an unread argument.
|
||||
|
||||
> **Why this exists (Del 4, Endring 9c).** Del 4 was LOCK-ready on an early
|
||||
> version (v8). Then a "Security Champions" pivot added a ~260-word section and a
|
||||
> ~270-word role-description section — roughly +42 % length, two new sections, a
|
||||
> new axis. The pipeline had no pivot-mode, so the whole post-lock chain had to be
|
||||
> re-opened by hand. This command makes the re-open a **named ritual**, not a
|
||||
> manual scramble.
|
||||
|
||||
## Command anatomy
|
||||
|
||||
```
|
||||
/linkedin:pivot
|
||||
--article NN (required; the edition article that changed)
|
||||
--reason "<one line>" (required; e.g. "Security Champions-anker")
|
||||
--to-phase draft | consistency-quality | factcheck-sweep (optional; default from the heuristic)
|
||||
```
|
||||
|
||||
## The pivot-detection heuristic
|
||||
|
||||
Compare the **current** draft against the version that **last cleared Step 6**
|
||||
(persona-sweep-prelock). A pivot-reopen is **suggested/required** when either:
|
||||
|
||||
- **word-count change > 20 %**, or
|
||||
- **> 2 new sections** (top-level headings added since the cleared version).
|
||||
|
||||
This heuristic is also checked as a **lock precondition in Step 8** of
|
||||
`/linkedin:newsletter`: if the draft has drifted past these bounds since Step 6
|
||||
cleared, the lock STOPS and points the operator here. (Length-band drift itself
|
||||
— soft/hard caps — is logged friction F1, not yet a gate.)
|
||||
|
||||
> **Worked example (acceptance test — Del 4 v8 → v11).** At v8 the persona sweep
|
||||
> had cleared a ~1 400-word draft. The Security Champions message pushed it to
|
||||
> ~1 992 words (+42 %, > 20 %) and added 2 sections (a new anchor + a
|
||||
> role-description) — at the boundary of the "> 2 new sections" rule and well past
|
||||
> the 20 % rule. **The heuristic fires:** `/linkedin:pivot --article 04 --reason
|
||||
> "Security Champions-anker"` would log the pivot, move `currentPhase` back to
|
||||
> `draft` (structural change → full re-treatment), and require fact-check +
|
||||
> editorial + persona + headless to re-pass on v11 before lock. That is exactly
|
||||
> the re-sweep the manual Del 4 run had to improvise.
|
||||
|
||||
## Step 1 — Load state + locate the article
|
||||
|
||||
1. Resolve the series root and read `<serie>/linkedin/edition-state.json`. Find
|
||||
`articles.NN` for the `--article` value. If it does not exist, stop and report.
|
||||
2. Read the current draft `<serie>/NN-utkast.md` and note `currentPhase` and
|
||||
`locked`.
|
||||
|
||||
## Step 2 — Measure the pivot scope
|
||||
|
||||
1. **Current word count:** `cd <serie-mappe> && wc -w NN-utkast.md`.
|
||||
2. **Baseline word count:** the word count of the version that last cleared
|
||||
Step 6, recorded by newsletter Step 6 in
|
||||
`articles.NN.personaSweep.resonance.wordCount`. If that field is absent (older
|
||||
state), ask the operator for the cleared-version word count, or treat the
|
||||
pivot as structural by default.
|
||||
3. **Compute** `deltaPct = round((current - baseline) / baseline * 100)` and
|
||||
count `newSections` = top-level headings now present that were not in the
|
||||
cleared version (a `grep -c '^## '` delta is a reasonable proxy; confirm with
|
||||
the operator if ambiguous).
|
||||
4. **Classify scope** (drives the default `--to-phase`):
|
||||
- **Structural** (deltaPct > 20 % OR newSections > 2, or a new axis/thesis) →
|
||||
default `to-phase: draft` (Step 3b). The new material needs full prose
|
||||
expansion → consistency → fact-check → editorial → persona → headless.
|
||||
- **Moderate** (new examples/claims, no new sections, deltaPct ≤ 20 %) →
|
||||
default `to-phase: factcheck-sweep` (Step 5) so the new claims get verified,
|
||||
then editorial + persona + headless re-run.
|
||||
- The operator may override with explicit `--to-phase`.
|
||||
|
||||
## Step 3 — Log the pivot + reset the phase (the ritual)
|
||||
|
||||
1. **Append a pivot entry** to `articles.NN.pivots[]`:
|
||||
```json
|
||||
{
|
||||
"timestamp": "<ISO-8601>",
|
||||
"reason": "<--reason>",
|
||||
"fromPhase": "<currentPhase before this command>",
|
||||
"toPhase": "<resolved to-phase>",
|
||||
"wordCountBefore": <baseline>,
|
||||
"wordCountAfter": <current>,
|
||||
"deltaPct": <deltaPct>,
|
||||
"newSections": <newSections>,
|
||||
"gatesToRerun": ["factcheck-sweep", "editorial-review", "persona-sweep-prelock", "headless-review"]
|
||||
}
|
||||
```
|
||||
`gatesToRerun` always spans every gate from the reset phase through Step 6.5 —
|
||||
a pivot invalidates the fact-check, the editorial craft pass, the persona
|
||||
resonance verdict, AND the headless package, because all of them judged the
|
||||
pre-pivot text.
|
||||
2. **Reset `currentPhase`** to the resolved `toPhase`, and set the article's
|
||||
`phase` to match.
|
||||
3. **Un-lock if needed.** If `articles.NN.locked` was `true`, set `locked: false`
|
||||
and `status: "in-progress"` — a pivot means the edition is no longer locked.
|
||||
Surface this plainly (the prior `POST.html` is now stale and will be re-rendered
|
||||
at the next lock).
|
||||
4. **Invalidate the downstream verdicts** so they cannot be mistaken for current:
|
||||
set `personaSweep.resonance`, `editorialReview`, and `headlessReview.status`
|
||||
back to a re-run state (e.g. `headlessReview.status: "pending"`), and note in
|
||||
each that they were invalidated by pivot `<timestamp>`. Leave the `pivots[]`
|
||||
log and `factcheckLog` history intact (history is durable).
|
||||
5. **Update `updatedAt`** and write `edition-state.json`.
|
||||
|
||||
## Step 4 — Point the next step
|
||||
|
||||
Write a precise next-step line to `<serie>/STATE.md` (overwrite, ONE-system):
|
||||
|
||||
```
|
||||
PIVOT logged (<reason>, +<deltaPct>%, <newSections> new sections) →
|
||||
currentPhase reset to <toPhase>. Resume /linkedin:newsletter; it will re-run
|
||||
fact-check (5) → editorial (5.5) → persona (6) → headless (6.5) on the pivoted
|
||||
version BEFORE lock. Headless package: /linkedin:headless-review --article NN.
|
||||
```
|
||||
|
||||
Do not run the gates yourself — `/linkedin:newsletter` owns the pipeline and will
|
||||
resume deterministically from the reset `currentPhase` and re-run every gate in
|
||||
`gatesToRerun` before it permits lock.
|
||||
|
||||
```
|
||||
Pivot logged.
|
||||
- Article NN: <reason>
|
||||
- Scope: <structural|moderate> (Δ <deltaPct>%, <newSections> new sections)
|
||||
- currentPhase: <fromPhase> → <toPhase> locked: <true→false | unchanged>
|
||||
- Gates to re-run before lock: fact-check (5) · editorial (5.5) · persona (6) · headless (6.5)
|
||||
Next: resume /linkedin:newsletter (re-runs the gates) → then lock.
|
||||
```
|
||||
|
||||
## Reference Files
|
||||
|
||||
- `${CLAUDE_PLUGIN_ROOT}/commands/newsletter.md` — the pipeline this re-opens; Step 8 lock-precondition runs the same heuristic; the resumption table replays from the reset `currentPhase`
|
||||
- `${CLAUDE_PLUGIN_ROOT}/commands/headless-review.md` — the cold review package that must re-pass on the pivoted version
|
||||
- `${CLAUDE_PLUGIN_ROOT}/config/edition-state.template.json` — `articles.NN.pivots` schema + the heuristic notes
|
||||
Loading…
Add table
Add a link
Reference in a new issue