feat(linkedin-studio): N14 — foldIns-fangst + Step 11 retro + background-headless + språkregel-akkumulering [skip-docs]
Lukker sløyfen pluginen manglet: en rettelse operatøren gjør i utgave N håndheves i N+1 i stedet for å bli gjenoppdaget. Maskineriet fantes (foldIns-skjema + promote→ratify siden fix #1); det som manglet var wiring — ingenting skrev til køen og ingen fase tømte den. - Fangst (A2-F7): Steps 2.5/3a/5.5/6.5 appender rettelsen ordrett med trigger, decision "pending". Ubetinget og bevisst dum — å avgjøre ved fangst om noe "fortjener" en regel er nettopp slik køen holder seg tom og sløyfen dør. - Step 11 retro (A2-F8), ≤5 min ETTER scheduling: promoter køen med eksplisitt JA/NEI (mekanisk → atomisk contract-gate-promotering, teller kun med grønn --ratify; dømmekraft → operatørens språkregelfil; NEI → rejected, beholdes), effort-oppsummering fra MÅLT phaseLog (aldri re-estimert), og ÉN friksjons-spørring som besvares tilbake til operatøren. Faser 18 → 19; resumption-tabellen ruter scheduling → Step 11, retro → complete. - articles.NN.retro: additiv-valgfri (default null), schemaVersion forblir 1. - Background-headless (A2-F6): --background kjører pakken i en bakgrunnsagent som skriver rapporten til disk; drafting-sesjonen leser fila. Samme isolasjon som fersk sesjon, uten copy-paste-sømmen. Inline fan-out = eksplisitt fallback. - Språkregler (C-10): ${DATA}/language-rules/<lang>.md (opt-in, template). Leses TO ganger — av language-reviewer (fanger) og av Step 4 (forebygger). Shippet banliste forblir baseline; brukerfila utvider. - references/fold-in-loop.md (A2-F9): loopen dokumentert domene-generelt in-tree, så en adopter uten ekstern skrivekontrakt har hele sløyfen. Refs 28 → 29. Suiter (alle grønne): test-runner 197 → 217 (Section 16u: 18 ubetingede greps + non-vacuity self-test; fase-sveip 16 → 17 faser; floor 179 → 198) · hooks 174 · trends 300 · brain 134 · editions 72 · specifics-bank 45 · contract-gate 33 · tests 35 · render 60. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QxvWAjte7vPcF79QeSRvRJ
This commit is contained in:
parent
677eab9294
commit
f0532dce3f
9 changed files with 711 additions and 30 deletions
|
|
@ -61,12 +61,19 @@ They get **NOTHING** about: prior versions or version numbers, what was
|
|||
deliberately omitted, the pivot narrative, who has read it, what an editor said,
|
||||
how a persona voted, or what the author intended. Two layers enforce this:
|
||||
|
||||
1. **Layer 1 — fresh session (strongest).** For the publish-ready gate, the
|
||||
operator runs *this command in a brand-new Claude Code session*. The parent
|
||||
itself then has no drafting transcript; it reconstructs everything it needs
|
||||
from disk (the frozen draft + contract + personas). This is the recommended
|
||||
path and the one KTG asked for.
|
||||
2. **Layer 2 — subagent isolation.** Each archetype is a `Task` subagent, which
|
||||
1. **Layer 1 — fresh session (strongest, manual).** The operator runs *this
|
||||
command in a brand-new Claude Code session*. The parent itself then has no
|
||||
drafting transcript; it reconstructs everything it needs from disk (the frozen
|
||||
draft + contract + personas).
|
||||
2. **Layer 1b — background run (`--background`, equal isolation, no seam).** The
|
||||
drafting session spawns this package as a **background agent** with its own
|
||||
context window, which writes the consolidated report to a file; the drafting
|
||||
session then reads that file from disk. The background agent gets only the
|
||||
cold-contract inputs — it cannot see the parent's transcript — so the
|
||||
isolation matches a fresh session, with **no copy-paste** of the report back
|
||||
into the drafting session and no manual session switch. See "Background run"
|
||||
below. This is the default recommendation for the Step 6.5 gate.
|
||||
3. **Layer 2 — subagent isolation.** Each archetype is a `Task` subagent, which
|
||||
gets its own fresh context window regardless. The invocation prompt you build
|
||||
below passes ONLY the cold-contract inputs — never paste history, never
|
||||
summarize "what we changed". If you find yourself about to tell a reviewer
|
||||
|
|
@ -91,11 +98,33 @@ how a persona voted, or what the author intended. Two layers enforce this:
|
|||
--persona <name> (persona modes only; default: the primær)
|
||||
--article NN (optional; persist into edition-state.json)
|
||||
--output <path> (default: <serie>/review/NN-headless-<stamp>.md)
|
||||
--background (run the package in a background agent
|
||||
that writes --output; caller reads the file)
|
||||
```
|
||||
|
||||
No `--type` (or `--type all`) runs the **whole package in parallel**. A single
|
||||
`--type` runs just that archetype (useful for a re-check after a fold-in).
|
||||
|
||||
### Background run (`--background`)
|
||||
|
||||
With `--background`, do **not** fan the archetypes out here. Spawn **one**
|
||||
background agent that runs Steps 1–5 of this command itself, and let it write the
|
||||
report:
|
||||
|
||||
- Launch it with `run_in_background: true` and a prompt carrying **only** the
|
||||
cold-contract inputs — draft path, contract path, persona names + block path,
|
||||
`--type`, and the absolute `--output` path — plus the instruction to write the
|
||||
consolidated report to `--output` and return that path.
|
||||
- **Never** put drafting history, version notes, or "what we changed" in that
|
||||
prompt. The background agent has its own context window; the only way session
|
||||
framing reaches it is if you type it in.
|
||||
- When it completes, `Read` the report at `--output` and continue at Step 5
|
||||
(surface + persist). The drafting session sees the *report*, not the reviewers'
|
||||
reasoning, and the reviewers never see the drafting session — the same
|
||||
independence a fresh session gives, with **no copy-paste seam** between them.
|
||||
- If background execution is unavailable, say so plainly and fall back to the
|
||||
inline fan-out (Step 3) — never silently downgrade the isolation.
|
||||
|
||||
## Step 1 — Resolve inputs (from disk, not from memory)
|
||||
|
||||
1. **Draft.** Use `--draft`. It must be a long-form draft `.md` (the same
|
||||
|
|
@ -219,18 +248,20 @@ Headless review complete (COLD).
|
|||
- Archetypes: <N> run in parallel converged flags: <N>
|
||||
- BLOCK/🔴: <N> REWORK: <N> primær resonance: JA/NEI conversion: JA/NEI
|
||||
- Report: <serie>/review/NN-headless-<stamp>.md (surfaced via SendUserFile)
|
||||
- Isolation: background agent (report read from disk) | fresh session | inline fan-out (fallback)
|
||||
- Persisted: edition-state.json articles.NN.headlessReview (or: standalone, not persisted)
|
||||
Operator gates the fold-in. For maximum independence, run this command in a FRESH session.
|
||||
Operator gates the fold-in. For maximum independence with no manual seam, run with --background.
|
||||
```
|
||||
|
||||
## Relationship to the pipeline + the in-session gates
|
||||
|
||||
- **Step 6.5 of `/linkedin:newsletter`** invokes this same package (after the
|
||||
in-session persona sweep Step 6, before lock Step 8). The pipeline may fan the
|
||||
reviewers out inline, but the **strongest** isolation is the operator running
|
||||
`/linkedin:headless-review` in a fresh session and pasting the consolidated
|
||||
report back. Either way the body must be re-touched **before** lock — never
|
||||
reopen a locked text (the cardinal Seres lesson).
|
||||
reviewers out inline, but the recommended path is `--background`: full
|
||||
isolation, the report read from disk, and no manual step between the review and
|
||||
the fold-in. A fresh session remains available and is equally cold. Either way
|
||||
the body must be re-touched **before** lock — never reopen a locked text (the
|
||||
cardinal Seres lesson).
|
||||
- **Deliberate redundancy.** `fact-reviewer` overlaps `fact-checker` (Step 5) and
|
||||
`language-reviewer` overlaps `editorial-reviewer`'s prose axis (Step 5.5) **on
|
||||
purpose**. The in-session gates ran with framing-bias; the cold re-read catches
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ 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 (18 phases)
|
||||
## Pipeline overview (19 phases)
|
||||
|
||||
The phase order is fixed. Two gates run **BEFORE prose** (skeleton + spine
|
||||
prose), an **editorial craft gate** runs before the persona sweep, the persona
|
||||
|
|
@ -113,9 +113,10 @@ split; v3.1 / Endring 9 on adversarial independence + framing-bias).
|
|||
| 8 | **LOCK → delivery** | POST.html "all in one place"; auto-gull (gold corpus) + **serie-minne** (series distillate + specifics-bank usage log) | `render/build-linkedin.mjs` + `scripts/editions` (`distil-append`) + `scripts/specifics-bank` (`record-usage`) |
|
||||
| 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; close the editions-register row (measured lead time) | `hooks/scripts/queue-manager.mjs` + `scripts/editions` (`register-complete`) |
|
||||
| 11 | **Retro — make the corrections stick** | ≤5 min AFTER delivery: promote the pending `foldIns` (mechanical → a contract-gate rule; judgment → the language-rules file), summarize the MEASURED effort from `phaseLog`, ask ONE friction question. The loop that makes edition N's correction enforced in N+1 | `scripts/contract-gate` (`--ratify`) + `scripts/editions` (`register-list`) + `references/fold-in-loop.md` |
|
||||
|
||||
> **Build status:** all 18 phases (Steps 0, 1, 1.5, 2, 2.5, 3a, 3b, 4, 4.5, 5,
|
||||
> 5.5, 6, 6.5, 7, 7.5, 8–10) are implemented below. This command takes an edition
|
||||
> **Build status:** all 19 phases (Steps 0, 1, 1.5, 2, 2.5, 3a, 3b, 4, 4.5, 5,
|
||||
> 5.5, 6, 6.5, 7, 7.5, 8–11) are implemented below. This command takes an edition
|
||||
> end-to-end:
|
||||
> load → calibration → **lived-specifics extraction (elicitation + bank binding,
|
||||
> BEFORE research)** → verified research (scoped by the binding) → **skeleton + section pitch (operator +
|
||||
|
|
@ -125,7 +126,8 @@ split; v3.1 / Endring 9 on adversarial independence + framing-bias).
|
|||
> pre-lock persona sweep → **headless adversarial review (cold review package,
|
||||
> operator-gated BEFORE lock)** → optional annotation → **visual assets
|
||||
> (cover/figures or carousel, operator-gated BEFORE lock)** → LOCK/delivery →
|
||||
> post-lock hook gate → scheduling, persisting each phase to `edition-state.json`
|
||||
> post-lock hook gate → scheduling → **retro (promote this edition's corrections
|
||||
> so the next one starts with them enforced)**, persisting each phase to `edition-state.json`
|
||||
> (machine) and `<serie>/STATE.md` (narrative) and stopping cleanly between
|
||||
> sessions.
|
||||
|
||||
|
|
@ -240,7 +242,8 @@ Look up `edition-state.json` → `articles.<currentArticle>` (and the top-level
|
|||
| `visual-assets` | Step 8 — LOCK → delivery |
|
||||
| `lock-delivery` | Step 9 — Hook / conversion gate |
|
||||
| `hook-conversion-gate` | Step 10 — Scheduling |
|
||||
| `scheduling` | **Edition complete** — nothing to resume (start the next article or edition) |
|
||||
| `scheduling` | Step 11 — Retro *(N14 — promote the fold-in queue; the edition is delivered but the loop is still open)* |
|
||||
| `retro` | **Edition complete** — nothing to resume (start the next article or edition) |
|
||||
|
||||
The phase identifiers are the canonical ones defined in
|
||||
`${CLAUDE_PLUGIN_ROOT}/config/edition-state.template.json` (`_doc.phases`); the
|
||||
|
|
@ -770,6 +773,14 @@ Next: Step 2.5 — Skeleton + section pitch (operator + persona gate BEFORE pros
|
|||
link — the operator annotates with the re-use visible, not after the fact.
|
||||
4. The operator annotates in the browser and pastes the annotated markdown
|
||||
back. Fold the notes into `<serie>/NN-skjelett.md` by tightening (rule 6).
|
||||
|
||||
**↳ Fold-in capture.** Any note here that would be just as true of the
|
||||
*next* edition — a rule, not a fact about this one — appends **one row** to
|
||||
`articles.NN.foldIns[]`: `correction` (near-verbatim), `trigger` (where it
|
||||
surfaced), `classification: null`, `decision: "pending"`. Capture is
|
||||
unconditional and costs seconds; **Step 11** classifies and promotes it. An
|
||||
edition-specific fix ("that number is 4.2") is not a rule — leave it out.
|
||||
Full loop: `${CLAUDE_PLUGIN_ROOT}/references/fold-in-loop.md`.
|
||||
5. **Receipt, not gate.** After folding in the annotations, use
|
||||
`AskUserQuestion` only as a *receipt* — «skeleton revised per your notes —
|
||||
JA proceed, or another round?». `AskUserQuestion` (JA / REVIDER / NEI) is
|
||||
|
|
@ -953,6 +964,12 @@ Typically ~20–30 % of the edition's final length.
|
|||
`file://` link).
|
||||
3. The operator annotates and pastes back; fold the notes in by tightening
|
||||
(rule 6 of `references/longform-quality-rules.md`).
|
||||
|
||||
**↳ Fold-in capture.** Same rule as Step 2.5: a note that generalizes past
|
||||
this edition appends one `articles.NN.foldIns[]` row (`decision:
|
||||
"pending"`, `classification: null`) with the correction near-verbatim and
|
||||
the trigger. **Step 11** empties the queue; nothing here decides whether a
|
||||
correction "deserves" a rule.
|
||||
4. **Receipt, not gate.** `AskUserQuestion` as a receipt — «spine revised per
|
||||
your notes — JA proceed to expansion, or another round?» (also the fallback
|
||||
gate when rendering is unavailable):
|
||||
|
|
@ -1075,6 +1092,18 @@ cutting, not by expansion**; hold the length flat (plan §8).
|
|||
> step S11 and extracted to the reference file at S12, per the original
|
||||
> forward-reference note — no rule text is duplicated.)
|
||||
|
||||
> **Plus the rules THIS operator has accumulated (N14 / C-10).** Read
|
||||
> `${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}/language-rules/<lang>.md`
|
||||
> (`<lang>` = `edition-state.language`) and apply it alongside the reference file.
|
||||
> It holds the judgment-class corrections the operator confirmed in earlier
|
||||
> editions and Step 11 promoted — reading it *here*, while the draft is still
|
||||
> being cleaned, is what makes a rule **prevent** the defect instead of merely
|
||||
> catching it at Step 6.5. The shipped ban-list (rule 3) is the baseline and the
|
||||
> user file extends it; where they disagree, the stricter wins. Absent the file
|
||||
> (the default — it is opt-in, template at
|
||||
> `${CLAUDE_PLUGIN_ROOT}/config/language-rules.template.md`), apply the baseline
|
||||
> alone and say nothing.
|
||||
|
||||
**Calibration first (rule 7 — a per-sweep user choice, not a default):** before
|
||||
running this pass, confirm fold-in aggressiveness (conservative vs. aggressive),
|
||||
jargon handling, and — when it matters later — persona weighting on conflict. Ask
|
||||
|
|
@ -1373,6 +1402,15 @@ and `persona-reviewer` never flags em-dash density (that is this step).
|
|||
iteration. The editor (this session) holds the pen — never paste the agent's
|
||||
direction as copy.
|
||||
|
||||
**↳ Fold-in capture.** A flag the operator approved that names a *recurring*
|
||||
craft defect (an em-dash habit, a phrase that keeps returning, a conclusion
|
||||
shape that keeps overloading) appends one `articles.NN.foldIns[]` row —
|
||||
correction near-verbatim, `trigger` = the flag's category (P1–P5 / A1–A5),
|
||||
`decision: "pending"`. This is the queue **Step 11** promotes: mechanical
|
||||
flags become deterministic gate rules that die at Step 4.5 next edition,
|
||||
judgment flags become checklist lines. A flag about *this draft's* specific
|
||||
sentence is not a rule.
|
||||
|
||||
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.
|
||||
|
|
@ -1545,11 +1583,16 @@ command runs — see `commands/headless-review.md` for the full cold contract):
|
|||
summarize "what we changed" into a reviewer prompt — that is the context
|
||||
pollution the package exists to eliminate.
|
||||
|
||||
> **Maximum-independence path.** The strongest isolation is the operator
|
||||
> running `/linkedin:headless-review --draft <frozen> --article NN` in a
|
||||
> **fresh session** (the parent then has no drafting transcript at all) and
|
||||
> pasting the consolidated report back. The inline fan-out here is the
|
||||
> single-session path; both use the same agents.
|
||||
> **Maximum-independence path — no session switch, no paste-back (N14).** The
|
||||
> strongest isolation that costs the operator nothing is the **background
|
||||
> run**: `/linkedin:headless-review --draft <frozen> --article NN --background`
|
||||
> spawns the package in a background agent with its own context window, which
|
||||
> writes the consolidated report to disk. This session then **reads that file**
|
||||
> — it never sees the reviewers' reasoning, and the reviewers never see this
|
||||
> session's drafting history. Same isolation as a fresh session, without the
|
||||
> manual copy-paste seam that used to sit here. Run it, then `Read` the report
|
||||
> path and continue at step 5 below. The inline fan-out above stays the
|
||||
> fallback when background execution is unavailable; both use the same agents.
|
||||
|
||||
4. **Degradation gate.** Confirm each call returned structured, populated output
|
||||
(real flags / a verification log), not empty or a hedged paragraph. Re-run any
|
||||
|
|
@ -1573,6 +1616,13 @@ command runs — see `commands/headless-review.md` for the full cold contract):
|
|||
quotes**, fire the deterministic **scoped fact-reviewer** mini-recheck on those
|
||||
sentences (see the invariant after Step 5) before advancing.
|
||||
|
||||
**↳ Fold-in capture.** The cold reviewers are the richest source of rules the
|
||||
in-session gates never see — a language flag two independent readers converge
|
||||
on is almost always a standing rule, not a one-off. Append one
|
||||
`articles.NN.foldIns[]` row per approved flag that generalizes (`decision:
|
||||
"pending"`, `trigger` = the C/L/F category, ⚑ converged noted), and let
|
||||
**Step 11** decide mechanical vs judgment. Do not classify here.
|
||||
|
||||
7. **Persist + checkpoint state.** Record the run in `edition-state.json` →
|
||||
`articles.NN.headlessReview` (`frozenDraft`, per-reviewer `{reportPath,
|
||||
summary, status}`, `consolidatedReport`, `foldedIn`/`waived`, `status:
|
||||
|
|
@ -2162,6 +2212,129 @@ Edition complete. Visible in /linkedin:calendar; mark live via /linkedin:calenda
|
|||
|
||||
---
|
||||
|
||||
## Step 11: Retro — make this edition's corrections stick (≤5 min, AFTER scheduling)
|
||||
|
||||
The edition is delivered. This step is not about it — it is about **the next
|
||||
one.** Every correction the operator made during production is sitting in
|
||||
`articles.NN.foldIns[]` marked `pending`; if the session ends here, those
|
||||
corrections live only in a transcript and get re-discovered in three editions'
|
||||
time. Step 11 empties that queue into permanent, enforced homes.
|
||||
|
||||
> **Why AFTER scheduling, and why capped.** The retro is cheap only if it is
|
||||
> short: three fixed jobs, one operator pass, no open-ended reflection. It runs
|
||||
> after Step 10 so nothing about shipping waits on it, and it is the last thing
|
||||
> the edition does — the pipeline is not complete until the loop is closed.
|
||||
> The full model (capture → classify → promote → enforce) is documented
|
||||
> domain-generally in `${CLAUDE_PLUGIN_ROOT}/references/fold-in-loop.md`. `[OPERATØR]`
|
||||
|
||||
**Procedure — three jobs, in order:**
|
||||
|
||||
1. **Promote the fold-in queue (the operator gates each row).** Read every
|
||||
`articles.NN.foldIns[]` row with `decision: "pending"`. For each, propose a
|
||||
`classification` and ask for a **JA / NEI** — one compact list, not one
|
||||
question per row:
|
||||
|
||||
- **`mechanical-block` / `mechanical-warn`** — provable by string, regex, or
|
||||
count with ~zero false positives. **JA →** promote **atomically**: add the
|
||||
rule to `scripts/contract-gate/src/rules.ts`, the matching row to the
|
||||
writing contract, and the manifest row that binds them; set the fold-in's
|
||||
`decision: "promoted"` and `ruleId`. Then prove it:
|
||||
|
||||
```bash
|
||||
cd "${CLAUDE_PLUGIN_ROOT}/scripts/contract-gate" && node --import tsx src/cli.ts --ratify
|
||||
```
|
||||
|
||||
**Red ratify means the promotion did not happen** — rules and contract are
|
||||
out of sync, and a gate enforcing something undocumented is exactly the
|
||||
drift `ratify` exists to refuse. Fix it before recording the promotion.
|
||||
From the next edition, that correction dies at **Step 4.5**, before any
|
||||
human reads the draft.
|
||||
- **`judgment`** — real editorial discretion, no gate can prove it. **JA →**
|
||||
append it to the operator's accumulating language file,
|
||||
`${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}/language-rules/<lang>.md`
|
||||
(`<lang>` = `edition-state.language`; template
|
||||
`${CLAUDE_PLUGIN_ROOT}/config/language-rules.template.md`), under `## Rules`,
|
||||
with the date and this edition number. That file is read by **Step 4** while
|
||||
the next draft is being cleaned *and* by `language-reviewer` at Step 6.5 — so
|
||||
the rule prevents the defect as well as catching it. If the file does not
|
||||
exist, say so once and offer the one-line copy from the template; never
|
||||
create it silently.
|
||||
- **NEI** → `decision: "rejected"`, **kept** — "we considered this and said
|
||||
no" is itself worth not re-discovering. Never delete a fold-in row.
|
||||
|
||||
**When unsure, classify as `judgment`.** A mechanical rule with false
|
||||
positives trains the operator to ignore the gate, and a gate nobody trusts
|
||||
enforces nothing.
|
||||
|
||||
2. **Effort summary — read the measurement, do not re-estimate it.** The numbers
|
||||
already exist in `articles.NN.phaseLog` (written deterministically at every
|
||||
phase transition since N12). Report exactly three things:
|
||||
|
||||
```bash
|
||||
node --import tsx "${CLAUDE_PLUGIN_ROOT}/scripts/editions/src/cli.ts" register-list --all
|
||||
```
|
||||
|
||||
- **transitions** — how many phases this edition logged.
|
||||
- **recurred phases** — any phase appearing more than once in `phaseLog`: a
|
||||
gate that had to re-run, i.e. where the rounds actually went. This is the
|
||||
signal worth reading; a phase that recurs across several editions is a
|
||||
process problem, not an edition problem.
|
||||
- **lead time** — first transition → `scheduling`, straight from the log.
|
||||
|
||||
No new measuring apparatus, no stopwatch, no asking the operator how long it
|
||||
felt. If `phaseLog` is absent (an edition started before N12), say
|
||||
"not measured" and move on — never estimate a number and present it as data.
|
||||
|
||||
3. **One process-friction question — asked once, answered by them.** Ask exactly
|
||||
one: *"Any process friction from this edition worth recording?"* Take the
|
||||
answer, hand it back in a form they can paste, and stop. **The plugin must
|
||||
never write into the operator's own notes, register, or repo** — their record
|
||||
is theirs, and a tool that files entries in someone else's log on their behalf
|
||||
is a tool they stop trusting. One question, no follow-ups, no second round.
|
||||
|
||||
While the queue is in view, name the **other accumulation silos** so the
|
||||
operator can see the whole picture in one place — specifics-bank (Step 1.5 /
|
||||
Step 8), brain-consolidate (Step 8), the voice drift log (`voice-scrubber`),
|
||||
and A/B learnings (`/linkedin:ab-test`). A retro that empties one queue while
|
||||
the others fill silently teaches the operator that everything is empty.
|
||||
|
||||
4. **Persist + close the loop.** Record the retro in `edition-state.json` →
|
||||
`articles.NN.retro` (`promoted`, `rejected`, `ruleIds`,
|
||||
`languageRulesAppended`, `effort`, `frictionNoted`, `completedAt`) and set
|
||||
`currentPhase: "retro"`.
|
||||
**↳ Phase transition** — run the protocol (Step 0) for `retro`,
|
||||
`--next "edition closed — corrections promoted"`. This appends the `retro`
|
||||
entry to `phaseLog` **and re-activates the register row** (the same
|
||||
re-activation `/linkedin:pivot` relies on), so close it again:
|
||||
|
||||
```bash
|
||||
node --import tsx "${CLAUDE_PLUGIN_ROOT}/scripts/editions/src/cli.ts" register-complete \
|
||||
--series "<slug>" --edition "<NN>"
|
||||
```
|
||||
|
||||
> **Which lead time is which.** The register row's `completedAt` now marks the
|
||||
> end of the *retro*, not of delivery. The **delivery** lead time — the number
|
||||
> the cadence work is calibrated on — is always readable exactly from
|
||||
> `phaseLog` (first entry → the `scheduling` entry), which is why the register
|
||||
> is a mirror and `edition-state.json` the source of truth. Report the
|
||||
> `phaseLog` number, not the row's.
|
||||
|
||||
Write a "retro complete — <N> promoted, <N> rejected → next edition starts
|
||||
with them enforced" line to `<serie>/STATE.md` (overwrite). The edition is
|
||||
now done.
|
||||
|
||||
```
|
||||
Retro (loop closed) — complete.
|
||||
- Fold-ins reviewed: <N> promoted: <N> (<N> mechanical → rules.ts · <N> judgment → language-rules/<lang>.md) rejected (kept): <N>
|
||||
- Ratify after promotion: ✓ in sync (or: not run — no mechanical promotion this edition)
|
||||
- Effort (measured, phaseLog): <N> transitions · recurred: <phase list or none> · lead time <N> days
|
||||
- Process friction: noted and handed back (or: none) — the operator's own register is untouched
|
||||
- Other silos in view: specifics-bank · brain · voice drift log · A/B learnings
|
||||
Edition CLOSED. The next edition starts with these corrections already enforced.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Distribution channel — native LinkedIn Newsletter vs a long-form post (honest mechanics)
|
||||
|
||||
A long edition can ship two ways: as a **regular long-form post** (what Steps 8–10
|
||||
|
|
@ -2249,6 +2422,8 @@ the honest decision surface; it sells nothing.
|
|||
- `${CLAUDE_PLUGIN_ROOT}/commands/react.md` — multi-source synthesis discipline (reused in Step 2)
|
||||
- `${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}/voice-samples/authentic-voice-samples.md` — voice matching
|
||||
- `${CLAUDE_PLUGIN_ROOT}/references/longform-quality-rules.md` — canonical long-form rules (Steps 2.5, 3a, 3b, 4–9 all reference)
|
||||
- `${CLAUDE_PLUGIN_ROOT}/references/fold-in-loop.md` — the capture → classify → promote → enforce loop (N14): Steps 2.5/3a/5.5/6.5 capture into `articles.NN.foldIns`, Step 11 promotes. Domain-general; needs no external writing contract
|
||||
- `${CLAUDE_PLUGIN_ROOT}/config/language-rules.template.md` — the operator's accumulating per-language rules (opt-in; read by Step 4 + `language-reviewer`, appended by Step 11)
|
||||
- `${CLAUDE_PLUGIN_ROOT}/render/build-linkedin.mjs` — POST.html delivery; reads `linkedin/NN/cover.png` + credit/caption (Step 8)
|
||||
- `${CLAUDE_PLUGIN_ROOT}/render/build-html.mjs` — annotatable review renderer (Step 7)
|
||||
- `${CLAUDE_PLUGIN_ROOT}/render/build-carousel.mjs` — carousel deck renderer (`## SLIDE N —` → PDF via weasyprint) — Step 7.5 carousel branch
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue