feat(linkedin-studio): N24 — promo-post-motor (hook-forge + shareability-gate) [skip-docs]

Step 9 (post-lock distribution gate) får to tillegg, begge scoped til utgave-promo:

1. Hook-forge (E#7): 5-8 krok-varianter for delingsteksten. 110-140-båndet
   håndheves PER VARIANT og MÅLES (perl -CSD; awk length/wc -c teller bytes og
   lyver på æ/ø/å). Utenfor båndet = diskvalifisert, ikke rangert lavere.
   Settet må spenne minst tre krok-typer, ellers er det omskrivinger, ikke valg.
   Hver variant må spores til en påstand kroppen faktisk gjør (ingen bait).
   Ingen predicted-engagement score — et tall som påstår å vite hva som sprer
   seg er oppfunnet (N22-defektklassen); operatøren rangerer.
   Valgt variant går GJENNOM randsone-gaten, aldri utenom.

2. Shareability-gate (E#8): konverter-modus får en ANDRE binær — deling.
   «Hvem deler dette til en kollega, og hvorfor?» + RESHARE/SAVE/SEND.
   Svaret må navngi en rolle og et avsender-motiv; «nyttig for alle i tech»
   er NEI. Blokkerende: to mislykkede omramminger => operatørvalg (pivot eller
   registrert foldIn), aldri en stille passering.

Ti suiter grønne: test-runner 300/0 (287->300, +13 ubetingede; floor 268->281)
· trends 300 · analytics 202 · hooks 191 · brain 134 · editions 72 · render 63
· specifics-bank 45 · tests 35 · contract-gate 33. Begge nye compound-predikater
mutasjonstestet mot faktisk fil (fjernet literal => rød).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RvtDSvQDUmjd5bXdAxUu6D
This commit is contained in:
Kjell Tore Guttormsen 2026-07-31 21:22:49 +02:00
commit 77426135a5
7 changed files with 337 additions and 56 deletions

View file

@ -171,7 +171,7 @@ contains ONLY the cold-contract inputs. Map `--type` to archetypes:
| `language` | `linkedin-studio:language-reviewer` | — | frozen draft + contract |
| `fact` | `linkedin-studio:fact-reviewer` | — | frozen draft + contract |
| `persona-resonance` | `linkedin-studio:persona-reviewer` | `mode: resonans`, one call **per active persona** | frozen draft + persona block |
| `persona-conversion` | `linkedin-studio:persona-reviewer` | `mode: konverter`, **primær only** (hook only) | distribution hook / first two lines |
| `persona-conversion` | `linkedin-studio:persona-reviewer` | `mode: konverter`, **primær only** (klikk + deling) | distribution copy: hook / first two lines + the promise it makes |
`all` = every row above (resonance fans out one call per active persona;
conversion runs the primær). **Cold-prompt template** for each call:
@ -215,7 +215,7 @@ yourself or pick winners between reviewers — surface them, the operator gates.
| # | F-kat | 🔴/🟡/🟢 | Påstand | Kilde / retning |
… + Pivot-risk: <claims that look freshly added, or "none">
### persona-resonance — <per persona: JA/NEI + ≤5 flags>
### persona-conversion — <primær JA/NEI on the hook>
### persona-conversion — <primær klikk JA/NEI on the hook + deling JA/NEI (forwarder role, motive, RESHARE/SAVE/SEND)>
## Cross-archetype signal
- BLOCK / 🔴 total: <N> REWORK total: <N> primær resonance: JA/NEI primær conversion: JA/NEI

View file

@ -877,7 +877,7 @@ Next: Step 2.5 — Skeleton + section pitch (operator + persona gate BEFORE pros
`<serie>/NN-skjelett.md`, and **`mode: skjelett`** (the before-prose mode —
five spine axes, ≤3 flags as direction, HOLDER/TVILER/MANGLER scoring).
This is NOT resonans mode (Step 6 — that runs on full prose) and NOT
konverter mode (Step 9 — that judges the hook only).
konverter mode (Step 9 — that judges the distribution copy: klikk + deling).
8. **Collect skjelett verdicts and gate.** Each call returns per-axis flags
(HOLDER/TVILER/MANGLER), ≤3 direction-only flags, a section-pitch check
@ -1617,7 +1617,7 @@ command runs — see `${CLAUDE_PLUGIN_ROOT}/commands/headless-review.md` for the
- `linkedin-studio:language-reviewer` — language quality (L1L5; grades against `edition-state.language`, Norwegian-specific rules when `language: no`)
- `linkedin-studio:fact-reviewer` — cold re-verification (F1F4, 🔴/🟡/🟢, incl. pivot premises)
- `linkedin-studio:persona-reviewer` `mode: resonans` — **one call per active persona**
- `linkedin-studio:persona-reviewer` `mode: konverter`**primær only** (hook)
- `linkedin-studio:persona-reviewer` `mode: konverter`**primær only** (hook + share; advisory here, blocking at Step 9)
Each call's prompt carries ONLY the cold-contract inputs (frozen draft path,
`language`, contract path if it ships, persona for the persona modes) + the
@ -2061,18 +2061,22 @@ Next: Step 9 — Hook / conversion gate (post-lock).
The locked edition still has to earn the feed. Before it ships, the
**feed-facing surfaces** the reader actually meets — the **delingstekst hook**,
the **samle post**, the **carousel slide text**, and the **edition title**
face two final gates: a **randsone fact + language gate** (so nothing false or
clumsy reaches the feed in the most-read, most-requoted copy — C-4/C-9) and the
**hook conversion binary** (would the primær persona, scrolling, actually stop
and open this?). Both operate on **distribution copy only** — the post-lock
sweep, distinct from the pre-lock resonance sweep (Step 6), never the locked
body. Until N9 only the hook's click-worth was judged; the hook's *truth and
language*, the samle post, the carousel slides and the title reached the feed
ungated.
face a **hook-forge** (the krok competes against alternatives instead of shipping
the one the draft happened to end on) and three gates: a **randsone fact +
language gate** (so nothing false or clumsy reaches the feed in the most-read,
most-requoted copy — C-4/C-9), the **hook conversion binary** (would the primær
persona, scrolling, actually stop and open this?), and the **shareability gate**
(would that reader pass it on — and to whom?). All operate on **distribution copy
only** — the post-lock sweep, distinct from the pre-lock resonance sweep (Step 6),
never the locked body. Until N9 only the hook's click-worth was judged; the hook's
*truth and language*, the samle post, the carousel slides and the title reached
the feed ungated — and until N24 the hook shipped unchallenged and nobody asked
who would forward the edition.
> **Order assertion (enforced).** This gate (Step 9) runs AFTER lock (Step 8) — it
> operates on the **distribution copy** of an already-locked edition and must never
> reopen the locked body. Both the randsone fact/language gate and the hook binary
> reopen the locked body. The hook-forge, the randsone fact/language gate, the hook
> binary and the shareability gate all
> revise only distribution surfaces (delingstekst, samle, carousel text,
> distribution title) and re-render via Step 8's `build-linkedin.mjs` /
> `build-carousel.mjs` — never the edition text. A defect that traces into the
@ -2101,7 +2105,38 @@ lock invariant without breaking phase order.
- the **edition title** — the edition's own headline (its distribution / feed
title), never strength-gated before now.
2. **Randsone fact + language gate (scoped — C-4/C-9).** Run two scoped reviewers
2. **Hook-forge — forge the alternatives before gating one (E#7).** The hook that
exists is the one the draft happened to end on; it has never competed against
anything. Forge **five to eight hook variants** for the delingstekst krok, then
let the operator choose — the gates below judge the chosen krok, not the accident.
- **Measure the band, per variant.** Each variant's opening line must land in
**110140 characters** (the mobile "…see more" cutoff — the hook rule the
short-form surfaces already hold). Measure it, never estimate it:
`perl -CSD -ne 'chomp; printf "%d\n", length($_)'`. Norwegian æ/ø/å are
multibyte, so `awk length` and `wc -c` count BYTES and over-report. A variant
outside the band is **disqualified, not ranked lower** — the cutoff is
physical, not a preference, and it is enforced per variant, never on the set.
- **Span the hook types.** Name each variant's type from
`${CLAUDE_PLUGIN_ROOT}/references/engagement-frameworks.md`. The surviving set
must cover **at least three distinct hook types** — otherwise the forge
produced rewordings of one idea and the operator has no real choice.
- **Trace every variant to the locked body.** A variant must rest on
**a claim the locked body actually makes**. One that promises what the
edition does not deliver is disqualified — it is bait, and the randsone fact
gate below would 🔴 it anyway.
- **Carry only what can be checked.** Each variant ships with its measured
length, its hook type and its body-trace — and
**no predicted-engagement score**. A number claiming to know which krok will
travel is invented; the ranking is the operator's, on variants the plugin can
honestly describe.
- **Fewer than five survivors → forge again.** Presenting three survivors as
"the set" hides that the band or the body constrained the forge.
- The operator picks one via `AskUserQuestion` — the gate that already exists
here. The chosen variant becomes the delingstekst hook and goes
**through the randsone gate, never around it**: the same fact, language and
length rules as any other distribution copy. `[GATE]`
3. **Randsone fact + language gate (scoped — C-4/C-9).** Run two scoped reviewers
over *only* these surfaces (never the locked body), issued from THIS command
layer in the foreground, `subagent_type` namespaced:
- `linkedin-studio:fact-reviewer`**F1** (verifiable claims) + **F3** (number
@ -2114,7 +2149,7 @@ lock invariant without breaking phase order.
Pass each reviewer only the four surfaces + the sources they cite + `language`.
This is a **scoped mini-pass**, not a re-review of the article. `[GATE]`
3. **Title-strength gate (C-9).** The edition's own title was never strength-gated —
4. **Title-strength gate (C-9).** The edition's own title was never strength-gated —
only the hook's two lines were. Judge the **title-strength** of the **edition
title** here: does it earn the open on its own, or is it a generic label? The
strongest candidate becomes the distribution title. The verdict is **binding on
@ -2122,7 +2157,7 @@ lock invariant without breaking phase order.
canonical (locked) title** — changing that is a body edit → STOP, run
`/linkedin:pivot`; never edit the locked title in place.
4. **Resolve the randsone gate.**
5. **Resolve the randsone gate.**
- **Fact 🔴 / L-BLOCK on a distribution surface** → revise that surface **by
tightening** (hook, samle, carousel text, or distribution title — all
distribution copy), **re-render** the affected artifact (POST.html via Step 8's
@ -2132,32 +2167,63 @@ lock invariant without breaking phase order.
pivot: STOP, run `/linkedin:pivot`. The randsone gate never reopens the locked
body in place — the same invariant as the conversion loop. `[GATE]`
5. **Run the hook conversion binary** (`subagent_type:
linkedin-studio:persona-reviewer`, **`mode: konverter`** — the after-lock,
hook-only mode, NOT resonans) for the **primær** persona only. The agent returns
a single binary verdict, **JA / NEI**, on «would YOU click?» — no axis scoring,
no flags, no rewritten copy (the jury judges, the editor writes).
- **JA** → the hook converts. Proceed to Step 10.
6. **Run the distribution binaries** (`subagent_type:
linkedin-studio:persona-reviewer`, **`mode: konverter`** — the after-lock
distribution mode, NOT resonans) for the **primær** persona only, on the chosen
forge variant. The agent returns **two binary verdicts****klikk** («would YOU
click?») and **deling** (item 7) — no axis scoring, no flags, no rewritten copy
(the jury judges, the editor writes; the forge is the editor's pen).
- **JA** → the hook converts. Proceed to the shareability gate.
- **NEI** → revise the **delingstekst hook only** (sharpen the krok by tightening,
body frozen), **re-render POST.html** via `build-linkedin.mjs`, and re-run the
conversion check. Loop until JA. `[GATE]`
or take the next forge variant — body frozen), **re-render POST.html** via
`build-linkedin.mjs`, and re-run the conversion check. Loop until JA. `[GATE]`
6. **Persist.** Record the randsone-gate result in `edition-state.json`
7. **Shareability gate — «hvem deler dette til en kollega, og hvorfor?» (E#8).**
A click is one reader; a forward is peer acknowledgement, and it is the signal
the edition was written to earn. The `konverter` call's second binary is the
**deling verdict**: judged by the primær persona on the same distribution copy —
**who forwards this to a colleague, and why** — plus which action the edition
actually earns from that reader: **RESHARE / SAVE / SEND**.
- **A plausible answer names a role and a motive.** It must name a role the
reader could actually point at, and what forwarding does *for the sender*
signals their judgment, saves a colleague a decision, settles a running
argument. «Useful for anyone in tech» names nobody: that is a **NEI**.
- **NEI → revise the distribution copy** (the promise may simply be framed for a
reader nobody forwards to), re-render, re-check. Body frozen, as everywhere in
this step.
- **Two failed re-framings → stop; do not lower the bar.** If the honest reason
is that the edition offers nothing a reader would pass on, that is a
body-level finding, not a copy problem: put it to the operator as a choice —
run `/linkedin:pivot`, or ship and record it as an `articles.NN.foldIns` row
for the Step 11 retro. There is **never a silent pass**: this gate is resolved
by a fix or by a recorded operator decision, never by re-reading the same copy
more generously. `[GATE]`
8. **Persist.** Record the forge in `edition-state.json`
`articles.NN.hookForge` (each variant with its measured length, hook type,
body-trace and disqualification reason if any, plus which one the operator
chose), the randsone-gate result in
`articles.NN.randsoneGate` (per-surface fact/language verdicts + title-strength +
what was revised) and the conversion verdict in
`articles.NN.personaSweep.conversion`; set `currentPhase: "hook-conversion-gate"`.
what was revised), the click verdict in
`articles.NN.personaSweep.conversion` and the share verdict in
`articles.NN.personaSweep.deling` (verdict + the named forwarder role + the
RESHARE/SAVE/SEND action, or the recorded operator decision);
set `currentPhase: "hook-conversion-gate"`.
**↳ Phase transition** — run the protocol (Step 0) for `hook-conversion-gate`,
`--next "Step 10 — scheduling"`.
```
Randsone + conversion gate (post-lock, distribution copy only).
Forge + randsone + conversion + shareability gate (post-lock, distribution copy only).
- Hook-forge: <N> forged / <N> disqualified (band <N>, body-trace <N>) · types spanned: <N> → chose #<k> (<measured> chars, <type>)
- Surfaces gated: delingstekst hook · samle post · carousel slide text · edition title
- Fact (F1/F3): <N> 🔴 → resolved (or pivot if it traces to the body)
- Language (L1/L2): <N> BLOCK → tightened
- Title-strength: <verdict> (distribution title sharpened; canonical-title weakness → pivot)
- Conversion (primær, konverter): JA (else: NEI — revise hook, re-render, re-check)
- Deling (primær, konverter): JA — <role> sends it to <role> because <motive> · action: RESHARE|SAVE|SEND
(else: NEI — reframe the copy; twice failed → operator decision, never a silent pass)
- Body: untouched (locked in Step 8)
Gate: [PASS — randsone clean + JA] (else loop on distribution copy, or pivot)
Gate: [PASS — randsone clean + klikk JA + deling JA] (else loop on distribution copy, or pivot)
Next: Step 10 — Scheduling.
```