Append the S29c verification record to docs/hardening/log.md (anchored
"### S29c terminology-scrub" entry, matching S29a/S29b format): the 34-edit replacement map
across 15 reference files, the S29e filename lock (thought-leadership-angles.md ->
content-angles.md) with the canonical file's in-file title/headers scrubbed now, the
KEPT-BY-DESIGN items (ironic quote, TL;DW false positive), and the verify block (FORM A in
references/ = only the kept ironic quote; canonical in-file FORM A = NONE; FORM B unchanged 4;
filename pointers unchanged 3; gate 81/0/0; counts 29/19/26/6 unchanged). Documents fix commit
25b356f.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016qgzo6rxthw7KuxHjn5vyE
157 KiB
LinkedIn Studio — Command Hardening Log
Per-command audit trail for the hardening phase (
docs/hardening/brief.md+plan.md). One anchored entry per command surface. The operator's parallel live-testing cross-references every change here.Entry contract (SC-A…SC-E). Each entry begins with the UNIQUE anchored header
### /linkedin:<command-name> — <one-line intent>(coverage greps^### /linkedin:<name>, never the bare word). Every entry carries: INTENT · SIMULATE (persona + the CONCRETE before-output + friction log) · EVALUATE (4 axes, with the per-type mechanical predicate — never "N/A → judgment") · HARDEN (surgical diff + concrete after-output, or "no edit — passes") · VERIFY (lintFailed: 0+ counts
- the failing axis now passes). The cold
/trekreviewreviewer adjudicates every hardened command's before/after — the author does not self-certify.Mechanical-predicate classes: post-emitting (hook 110–140 · length band · no body link · no banned buzzword · topic→5 pillars) · routing (every emitted target resolves to a real
commands/<x>.md) · analytics (graceful-degradation present + saves/dwell honesty intact) · guided/stateful (primary promised artifact actually produced; promisedsubagent_typetargets resolve).Stopping rule (anti-gold-plating): harden until every axis returns pass OR a recorded deferral; no NICE-only polish beyond axis-pass.
Method discipline (learned the hard way in the S1 calibration — three stumbles). Write the HARDEN / after-output section only from the applied + re-grepped diff, and assert a gap only after reading the actual file line. Every number (char counts, edit counts) must come from a tool, not from memory. The S1 calibration produced three assert-before-verify errors — (1) a non-existent inline buzzword list in
quick, (2) a non-existent "unused Task" inquick, (3)onboarding/first-postedits asserted as landed when the Edits had failed on wrong strings, plus a false "25 commands → stale" claim (the file already said 29). All were caught by failed Edits / empty greps / the git status, and corrected here. This is exactly the failure mode the independent/trekrevieworacle exists to catch — verify-before-assert is part of the method, not optional.
Session 1 — Method calibration (quick) + Start journey
S1 status: calibration corrected + method locked (operator, 2026-05-31). onboarding / first-post / setup follow below under the same entry shape. Field-notes inbox: absent at S1 start → graceful no-op (SC-I).
/linkedin:quick — 5-minute 3-line post from a topic, ≤1 question, clipboard-ready
INTENT. quick is the Create journey's speed path: a topic in → a publishable
150–500-char post out in ~5 minutes, max one question, auto-copied to clipboard. It must
honor the content-quality bar mechanically (hook 110–140, length 150–500, no body
links, no banned buzzword, topic maps to one of the 5 pillars, exactly one CTA) and the
algorithm bar (hook decisive before the mobile fold; links to first comment not body;
native; a CTA that invites comments without manufactured engagement-bait). Its defining
constraint is speed — "skip interrogation, generate immediately."
SIMULATE.
-
Persona (ICP): the author — 1048 followers, "Validation", 5 pillars; voice = direct/technical/low-formality, NO/EN mix, short sentences, contrarian openings (grounded in the state file + the gitignored
authentic-voice-samples.local.mdthe command reads at runtime).recent_posts: []→ no rotation conflict. Fresh-adopter path (no voice samples) reasoned, not separately re-drafted:quickreads voice from SKILL.md and falls back to defaults; the personalization score is hidden < 3 posts and the voice guardian is suppressed < 5 samples — degrades cleanly, no block, no dead-end. -
Invocation:
/linkedin:quick AI-kodeassistenter i offentlig sektor(pillars "AI-rådgivning i offentlig sektor" / "Claude Code / agentisk koding"). -
Walk: topic from
$ARGUMENTS(no question) → load voice + pillars → infer type (HOT TAKE — contrarian) → 3-line formula → auto-CTA → quality check → de-AI/differentiation gate (skip unless commodity) → clipboard → present. -
CONCRETE before-output (produced under
quick.mdas written, pre-fix):Alle vil ha AI-kodeassistenter i staten. Men hvem tar ansvaret når koden tar feil i produksjon?
Verktøyet skriver koden på sekunder. Ansvaret for at den er riktig flyttes ikke — det blir ditt, raskere enn før.
Hvordan kvalitetssikrer dere AI-generert kode hos dere?
(Pillar: Claude Code / agentisk koding · type: HOT TAKE · hook = 95 chars (node-verified) · body has 0 links / 0 buzzwords.)
-
Friction log: the 95-char hook passes
quick.md's own checks — Step 2 said "Hook (under 140 characters)" and the Step 5 checklist asked "Hook works in 140 chars?", both upper-bound only — yet it breaks the canonical 110 floor (the PreToolUse gate: "under 110: wasting prime real estate"). Same one-sidedness on length ("Under 500?" vs the 150–500 band). The Step 5 checklist also had no buzzword line, and a quick post is auto-copied to clipboard (no file Write), so the PreToolUse file gate may not fire — the checklist is the load-bearing surface. No dead-ends.
EVALUATE (4 axes).
- (a) intention fidelity — PASS. One-question speed path, 3-line formula, 8 templates,
auto-CTA, clipboard, why-hook/reach tips,
/linkedin:postupgrade path — delivers the promise. - (b) algorithm bar — PASS. No body link (links → first comment); native; CTA invites
comments (comments > reactions) without bait; de-AI gate cites the confirmed low-substance
down-rank. Consistent with
references/algorithm-signals-reference.md. - (c) MECHANICAL predicate (post-emitting) — GAP → fixed. no body link ✓ · topic→pillar ✓ · hook band ✗ (spec + checklist enforced ≤140, omitted the 110 floor; the 95-char before-hook is the live proof) · length band ✗ (checklist enforced <500, omitted the 150 floor) · buzzword ✗ (no checklist line; clipboard path bypasses the file gate).
- (d) agent-wiring + graceful degradation — PASS (verified).
quickconditionally delegates todifferentiation-checkerviaTask(quick.md:151,subagent_type: linkedin-studio:differentiation-checker) — only when the take is commodity, preserving the 5-minute promise by default.Taskinallowed-toolsis therefore used, not vestigial. Fresh-adopter degradation works (defaults; guardian suppressed < 5 samples).
HARDEN (surgical — 2 edits, axis-c only — both grep-confirmed landed).
-
commands/quick.md:68—**Line 1: Hook (under 140 characters)**→**Line 1: Hook (110-140 characters)**. -
commands/quick.mdStep 5 checklist — hook check"Hook works in 140 chars?"→"Hook in the 110-140 band (not just under 140)?"; length check"Under 500 characters?"→"In the 150-500 band (not just under 500)?"; added"No corporate buzzwords?"; count**All 6 = Yes?**→**All 7 = Yes?**. -
Deferrals: none (the earlier "incomplete buzzword list" and "unused Task" findings were file-misreads, struck — see Method discipline).
-
CONCRETE after-output (under the hardened spec — hook expanded into the 110–140 band):
Alle vil ha AI-kodeassistenter i staten. Få spør hvem som tar ansvaret når assistenten foreslår noe ingen kan forklare etterpå.
Verktøyet skriver koden på sekunder. Ansvaret for at den er riktig flyttes ikke — det blir ditt, raskere enn før.
Hvordan kvalitetssikrer dere AI-generert kode hos dere?
(hook = 127 chars (node-verified, in band) · 0 body links · 0 buzzwords · same pillar.)
VERIFY.
bash scripts/test-runner.sh→Failed: 0+ exit 0 + counts 29/19/25/6 unchanged (re-run AFTER the real edits; recorded at the session gate).- Before/after delta: axis (c) failing sub-checks (hook 110 floor, length 150 floor,
buzzword) now pass — the 95-char before-hook slips
quick.md's old checks; the hardened checklist catches it and the after-hook is 127 chars, buzzword-clean. The two edits are the cause. - Disposition: HARDENED (2 edits, axis-c) · 0 deferrals · axes a/b/d PASS.
/linkedin:onboarding — zero→published first post as one guided wizard (Start front-door)
INTENT. Multi-phase wizard taking a brand-new user from zero to a published first post as one cohesive flow (profile → personalization → first-post), so they don't navigate the full command surface alone. Primary artifacts: a saved profile + a drafted first post (the S15-B1 inline-draft). Guided/stateful; inlines rather than spawning subagents.
SIMULATE.
- Persona (fresh adopter — the right persona here): just installed, no profile, no voice
samples,
recent_posts: []. - Invocation:
/linkedin:onboarding. - Walk: Phase 0 already-onboarded check → Phase 1 profile/topic-relevance checklist → Phase 2 personalization (voice + user profile, or defaults when < 3 posts) → Phase 3 first post (3.1 topic → 3.2 3-line draft → 3.3 quality check → 3.4 present+clipboard → 3.5 record) → Phase 4 summary. CONCRETE artifact produced: a refined first-post inline draft (S15-B1 path — spot-confirmed still delivers: Phase 3.2 "Draft the post… Line 1/2/3", 3.4 "present and copy").
- Friction log: Phase 3.2 said "Line 1 — Hook (under 140 chars)" and the Phase 3.3 check asked "Hook works in 140 chars?" — both upper-bound only, so a 95-char hook would pass while breaking the 110 floor. (Phase 3.2 line 204 already states "150-500 characters" + "No external links in the post body", so length + links were NOT gaps — only the hook floor.) The description + Phase-4 tip hardcode "29 commands" — accurate today, not stale (an earlier "25 commands" claim was a misread, struck).
EVALUATE (4 axes).
- (a) intention fidelity — PASS. Cohesive zero→post wizard; S15-B1 inline draft holds (Phase 3).
- (b) algorithm bar — GAP → fixed. Phase 3 emitted a post but enforced only the hook upper bound; now the full 110–140 band (length 150–500 + no-body-links were already present).
- (c) MECHANICAL predicate (guided/stateful) — PASS; one post-emitting sub-check fixed. Primary artifact (first-post draft) produced ✓; the one-sided hook bound in Phase 3.2 + 3.3 closed.
- (d) agent-wiring + graceful degradation — PASS. No
Taskinallowed-tools— onboarding inlines every step (Phase 2 "delegate to setup" = inline its logic; commands aren't subagents, so no brokensubagent_type). Built for the no-profile path; degrades cleanly.
HARDEN (surgical — 2 edits, hook floor — both grep-confirmed landed).
commands/onboarding.md:200—**Line 1 — Hook (under 140 chars):**→**Line 1 — Hook (110-140 chars):**.commands/onboarding.md:209(Phase 3.3 check) —Hook works in 140 chars?→Hook in the 110-140 band (not just under 140)?.- Deferred (NICE-only, stopping rule): the hardcoded "29 commands" (description + Phase-4 tip) is correct now; making it count-free is drift-proofing, not an axis fix → recorded, not edited.
VERIFY. lint Failed: 0 + counts unchanged (recorded at gate); S15-B1 inline-draft
spot-confirmed; hook floor now enforced in Phase 3.2 + 3.3. Disposition: HARDENED (2 edits) ·
1 recorded deferral.
/linkedin:first-post — zero→published in <10 min, maximum hand-holding
INTENT. First-post accelerator: from "never posted" to "just published" in <10 min, breaking the blank-page barrier. Produces one published first post. Guided/stateful; inlines.
SIMULATE.
- Persona (fresh adopter): no profile (Step 2 offers a voice quick-setup or 5-question calibration; proceeds either way — momentum over completeness).
- Invocation:
/linkedin:first-post. - Walk: Step 1 welcome → Step 2 voice setup (samples or 5 Qs; graceful if none) → Step 3 topic (5 angles) → Step 4 write (3-line formula) → Step 5 simplified quality check → Step 6 present + clipboard → Step 7 record → Step 8 first-hour engagement guidance.
- CONCRETE before (the gap): Step 4 "Line 1: Hook (under 140 characters)" and the Step 5 check "Hook works in 140 chars?" were both upper-bound only — a 95-char hook would pass. (Step 4 already states "Target: 150-500 characters" and "No external links in the post body", so length + links were NOT gaps — only the hook floor.)
- Friction log: the hook bound was one-sided in Step 4 + Step 5; length + no-links already covered.
EVALUATE (4 axes).
- (a) intention fidelity — PASS. Delivers zero→published with hand-holding; first-hour guidance present.
- (b) algorithm bar — PASS. First-hour engagement window cited; no-body-links already in Step 4 tips.
- (c) MECHANICAL predicate (post-emitting) — GAP → fixed. Hook bound was upper-only in Step 4 + Step 5; now the full 110–140 band (length 150–500 + no-body-links already present).
- (d) agent-wiring + graceful degradation — PASS. No
Task; inlines; no-profile/no-samples path graceful. Differentiation-checker deliberately skipped (a first post optimizes for momentum).
HARDEN (surgical — 2 edits, hook floor — both grep-confirmed landed).
commands/first-post.md:101—**Line 1: Hook (under 140 characters)**→**Line 1: Hook (110-140 characters)**.commands/first-post.md:125(Step 5 check) —Hook works in 140 chars?→Hook in the 110-140 band (not just under 140)?.- Deferrals: none.
VERIFY. lint Failed: 0 + counts unchanged; Step 4 ↔ Step 5 hook bound now consistent (both 110-140).
Disposition: HARDENED (2 edits) · 0 deferrals.
/linkedin:setup — guided personalization (5 pillars + voice profile + prefs)
INTENT. Build the user's voice profile, expertise pillars, and content preferences into the state/asset files so every post sounds like them. Primary artifact: a populated voice profile + populated asset templates (8-category personalization score). Guided/stateful; delegates voice to an agent.
SIMULATE.
- Persona (fresh adopter): no existing data (all templates at placeholder).
- Invocation:
/linkedin:setup. - Walk: Step 0 calculate score → Step 1 dashboard → Step 2 choose what to set up → Step 3a–3f
sub-workflows (voice / case study / framework / post analysis / demographics / user profile) →
Step 4 recalculate → Step 5 continue or exit. CONCRETE artifact: e.g. Step 3a writes a real
voice profile to
assets/voice-samples/authentic-voice-samples.md(placeholder sentinel removed). - Friction log: none — no dead-ends, no ambiguous steps.
EVALUATE (4 axes).
- (a) intention fidelity — PASS. Delivers the personalization the description promises (score + 6 sub-flows).
- (b) algorithm bar — PASS (n/a-direct). Emits no post; the expertise/pillar capture is the topic-relevance foundation the bar depends on.
- (c) MECHANICAL predicate (guided/stateful) — PASS. Primary artifact (populated profile/assets)
produced ✓; the promised
subagent_type: linkedin-studio:voice-trainer(setup.md:86) resolves to a realagents/voice-trainer.md(verified). - (d) agent-wiring + graceful degradation — PASS. voice-trainer invoked via
Task(correct namespaced type); the placeholder-sentinel logic is explicit; samples optional → degrades if none.
HARDEN. No edit — passes all four axes. (Demonstrates a legitimate zero-edit pass; per the
plan, "command file modified" is not a coverage predicate — the log.md entry + /trekreview are.)
VERIFY. lint Failed: 0 + counts unchanged; voice-trainer target resolves.
Disposition: PASS, no edit · 0 deferrals.
Session 2 — Create I (post)
S2 status: the v1 autonomous attempt fabricated and was reverted (→ v2 method; see
plan.mdheader). This is the v2 re-run: parked at step 5 across a/clear, re-grounded from STATE.md's two P4 findings against the actual file lines before talking (jerndisiplin: assert-after-read). Field-notes inbox absent at S2 → graceful no-op (SC-I).
/linkedin:post — interactive full-workflow post (angle→write→quality→refine→publish), 1200–1800 chars
INTENT. post is the Create journey's full path: from raw material (data / article / experience /
observation / opinion / question) to a publishable 1,200–1,800-char thought-leadership post via an
8-step workflow — angle → format → structure+write → quality check → present → refine → pre-publish
→ deterministic state update. Post-emitting, so it must honor the content bar mechanically (hook
110–140, length 1,200–1,800, no body links, no banned buzzword, topic→5 pillars) and the
algorithm bar (hook decisive before the mobile fold, links→first comment, native, comment-inviting
CTA without bait, de-AI substance signals).
SIMULATE.
- Persona (ICP): the author — 1048 followers, "Validation", 5 pillars; direct/technical NO/EN voice.
- Invocation:
/linkedin:post about AI-kodeassistenter i offentlig sektor. - Walk: Step 0 load state/SKILL → Step 1 type=Opinion → Step 2 angle (contrarian) → Step 3 medium text → Step 4 structure (hook 110–140 ✓ internally) → Step 5 quality check (the gap) → Step 6 present+clipboard → Step 7 refine → Step 8 pre-publish + state.
- CONCRETE friction (spec-level, the live proof — anchored, not a generated post): at Step 5
the quality checklist (
post.md:127–135, 9 items) had no buzzword line, so a draft opening "How to leverage AI to drive synergy in the public sector…" would pass Step 5 unflagged — the banned-list (content rule #4,CLAUDE.md:124) was never enforced at the gate. Step 5 also routes toquality-scorecard.md(post.md:125), which self-contradicted on the hook bound: l.32 "Works in 140 characters" + l.114 "Hook works in 140 chars?" (upper-only) vs l.128 "110-140" — the same one-sided bound S1 fixed in the command files, surviving in the shared asset. - Friction log:
post.mditself is internally consistent on the hook (110–140 at l.100/113/127); the only command-side gap is the missing Step-5 buzzword line. The shared scorecard carried both gaps (buzzword absent + two one-sided hook bounds). Scorecard is shared by 8 surfaces (pipeline · video · post · react · batch+ 3 skills) — fixing it is high-leverage, operator-approved.
EVALUATE (4 axes).
- (a) intention fidelity — PASS. Full 8-step workflow delivers the description's promise.
- (b) algorithm bar — PASS. No body link (
post.md:133/176); comment-inviting CTA; de-AI gate cites the confirmed reach-suppression (post.md:137–141). Consistent withalgorithm-signals-reference.md. - (c) MECHANICAL predicate (post-emitting) — GAP → fixed. hook band ✓ · length band ✓ · no-body-link ✓ · topic→pillars ✓ · subagent resolves ✓ · buzzword ✗ (Step-5 checklist had no line; grep NONE). Shared scorecard added two sub-gaps: hook one-sided at l.32 + l.114.
- (d) agent-wiring + graceful degradation — PASS.
differentiation-checker(post.md:141, conditional) +content-optimizer(post.md:166, conditional) both resolve, both correctlysubagent_type: linkedin-studio:-namespaced. Voice→defaults; fresh-adopter path graceful.
HARDEN (surgical — 4 edits across 2 files, all grep-confirmed landed).
commands/post.md:134— added Step-5 checklist line:- [ ] No corporate buzzwords (leverage, synergy, paradigm shift, thought leader, disruptive, value proposition, ecosystem, holistic approach).assets/checklists/quality-scorecard.md:32—Works in 140 characters→Works in 110-140 characters(NotesMobile threshold→Mobile band (floor + ceiling)).assets/checklists/quality-scorecard.md:114—Hook works in 140 chars?→Hook works in 110-140 chars?.assets/checklists/quality-scorecard.md:132— added Pre-Publish Basic Checklist line:- [ ] No corporate buzzwords (…)(same banned list).- Deferrals: none. Scope note: the 3 scorecard edits improve all 8 consumers; only
postis hardened this session —react/batch/video/pipelineget their own EVALUATE in S3/S5/S6/S8.
VERIFY.
bash scripts/test-runner.sh→Passed: 81 · Failed: 0 · Warnings: 0; counts 29/19/26/6 unchanged.- Anti-check grep: no one-sided bare
140 charhook bound remains in the scorecard (110-140at l.32/114/128). Buzzword line present in both files (post.md:134,quality-scorecard.md:132). - Before/after delta: axis (c) buzzword sub-check now enforced at the load-bearing Step-5 gate; the scorecard hook self-contradiction is resolved (all three mentions banded). The 4 edits are the cause.
- Disposition: HARDENED (4 edits, axis-c + shared-asset consistency) · 0 deferrals · axes a/b/d PASS.
Session 3 — Create I (react)
S3 status: re-grounded STATE's S3 predicate against the actual
react.mdlines BEFORE talk (jerndisiplin: assert-after-read). Field-notes inbox absent at S3 → graceful no-op (SC-I). Allfile:linebelow are tool-grounded against the FINAL (post-edit) file.
/linkedin:react — URL-to-post pipeline (single + comparison), your-take-as-hook, 1,200–1,800 chars
INTENT. react is the Create journey's URL→post path: fetch external content
(article / news / research / YouTube), extract the key points, pick an angle, and draft in the
author's voice. Post-emitting (medium 1,200–1,800), two paths — single-URL (Steps 1–8) +
comparison/multi-URL (Steps 1b–8b). Must honor the content bar mechanically (hook 110–140,
length 1,200–1,800, no body link, no banned buzzword, topic→5 pillars) and the algorithm bar
(URL→first comment not body, post stands alone, your reaction is the hook not a summary,
comment-inviting CTA, de-AI substance). Distinct from post/quick: the value-add is YOUR
perspective extending the source, not echoing it — the commodity-reaction guard (differentiation-checker).
SIMULATE.
- Persona (ICP): the author — 1048 followers, "Validation", 5 pillars; direct/technical NO/EN voice.
- Invocation:
/linkedin:react <public-sector-AI news URL>. - Walk: Step 0 load → Step 1 single URL → Step 2 WebFetch extract → Step 3 classify (Product Launch) → Step 4 angle (First-Take Analysis) → Step 5 draft (hook 110–140 ✓) → Step 6 quality check (the gap) → Step 7 present+clipboard → Step 8 state.
- CONCRETE friction (spec-level, anchored — not a generated post): at Step 6 the quality
checklist (pre-edit
react.md:122–128, 7 items) enforced hook/links/standalone/voice/charcount/ topic/CTA but had no buzzword line, so a draft opening "This launch lets agencies leverage AI to unlock synergy across the value proposition…" passes unflagged — the banned-list (content rule #4,CLAUDE.md:124) was never enforced at the gate. Step 6b (:237"Same as Step 6, plus") inherits the hole.reactauto-copies to clipboard (:144–148, no file Write) → the PreToolUse file gate may not fire → Step 6 is the load-bearing surface. Same gap S2 fixed inpost. - Second friction (axis d, URL-pipeline-specific):
grepfor fetch-failure/paywall/transcript/ fallback → NONE. Step 2 (:54) "Use WebFetch to extract" had no fallback when extraction yields nothing (paywall / JS-heavy SPA / YouTube-no-transcript — an explicitly accepted input,:37/:71); Step 2b (:185) same. Risk: proceed on a thin/empty extraction or fabricate from the URL string.
EVALUATE (4 axes).
- (a) intention fidelity — PASS. Both paths, angle selection, your-take-not-summary, commodity guard, clipboard, URL→first comment — delivers the description's promise.
- (b) algorithm bar — PASS. No body link (
react.md:115/125/235); URL→first comment (:116/:144/:253); stands alone (:118/:126); take-as-hook (:101/:118); de-AI gate bans mechanical engagement-bait (:135–137). Consistent withreferences/algorithm-signals-reference.md. - (c) MECHANICAL predicate (post-emitting) — GAP → fixed. hook band ✓ (
:101/:124/:221) · length band ✓ (:119/:128/:239) · no-body-link ✓ (:115/:125/:235) · topic→pillars ✓ (:129) · subagent resolves ✓ (:137→agents/differentiation-checker.md) · buzzword ✗ (grep NONE; no inline line in Step 6/6b). - (d) agent-wiring + graceful degradation — wiring PASS; degradation GAP → fixed.
differentiation-checkerresolves, namespaced, conditional (:137). Graceful degradation: no WebFetch-failure/empty-extraction fallback on EITHER path (grep NONE) — YouTube-no-transcript the sharpest, since it is a stated accepted input. - Shared asset:
quality-scorecard.mdalready clean post-S2 (110-140at:32/:114/:128+ buzzword:132) —react's referenced asset (react.md:270) is good; the gap wasreact's OWN inline Step 6.
HARDEN (surgical — 3 edits, 1 file, all grep-confirmed landed).
commands/react.md:131— added Step-6 checklist line:- [ ] No corporate buzzwords (leverage, synergy, paradigm shift, thought leader, disruptive, value proposition, ecosystem, holistic approach). Covers Step 6b via "Same as Step 6".commands/react.md:60— added Step-2 WebFetch fallback: "If WebFetch can't extract usable content (paywall / JS-heavy / YouTube-no-transcript): say so, ask the user to paste the key points or choose another URL; never fabricate from the URL string or title."commands/react.md:194— added Step-2b pointer: "If a source can't be extracted: apply the Step 2 fallback — drop it if 2+ usable sources remain, else ask the user; never fabricate."- Deferrals: none.
- CONCRETE after: the "leverage…synergy…value proposition" draft now trips the Step-6 buzzword line; a YouTube-no-transcript invocation now degrades to "paste the key points / pick another URL" instead of a fabricated reaction.
VERIFY.
bash scripts/test-runner.sh→Passed: 81 · Failed: 0 · Warnings: 0; counts 29/19/26/6 unchanged (ls commands/*.md | wc -l== 29;git diff --stat=react.mdonly, +5 insertions, 0 deletions).- Before/after delta: axis (c) buzzword sub-check now enforced at the load-bearing Step-6 gate (both paths via "Same as Step 6"); axis (d) WebFetch-failure now has a sensible fallback on both paths. The 3 edits are the cause.
- Disposition: HARDENED (3 edits, axis-c + axis-d) · 0 deferrals · axes a/b PASS.
Session 4 — Create III (multiplatform)
S4 status: re-grounded the proposed predicates against the actual
multiplatform.mdlines BEFORE talk (jerndisiplin: assert-after-read). Field-notes inbox absent at S4 → graceful no-op (SC-I). Allfile:linebelow are tool-grounded against the FINAL (post-edit) file. Class call (operator-agreed): NOT post-emitting — output is Twitter/slides/YouTube, so the LinkedIn content predicates (hook 110–140, length band, no-body-link, topic→5 pillars) do not apply per platform; imposing them here would be the exact category error the Create-III brief warns against. Tested as guided/cross-format with a routing sub-predicate.
/linkedin:multiplatform — adapt existing LinkedIn content to short-/cross-format (Twitter thread · slides · YouTube script)
INTENT. multiplatform is the Create journey's cross-format adapter: take existing LinkedIn
content and re-shape it for other platforms (Twitter/X thread, presentation slides, YouTube script) —
write once, publish everywhere. It explicitly does not own long-form (newsletters / blog / essays
→ /linkedin:newsletter, the single long-form entry point). It is an adapter, not a post-generator:
the value-add is adaptation fidelity (each platform's own rules) + correct routing of out-of-scope
(long-form) requests, not LinkedIn-feed quality gating.
SIMULATE.
- Persona (ICP): the author — a finished LinkedIn post in drafts, wants to reuse it as a Twitter thread.
- Invocation:
/linkedin:multiplatform→ pick "Twitter/X thread". - Walk: Step 0 (
:21) load source fromdrafts/+ state → Step 1 (:31) AskUserQuestion pick Twitter → Twitter template (:53, hook ≤280 + 🧵 + one-idea tweets + CTA) → Step 2 (:115) savedrafts/multiplatform/twitter-[slug].md(:118) + clipboard, "Copied" (:123). Promised artifact produced. - CONCRETE friction (axis d, adapter-specific — anchored, not a generated post):
grepfor an empty-source / fabrication guard in Step 0 → only matched l.23 "Ask the user to provide … or read from drafts" — no fallback for the case where drafts is empty/absent, state has no recent posts, AND the user pasted nothing. Risk: the model fabricates a LinkedIn post to adapt rather than stopping. (Same failure class as S3's WebFetch-no-extraction gap.) - Second friction (axis c, voice hygiene): the banned-buzzword list (content rule #4) is platform-agnostic voice hygiene, not a char rule — and adaptation rewrites the source (condense the hook to 280, expand to a script), which can introduce buzzwords absent from the clean source. Pre-edit the file mentioned buzzwords nowhere (full read). Operator-judged in scope (light line, not a full gate).
EVALUATE (4 axes).
- (a) intention fidelity — PASS. Three adapters (Twitter/slides/YouTube), source-loading, save + clipboard, long-form correctly delegated — delivers the description's promise.
- (b) algorithm/platform bar — PASS. Per-platform rules correct, no LinkedIn-rule leak:
Twitter "280 chars max" (
:53); no110/140hook band anywhere in the file (grep NONE — the desired result for a non-LinkedIn surface). Long-form routing intact (see (c)). - (c) MECHANICAL predicate (routing sub-predicate) — PASS; voice-hygiene sub-gap fixed. Every
emitted
/linkedin:newsletter(:6/:34/:36/:132) resolves to a realcommands/newsletter.md(verified, ls) ✓; both reference files resolve —references/linkedin-formats.md(:128) +engagement-frameworks.md(:129) (verified, ls) ✓. Buzzword voice-hygiene line absent → added (:45). - (d) agent-wiring + graceful degradation — wiring N/A; degradation GAP → fixed. No subagents
invoked (
grep subagent_type→ NONE — nothing to resolve). Graceful degradation: no empty-source/fabrication guard in Step 0 (grep matched only the weak "ask … or read from drafts") → added a stop-and-ask-never-fabricate fallback (:28).
HARDEN (surgical — 2 edits, 1 file, both grep-confirmed landed).
commands/multiplatform.md:28— added Step-0 empty-source fallback: "If none of these yields source content (empty/absent drafts, no recent posts, and nothing pasted), stop and ask the user to paste the LinkedIn post to adapt — never fabricate source content to adapt."commands/multiplatform.md:45— added an "Adaptation Templates" voice-hygiene blockquote: "adaptation rewrites the source — keep the adapted copy free of the banned corporate buzzwords (content rule #4: leverage, synergy, paradigm shift, thought leader, disruptive, value proposition, ecosystem, holistic approach) on every platform; don't let the rewrite introduce them."- Deferrals: none. Scope note (flagged, not touched): Step 2's "Copied to clipboard." (
:123) is unconditional, butclipboard-helper.mjsis shared, tested infra used identically by ~9 content commands — re-gating it here would be scope-creep into a shared pattern (surgical discipline).
VERIFY.
bash scripts/test-runner.sh→Passed: 81 · Failed: 0 · Warnings: 0; counts 29/19/26/6 unchanged (ls commands/*.md|wc -l== 29,ls agents/*.md|wc -l== 19;git diff --stat=multiplatform.mdonly, +9 insertions, 0 deletions).- Before/after delta: axis (d) empty-source now degrades to "paste the post / never fabricate" instead of an invented source; axis (c) the rewrite is now bound by the banned-buzzword list on every platform. The 2 edits are the cause.
- Disposition: HARDENED (2 edits, axis-c + axis-d) · 0 deferrals · axes a/b PASS · class confirmed non-post-emitting (no LinkedIn predicate imposed).
Session 5 — Create II (carousel)
S5 status: re-grounded the proposed predicates against the actual
carousel.mdlines BEFORE talk (jerndisiplin: assert-after-read). Field-notes inbox absent at S5 → graceful no-op (SC-I). Allfile:linebelow are tool-grounded against the FINAL (post-edit) file. Class call (operator-agreed): hybrid guided/stateful + post-emitting on the caption — the deck/images are the guided artifact, but the caption IS LinkedIn feed text, so the post predicates apply to the caption (not to the slides). Slides are bound by mobile-readability rules, not the feed bar.
/linkedin:carousel — template→slide-by-slide deck + caption + optional mcp-image, full deck to clipboard
INTENT. carousel is the Create journey's document-post path: from a chosen template
(How-To / Listicle / Story / Comparison / Framework) + a topic, produce a publish-ready carousel —
structured slide-by-slide copy (header + body + visual note per slide) + a feed caption + optional
slide images (mcp-image), all assembled into ONE clipboard payload. Carousels/documents are the
top organic format (~7%; references/algorithm-signals-reference.md). Hybrid class: the deck is the
guided/stateful artifact; the caption is post-emitting and must honor the content bar mechanically
on the caption (hook 110–140, no banned buzzword, topic→5 pillars) + graceful mcp-image degradation.
SIMULATE.
- Persona (ICP): the author — 1048 followers, "Validation", 5 pillars; direct/technical NO/EN voice. Builds a How-To Guide carousel on a pillar topic; tested both mcp-image-available and -unavailable.
- Invocation:
/linkedin:carousel→ pick template 1 (How-To) → topic + audience. - Walk: Step 0 (
:24) load state/voice/recent → Step 1 (:30) AskUserQuestion template → Step 2 (:50) topic+audience → Step 3 (:58) slide copy → Step 4 (:94) caption (hook 110–140:97, band 300–500:103) → Step 5 quality + De-AI gate (the gap) → Step 5.5 (:127) mcp-image (graceful) → Step 6 (:156) present full deck → clipboard one-payload (:191–213) → Step 7 (:218) state. - CONCRETE friction (spec-level, anchored — not a generated deck): at Step 5 the De-AI /
Differentiation gate (pre-edit
:121–123) confirmed personal substance · original thinking · concrete specifics · genuine voice and banned mechanical engagement-bait, but had no buzzword line —grep -niE "buzzword|leverage|synergy|paradigm"over the whole file = NONE. So a caption opening "How to leverage AI to drive synergy across the public-sector ecosystem…" would pass Step 5 unflagged; content rule #4 (CLAUDE.md:124) was never enforced at the caption gate. Same failure class S2/S3 fixed inpost/react. (Caption generation in Step 4 is exactly where a rewrite can slip buzzwords in.) - No dead-ends: all 5 referenced files exist (
agents/differentiation-checker.md,assets/templates/carousel-templates.md,references/algorithm-signals-reference.md,hooks/scripts/clipboard-helper.mjs,hooks/scripts/state-updater.mjs—[ -f ]all FINNES).
EVALUATE (4 axes).
- (a) intention fidelity — PASS. Template→slides→caption→full-deck-clipboard-as-one-payload
(
:191–213, explicitly "the whole carousel, not just the caption") + state — delivers the promise. - (b) algorithm bar — PASS. ~7% (
:37) matches the ref exactly (algorithm-signals-reference.md:55, "Documents / carousels | Top organic format (~7%…)"); "document post" framing correct (:170, LinkedIn removed native carousels Dec 2023); caption hook 110–140 (:97). - (c) MECHANICAL predicate (post-emitting, on the caption) — GAP → fixed. hook band ✓ (
:97) · caption band 300–500 ✓ (:103) · topic→pillars ✓ (:26/:56) · subagent resolves ✓ (:125) · buzzword ✗ (grep NONE; De-AI gate had no rule-#4 line). no-body-link not imposed: a carousel caption is not a typical link site and the command never asks for links — minor, deferred (matches S2–S4 which left it untouched). - (d) agent-wiring + graceful degradation — PASS.
differentiation-checkerresolves, namespaced, conditional (:125,subagent_type: linkedin-studio:differentiation-checker). mcp-image graceful degradation solid: "If mcp-image is unavailable or fails, skip… degrades to text-only" (:129), per-call failure logged + continue, all-fail → text-only Step-6 design-guide branch (:154,:176).state-updaterexportsupdatePostTracking(:55) +writeState(:346) — Step-7 wiring correct.
HARDEN (surgical — 1 edit, 1 file, grep-confirmed landed).
commands/carousel.md:123— extended the Step-5 De-AI gate with content rule #4:**Strip corporate buzzwords** from the caption (Content Quality Rule #4: leverage, synergy, paradigm shift, thought leader, disruptive, value proposition, ecosystem, holistic approach) — caption generation can slip them in, and they trip the same low-substance signal.- Deferrals: no-body-link on the caption (low risk, command never emits links; S2–S4 precedent)
- two cosmetic notes recorded, not edited (slide line-count 5 vs 7 between
:73–77and:87; both are NICE-only, below the stopping-rule's axis-pass bar).
- two cosmetic notes recorded, not edited (slide line-count 5 vs 7 between
- CONCRETE after: the "leverage…synergy…ecosystem" caption now trips the Step-5 buzzword line before the deck is presented.
VERIFY.
bash scripts/test-runner.sh→Passed: 81 · Failed: 0 · Warnings: 0; counts 29/19/26/6 unchanged (ls commands/*.md|wc -l== 29,ls agents/*.md|wc -l== 19;git diff --stat=carousel.mdonly, 1 line changed). Only.mdtouched → hooks/analyticsnode --testnot needed.- Before/after delta: axis (c) buzzword sub-check now enforced at the load-bearing Step-5 caption gate. The 1 edit is the cause.
- Disposition: HARDENED (1 edit, axis-c) · 2 recorded deferrals (no-body-link + cosmetic) · axes a/b/d PASS.
Session 6 — Create II (video)
S6 status: re-grounded the proposed predicates against the actual
video.mdlines BEFORE talk (jerndisiplin: assert-after-read). Field-notes inbox absent at S6 → graceful no-op (SC-I). Allfile:linebelow are tool-grounded against the FINAL (post-edit) file. Class call (operator-agreed): hybrid guided/stateful + post-emitting on the post caption — the script / captions / thumbnail are the guided artifact (bound by video rules: muted-autoplay, 2.5 wps, completion-rate), but the POST CAPTION (200–400) IS LinkedIn feed text, so the post predicates apply to the caption (not the script). Hook 110–140 deliberately NOT imposed on the caption (operator-agreed): the caption accompanies the video; the primary hook discipline is the muted-autoplay opening (:100), not a standalone-post hook — imposing it would be S4's category error.
/linkedin:video — type→length→angle→video-scripter script + captions + 200–400 post caption + first comment
INTENT. video is the Create journey's video-script path: from type (talking-head / screen-rec /
slideshow / convert-a-text-post) + length (30/60/90/120 s) produce a production-ready script via the
video-scripter agent — timing markers, visual/energy cues, captions, thumbnail, a 200–400-char post
caption, and a first comment — then save to drafts + deterministic state update. Hybrid class: the script
is the guided/stateful artifact; the post caption is post-emitting and must honor the content bar
mechanically on the caption (no banned buzzword, topic→5 pillars, no body link) + 2.5-wps pacing +
graceful degradation when voice samples are absent.
SIMULATE.
- Persona (ICP): the author — 1048 followers, "Validation", 5 pillars; direct/technical NO/EN voice. Builds a 60-s talking-head on a pillar topic. + fresh-adopter path (no voice samples) reasoned to exercise graceful degradation (relevant here because of the pre-edit "REQUIRED before scripting").
- Invocation:
/linkedin:video→ talking-head → 60 s → pillar topic. - Walk: Step 0 load state/voice/refs → Step 1 type → Step 2 length (2.5-wps budgets) → Step 3 angle
(topic→pillars) → Step 4
video-scriptergenerates → Step 5 quality + De-AI gate (the gap) → Step 6 present + clipboard post caption → Step 7 refine → Step 8 save + state. - CONCRETE friction (spec-level, anchored — not a generated script):
- (axis c) at Step 5 the only buzzword line (
:106, pre-edit) sat under the "Natural Speech Test" = the script's spoken language; the caption De-AI gate (:129) carried no rule-#4 line (grep buzzword→ single hit at:106). A caption opening "How to leverage AI to drive synergy across the public-sector ecosystem…" would pass the caption gate unflagged. Same failure class S2/S3/S5 fixed inpost/react/carousel(the caption is re-shaped from a text idea in Step 4 — exactly where a rewrite slips buzzwords in). - (axis d)
:42(pre-edit) "voice-samples … (REQUIRED before scripting)" +:90"Match voice against voice-samples/" had no fallback for a fresh adopter with an empty/absent samples dir — "REQUIRED" reads as a hard block / dead-end. Same failure class as S3 (WebFetch-no-extraction) / S4 (empty-source).
- (axis c) at Step 5 the only buzzword line (
EVALUATE (4 axes).
- (a) intention fidelity — PASS. 8-step workflow delivers the description's promise (script + pacing + cues + captions + thumbnail + 200–400 caption + first comment + refine + save + state).
- (b) algorithm bar — PASS. Muted-autoplay correctly de-mythologized (
:100, "three-second hook = folklore; LinkedIn's only official 3 s = minimum length"); captions = the enforceable spec (:120); 60 s sweet spot; 2.5-wps budgets exact (:64/:66, 75/30 = 150/60 = 225/90 = 300/120 = 2.5). Honesty note (deferred, operator-agreed)::69"LinkedIn requires 30 % completion or zero distribution" is more absolute than the declared SSOTalgorithm-signals-reference.md:56(no 30 %, confidence medium); it is consistent withlinkedin-formats.md(cited at:39, l.58). Inter-reference tension, NOT a video-command gap — deferred (brief Non-Goal: no re-litigation of the bar). - (c) MECHANICAL predicate (post-emitting, on the caption) — GAP → fixed. no-body-link ✓ (
:125) · topic→pillars ✓ (:124+ Step 3) · caption band 200–400 ✓ (:121) · subagent resolves ✓ (:83/:131) · buzzword ✗ (grep: single hit:106, under Natural Speech = script not caption; caption De-AI gate had no rule-#4 line). hook 110–140 deliberately not imposed on the accompanying caption (class boundary, operator-agreed; primary hook = muted-autoplay:100). - (d) agent-wiring + graceful degradation — wiring PASS; degradation GAP → fixed.
video-scripter(:83) +differentiation-checker(:131, conditional) both resolve to realagents/*.md, bothsubagent_type: linkedin-studio:-namespaced. Graceful degradation: the "REQUIRED before scripting" voice-samples dead-end closed → fresh-adopter fallback to SKILL.md/defaults. (mcp-image n/a — video generates no images.)
HARDEN (surgical — 2 edits, 1 file, both grep-confirmed landed).
commands/video.md:129— extended the Step-5 De-AI caption gate with Content Quality Rule #4: "Strip corporate buzzwords from the post caption (… leverage, synergy, paradigm shift, thought leader, disruptive, value proposition, ecosystem, holistic approach) — re-shaping a text idea into a video caption can slip them in, and they trip the same low-substance signal."commands/video.md:42 + :45— softened "(REQUIRED before scripting)" → "(read before scripting)" and added a Step-0 graceful-degradation line: "ifvoice-samples/is empty or absent, don't block — fall back to the voice settings in SKILL.md (or neutral defaults) … the voice-guardian is suppressed under 5 samples, so there is no hard gate to satisfy."- Deferrals (2, recorded): (1) hook 110–140 on the caption — deliberate class boundary, not a gap
(operator-agreed); (2)
:69"zero distribution" honesty — inter-reference tension, brief Non-Goal (no re-litigation of the algorithm bar); leave to a future reference-consistency pass if desired. - CONCRETE after: the "leverage…synergy…ecosystem" caption now trips the Step-5 buzzword line before the script is presented; a fresh adopter with no voice samples now degrades to SKILL.md/defaults instead of hitting a "REQUIRED" dead-end.
VERIFY.
bash scripts/test-runner.sh→Passed: 81 · Failed: 0 · Warnings: 0, exit 0; counts 29/19/26/6 unchanged (ls commands/*.md|wc -l== 29,ls agents/*.md|wc -l== 19;git diff --stat=video.mdonly, +4/−2). Only.mdtouched → hooks/analyticsnode --testnot needed.- Before/after delta: axis (c) buzzword sub-check now enforced at the load-bearing Step-5 caption gate; axis (d) the voice-samples dead-end now degrades gracefully. The 2 edits are the cause.
- Disposition: HARDENED (2 edits, axis-c + axis-d) · 2 recorded deferrals (caption-hook boundary + :69 honesty) · axes a/b PASS.
Session 7 — Create II (batch)
S7 status: re-grounded the proposed predicates against the actual
batch.mdlines BEFORE talk (jerndisiplin: assert-after-read). Field-notes inbox absent at S7 → graceful no-op (SC-I). Allfile:linebelow are tool-grounded against the FINAL (post-edit) file. Class call (operator-agreed): hybrid guided/stateful + post-emitting per post — each of the 3–5 drafts IS a feed post, so the post predicates apply per post; the orchestration around them (state-load, agent-delegation, scheduling, queue,.ics) is the guided/stateful layer.
/linkedin:batch — one theme/pillar → 3–5 mixed-format feed posts, scheduled + queued + .ics
INTENT. batch is the Create journey's volume path: from one theme or pillar produce a full
week (3–5 posts) with varied angles + formats, each scheduled, queued (so it shows in
/linkedin:calendar + session-start reminders), and exported to a .ics. It is an orchestrator —
delegates angle discovery to trend-spotter, the balanced batch plan to content-planner, and owns
scheduling/queue/ical itself. Post-emitting per post, so each draft must honor the content bar
mechanically (hook 110–140, format-appropriate length band, no body link, no banned buzzword,
topic→5 pillars); guided/stateful for the orchestration (subagent targets + node helpers resolve;
graceful degradation).
SIMULATE.
- Persona (ICP): the author — 1048 followers, "Validation", 5 pillars; direct/technical NO/EN voice. "Sunday prep": one theme → a week of mixed-format posts (standard → carousel → quick → video rotation).
- Invocation:
/linkedin:batch→ "One main theme" → 3–5 angles. - Walk: Step 0 (
:23) load state/SKILL/plan/templates → Step 1 (:33) theme/pillar (+trend-spotterfor timely angles) → Step 2 (:45)content-plannerplan + schedule (slot template byweekly_goal, queue-conflict check:58) → Step 3 per post: 3a draft (:86) → 3b Quick Quality Check (:94, the gap) → 3c save (:101) → 3d queueAdd (:124) → Step 4 review (:130) → Step 5 finalize +.ics(:172). - CONCRETE friction (spec-level, anchored — not a generated batch): at Step 3b the per-post check
:95read "Character count in range" — no band named (range of what?), so it is unenforceable; and the Step 3a "standard structure" (:88–92: hook 110–140 + context 200–300 + insight 400–800 + implication 200–300 + CTA 50–100) sums to 960–1640, whose floor sits below the canonical standard band 1,200–1,800 (CLAUDE.md rule #2). A "standard" post drafted to the structure can land ~1,000 chars and pass:95"in range" unflagged. Complication: batch is mixed-format, so the band is format-dependent — imposing 1,200–1,800 on everything would wrongly fail a quick post (the S4 category error in miniature). Buzzword + no-body-link were NOT gaps here (:98+:97already present — the hole S2–S6 kept finding is already closed inbatch).
EVALUATE (4 axes).
- (a) intention fidelity — PASS. Theme→plan→schedule→per-post draft/check/save/queue→review→finalize+
.icsdelivers the week-of-content promise. Tension (deferred): Step 3a imposes one "standard structure" though Step 2 (:76) promises format variety —batchis an orchestrator, so carousel/video inherit their own formats' rules; recorded, not edited. - (b) algorithm bar — PASS. No body link (
:97); buzzword-clean (:98); pillar-aligned scheduling (scheduling-strategy.md); 5x5x5 reminder (:169).batchuses a deliberately lighter "Quick Quality Check" (no per-postdifferentiation-checker) — breadth-over-depth by design for a week-at-once tool; note, not a fix. - (c) MECHANICAL predicate (post-emitting, per post) — GAP → fixed. hook 110–140 ✓ (
:88) · no-body-link ✓ (:97) · buzzword ✓ (:98) · topic→pillars ✓ (:39/:77/:112) · subagent resolves ✓ (:43/:47) · length band ✗ (:95"in range" named no band; 3a structure sums 960–1640, under the 1,200 standard floor). - (d) agent-wiring + graceful degradation — wiring PASS; PASS.
trend-spotter(:43) +content-planner(:47) both resolve to realagents/*.md, bothsubagent_type: linkedin-studio:-namespaced. All 5 node helpers resolve with matching signatures:queueUpcoming(days=7)/queueAdd(…8 params)(batch passes 8 args) /queueFormatSummary(entries)(queue-manager.mjs:52/:63/:112),generateIcalFromQueue/writeIcalFile(ical-generator.mjs:183/:201). Degradation: no-plan→:31"create one first"; empty queue→:181guard. Minor (deferred): no fallback ifweekly_goalis unset (:52slot-template lookup) — micro, below axis-pass.
HARDEN (surgical — 1 edit, 1 file, grep-confirmed landed).
commands/batch.md:95—- Character count in range→- Character count in the band for this post's format (standard 1,200–1,800 · quick 150–500 · carousel/video caption per that format) — not just "in range".- Deferrals (3, recorded): (1) Step 3a single-structure vs mixed-format promise (orchestrator inherits
per-format rules); (2) no per-post differentiation gate (deliberate breadth-over-depth design); (3)
weekly_goal-unset fallback (micro-degradation). All below the stopping-rule's axis-pass bar. - CONCRETE after: a ~1,000-char "standard" draft now trips the format band (under the 1,200 floor) instead of passing the vague "in range"; a quick post is judged against 150–500, not wrongly against 1,200–1,800.
VERIFY.
bash scripts/test-runner.sh→Passed: 81 · Failed: 0 · Warnings: 0; counts 29/19 confirmed (ls commands/*.md|wc -l== 29,ls agents/*.md|wc -l== 19;git diff --stat=batch.mdonly, 1 insertion / 1 deletion). Only.mdtouched → hooks/analyticsnode --testnot needed.- Anti-check grep: bare vague
^- Character count in range$→ NONE (gone); format-band line present (:95). - Before/after delta: axis (c) length-band sub-check now enforced + format-aware at the load-bearing Step-3b gate. The 1 edit is the cause.
- Disposition: HARDENED (1 edit, axis-c) · 3 recorded deferrals · axes a/b/d PASS.
Session 8 — Pipeline (pipeline)
S8 status: re-grounded the proposed predicates against the actual
pipeline.mdlines BEFORE talk (jerndisiplin: assert-after-read). Field-notes inbox absent at S8 → graceful no-op (SC-I). Allfile:linebelow are tool-grounded against the FINAL (post-edit) file. Class call (operator-delegated → quality + precedent): hybrid guided/stateful + post-emitting on the final post — the 8-step idea→publish→analysis pipeline produces ONE feed post (Step 2 draft:57–62→ Step 3 gate:66–86→ Step 6 publish:135), so the post predicates apply to that post; the orchestration around it (Step 0 load · Step 1 agent-deleg · Step 4 schedule/queue · Step 5 5x5x5 · Step 7 first-hour · Step 8 analysis · state-update:186–199) is the guided/stateful layer.
/linkedin:pipeline — full idea→publish→analysis pipeline, one 1,200–1,800-char feed post, 8 steps
INTENT. pipeline is the Create journey's end-to-end path: from idea (or $ARGUMENTS topic)
through ideation → draft → optimize → schedule → 5x5x5 pre-engagement → publish → first-hour → 48h
analysis, with a deterministic state update. Post-emitting on the final post (hook 110–140, length
1,200–1,800, no body link, no banned buzzword, topic→5 pillars); guided/stateful for the
orchestration (subagent targets + 5 node helpers resolve; graceful degradation).
SIMULATE.
- Persona (ICP): the author — 1048 followers, "Validation", 5 pillars; direct/technical NO/EN voice.
- Invocation:
/linkedin:pipeline about AI-kodeassistenter i offentlig sektor(topic in$ARGUMENTS→ Step 1 ideation skipped,:41). - Walk: Step 0 load state/SKILL/voice → Step 1 skipped → Step 2 angle + draft to the structure
(
:57–62) → Step 3 optimize gate (:66–86, the gap) → Step 4 schedule (+ Option-3 queue) → Step 5 5x5x5 → Step 6 publish+clipboard → Step 7 first-hour → Step 8 analysis → state. - CONCRETE friction (spec-level, anchored — not a generated post): at Step 3 the inline quality
scorecard (
:75–81) carried the buzzword line (:79) but as a bare- [ ] No corporate buzzwords— no inline enumeration; it leaned on the scorecard reference (:75→quality-scorecard.md:132). A draft opening "How to leverage AI to drive synergy across the public-sector ecosystem…" relies on the operator cross-referencing a long shared asset rather than the inline gate the AI actually executes. Unlike S2/S3/S5/S6 the line was PRESENT — the gap was that it was not self-contained, making pipeline the odd-one-out among post-emitting commands (post:134· react:131· carousel:123· video:129all enumerate inline).
EVALUATE (4 axes).
- (a) intention fidelity — PASS. 8-step idea→publish→analysis delivers the description's promise.
- (b) algorithm bar — PASS. Step 3 signals (
:70–73) cited to the SSOT (saves rank highest · a 15+-word comment ≈ 2× a like · dwell >30 s +25 %); no body link (:78); 5x5x5 (:120–133); first-hour (:158–169). No 30 %-claim → untouched by the open reference-consistency follow-up. - (c) MECHANICAL predicate (post-emitting, on the final post) — GAP → fixed. hook 110–140 ✓
(
:58/:76) · length band ✓ (:77names 1,200–1,800) · no-body-link ✓ (:78) · topic→pillars ✓ (:80+:49content-planner pillar-situating) · subagent resolves ✓ (:49) · buzzword present-but-not-self-contained ✗→fixed (:79bare → enumerated inline). - (d) agent-wiring + graceful degradation — PASS.
content-planner+trend-spotter(:49) resolve to realagents/*.md, bothsubagent_type: linkedin-studio:-namespaced. All 5 node helpers export with matching signatures:queueUpcoming(days=7)(qm:52) ·queueAdd(…8 params)(qm:63; pipeline passes 8 args:116) ·queueFormatSummary(qm:112) ·writeState(su:346) ·updatePostTracking(su:55). Degradation: Step 1 (:43–47) handles no-planned-topic/no-input via AskUserQuestion; Step 0 voice-samples is a soft read (no "REQUIRED" dead-end).
HARDEN (surgical — 1 edit, 1 file, grep-confirmed landed).
commands/pipeline.md:79—- [ ] No corporate buzzwords→- [ ] No corporate buzzwords (leverage, synergy, paradigm shift, thought leader, disruptive, value proposition, ecosystem, holistic approach)(same banned list as the other post-emitting gates + the scorecard).- Deferral (1, recorded): the Step-2 component structure (
:58–62: hook 110–140 + context 200–300 + insight 400–800 + implication 200–300 + CTA 50–100) sums 960–1 640, whose floor sits below the Step-3 band floor 1,200 (:77) — identical structure to batch's 3a (:88–92). NOT edited: pipeline's Step-3 gate already NAMES the band (the S7 fix was naming the band on an unenforceable gate; here it is already named), so a minimum-path draft is caught by the gate, not shipped — and S7 did not edit the analogous 3a structure either. Editing Step 2 here would exceed precedent (over-engineering). Below the axis-pass bar. - CONCRETE after: the "leverage…synergy…ecosystem" draft now trips the Step-3 buzzword line inline before optimize completes, without the operator cross-referencing the shared scorecard.
VERIFY.
bash scripts/test-runner.sh→Passed: 81 · Failed: 0 · Warnings: 0; counts 29/19 confirmed (ls commands/*.md|wc -l== 29,ls agents/*.md|wc -l== 19;git diff --stat=pipeline.mdonly, 1 insertion / 1 deletion). Only.mdtouched → hooks/analyticsnode --testnot needed.- Before/after delta: axis (c) buzzword sub-check is now self-contained at the load-bearing Step-3 gate (was a bare, reference-dependent line). The 1 edit is the cause.
- Disposition: HARDENED (1 edit, axis-c) · 1 recorded deferral (Step-2 component-sum, gate-caught) · axes a/b/d PASS.
Session 9 — Longform orchestrator (newsletter)
S9 status: re-grounded STATE's 7 S9 predicates against the actual
newsletter.md(1594 lines, 16 phases) BEFORE talk (jerndisiplin: assert-after-read). Class agreed S9 steps 1–2: guided/stateful long-form orchestrator, NOT post-emitting — the feed-post predicates (hook 110–140, 1,200–1,800 band, no-body-link) do NOT apply; imposing them would be the S4/video category error the command itself already rejects (:38–42). Allfile:linebelow are tool-grounded against the FINAL file (no edits this session → final ==52e888a).
/linkedin:newsletter — long-form edition end-to-end, 16-phase stateful pipeline, NOT post-emitting
INTENT. newsletter is the Longform orchestrator: take an edition (newsletter / essay / series
article) from load → calibration → verified research → skeleton+spine gates BEFORE prose → full draft
→ consistency/quality+voice-scrub → fact-check → editorial craft gate → persona sweep → headless
adversarial review → visual assets → LOCK (POST.html) → hook-gate → scheduling. Multi-session with a
maintained edition-state.json. Long-form quality is enforced by the pipeline phases, not
short-form hooks.
SIMULATE (grounded persona-sim, anchored to Step 6.5 headless fan-out).
- Persona (operator): KTG producing a series edition; primær reader chosen in Step 1.
- Walk: Step 0 load (voice/persona graceful
:258) → … → Step 6 persona sweep PASS → Step 6.5 freeze → fan out 5 cold archetypes (:1062–1069, single message, alllinkedin-studio:-namespaced, foreground per principle 4; background loses Task:79) → degradation gate (:1084–1086"do not proceed with a missing reviewer[GATE]") → consolidate viaSendUserFile→ Step 7.5 visual assets (mcp-image not a hard dependency, externalcover-raw.pngfallback:1222–1230) → Step 8 LOCK (build-linkedin.mjs→linkedin/NN/POST.html, exit-code N3:1388) → Step 10queueAdd(:1486). - Friction sought (the S2–S8 pattern: a missing buzzword gate / a missing fallback): NONE found. The category-correct equivalent of the short-form buzzword gate is the de-AI/voice-scrub + editorial + language-reviewer gates, all present and wired. Every fan-out has a structured-return degradation gate.
EVALUATE (4 axes).
- (a) intention fidelity — PASS. The 16-phase pipeline delivers the description's promise; primær
artifact
POST.htmlis produced end-to-end at Step 8 lock (:1379–1395) with exit-code verification. - (b) algorithm/format bar (long-form honesty, NOT feed-post predicates) — PASS. Native-newsletter §
(
:1508–1569) is nøktern: "sells nothing", notification dedup not oversold ("not three guaranteed touchpoints"), cold-start not inflated ("0→9K in 7 days were not cold starts"), downsides disclosed (non-exportable / no-canonical / no-analytics / decay), sourcing note (:1564) separates LinkedIn help-docs (high conf.) from practitioner ranges (medium) + flags the contested email-dedup; citationdocs/remediation/research/03-coverage-gap-specs.md§D5 exists (225 lines, §D5 ×8 — not dangling). - (c) quality rules (category-appropriate) — PASS. Long-form quality is enforced by the pipeline
gates (skeleton 2.5 · spine 3a · consistency+voice-scrub 4 · fact-check 5 · editorial 5.5 · persona 6
· headless 6.5 · hook 9), all present + wired. Short-form hooks correctly NOT imposed (
:38–42); no hollow gate found. - (d) agent-wiring + graceful degradation — PASS. All 8 invoked subagents resolve to real
agents/*.md, allsubagent_type: linkedin-studio:-namespaced (persona-reviewer ×5, fact-checker ×2, voice-scrubber, language-reviewer, fact-reviewer, editorial-reviewer, content-reviewer, content-repurposer). Render/queue helpers exist;queueAdd(id, draftPath, schedDate, schedTime, pillar, format, hookPreview, charCount)8-arg signature (qm:63) matches the call (:1486). All 9 plugin-root ref/template files (:1575–1594) exist. Phase strings:_doc.phases(16) ↔ resumption table (16)diffIDENTICAL. Degradation: voice/persona:258· mcp-image:1222–1230· exit-codes ×4 (:443/580/1144/1388) · optional config+delingstekst:1373–1377· fan-out gates ×3 (:340/789/1086).
HARDEN — NO CHANGE (verified clean).
- 0 edits.
newsletteris among the most iterated commands (v2.0→v4.1 hardened the long-form gates across multiple production runs: Seres, Del 4 / Endring 9), and it shows: every axis passes with no surgical opportunity at or below the axis-pass bar. - Deferrals: none. Anti-gold-plating: no NICE-only polish pursued beyond axis-pass (stopping
rule, brief §). The native-newsletter follow-up noted in S2 STATE (reference-consistency for the
separate
video.md/linkedin-formats.md30 % surface) is NOT this command's surface — left in the open-follow-ups list, not touched here.
VERIFY.
bash scripts/test-runner.sh→Passed: 81 · Failed: 0 · Warnings: 0; counts 29/19/26 (+6 skills) unchanged;git status --porcelainempty → working tree byte-identical to52e888a(S8).- Phase-string diff reproduced:
_doc.phasesids vs resumption-tablecurrentPhaseids → IDENTICAL, 16↔16, in order. - Disposition: VERIFIED — NO CHANGE (0 edits) · 0 deferrals · axes a/b/c/d all PASS.
Session 10 — Longform companion (headless-review)
S10 status: re-grounded STATE's predicates against the actual
headless-review.md(248 lines, 13 KB) BEFORE talk (jerndisiplin: assert-after-read). Class agreed S10 steps 1–2: cold adversarial review-orchestrator, NOT post-emitting — it emits a consolidated review report + optionaledition-statepersistence, never a feed post and never drafts prose; the feed-post predicates (hook 110–140, 1,200–1,800 band, no-body-link) do NOT apply — imposing them would be the S4/video category error (even further from feed-post thannewsletter). The four archetype agents are SHARED withnewsletterStep 6.5 → S9 agent findings reused as baseline. Allfile:linebelow are tool-grounded against the FINAL file (no edits this session → final ==1c31644).
/linkedin:headless-review — cold adversarial review package on a FROZEN long-form draft, NOT post-emitting
INTENT. headless-review is the standalone surface of newsletter Step 6.5: read a frozen,
publish-ready (or pivoted) long-form draft COLD — with NONE of the drafting session's framing-bias —
through five independent archetypes and return direction-only flags, consolidated into one
operator-gated report. Two isolation layers: fresh session (strongest, :64–68) + per-archetype
subagent context (:69–74). The adversarial-independence layer the in-session gates structurally
cannot be (:30–48).
SIMULATE (grounded persona-sim, anchored to the Step 3 cold fan-out).
- Persona (operator): KTG in a FRESH session running
--type allon<serie>/NN-utkast.md. - Walk: Step 1 resolve-from-disk (draft → edition-state
currentArticlefallback → ask-once:103–104; contract 3-tier fallback ending at always-presentlongform-quality-rules.md:111–114; personas = newsletter Step 1 chain:116–118) → Step 2 freeze (cpsnapshot:126, live-draft fallback ifcpunavailable:130–131) → Step 3 fan out 5 archetypes (single message,:135–136; 4linkedin-studio:-namespaced types, persona-reviewer ×2 modes:141–146) → degradation gate (:161–164"re-run that one archetype — do not paper over a missing reviewer[GATE]") → Step 4 consolidate (operator gates, never auto-resolve flags:168–169/:196–197; convergence marked:200–202) → Step 5 surface viaSendUserFile(elsefile://:208–210) + optional persistarticles.NN.headlessReview(:211–215). - Friction sought (the S2–S8 pattern: a missing buzzword gate / a missing fallback): NONE found. Not post-emitting → the category-correct quality bar is the reviewers grading against the writing contract + the structured-return degradation gate, both present. Every fan-out call has a degradation re-run path.
EVALUATE (4 axes).
- (a) intention fidelity — PASS. The 5-step flow (resolve → freeze → parallel fan-out → consolidate
→ surface/persist) delivers the description's promise; primær artifact is the consolidated report
(
:171–198), surfaced + optionally persisted (:204–215).allowed-tools(:18–26) complete and fully used (Read/Glob/Grep · Bash freeze · AskUserQuestion ask-once · Task fan-out · Write report+state). - (b) algorithm/format bar (long-form honesty, NOT feed-post predicates) — PASS. Cold contract
(
:50–74) nøktern: reviewers get a "deliberately starved context", exactly-what-they-get / exactly-what-they-don't enumerated; two-layer isolation with honest caveats (Layer 1 "recommended … strongest" not absolute; reload caveat for the v3.1.0 agents:80–82). Deliberate redundancy (fact-reviewer↔fact-checker,language-reviewer↔editorialprose axis) disclosed as on-purpose, not collapsed (:234–237). No feed-post predicate imposed. - (c) quality rules (category-appropriate) — PASS. Review quality enforced by (1) reviewers judging
against the writing contract (
:111–114), (2) the degradation gate requiring structured/populated returns, not a hedged paragraph (:161–164), (3) operator-gates-the-fold-in — the command recommends, never rewrites/gates (:168–169/:196–197/:210), (4) convergence-as-signal (:200–202). No hollow gate found. - (d) agent-wiring + graceful degradation — PASS. 4/4 invoked subagent types resolve to real
agents/*.mdwith matching frontmattername:, allsubagent_type: linkedin-studio:-namespaced (content-reviewer · language-reviewer · fact-reviewer · persona-reviewer ×2 modes → "five archetypes":5–6/:30–31). 8/8 Reference Files (:241–248) exist.articles.NN.headlessReviewschema present + complete inedition-state.template.json(:56–69: frozenDraft · reviewers {content,language,fact,personaResonance,personaConversion} · consolidatedReport · foldedIn · waived · status; ladder pending→run→folded:29). Degradation ×5: freezecpfallback:130· draft-missing ask-once:104· persona fallback:117·[GATE]re-run:163–164· output-default:93+ SendUserFile-else-file://:208–210.
HARDEN — NO CHANGE (verified clean).
- 0 edits. Borderline surfaced at talk: the freeze step (
:126) assumesreview/exists (nomkdir -p). Operator chose Alt A (no change). Rationale: the freeze block is byte-identical tonewsletter:1050(S9-verified-clean), andreview/is created by the render pipeline that produces the draft (build-html.mjs→./review/newsletter:1136; skeleton/draft render:444/:580); addingmkdir -ponly here would drift from its S9-clean twin, and fixing both would re-open S9 (out of S10 scope). Thecp-unavailable fallback (:130) covers the degraded path loosely. - Deferrals: none. Anti-gold-plating: the
mkdir -probustness improvement is a NICE below the axis-pass bar — left as the operator's logged decision (Alt A), not pursued.
VERIFY.
bash scripts/test-runner.sh→Passed: 81 · Failed: 0 · Warnings: 0; counts 29/19/26 (+6 skills) unchanged (count/version-consistency guards inside the lint passed);git status --porcelainempty → working tree byte-identical to1c31644(S9).- Predicates re-grounded against the final file: 4 namespaced subagent types (frontmatter
name:match) · 8/8 ref files exist ·headlessReviewschema:56–69· 5 degradation points · persona chain = newsletter:179–183· "five archetypes" (wrapped) = 5 modes from 4 agents. - Disposition: VERIFIED — NO CHANGE (0 edits) · 0 deferrals · axes a/b/c/d all PASS.
Session 11 — Longform companion (pivot)
S11 status: re-grounded STATE's predicates against the actual
pivot.md(162 lines) BEFORE talk. Class agreed steps 1–2: pure state-mutation / orchestration command, NOT post-emitting, invokes NO agents, never drafts prose. It re-opens a long-form edition after a late substantive change so the cleared gates re-run before lock — mutatingedition-state.json(appendpivots[], resetcurrentPhase, un-lock, invalidate downstream verdicts), writing a next-step line to<serie>/STATE.md, and deferring the actual gate-runs to/linkedin:newsletter(:144). Feed-post predicates (hook 110–140, 1,200–1,800 band, no-body-link) do NOT apply — even further from feed-post thanheadless-review(this one does not even produce a review of prose). The pivot heuristic +pivots[]schema + gates-to-rerun chain are SHARED withnewsletter(Step 8) andheadless-review→ S9/S10 findings reused as baseline. Unlike S9/S10 this was NOT a no-change session — P4 surfaced a real cross-file off-by-one bug.
/linkedin:pivot — re-open a cleared edition for re-review, NOT post-emitting
INTENT. Make the post-lock re-open a NAMED RITUAL, not a manual scramble (the Del 4 Security
Champions case, :33–38): log the pivot, reset currentPhase so newsletter's deterministic resumption
re-runs the invalidated gates (fact-check 5 → editorial 5.5 → persona 6 → headless 6.5), un-lock if
needed, and invalidate the stale downstream verdicts so a pre-pivot PASS cannot be mistaken for current.
SIMULATE (grounded persona-sim).
- Persona (operator): KTG having made a late change to a LOCKED edition, running
/linkedin:pivot --article NN --reason "<...>". - Walk: Step 1 load state + locate article (missing → stop+report
:75) → Step 2 measure scope (wc -wcurrent vs baselinepersonaSweep.resonance.wordCount; baseline-absent → ask/default structural:84–86; ambiguous sections → confirm:90) → Step 2 classify → default--to-phase→ Step 3 appendpivots[]+ resetcurrentPhase+ un-lock + invalidate verdicts (:100–131) → Step 4 write next-step line to<serie>/STATE.md, defer gates to newsletter (:133–155). - Friction sought (the S2–S8 pattern): FOUND — a phase-reset off-by-one (P4).
EVALUATE (4 axes — re-tolket for a non-post-emitting orchestrator).
- (a) intention fidelity — PASS after fix. The ritual (log → reset → un-lock → invalidate → point)
delivers the promise;
allowed-toolscomplete and used. The off-by-one (below) made the moderate branch silently betray the stated intent ("so the new claims get verified") → fixed. - (b) format bar (heuristic-consistency, NOT feed predicates) — PASS. Three-way SSOT verified
identical: pivot heuristic (>20 % words OR >2 sections, baseline =
personaSweep.resonance.wordCount) == newsletter Step 8 lock-precondition (:1348–1362) == template_doc.pivots(:30). Newsletter Step 6 actually writes the baseline field (:990–994,:1005) → not a phantom. Cardinal rule ("never reopen a locked text", newsletter:1034–1036) honoured: pivot is the sanctioned exception — it loudly un-locks + flags POST.html stale (:124) + invalidates verdicts (:126–130). - (c) quality rules (state-integrity) — PASS.
gatesToRerun:113= the 4 real gate phase-names; invalidation targets (personaSweep.resonance·editorialReview·headlessReview.status) all exist in the schema;factcheckLog+pivots[]left intact (durable history:130). - (d) agent-wiring + graceful degradation — PASS. No agents (orchestrator). 3 degradation points
enumerated (article-missing
:75· baseline-absent:84–86· ambiguous-sections:90). 3/3 ref files exist.
THE BUG (P4 — confirmed cross-file off-by-one). Newsletter's resumption table is explicit
(:196–198, :203–221): currentPhase = the last completed phase, and the pipeline resumes at the
step after it (draft→Step 4, consistency-quality→Step 5, factcheck-sweep→Step 5.5). But
pivot.md set the moderate default to to-phase: factcheck-sweep "so the new claims get verified" —
which resumes at Step 5.5 (editorial), SKIPPING the Step 5 fact-check the moderate pivot exists to
run. Self-contradictory, and a violation of the command's own invariant that "a pivot always invalidates
the fact-check" (:116–119). The structural branch (to-phase: draft→Step 4→fact-check at 5) was
functionally safe but mis-labelled "(Step 3b)". Root cause: conflating "the phase to resume AT" with the
currentPhase (last-completed) value to write.
THE FIX (4 surgical edits, confined to command-anatomy + Step 2).
- Moderate default
:96–97:factcheck-sweep→consistency-quality(resumes Step 5, fact-check runs) — the bug. - Structural label
:92–95: "(Step 3b) … full prose expansion" → "resumes Step 4 (consistency-quality) … then fact-check (5) → editorial (5.5) → persona (6) → headless (6.5)". - Off-by-one guard callout
:102–108: explainsto-phaseis acurrentPhase(last-completed) value and newsletter resumes at the NEXT step → why a pivot never resets tofactcheck-sweep. - Anatomy enum
:46: droppedfactcheck-sweepfrom the offered values (it skips fact-check, violating the always-invalidate-fact-check invariant) →draft | consistency-quality.gatesToRerun:113and the worked example:64–70(structural,draft) left intact — both correct.
VERIFY.
- Re-grepped final file:
factcheck-sweepnow only at:106(guard, as the forbidden value) +:123(gatesToRerun gate-name); to-phase defaults =draft(:93) /consistency-quality(:97); enum:46= two values; guard landed:102. bash scripts/test-runner.sh→Passed: 81 · Failed: 0 · Warnings: 0; counts 29/19/26 unchanged (count/version/model-consistency guards passed; .md-only edit, node/analytics tests not triggered).- One NICE left (anti-gold-plating): template
:30says "+530 words" (sum of the 2 named sections) vs worked-example 1400→1992 = +592; both "", both +42 % — cosmetic, below the axis-pass bar, left. - Disposition: FIXED (4 edits, all in
commands/pivot.md) · 0 deferrals · axes a/b/c/d all PASS post-fix.
Session 12 — Hardening (firsthour)
S12 status: re-grounded STATE's predicates against the actual
firsthour.md(119 lines) BEFORE talk. Class agreed steps 1–2: post-publish engagement orchestrator — first-hour / reply-loop sprint. NOT post-emitting / feed-draft. It builds a first-hour plan (target list + draft comments + timeline) by DELEGATING construction toengagement-coach(Step 2,Task), presents + auto-copies the draft comments (Step 3), persists viarecordFirstHourPlan(Step 4), and hands off topost-feedback-monitor(Step 5). It emits COMMENT copy, not a feed post → the feed-format predicates (hook 110–140, 1,200–1,800 band, no-body-link) do NOT apply; the inline comment band (25–50 words, voice, no bait, no generic praise) is its own surface. Axis-d heavy: 2 agents + a state-writer + a hand-off chain.
WHAT VERIFIED CLEAN (no change).
- Agent wiring (axis-d): both
subagent_type: linkedin-studio:-namespaced.engagement-coachfrontmatter = name / model:sonnet / color:magenta;post-feedback-monitor= name / model:opus / color:lime — both match the CLAUDE.md table exactly. - State-writer (axis-d):
recordFirstHourPlanexported (state-updater.mjs:235), additive,$-safe (function-replacements), stampslast_firsthour_date+firsthour_active, writes## First-Hour Plans— exactly as Step 4 claims.writeState/clipboard-helper.mjs/ both ref files present. - Delegation sound (axis-d): CEA / 5x5x5 / first-hour / target-selection genuinely owned by
engagement-coach.md(whales / inner-circle, velocity table). Hand-off coach→monitor present (Step 5). - Axis-c: the draft-comment band is consistent with the SSOT AI-slop suppression + the 15+-word floor.
- Principle 2 "comments rank above reactions" (
:111) IS supported — SSOT:38saves > shares > quality comments > reactions/likes+:160. (My initial narrow grep was a false negative — withdrawn.)
THE FIX (2 findings, 3 surgical edits, confined to prose + footer).
- [REWORK · axis-b]
~70%-stat MISATTRIBUTED to "the first 60 min". The command (desc:4, body:22) said the first hour / "first 60 minutes" decide ~70% of reach. SSOTalgorithm-signals-reference.md:81pins ~70% to the first 15–30 min sub-window (golden window = 60–90 min); the command even cites that SSOT (:118) → it contradicted its own source. Fix: desc + body re-attributed to "first 15–30 minutes decide ~70%", framing the hour as the golden window you work. (Operational guidance was already front-loaded — the 5/15/30/60 velocity checkpoints were left unchanged.) - [REWORK-low · axis-a] Reference-label:
engagement-frameworks.mddoes NOT contain CEA. The footer labelled it "hook types, CEA, engagement hierarchy" — but CEA lives inalgorithm-signals-reference.md:162engagement-coach.md; the ref carries hook types + "Engagement Quality Hierarchy" only. Fix: dropped "CEA" from the footer line (CEA already covered by the Step 2 coach-delegation + the SSOT pointer).
VERIFY.
- Re-grepped the final file:
~70%is now attributed to "15–30 minutes" at desc:4+ body:22; no "first 60" / "60 minutes set" attribution remains (:66"5/15/30/60-minute" is the velocity-checkpoints table, unchanged). CEA now only at:6 / :44 / :54 / :65 / :112(desc + Step 2 + Step 3 + principle), GONE from the footer; footer:118= "hook types, engagement hierarchy". bash scripts/test-runner.sh→Passed: 81 · Failed: 0 · Warnings: 0; counts 29/19/26 unchanged (count / version / model / stat-consistency guards passed; .md-only edit, node/analytics tests not triggered).- One NICE left (anti-gold-plating): no degradation note for an
engagement-coach-Task failure / absent voice-samples (thin orchestrator, fully coach-dependent) — consistent with the suite's posture, below the axis-pass bar, left. - Disposition: FIXED (3 edits, all in
commands/firsthour.md) · 0 deferrals · axes a/b/c/d all PASS post-fix.
Session 13 — Hardening (calendar)
S13 status: read-and-show of every mechanical dependency against the actual
queue-manager.mjs+state-updater.mjsBEFORE talk. Class agreed steps 1–2: stateful queue / publish command — view + manage the scheduling queue + run the publish action. NOT post-emitting / feed-draft. It loads the queue (queueToday/Upcoming/Overdue/Count/FormatSummary), renders a 14-day view, offers actions (mark-published / reschedule / cancel / view-draft), and on publish doesqueueUpdateStatus('published')→updatePostTracking(state) → a quick first-hour plan that defers the full sprint to/linkedin:firsthour+post-feedback-monitor. It DISPLAYS hook previews of already-queued drafts → it emits no feed content → the feed-format predicates (hook 110–140, 1,200–1,800 band, no-body-link, buzzwords, rotation) do NOT apply. Axis-a/d heavy.
WHAT VERIFIED CLEAN (no change).
- Queue wiring (axis-a/d): Step 1 (
queueToday/Upcoming/Overdue/Count/FormatSummary), 3c + Cancel (queueUpdateStatus) all match exports inqueue-manager.mjs:41–112exactly. - State-writer (axis-d):
updatePostTracking(stateContent, { postDate, postTopic, hookText, charCount, format })(state-updater.mjs:55) +writeState(:346) — signature matches Step 3d's call verbatim. - Agent wiring (axis-d):
subagent_type: linkedin-studio:post-feedback-monitor(:156) namespaced, agent file present,Taskinallowed-tools. Hand-off to/linkedin:firsthour(:138) = S12 chain. - Graceful degradation (axis-d): missing/corrupt queue →
ensureQueue()+readQueue()try/catch →[](queue-manager.mjs:12–27); the "No posts scheduled" branch (:106–111) covers the empty case. - Algorithm bar (axis-b): the quick first-hour plan (
:151"15+ engagements in first 60 min", check at 30/60) is deliberately light and delegates the full sprint to/linkedin:firsthour. No ~70%-reach misattribution (the S12 bug is absent here). SSOT:81golden window 60–90 min / first 15–30 min — not contradicted. PASS. - Content-quality (axis-c): emits no feed content; the hook "preview" is a truncated display of an existing draft, not a generated hook → feed predicates N/A → PASS.
THE FIX (1 finding, 1 surgical edit, confined to the Reschedule action).
- [REWORK · axis-a/d] The Reschedule action (
:164–170) was under-determined vs its sibling actions: prose-only with NO bash snippet (unlike Cancel:177–180and publish 3c:116–118), and it referencedqueue_update_status + queue_add— snake_case that does not match the exportsqueueUpdateStatus/queueAdd(queue-manager.mjs:63,82). An agent executing it had no concrete command and the names would not resolve if copied literally. Fix: replaced step 3 with a concretequeueAddone-liner using the same id (sincequeueAddfilters out the prior id first,:64, re-adding moves the post in place — no duplicate), carrying the unchanged fields from the Step-2 entry. Mirrors the Cancel snippet pattern.
VERIFY.
- Re-grepped the final file: no
queue_update_status/queue_addremains; thequeueAddreschedule snippet is at:174; everyqueue*reference in the file is now camelCase and matches an export. bash scripts/test-runner.sh→Passed: 81 · Failed: 0 · Warnings: 0, exit 0; counts 29/19 unchanged (.md-only edit, node/analytics tests not triggered — unchanged from S12).- One NICE left (anti-gold-plating): the quick first-hour plan could name the SSOT "first 15–30 min"
sub-window, but it deliberately defers to
/linkedin:firsthour; duplicating it would be scope creep — left. - Disposition: FIXED (1 edit in
commands/calendar.md) · 0 deferrals · axes a/b/c/d all PASS post-fix.
Session 14 — Hardening (import)
S14 status: read-and-show of the analytics CLI (
csv-parser.ts,cli.ts handleImport,storage.ts,alerts.ts) BEFORE simulate, then a GROUNDED run against a throwaway fixture (ANALYTICS_ROOT=/private/tmp/…, 5-row CSV, discarded after). Class agreed steps 1–2: analytics ingest — CSV export → structured weekly JSON viacli.ts import, delegating all analysis to/linkedin:report(Step 6). NOT post-emitting → the feed-format predicates (hook 110–140, length band, no-body-link, buzzwords, rotation) do NOT apply. Axis-a/d heavy (path-seam consistency + graceful degradation + the over-promise).
/linkedin:import — CSV export → structured weekly JSON, intra-batch anomaly surface, analysis delegated to report
WHAT VERIFIED CLEAN (no change).
- Path-seam (axis-a):
getAnalyticsRoot()(storage.ts:67–72) →getDataRoot("analytics")(:54–59) =${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}/analytics= the exact path the prose tells the user to use (import.md:37,62,91); identicalLINKEDIN_STUDIO_DATAoverride.ANALYTICS_ROOTback-compat override (storage.ts:68) confirmed (validates the throwaway isolation). - saves/dwell honesty (axis-c): grounded run → EU
"5.234"→5234, US"8,710"→8710;parseOptionalCount(csv-parser.ts:71–85) kept saves 42/128 on data rows, blank → nosavesfield (unknown, not 0);engagementRateexcludes saves (:203–208); 0 dwell field anywhere. README boundary blockquote (import.md:26–30) intact. - Wiring (axis-d):
/linkedin:report→commands/report.mdpresent; 0subagent_type(CLI-delegating, correct); state-file Step 6b =~/.claude/linkedin-studio.local.md. - Degradation (axis-d):
npm installpre-step (:114–121) covers fresh-cloneERR_MODULE_NOT_FOUND; file-not-found exit 1 (cli.ts:67–71) ↔ Error Handling; empty title (file line 5) + bad date (line 6) skipped in the run (csv-parser.ts:186–195).
THE FIX (1 finding, 5 surgical edits, all in commands/import.md).
- [REWORK · axis-a/d] Over-promise: baseline / metadata infrastructure the code never had.
import.md repeatedly promised baseline comparison + rolling 4-week averages + a
baselines.json/metadata.jsonthe importer "creates" + ">2 sigma from baseline" alerts. Grep over the whole repo (scripts/analytics/src+ all*.mjs/ts/py/js) = NONE writes either file;saveBatchwrites onlyposts/*.json(storage.ts:157);detectAlerts(alerts.ts:18–69) flags intra-batch std-dev from the batch's own mean, not a stored baseline. Concrete bug: Step 5b'scat baselines.json 2>/dev/nullis always empty → the command falls forever to "first import — baselines will be established", on every import. Fix: rewrote 5 sections to the truth — Step 5 (real CLI fields +YYYY-MM-DD-<shortid>.jsonfilename; dropped "Duplicates skipped" / "340% above baseline" / "Viral threshold"), Step 5b (honest intra-batch surfacing; cross-week analysis deferred to/linkedin:report), Step 7 (Next-Steps conditioned on the report's trend, not a local baseline), State Tracking + Reference Files (nobaselines.json/metadata.json; correct batch filename).
VERIFY.
- Re-grepped the final file:
metadata.json/YYYY-WXX.json(filename) / "Duplicates skipped" / "340%" / "Viral threshold" all GONE; the onlyYYYY-WXXleft is:226(last_import_weekISO-week state field — legitimate); the 3 remaining "baseline" hits are the new honest negations ("keeps no baseline file", "no persisted baseline"). bash scripts/test-runner.sh→Passed: 81 · Failed: 0 · Warnings: 0, exit 0; counts 29/19 unchanged (.md-only edit, node/analytics tests not triggered).- Grounded simulation passes the failing axis: the rewritten prose matches the observed CLI output
verbatim (filename
2026-06-02-batch-17.json, "No anomalies detected in imported data.", "Saves entered: 170 across 2 post(s) (manual)"). - Disposition: FIXED (5 edits, all in
commands/import.md) · 0 deferrals · axes a/b/c/d all PASS post-fix.
/linkedin:report — imported analytics → weekly/monthly/heatmap report, alerts surfaced, interpretation delegated to analytics-interpreter
WHAT VERIFIED CLEAN (no change).
- Path-seam (axis-a):
getAnalyticsRoot()(storage.ts:67–72) →getDataRoot("analytics")(:54–59) = the exact${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}/analyticspaths the prose reads;ANALYTICS_ROOToverride confirmed (the grounded sim ran isolated in/private/tmp). - CLI surface (axis-a):
report --week/--month,trends --period --metric,heatmapall dispatch (cli.ts:447–459); grounded sim produced verbatim weekly report + trends + heatmap on a 3-row fixture. - Wiring (axis-d):
subagent_type: linkedin-studio:analytics-interpreter(report.md:305) resolves —agents/analytics-interpreter.mdpresent with report-mode (:10,40,295); one namespacedTask. - Degradation (axis-d):
trends/heatmap"No posts found. Import some data first." exit 1 (cli.ts:245–248,397–400); weekly report try/catch exit 1 (:191–194); Step 1 import-nudge; npm-install Step 1b for fresh-cloneERR_MODULE_NOT_FOUND. - saves/dwell honesty (axis-c):
totalSavessurfaced only when present, labelled "(manual entry — top engagement signal)" (cli.ts:144–146,342–344;weekly.ts:172–173); grounded run — FIXTURE B's blank Saves cell produced no saves suffix (unknown≠0); never folded into engagement. dwell absent, explicit "do not fabricate a dwell field" (types.ts:26–28).
THE FIX (3 findings, 6 surgical edits, all in commands/report.md).
- [REWORK · axis-a/d] Over-promise:
baselines.json+metadata.jsoninfrastructure the code never had (the S14 import twin). Step 5c told the model tocat baselines.jsonand flag ">2 standard deviations above/below mean"; Reference Files listed both files. Grep overscripts/analytics/src= NONE writes either;storage.tswrites onlyposts/<date>-<shortid>.json,weekly-reports/<week>.json,monthly-reports/<month>.json;ensureDirectories(:77–90) makes no baselines dir; a full import+report cycle in the fixture created NEITHER. The real alerts aredetectAlerts(intra-week) +detectWeeklyAlerts(WoW) surfaced in the report's ownalerts[](weekly.ts:222–238). Fix: Step 5c rewritten to readalerts[]straight from the generated weekly-report JSON; Reference Files dropped both phantoms, fixed the posts filename toYYYY-MM-DD-<shortid>.json, added the realmonthly-reports/file. - [REWORK · axis-a] Broken metric flag
engagement_rate(snake_case,:172). Grounded:--metric engagement_rate→ exit 1 "Invalid metric"; the CLI accepts only camelCaseengagementRate(cli.ts:47,202–209). Fix::172snake→camel (the other call, old:363, was already correct). - [REWORK · axis-a] Step 4 / Step 6 schema field names that don't exist. Step 4 claimed JSON fields
dateRange,postCount,aggregateMetrics; the realWeeklyReport(weekly.ts:124–149) top keys areweek, generatedAt, summary, topPerformers, underperformers, trends, alerts(no dateRange, no aggregateMetrics, no top-level postCount — it issummary.totalPosts). Fix: Step 4 rewritten to the real schema; Step 6 template({dateRange})dropped,{postCount}→{summary.totalPosts}, eng-rate→{summary.avgEngagementRate}; Deep-Dive post-search fixed from the non-existentposts/<YYYY-WXX>.jsonto iterating the real per-batchposts/*.json.
VERIFY.
- Re-grepped the final file:
engagement_rate/baselines.json/metadata.json/aggregateMetrics/({dateRange})/{postCount}/posts/<YYYY-WXX>.jsonall GONE; corrected strings present (metric engagementRate:171,366;get('alerts', []):227;posts/YYYY-MM-DD-<shortid>.json:414;monthly-reports/YYYY-MM.json:416; Step 4summaryschema:143; Step 6{summary.totalPosts}/{summary.avgEngagementRate}:271–272); no residualdateRange/postCount. bash scripts/test-runner.sh→Passed: 81 · Failed: 0 · Warnings: 0, exit 0; counts 29/19 unchanged (.md-only edit).- Grounded simulation (throwaway
ANALYTICS_ROOT=/private/tmp/claude-report-fixture, discarded): import seeded 3 fake W25 posts →report --week 2026-W25printed "Total saves: 10 (manual entry…)", FIXTURE B (blank saves) showed no suffix, empty alerts (no baseline consulted);trends --metric engagementRateok,--metric engagement_rateexit 1; heatmap rendered. - Disposition: FIXED (6 edits, all in
commands/report.md) · 0 deferrals · axes a/c/d all PASS post-fix (b N/A — not feed-emitting).
/linkedin:analyze — diagnose why content underperforms (reach drop / low traction / low engagement) → recovery plan, analytics grounded via analytics-interpreter
INTENT. Prose-diagnosis + conditional agent-delegation — NOT CLI-backed (allowed-tools: Read, AskUserQuestion, Task, no Bash, analyze.md:9–12). Measure-journey diagnostic. Steps 1–8 are a
faithful restatement of references/troubleshooting-guide.md (drop-% tiers, 14-day recovery protocol,
timeline table, prevention checklist).
SIMULATE. ICP author, scenario 1 (reach −50 %, 1 wk ago, 2 off-pillar posts, 1 body-link). Step 1
picks "Reach suddenly dropped" (:32); Step 2 analytics present → Task subagent_type: linkedin-studio:analytics-interpreter interpret-mode (:41); Step 3 → pattern "Good
Content, Low Reach" (:95–102); Step 4 checklist flags external link + topic drift — and, before fix,
asked "5+ hashtags?" (:149); Step 5 → "Algorithmic suppression likely" → 14-day recovery
(:167–173); Step 6 → /linkedin:profile (:189); Step 7 → "Moderate 50–70 %: 2–3 wks initial"
(:231). Friction: exactly one unsourced checklist item.
EVALUATE (4 axes; analytics-class predicate = graceful degradation + saves/dwell honesty).
- axis-a (intent): PASS — faithful render of the cited guide; AskUserQuestion → framework → recovery flow intact.
- axis-b′ (algorithm-claim vs SSOT — feed-bar reframed since not feed-emitting): 1 FUNN.
:149"Did you use 5+ hashtags in posts?" is a penalty check absent from both the SSOT (grep hashtag references/algorithm-signals-reference.md= NONE — hashtags deliberately omitted) and the citedreferences/troubleshooting-guide.md(NONE; its own penalty checklist is 6 items:101–106). Command-only unsourced folklore carrying a concrete number ("5+"). - axis-c (saves/dwell honesty): PASS — no Bash; never claims to read analytics itself; delegates honestly; no saves/dwell mention anywhere → no over-promise.
- axis-d (wiring + degradation): PASS —
linkedin-studio:analytics-interpreterresolves; interpret-mode is real/default (agent:6,39,141); shared seam${LINKEDIN_STUDIO_DATA:-…}/analytics/(analyze:41↔agent:49);/linkedin:profileresolves (commands/profile.md); "if analytics exists → delegate, else self-report" IF-branch (:41); all 4 referenced files exist.
HARDEN (1 surgical edit, commands/analyze.md).
- [REWORK · axis-b′] Dropped
:149"Did you use 5+ hashtags in posts?" — unsourced in both the SSOT and the cited guide. Step 4 checklist 8 → 7 items; kept:150"tag unrelated people for reach" (defensible — aligns with the SSOT bait/pod-suppression direction, no numeric claim).
Out-of-scope (logged follow-up, NOT touched in S16). troubleshooting-guide.md:127 "External link
overuse — LinkedIn penalizes directing traffic away" contradicts the SSOT (:69–75: LinkedIn denies an
intentional penalty; soften to "body links correlate with lower reach"). analyze.md:102 only echoes the
milder guide wording verbatim (guide:15) — softening the command alone would drift it from its own cited
source, so the real fix belongs to the reference-consistency pass.
VERIFY.
- Re-grepped final file:
grep hashtag commands/analyze.md→ NONE; Step 4 checklist now 7 items (:143–149),:149= "tag unrelated people for reach" (survived). git diff --stat= 1 file, 1 deletion.bash scripts/test-runner.sh→Passed: 81 · Failed: 0 · Warnings: 0, exit 0; counts 29/19 unchanged (.md-only edit).- Disposition: FIXED (1 edit,
commands/analyze.md) · 0 deferrals · axes a/c/d PASS, b′ PASS post-fix.
/linkedin:audit — quarterly content-strategy audit (top/bottom posts · topic & format mix · trends · milestone) → report + routes to strategy/profile
INTENT. Prose-heavy, self-contained quarterly audit — NOT CLI-backed, NOT agent-delegated
(allowed-tools: Read, Glob, Grep, AskUserQuestion post-fix, no Bash, no Task, audit.md:8–12).
Measure-journey (reachable via /linkedin:measure). The 8 steps (0–8 + 5.5) faithfully cover the
description scope: top/bottom performers, topic distribution, format mix, engagement trends, milestone
progress, profile alignment — quarterly cadence. Names the gap; routes the fix to /linkedin:strategy
(trajectory) + /linkedin:profile (profile audit).
SIMULATE. ICP author, scenario A (partial data). Step 0 reads state + plans/ + checks analytics/
- audience-insights/examples, asks user for top-5/bottom-5 + screenshot; Steps 1–2 tabulate vs 7 factors
(
:41–49); Step 3 topic-mix vs pillars (:69–81); Step 4 format mix → emits "Increase carousel content (highest save rate)" (:93, before fix); Step 5 trends; Step 5.5 milestone iffollower_count>0; Step 6 routes to/linkedin:profile(:151); Step 7 report; Step 8 AskUserQuestion. Scenario B (fresh adopter, no data): Step 0:26"Check for any" = soft, audience files absent → degrades to user-provided data; Step 5.5:141follower_countnot >0 → "Skip this step. Add note: …not configured" — no crash. Friction: one orphan tool-grant + one unsourced format-claim.
EVALUATE (4 axes; analytics-class predicate = graceful degradation + saves/dwell honesty).
- axis-a (intent): PASS — 8 steps faithfully cover the description scope; routing-by-delegation (not
agent delegation) is honest ("names the gap, strategy/profile prescribe the fix",
:145–156). - axis-b′ (algorithm/format claim vs SSOT): 1 FUNN.
:93"(highest save rate)" — the specific metric-attribution is absent from the SSOT (which sources "carousels = top organic format",algorithm-signals-reference.md:55, and "saves = top engagement signal",:42, but never "carousels = highest save rate") AND from the cited refs (playbook:248"Carousels: 1.6x",:192"60–70 % reduced reach"; no save-rate superlative). Postulated mechanic embedded in an example block. - axis-c (quality rules): PASS — emits no content; no format/length advice contradicting CLAUDE.md.
- axis-d (wiring + degradation): 1 FUNN. No Task → claims no agent delegation (
grep subagent_type|Task= NONE) ✅;/linkedin:strategy+/linkedin:profileresolve ✅; graceful degradation present (Step 5.5 explicit skip + user-provided-data primary path) ✅; data-seam consistent (${LINKEDIN_STUDIO_DATA:-…}/data,~/.claude/linkedin-studio.local.mdstate,${CLAUDE_PLUGIN_ROOT}/refs) ✅; saves/dwell not over-promised (no Bash; never claims auto-track) ✅. FUNN: WebFetch orphan tool-grant —:12granted it; body:20–234never fetches (grep = declaration line only).
HARDEN (2 surgical edits, commands/audit.md).
- [REWORK · axis-d] Dropped
WebFetchfrom allowed-tools — granted but never invoked; audit reads local files + asks user + routes, fetches no URL. Tool-surface now matches behavior (5 → 4 tools). - [REWORK · axis-b′]
:93→:92"(highest save rate)" → "(top organic format)" — aligned to the SSOT's sourced framing; dropped the unsourced save-rate superlative.
Out-of-scope (logged, NOT touched in S17). :61 "off-topic (topic-relevance penalty)" — SSOT frames
topic-relevance as a positive distribution driver (:30,89, high), not a named penalty; but off-topic →
weaker relevance match → less reach is defensible and "topic-relevance signal" is plugin convention
(CLAUDE.md rule #5). Left as-is (NICE, directionally correct diagnostic parenthesis).
VERIFY.
- Re-grepped final file:
grep WebFetch commands/audit.md→ NONE (allowed-tools now Read/Glob/Grep/AskUserQuestion,:9–12);grep "highest save rate"→ NONE;:92= "Increase carousel content (top organic format)". git diff --stat= 1 file, +1 / −2.bash scripts/test-runner.sh→Passed: 81 · Failed: 0 · Warnings: 0, exit 0; counts 29/19 unchanged (.md-only edit).- Disposition: FIXED (2 edits,
commands/audit.md) · 0 deferrals · axes a/c PASS, b′ + d PASS post-fix.
/linkedin:ab-test — design/log/analyze/history/suggest A/B experiments → managed test files, challenger rewrite delegated to content-optimizer
INTENT. Stateful analytics command — the most composite class in the queue so far. CLI-backed (Bash
ls/cat/mkdir -p + Write of [test-name].md test files under the data-dir), agent-delegated
(content-optimizer via Task subagent_type: linkedin-studio:content-optimizer, :119), AND routing
(/linkedin:post :448, /linkedin:report :459, /linkedin:analyze :467). Measure-journey
(reachable via /linkedin:measure). Five lifecycle modes (2a–2e) map 1:1 to the description: design ·
log · analyze · history · suggest. (STATE predicted analytics-interpreter delegation; actual is
content-optimizer.)
SIMULATE. ICP author → analyze an active hook experiment. Throwaway 2-experiment fixture in
/private/tmp/claude-abtest-fixture/analytics/ab-tests/ (ACTIVE 6-post + COMPLETED), run via
LINKEDIN_STUDIO_DATA=<fixture> to exercise the real seam. Seam-discovery (:37,:270) found both
files; analyze arithmetic computed correct (eng-rate :236 per-post 3.0%/5.0%; variant avg + %-diff
:278–279 → eng +66.7%, comments +200%, impressions/reposts +0%); directional test (:311) cleared
20% AND consistent across all 3 paired posts → "Adopt B (directional)"; significance honesty (:320–331)
correctly flagged 3/variant << ~50 → directional, NOT significant. History-parse targets all present in
COMPLETED fixture. Empty weekly-reports/ + posts/ → graceful degradation (:485–488). Fixture
discarded (find -delete).
EVALUATE (8 predicates across 4 axes; class = stateful + analytics + agent-wiring + routing).
- P1 (axis-d wiring): PASS —
content-optimizerresolves;agents/content-optimizer.mdname:matches the namespaced invocation form. - P2 (routing): PASS —
post/report/analyze.md all resolve. - P3 (intent refs): PASS —
ab-testing-framework.md+algorithm-signals-reference.mdexist. - P4 (axis-b′ SSOT): 1 FUNN. ② 20%-threshold verbatim from framework SSOT (
fw:173=ab:311) ✅; ③ significance honesty under-claims (a real significance test needs more than ~50/variant → the framing can only make the "directional not significant" verdict safer) ✅; ①:128"(Tue-Thu, 8-9 AM optimal)" — sourced (cites the ref) but "optimal" over-claims precision against the SSOT's own:23"trust the ordering, test the number", and Thu is 9 AM–1 PM in SSOT (alg:144), not 8 AM; it is the default slot held constant while testing another variable, so "optimal" is the wrong word. - P5 (data-seam): PASS — all data via
${LINKEDIN_STUDIO_DATA:-…}/;:44= state file (correct), not a leak; refs via${CLAUDE_PLUGIN_ROOT}/. - P6 (graceful degradation): PASS — empty weekly-reports/posts → proceed test-only (
:485–488); 4 error modes (:474–493). - P7 (saves/dwell honesty): PASS — no saves/dwell mention; eng-rate
:236excludes saves (S16-consistent). - P8 (stateful artifact trace): PASS — see SIMULATE; full analyze + history path sound against a realistic file.
HARDEN (1 surgical edit, commands/ab-test.md).
- [REWORK · axis-b′]
:128"(Tue-Thu, 8-9 AM optimal)" → "(Tue-Thu mornings)" — dropped the precision over-claim ("optimal" + the inaccurate 8 AM window); the line stem already citesalgorithm-signals-reference.md, so source attribution is retained.
Out-of-scope (logged, NOT touched in S18). :284 "baseline comparison" cross-ref vs weekly-reports/
— echoes the S15 "baselines/metadata phantom" vocabulary, but here it reads an existing artifact (the
report command's weekly reports), optional + graceful-degraded; legitimate soft context, not a phantom.
Left as-is (low, no-change).
VERIFY.
- Re-grepped final file:
grep "8-9 AM optimal"→ NONE;:128= "...based on algorithm-signals-reference.md (Tue-Thu mornings)". git diff --stat= 1 file, +1 / −1.bash scripts/test-runner.sh→Passed: 81 · Failed: 0 · Warnings: 0, exit 0; counts 29/19 unchanged (.md-only edit).- Disposition: FIXED (1 edit,
commands/ab-test.md) · 0 deferrals · P1–P3,P5–P8 PASS, P4 PASS post-fix.
/linkedin:strategy — phase-aware growth + authority-building plan (S19)
INTENT. Grow-journey front-door (CLAUDE.md elevates onboarding/strategy as the Start/Grow
front-doors) and atomic command. Prose-heavy, no Bash (allowed-tools: Read·Glob·Grep·
WebFetch·AskUserQuestion·Task). Reads state (follower_count → phase auto-detect) + 8 local refs,
delegates the growth recommendation to strategy-advisor, routes the profile audit to
/linkedin:profile. Most composite non-CLI class: prose + state-read + agent-delegation + routing +
axis-b′.
SIMULATE (ICP author, grounded prose-trace — no fixture; touches no real state/data). "What should
I focus on at my level?" → Step 0.5 auto-detects phase from follower_count (graceful: :43 falls
through to Step-1 questions if 0/missing) → AskUserQuestion → Step 3 delegates to
linkedin-studio:strategy-advisor (:154) → phase strategy + Step 3.5 trajectory overlay (graceful:
:285 "Skip this step. Note: …" when no milestone data) → Step 3.6 authority-building (Phase 2+).
Friction: none surfaced; phase bands consistent between Step 0.5 (:38–42) and the Step 2 headers
(:79/:93/:107/:122/:137).
EVALUATE (4 axes; mechanical predicate per axis).
- (a) intention: PASS — body delivers exactly the description: phase-specific guidance 0–1K→10K+, trajectory overlay, Phase 2+ signature-content compounding.
- (b) algorithm/format-bar (axis-b′): PASS — topic-relevance is the SSOT signal (
:88/:175/:520); growth rates / timelines are roadmap-sourced (command loadsgrowth-roadmaps.md+trajectory-strategy-adjustments.md), not postulated in-command; saves-honesty intact (:300/:408"read from native LinkedIn analytics — not auto-tracked by this tool"). - (c) quality rules: PASS — no buzzwords, no body-links; prose-only command (no post emission).
- (d) agent-wiring + graceful degradation: 1 FINDING — P-checks: agent
linkedin-studio:strategy-advisor(:154, namespaced) →agents/strategy-advisor.mdresolves; routing/linkedin:profile(:293/:361) →commands/profile.mdresolves; 8/8 referenced files exist; graceful degradation present (:43/:285/:408). allowed-tools over-grant::16WebFetchis the ONLY occurrence in the file (grep -n WebFetch=:16only) — never used in the body (no URL fetch anywhere; body reads local refs + state, delegates, AskUserQuestion); delegatestrategy-advisoris Read+Glob only, so it doesn't need it either. Exact S17 pattern (62b7081). Borderline Grep/Glob left as-is (local, low-risk, plausibly used for state/analytics reads) — only the external-network WebFetch trimmed.
HARDEN (1 surgical edit, commands/strategy.md).
- [REWORK · axis-d]
:16removed- WebFetchfromallowed-tools— orphan grant (external-network capability, zero usage). allowed-tools now Read·Glob·Grep·AskUserQuestion·Task.
VERIFY.
- Re-grepped final file:
grep -n WebFetch commands/strategy.md→ NONE; allowed-tools block = Read/Glob/Grep/AskUserQuestion/Task. git diff --stat= 1 file, −1.bash scripts/test-runner.sh→Passed: 81 · Failed: 0 · Warnings: 0, exit 0; counts 29/19 unchanged (.md-only edit).- Disposition: FIXED (1 edit,
commands/strategy.md) · 0 deferrals · axes a/b/c PASS, axis-d PASS post-fix.
/linkedin:competitive — niche thought-leader analysis → landscape map · gap matrix · differentiation plan (S20)
INTENT. Grow-journey atomic command (with monetize/outreach/profile). Prose-heavy guided
analysis — not post-emitting, not routing (no /linkedin:Y emitted), not own-data
analytics. Six-step flow (Step 0–6) producing prose output (no persisted artifact: no Write/Task).
User names 3–5 competitor profiles (or asks for help finding them) → competitive map + gap analysis +
differentiation plan. Ethics Note (:155-157) steers toward inspiration, not copying.
SIMULATE (ICP author, grounded prose-trace — no fixture; touches no real state/data). Two branches
proved against Step 0–6 (:19-153): A (names 3 profiles, choice 1 :30) → reads SKILL.md+state
(:21-23) → per-competitor template Step 2 (:46-76, all fields are [placeholders] the user/observation
fills — no fabricated data) → landscape map Step 3 → gap matrix Step 4 → differentiation plan Step 5 →
takeaways Step 6 → Ethics Note. B (choice 2 "help me find", :31) → triggers WebSearch (:34) →
same analysis loop. No branch invokes WebFetch.
EVALUATE (relevant axes; mechanical predicate each).
- (a) intention: PASS — body delivers exactly the description: posting frequency, content types, hooks, engagement strategy, gaps → differentiation.
- (b) algorithm/format-bar (axis-b′): PASS —
grep -nE "[0-9]+ ?(%|x|times)"= NONE; format fields (:54text X%/carousel Y%/video Z%) are letter-placeholders, not postulated stats; folklore grep hit only:8/:116(false positives). No unsourced algorithm claim. - (c) quality rules: PASS — prose-only command (no post emission), Ethics Note present.
- (d) agent-wiring + graceful degradation: 1 FINDING — no agent delegation (selbständig prose,
correct for class); 5/5 referenced files resolve (
:21,:161-163+ state PRESENT); graceful degradation present (Step 1 AskUserQuestion 3 branches + WebSearch fallback:34). allowed-tools over-grant::11WebFetchwas the ONLY occurrence (grep -n WebFetch=:11only) — never used in the body; WebSearch (:12grant +:34real use) covers the entire legitimate external need (finding thought leaders), and WebFetch against LinkedIn profile URLs cannot deliver the public feed content the grant implies (login/anti-bot). Exact S17/S19 pattern. Borderline Glob (:10grant, no body use) left as-is (local, low-risk read tool) — only external-network WebFetch trimmed.
HARDEN (1 surgical edit, commands/competitive.md).
- [REWORK · axis-d]
:11removed- WebFetchfromallowed-tools— orphan grant (external-network capability, zero usage, not realizable for LinkedIn profiles). allowed-tools now Read·Glob·WebSearch·AskUserQuestion.
VERIFY.
- Re-grepped final file:
grep -n WebFetch commands/competitive.md→ NONE; allowed-tools block = Read/Glob/WebSearch/AskUserQuestion. git diff --stat= 1 file, −1.bash scripts/test-runner.sh→Passed: 81 · Failed: 0 · Warnings: 0, exit 0; counts 29/19 unchanged (.md-only edit).- Disposition: FIXED (1 edit,
commands/competitive.md) · 0 deferrals · axes a/b/c PASS, axis-d PASS post-fix.
/linkedin:monetize — turn thought leadership into revenue (readiness → stage strategy → lead magnet → funnel → tracking)
INTENT. Prose-heavy guided monetization strategist (Grow-tier atomic, unlocks ~1K followers). 9-step flow
(Step 0–8 :22-487): load refs → readiness scorecard → stage-specific strategy → lead-magnet blueprint →
funnel content → CTA optimization → Featured section → revenue model worksheet → tracking dashboard. Output is
prose templates the user fills in; persists nothing.
SIMULATE (aspiring monetizer, grounded prose-trace — no fixture; touches no real state/data). Traced
Step 0–8 against the file. Step 1 collects follower count / engagement / offers / goals via AskUserQuestion
(:37) — does NOT read state, so it degrades gracefully (asks rather than depends). Stage-1 branch (0–1K,
score 0–30, :94-112) handles the sub-unlock case honestly ("Revenue is secondary… DO NOT sell aggressively").
All scorecards/blueprints/worksheets are [placeholder] fill-ins — no fabricated user data. No branch
invokes WebFetch, Write, Glob, or Grep.
EVALUATE (relevant axes; mechanical predicate each).
- (a) intention: PASS — body delivers the description (readiness scoring, stage strategy, lead magnets, CTA A/B, funnel, consulting-inquiry tracking). 7/7 referenced files resolve (Step 0 + Reference Files).
- (b) algorithm/conversion-bar (axis-b′): 1 FINDING —
:344-346postulated a generic time-decay curve ("same-day ~half / next-day 20-30% / 3+ days <10%"). SSOT (opportunity-generation.md:302-310) gives per-channel rates (speaking 30-50% same-day, consulting 20-30% within-24h, podcast 70-80%) + qualitative "speed matters", NOT a generic decay curve — and<10%is invented, no SSOT basis. Same over-precise -unsourced pattern as S18. (:495external-links claim was already SSOT-sourced + softened — clean.) - (c) quality rules: PASS — prose-only (no post emission); no buzzwords;
:495correctly sourced. - (d) agent-wiring + graceful degradation: 2 FINDINGS (allowed-tools over-grant) — no agent delegation
(selbständig prose, correct for class).
:13WebFetch= orphan grant, ONLY occurrence (grep -n WebFetch=:13only), zero body use, WebSearch not even granted → pure dead external-capability grant, exact S17/S19/S20 pattern.:15Write= orphan grant, ONLY occurrence, zero body use — command never persists a file; unused mutation capability (stronger least-privilege case than read grants). BorderlineGlob/Grep(:11-12, no body use) left as-is (local, low-risk read tools — S20 precedent).
HARDEN (2 surgical edits, commands/monetize.md).
- [REWORK · axis-d] removed
- WebFetchand- Writefromallowed-tools— orphan grants (zero usage; external-fetch never realized, file never written). allowed-tools now Read·Glob·Grep·AskUserQuestion. - [REWORK · axis-b′]
:343-346replaced the fabricated decay curve (incl. invented<10%) with the SSOT-supported qualitative claim ("speed compounds conversion — same-day converts far better than days-later") + cite toreferences/opportunity-generation.mdfor the real per-channel benchmarks.:313/:323"within 2 hours" left as-is (defensible tactical advice, not a fabricated statistic — operator OK).
VERIFY.
- Re-grepped final file:
grep -n WebFetch→ NONE;grep -n Write→ NONE;grep -n "roughly half|<10%|3+ days|20-30% conversion"→ NONE; allowed-tools block = Read/Glob/Grep/AskUserQuestion. git diff --stat= 1 file, +3 / −6.bash scripts/test-runner.sh→Passed: 81 · Failed: 0 · Warnings: 0, exit 0; counts 29/19 unchanged (.md-only edit).- Disposition: FIXED (2 edits,
commands/monetize.md) · 0 deferrals · axes a/c PASS, axes b′/d PASS post-fix.
/linkedin:outreach — collab + speaking outreach orchestrator (track select → readiness → targets → format/pitch → production → pipeline persist) (S22)
INTENT. Grow-tier orchestrator (unlocks ~1K), prose-heavy + agent-delegating + state-persisting.
Two tracks (collab + speaking) under one paradigm, 11 steps (Step 0–10 :65-1252). Absorbed
collab/speaking/authority (capability checklist :36-63 maps each predecessor function). First in
the queue to BOTH delegate to an agent AND mutate real state — shifts the weight onto axis-d.
SIMULATE (adversarial cold quality-reviewer; grounded prose-trace + throwaway state fixture — operator chose the thorough path; touches no real state/data-dir). Traced Step 0–10 against the file; verified every mechanical claim (refs resolve, agent resolves, mutation exists, grants match body use, axis-b′ claims trace to SSOT) with a tool, never by reasoning.
EVALUATE (relevant axes; mechanical predicate each).
- (a) intention: PASS — checklist maps both predecessors; all 5 refs + SKILL.md resolve (Step 0 +
Reference Files); state path
~/.claude/linkedin-studio.local.mdcorrect post-M0 (per CLAUDE.md). - (b) algorithm/conversion-bar (axis-b′): 2 FINDINGS. B1
:652"DM amplification can boost first-hour engagement 2-3x" — over-quantified: 2-3x is SSOT for collab reach (collaborations-guide.md:32/165/187), while the DM-loop's first-hour effect is held qualitative there (:335). B2:921-946Step 7 pod-warning fabricated magnitudes — "30-55% reach reduction", "shadow suppression", "account credibility score reduction", "penalizes", "Post-March 2025 Update" + "low dwell" detection (dwell unmeasurable per CLAUDE.md). SSOT (algorithm-signals-reference.md:98) states ONLY: "auto-comments demoted out of 'Most Relevant', scoped to own network; repeat offenders restricted" (Sachdeva 2026-02-16, high) + design rule "do not quote a percentage / soften penalty". Same S18/S21 + follow-up-#1 pattern. - (c) quality rules: PASS — prose templates only (no post emission); "thought leader"/"ecosystem"
appear only in search-queries / internal goals (
:230/:813/:820), not in published post-copy (Rule 4). - (d) agent-wiring + grants + state + graceful: 3 FINDINGS. D1 PASS —
Task subagent_type: linkedin-studio:network-builder(:172) resolves (agents/network-builder.md). D2 PASS —recordOutreachContactis NOT fabricated (state-updater.mjs:294, CLI--record-outreach :394, additive,$-safe). D3 Bash MISSING — Step 8c (:1064) runsnode …state-updater.mjs --record-outreach(needs Bash) but frontmatter didn't grant it;firsthour.mdgrants Bash for the samenode-mutation pattern → functional defect (command promised a mutation it couldn't execute). D4 WebFetch orphan (:19, zero body use). D5 Write orphan (:21;:410/:1040are prose "Write a post", not tool use).
HARDEN (5 edits across 2 files — operator-approved scope extension to also fix the SSOT-diverging guide source so the B2 rewrite can't be re-rendered from a stale reference).
- [REWORK · axis-d]
commands/outreach.mdfrontmatter: dropped- WebFetch+- Write(orphans), added- Bash(Step 8c needs it). allowed-tools now Read·Glob·WebSearch·AskUserQuestion·Task·Bash (borderline Glob kept — S20 precedent). - [REWORK · axis-b′]
:652(B1): re-attributed 2-3x to collab reach (where SSOT places it), kept the first-hour effect qualitative + cite tocollaborations-guide.md. - [REWORK · axis-b′] Step 7 (B2): replaced "Post-March 2025 Update" header + the fabricated detection/penalties block with the SSOT crackdown statement (demote out of "Most Relevant" / scope to own network / restrict repeat offenders) + cite; softened "penalizes", dropped "low dwell".
- [REWORK · axis-b′, scope-extension]
references/collaborations-guide.md:349-370(B2 propagation): same SSOT rewrite of the "March 2025 Crackdown" section — dropped "shadow banning ALL future content / 90+ days / 6+ months / permanent reach penalty", the date, and the speculative detection methods (browser-extension tracking, linguistic fingerprinting).
VERIFY.
- Re-grepped final files.
commands/outreach.md:grep WebFetch→ NONE,^ - Write$→ NONE,^ - Bash$→:21; B1 old form → NONE (new:651); B230-55%|Post-March 2025|penalizes engagement pods|credibility score|Low dwell|Shadow suppression→ NONE (SSOT text:928-929).references/collaborations-guide.md:90+ days|6+ months|never fully recover|permanent reach penalty|Shadow banning affects ALL|March 2025 Crackdown→ NONE (SSOT text:349/:364). - D2/D3 throwaway fixture (
/private/tmp/claude-*, fictional, deleted after):recordOutreachContactdirect-call (nowriteState), 10/10 assertions PASS — additive insert afterlast_post_date,outreach_activeuntouched when undeclared, pre-existing fields + custom section intact, newest-first append,$-safe (@kari$bosspreserved literally — S13 behavioral), section auto-created. git diff --stat= 2 files, +20 / −28.bash scripts/test-runner.sh→Passed: 81 · Failed: 0 · Warnings: 0, exit 0; counts 29/19 unchanged (.md-only edits — node hook/analytics tests not triggered).- Disposition: FIXED (5 edits, 2 files) · 0 deferrals · axes a/c PASS, axes b′/d PASS post-fix. Note: state-updater HTML-comment lands between newest+older rows on repeat append = cosmetic, logged as non-scope follow-up (the command calls the mutation correctly).
/linkedin:profile — profile/topic-relevance + profile-SEO audit walkthrough (7 sections → prioritized action plan); self-contained, no agent/routing/state (S23)
INTENT. Grow-tier atomic execution command, prose-heavy + guided (AskUserQuestion).
Self-contained — no agent delegation, no /linkedin:Y routing, no state mutation. Audits the
profile for the topic-relevance ranking signal + profile search-SEO.
SIMULATE (adversarial cold quality-reviewer; grounded prose-trace — pure prose, NO fixture: command
reads/mutates no state). Headline section (:79-96) traced against operator input
"AI-rådgiver | KI-transformasjon | Innholdsprodusent" → checklist :85-88 yields NO audience / NO
outcome / vague titles → concrete non-generic rewrite direction. Every mechanical claim (grant grep, SSOT
read, pattern greps) from a tool, never by reasoning.
EVALUATE (relevant axes; mechanical predicate each).
- (a) intention: PASS — desc + Grow-journey role coherent; 3 refs (
algorithm-signals-reference.md,troubleshooting-guide.md,SKILL.md) resolve. - (b) algorithm-bar (axis-b′): 1 systemic FINDING (B1) + 1 minor (B2). B1 — "profile-as-validated-object"
overclaim, 9 sites: the file repeatedly asserts the relevance model reads & validates your profile
and gates distribution on it —
:5"validates your profile BEFORE distributing content";:31"the model evaluates five criteria (see SSOT)" (false SSOT attribution — SSOT has no such breakdown);:35-39"Impact if Missing: HIGH/HIGH/MEDIUM…" (postulated coefficients SSOT forbids,:14/:23);:99"first signal telling … what you're qualified to discuss";:161"relevance validation";:173"checks if you're connected";:230"if LinkedIn's AI read my profile, would it believe";:51/:67SEO conflation ("tell the relevance model what you're expert in" / "the relevance model's expertise signal"). SSOT (algorithm-signals-reference.md:25-30/:85-90) confirms ONLY: topic/interest relevance is a ranking input — content matched to a viewer's interests is distributed incl. beyond your network (Jurka, high); no off-topic magnitude figure; no weighted profile criteria. File was internally inconsistent — its own soft, SSOT-true framing already at:17/:25/:27. Same class as follow-up #1 (audit.md:61) + v4.0.0 "reconcile to one sourced statement". B2:24"Goes to 10% of audience" — postulated old-model number (:131"40%" is an illustrative impact-bullet example → PASS). - (c) quality rules: PASS — no post emission (audit prose only); buzzword list cited correctly (
:73steers away from "thought leader/guru/ninja"). - (d) grants + graceful + wiring: PASS. Grant-hygiene REN (two-way):
allowed-tools=Read+AskUserQuestion(:11-13), both used (:21/:27/:31/:236Read;:77AskUserQuestion); WebFetch / Write / Bash / Task / subagent_type / .mjs → NONE (no orphans, no missing node/Bash grant). No agent/routing. Graceful degradation OK (Q&A runs regardless of ref availability). - P3 — profile-SEO honesty (
:41-73): largely defensible (about LinkedIn search, not the ranking model; correctly does NOT cite SSOT). One practitioner-claim-as-fact: "highest-weight search field" (:52prose +:61table) — self-justified mechanically, softened not removed.
HARDEN (12 edits, 1 file — commands/profile.md; all surgical re-source to SSOT framing).
- [REWORK · b′]
:5desc — "validates your profile BEFORE distributing content" → "a coherent, on-topic profile reinforces the topic-relevance signal LinkedIn uses to decide how widely your content is distributed". - [REWORK · b′]
:24(B2) — "Goes to 10% of audience" → "a slice of your network sees it". - [REWORK · b′]
:25/:27— "content matched to your demonstrated expertise" → "a viewer's interests" (SSOT wording) + added "LinkedIn confirms no off-topic reach-reduction figure — not a quantified penalty". - [REWORK · b′]
:31+ table:33-39— dropped "the model evaluates five criteria (see SSOT)" + HIGH/MEDIUM "Impact if Missing" weights → "LinkedIn does not publish a profile-scoring breakdown … practitioner heuristics", column → "Priority (heuristic)", High/Medium relabeled directional. - [REWORK · b′]
:99— "first signal telling … qualified to discuss" → "the clearest place to state … the strongest single contribution to a coherent topic signal". - [REWORK · b′]
:161— "Critical for profile/topic-relevance validation" → "Your top skills are a strong, searchable topic signal". - [REWORK · b′]
:173— "relevance checks if you're connected" → "a network concentrated in your expertise area reinforces your topic signal and social proof (heuristic — LinkedIn doesn't publish network as a profile-ranking factor)". - [REWORK · b′]
:230— "If LinkedIn's AI read my profile, would it believe I'm an expert" → "Does my profile make it obvious — to a human and to LinkedIn's topic-matching". - [REWORK · b′]
:51/:67SEO conflation — "tell the relevance model what you're expert in" → "make your topic legible … to topic-relevance distribution"; "the relevance model's expertise signal" → "carry your strongest on-topic signal". - [NICE · P3]
:52/:61— "highest-weight search field" → "highest-leverage" (×2; rest self-justified, kept).
VERIFY.
- Re-grepped final file. All overclaim/conflation patterns (
validates your profile before | evaluates five criteria | first signal telling | qualified to discuss | checks if you're connected | relevance validation | if linkedin's ai read | 10% of audience | highest-weight | demonstrated expertise | Impact if Missing | tell the relevance model | relevance model's expertise signal) → NONE. New SSOT text present (:26/:28/:33/ :38/:54/:178/:235). - Grant-hygiene unchanged:
allowed-tools= Read + AskUserQuestion (:11-13); WebFetch/Write/Bash/Task/.mjs → NONE. git diff --stat= 1 file, +28 / −22.bash scripts/test-runner.sh→Passed: 81 · Failed: 0 · Warnings: 0, exit 0; counts 29/19 unchanged (.md-only edits — node hook/analytics tests not triggered).- Disposition: FIXED (12 edits, 1 file) · 0 deferrals · axis-b′ FIXED, axes a/c/d PASS · no fixture needed (pure prose, no state).
/linkedin:create — content-creation front-door (guided "what to make?" → routes to the owning creation command); delegates only, no drafting (S24)
CLASS: routing front-door (Create-journey, v4.1). Predicate: every emitted /linkedin:Y resolves to
commands/Y.md; bidirectional grant-hygiene; "delegates only" (never drafts).
TEST (tool-grounded).
- Routing (main axis): 8/8 targets resolve —
commands/{post,quick,react,carousel,video,multiplatform, batch,newsletter}.mdall present (menu:38-45/ table:54-63). - Grant-hygiene (bidirectional):
Read(:13) used at:26(fixed-path state read);AskUserQuestion(:15) used at:36;Glob(:14) ORPHAN — zero body usage, only file access is the fixed-path Read (:26; Read handles the "if exists" itself — no pattern-matching). No missing grants (routing = narrative handoff, no tool). - Delegates-only: all 4 "draft" hits are the no-draft promise (
:7/:22, long-form lock:66) or target-description (:38= what/linkedin:postdoes); no drafting leak. - Persona (ICP author, no format named): Step 0
:24-28state glance → Step 1:30-45AskUserQuestion (8 opts) → Step 2:47-63route into target workflow, steps not inlined; URL fast-path:32-34→/linkedin:react. ✓
HARDEN (1 edit, 1 file — commands/create.md).
- [REWORK · grant-hygiene] dropped orphan
Globfromallowed-tools(:14); net = {Read, AskUserQuestion}.
VERIFY.
- Re-grep final:
Glob→ NONE;allowed-tools= Read + AskUserQuestion (:13-14). git diff --stat= 1 file, −1.bash scripts/test-runner.sh→Passed: 81 · Failed: 0 · Warnings: 0, exit 0; counts 29/19 unchanged (.md-only edit).- Disposition: FIXED (1 edit, 1 file) · 0 deferrals · routing axis PASS, delegates-only PASS, grant-hygiene FIXED · no fixture (pure routing prose).
- Scope note:
Glob-orphan may be systemic in sibling front-doors (measureS25,linkedinS26) — not expanded (one command per session); each catches its own.
/linkedin:measure — performance front-door (guided "how am I doing?" → routes to the owning analytics command); delegates only, no number-crunching (S25)
CLASS: routing front-door (Measure-journey, v4.1). Predicate: every emitted /linkedin:Y resolves to
commands/Y.md; bidirectional grant-hygiene; "delegates only" (never crunches numbers).
TEST (tool-grounded).
- Routing (main axis): 5/5 targets resolve —
commands/{import,report,analyze,audit,ab-test}.mdall present (menu:31-35/ table:44-48/ order-note:51). - Grant-hygiene (bidirectional):
AskUserQuestion(:13) used at:29;Glob(:12) +Read(:11) — neither named a tool in body, both hung only on the optional Step 0 filesystem glance (:22-25, pre-edit). UNLIKEcreate(Glob a pure orphan, no fs-check at all), measure HAS a Step 0 ("if…/analytics/holds imported data, note last import"), givingGloba real home — but the grant↔use link was implicit (body named no tool). - Delegates-only: 3 no-do promises (
:7,:20,:40); all crunch/analysis hits are negations — no leak. - Persona (ICP author, "how am I doing?"): Step 0 optional analytics glance → Step 1 AskUserQuestion (5
opts)
:29→ Step 2 route into target workflow:37-48; order-note:50-51(no data → import first). ✓ - No fixture (pure routing prose).
HARDEN (operator-chosen — explicit Glob, drop Read; 2 edits, 1 file — commands/measure.md).
- [REWORK · grant-hygiene] dropped
Readfromallowed-tools(:11, pre-edit) — redundant; the Step 0 import-date need is met by aGloblisting of the analytics dir. - [REWORK · grant↔use traceability] made Step 0 explicit: "You may
Glob…/analytics/; if it holds imported data, note last import" (:23), giving the retainedGlobgrant a named body home. Net grants = {Glob, AskUserQuestion}.
VERIFY.
- Re-grep final:
Readas a tool name → NONE;allowed-tools= Glob + AskUserQuestion (:11-12);Globnow in body:23. - Routing unchanged: 5 distinct targets, all present.
git diff --stat= 1 file, +1/−2.bash scripts/test-runner.sh→Passed: 81 · Failed: 0 · Warnings: 0, exit 0; counts 29/19 unchanged (.md-only edit).- Disposition: FIXED (2 edits, 1 file) · 0 deferrals · routing axis PASS, delegates-only PASS, grant-hygiene FIXED (Glob retained + made explicit, Read dropped).
- Scope note: the
Glob-orphan question is now resolved formeasure(it had a home via Step 0;createdid not).linkedin(S26) still to check independently.
/linkedin:linkedin — top router (five-journey menu + status line + queue glance); routes to every command/agent, executes nothing (S26)
CLASS: routing (the master router over the whole surface — the largest routing check: 28 command
pointers + 10 agent pointers). Predicate: every emitted /linkedin:Y resolves to commands/Y.md; every
"Suggest X agent" resolves to agents/X.md; bidirectional grant-hygiene; "delegates only" (shows
menu/status, never executes).
TEST (tool-grounded).
- Routing (main axis): 28/28 distinct
/linkedin:Ytargets resolve tocommands/Y.md(menu:66-127, ask-menu:136-140, direct-routing:157-198) — the full sub-command surface (+linkedinitself = 29). - Agent pointers (axis d): 10/10 "Suggest
Xagent" resolve toagents/X.md(analytics-interpreter, content-optimizer, content-planner, content-repurposer, differentiation-checker, engagement-coach, network-builder, post-feedback-monitor, trend-spotter, voice-trainer). - Grant-hygiene (bidirectional):
allowed-tools= Read/Bash/AskUserQuestion (:8-11); each has a body home — Read→state status line (:20), Bash→node queue-manager block (:34-42), AskUserQuestion→sub-choice (:145); no ungranted tool referenced, no Glob at all — third front-door is clean (unlike create's Glob-orphan / measure's Glob-via-Step-0). - Delegates-only: body routes/suggests;
:146"invoke it directly" = hand-off to the command, not self-execution. No drafting / number-crunch. PASS. - Graceful degrade (axis d): no-state fallback (
:28) + empty-queue fallback (:57). PASS. - Persona (ICP author types
/linkedin): graceful-degrade path — no fixture (pure routing prose).
FINDING (terminology — operator rule surfaced this session): "thought leadership" must not appear in the
plugin (it is named LinkedIn Studio). linkedin.md used it at :4 (frontmatter description) + :16 (body).
HARDEN (2 edits, 1 file — commands/linkedin.md).
- [REWORK · terminology]
:4"Main router for LinkedIn thought leadership commands" → "Main router for LinkedIn Studio commands". - [REWORK · terminology]
:16"You are a LinkedIn thought leadership assistant" → "You are the LinkedIn Studio assistant".
VERIFY.
- Re-grep final: "thought leadership" in linkedin.md → NONE;
:4/:16show "LinkedIn Studio". - Routing/agent axes unchanged: 28 + 10 targets all resolve.
git diff --stat= 1 file, +2/−2.bash scripts/test-runner.sh→Passed: 81 · Failed: 0 · Warnings: 0, exit 0; counts 29/19 unchanged (.md-only prose edit).- Disposition: FIXED (2 edits, 1 file) · 0 deferrals · routing PASS, agent-wiring PASS, grant-hygiene PASS (clean — no orphan; third front-door has no Glob), delegates-only PASS.
SURFACED (out of scope → queued as S29). "thought leadership" appears plugin-wide on 85 lines across
~45 files (commands, agents, references incl. the filename references/thought-leadership-angles.md,
skills, plus historical CHANGELOG/docs). Promoted to a dedicated terminology-scrub pass S29
(docs/hardening/plan.md); the user-facing-vs-historical boundary + the file rename are open scoping
questions for that pass.
S27 ref-consistency A — "penalty/penalizes" framing → SSOT (external links + topic-relevance)
CLASS: reference-consistency (NOT re-hardening of ✅ commands — surgical SSOT-reconciliation of a
documented divergence-class across multiple files; same tool-grounded discipline: read-and-show →
grep-confirm → re-grep final). Predicate: no surface frames external-link reach-loss or off-topic
reach-loss as a hard named penalty — SSOT (references/algorithm-signals-reference.md:69-75, :89-90)
says links correlate with lower reach (LinkedIn denies an intentional penalty) and topic relevance is
a positive ranking input with no quantified off-topic figure.
TEST (tool-grounded). Plugin-wide grep -rniE "penaliz|penalty" over commands/agents/references/skills.
The 3 plan-cited lines confirmed (line-nr drift ±1 since plan written: analyze.md:101 not :102,
audit.md:60 not :61). Catalog split into 4 buckets, operator-approved:
- Bucket A (fix now): 10 hard-penalty framings of link/topic-relevance in non-format files.
- Bucket B (defer → S28): 6 link-penalty lines in
references/linkedin-formats.md(:52,:91,:194,:198,:200,:432) — S28 already opens that file for format magnitudes; reconcile link + format in one pass. - Bucket C (leave — already SSOT):
first-comment-strategy.md:7,glossary.md:171(def cites SSOT); glossary term### Link Penalty :170kept (def is correct). - Bucket D (surface → new S30): other unsourced magnitudes (−68% hashtags, −25% short-post, −15-25% topic-gap, −30-50% bait, 55% AI-comment, −25%/post, poll-overuse) — a different class. Engagement-pod + AI-slop "penalized" left intact (officially confirmed, high confidence).
HARDEN (10 edits, 6 files — Bucket A).
commands/audit.md:60(topic-relevance penalty)→(topic relevance is a ranking input — off-topic gets lower reach).agents/trend-spotter.md:338ranking will penalize off-topic content→Topic relevance is a ranking input — off-topic content gets lower reach.agents/trend-spotter.md:353topic-relevance penalty, damages authority→off-topic content gets lower reach, damages authority.references/troubleshooting-guide.md:15External link penalizing reach→External links correlate with lower reach.references/troubleshooting-guide.md:127LinkedIn penalizes directing traffic away→body links correlate with lower reach (LinkedIn denies an intentional penalty; lead with value).commands/analyze.md:101External link penalizing reach→External links correlate with lower reach.references/first-comment-strategy.md:3without triggering algorithm penalties→without the lower-reach correlation of body links.references/first-comment-strategy.md:10Avoids link penalty→Avoids the body-link reach correlation.references/first-comment-strategy.md:147Avoid link penalty→Avoid body-link reach hit.references/url-processing-templates.md:396Reach penalty→Correlates with lower reach.
VERIFY.
- Re-grep final:
topic-relevance penalty|will penalize off-topicin audit/trend-spotter → NONE;link penalty|penalizing reach|penalizes directing|triggering algorithm penalties|Reach penaltyin the 4 link-files → NONE. All 10 new SSOT-framed lines present. git diff --stat= 6 files, +10/−10.bash scripts/test-runner.sh→Passed: 81 · Failed: 0 · Warnings: 0, exit 0; counts 29/19 unchanged (.md-only prose edits).- Disposition: FIXED (10 edits, 6 files) · Bucket A complete · Bucket B → S28 · Bucket D → S30.
SURFACED (out of scope → queued). Bucket D unsourced-magnitude class promoted to S30 magnitude-scrub
(docs/hardening/plan.md). Bucket B link-penalty lines folded into S28's pass over linkedin-formats.md.
S28 ref-consistency B — format magnitudes + folded-in link lines → SSOT (video.md + linkedin-formats.md)
CLASS: reference-consistency (NOT re-hardening — surgical SSOT-reconciliation of format-magnitude
divergences across commands/video.md + references/linkedin-formats.md, incl. the 6 link-penalty lines
folded in from S27 Bucket B; one pass over the file). Predicate: no surface states an unsourced hard
format coefficient as fact — SSOT (references/algorithm-signals-reference.md:51-63, the "trust ordering,
test the number — never hard coefficients" rule :12-23) carries no completion-rate gate, no video ER,
no poll/Live multiplier; native video = "captions are the enforceable spec, no hard gate".
TEST (tool-grounded). Full read of linkedin-formats.md (674 l.) + video.md:69 context. Plugin grep
[0-9]+%|zero.distribution|penaliz|penalty|punish|multiplier|aspect ratio. The "30% zero-distribution"
gate recurs 7× (video.md:69; formats:58,:291,:478,:543,:644,:662). Catalog bucketed,
operator-approved (run buckets A+B+C+E now; D → S30):
- A — "30% zero-distribution" hard-gate (7): the named S28 divergence.
- B — S27-folded link-penalty lines (6):
formats:52,:91,:194,:198,:200,:432. - C — other unsourced FORMAT magnitudes (6): video 5.60% ER (
:56), Live 12-24x (:59,:594), polls 1.64x (:81), 3x shares (:273), Creator-Mode 35% (:674).:4924.42% left (already hedged + reconciled:50). - E — internal contradiction (1):
:356"3 seconds determine 70% of retention" contradicted the already-reconciled:62/:100folklore note → reframed. - D — S30-class in this file (deferred, operator's call):
:647-50% reach-decline,:715%→31%,:176AI-comment −30%/−55%,:231/:279hashtags −68%. Left intact; S30 re-scoped to cover them + the other files.
HARDEN (20 edits, 2 files — Buckets A+B+C+E).
- A:
video.md:69+formats:58,:291,:478,:543,:644,:662→ "completion/dwell is a ranking input; shorter completes better; no published hard completion gate". - B:
formats:52,:91,:198,:200,:432→ "correlate with lower reach" framing;formats:194heading### The External Link Penalty→### External Links and Lower Reach. - C:
formats:565.60% ER→ "engagement varies (no reliable single rate)";:59,:59412-24x→ "strong … (multiplier unverified)";:811.64x→ "declining; audience research only (no reliable multiplier)";:2733x more shares→ "tend to earn more shares";:67435% more reach→ "tend to see more reach (figure unverified)". - E:
formats:3563 seconds determine 70% of retention→ "opening seconds carry the most weight … three-second hook is folklore".
VERIFY.
- Re-grep final: assertive 30%-gate forms (
requires 30%|30% minimum completion rate or|video gets zero distribution|…) → NONE (remaining "completion gate" hits are the negated SSOT form "no hard completion gate"); link penalty/penalized/punished informats→ NONE; stray magnitudes (5.60%|12-24x|1.64x|3x more shares|35% more reach) → NONE;:356old → NONE. - Bucket D preserved:
47-50%,15% to 31%,−68% reach, AI-comment30%/55%still present (S30). git diff --stat= 2 files, +20/−20.bash scripts/test-runner.sh→Passed: 81 · Failed: 0 · Warnings: 0, exit 0; counts 29/19 unchanged.- Disposition: FIXED (20 edits, 2 files) · Buckets A+B+C+E complete · Bucket D → S30.
SURFACED (out of scope → queued). Bucket D (this file's non-format coefficients) deferred to S30
magnitude-scrub, which is re-scoped to: linkedin-formats.md D-lines (:6,:7,:176,:231,:279) + the other
files (linkedin-growth-playbook, glossary, engagement-coach, firsthour, post-feedback-monitor,
ab-testing-framework, poll-strategy-guide). Pod/AI-slop "penalized" stays intact (officially confirmed).
S29a terminology-scrub — "thought leadership" → neutral (commands/)
CLASS: terminology-scrub (NOT re-hardening — surgical removal of the operator-banned brand phrase
"thought leadership", FORM A, from the user-facing command surface; memory no-thought-leadership-phrase).
First sub-pass of the plugin-wide S29 scrub. Predicate: no command surface uses the phrase "thought
leadership"; the plugin is named LinkedIn Studio.
SCOPE (operator-locked for ALL S29 sub-passes a–e).
- FORM A only ("thought leadership"). FORM B ("thought leader(s)" as role — 38 plugin-wide,
incl. the buzzword denylist
post.md:134) = untouched. - Layers = user-facing surface + forward-looking docs. Pure history (CHANGELOG,
hardening/log.md+plan.md,voyage-build/*,remediation/*) = untouched ("history → git"). Forward docs =docs/integration-test-guide.md+docs/expert-review/plan.md. - Per-directory sub-passes, one per session. Replacement map approved BEFORE edit.
- FORM A baseline = 140 in
.md(99 surface + 41 history) + 1 test-.mjs.
TEST (tool-grounded). Plugin grep thought.leadership (case-insensitive). commands/ = 26 hits;
split: 11 filename pointers to references/thought-leadership-angles.md (post×3, video×2, batch×2, react×1, pipeline×2, competitive×1) → deferred to S29e (atomic rename + pointer update);
competitive.md/pipeline.md carry only pointers → untouched here. 15 in-file phrase occurrences in
9 files = S29a scope. Read-and-show of all 15 in context before proposing the map.
HARDEN (15 edits, 9 files — 1:1).
post.md(4)::21"LinkedIn thought leadership content creator" → "LinkedIn content creator";:64"Select Thought Leadership Angle" → "Select Content Angle";:98"Standard Thought Leadership Structure" → "Standard Post Structure";:136"thought leadership test" → "the insight test".video.md(1)::146"8 thought leadership angles" → "8 content angles".strategy.md(3)::67"thought leadership & authority" → "authority & influence";:234table row "Thought leadership pieces" → "Signature pieces";:395"[Thought leadership milestone]" → "[Authority milestone]".batch.md(1)::113"[thought leadership angle]" → "[content angle]".setup.md(2)::256"Which thought leadership angle" → "Which content angle";:323"thought leadership & authority" → "authority & influence".react.md(1)::22"into thought leadership posts" → "into insightful posts".outreach.md(1)::813"Demonstrate thought leadership depth" → "Demonstrate subject-matter depth".onboarding.md(1)::18"a LinkedIn thought leadership onboarding guide" → "the LinkedIn Studio onboarding guide".monetize.md(1)::18"turn their thought leadership into revenue" → "turn their LinkedIn authority into revenue".
VERIFY.
- Re-grep final, assertive non-filename FORM-A in
commands/(grep -v thought-leadership-angles) → NONE. Remainingcommands/hits = 11, all filename pointers (S29e). - FORM B in
commands/count = 15, unchanged (incl.post.md:134denylist). git diff --stat= 9 files, +15/−15 (1:1, no collateral).bash scripts/test-runner.sh→Passed: 81 · Failed: 0 · Warnings: 0, exit 0; counts 29/19/26/6 + v0.5.0 unchanged.- Disposition: FIXED (15 edits, 9 files). Commit
e6db0dd; pushed 2026-06-19 22:38 (operator OK, in window).
SURFACED (queued, not swept). S29 remaining sub-passes: S29b agents/ ← next · S29c
references/ (in-file phrase; thought-leadership-angles.md body scrubbed but FILE renamed in S29e) ·
S29d skills/+config/+assets/+README.md+CLAUDE.md+hooks/prompts/+forward-docs+test-.mjs ·
S29e rename references/thought-leadership-angles.md + all 20 pointers atomically (new filename TBD).
S29b terminology-scrub — "thought leadership" → neutral (agents/)
CLASS: terminology-scrub (NOT re-hardening — surgical removal of the operator-banned brand phrase
"thought leadership", FORM A, from the agent surface; memory no-thought-leadership-phrase). Second
sub-pass of the plugin-wide S29 scrub. SCOPE inherits the S29a operator-lock verbatim (FORM A only;
FORM B untouched; per-directory sub-pass, map approved before edit).
TEST (tool-grounded). grep -in "thought leadership" (space) in agents/ = 15 in-file phrase
occurrences / 7 files; the 11 thought-leadership-angles.md filename pointers (hyphenated) are invisible
to the space-grep and deferred to S29e. Read-and-show of all 15 in context before proposing the map.
Discovery during the header anchor-check (grep "Value Test"): 2 same-class instances the phrase-grep
missed because abbreviated — trend-spotter.md:192/:257 "TL Value Test" (TL = Thought Leadership).
Surfaced as an addendum (#16–#17), operator-approved BEFORE edit; scope not expanded silently.
HARDEN (17 edits, 6 files — 1:1). Vocabulary consistent with S29a: "thought leadership angle(s)" → "content angle(s)"; "thought leadership" (positioning/practice) → "authority …"; the whole "Value Test" family → "Authority Value Test".
strategy-advisor.md(1)::219"Thought leadership and cross-platform visibility" → "Authority building and …".content-planner.md(1)::24"sustainable thought leadership growth" → "sustainable authority building".voice-trainer.md(1)::24"voice for LinkedIn thought leadership" → "… for LinkedIn authority building".network-builder.md(1)::26"compound their thought leadership reach and influence" → "compound their authority, reach, and influence".differentiation-checker.md(4)::47search query"[topic]" thought leadership 2025 2026→"[topic]" expert insights 2025 2026(functional-keyword judgment-call, operator chose option b);:147"marketing as thought leadership" → "marketing posing as expertise";:203header "## Thought Leadership Value Test" → "## Authority Value Test";:327in-file "thought leadership test" → "authority value test" (filename pointerthought-leadership-angles.mdleft for S29e).trend-spotter.md(9)::5frontmatter desc "suggest thought leadership angles" → "suggest content angles";:24"establish thought leadership positioning" → "establish authority positioning";:33"strongest thought leadership angle per trend" → "strongest content angle …";:156"map to the strongest thought leadership angle" → "… content angle";:179"Future Implication for thought leadership" → "… for authority positioning";:334"create thought leadership value" → "create authority value";:344"is the thought leadership" → "is the expertise";:192header "### TL Value Test" → "### Authority Value Test";:257"Run TL Value Test" → "Run Authority Value Test".
VERIFY.
- Re-grep final FORM A
thought leadership(space) inagents/→ NONE;\bTL\b→ NONE. - FORM B in
agents/= 2, unchanged (analytics-interpreter.md:419"(thought leader)",network-builder.md:562"Thought Leader" search term). - Filename pointers
thought-leadership-angles.mdinagents/= 11, unchanged (S29e). - 17 new replacement strings present (1:1 with edits).
bash scripts/test-runner.sh→Passed: 81 · Failed: 0 · Warnings: 0, exit 0; counts 29/19/26/6 + v0.5.0 unchanged.- Disposition: FIXED (17 edits, 6 files). Commit
ebe56c5(local; push parked per policy until operator OK).
SURFACED (queued, not swept). references/glossary.md:229 "### Thought Leadership Value Test" → its
own directory pass S29c (temporary cross-directory naming gap until then — inherent to the
per-directory design). differentiation-checker.md:278 "### Value Test: [X]/3 passed" is already neutral
(no FORM A / TL) and stays — consistent with the renamed header. Remaining S29 queue unchanged: S29c
references/ · S29d misc · S29e rename + 20 pointers.
S29c terminology-scrub — "thought leadership" → neutral (references/)
CLASS: terminology-scrub (NOT re-hardening — surgical removal of the operator-banned brand phrase
"thought leadership", FORM A, from the reference-doc surface; memory no-thought-leadership-phrase).
Third and largest sub-pass of the plugin-wide S29 scrub (~2× the S29a/S29b volume). SCOPE inherits the
S29a/S29b operator-lock verbatim (FORM A only; FORM B untouched; per-directory sub-pass, map approved
before edit).
TEST (tool-grounded). grep -in "thought leadership" (space) in references/ = 35 phrase lines /
15 files — 29 single-line across 14 files + the canonical thought-leadership-angles.md = 6 lines / 7
instances (line 7 ×2) ≈ 36 FORM A instances. The 3 hyphenated thought-leadership-angles.md filename
pointers are invisible to the space-grep and deferred to S29e. Read-and-show of every occurrence in
context before proposing the 34-row map. Anchor-check (grep "Value Test" / #thought-leadership /
#the-standard-thought): no anchor links to the changed headers anywhere in the plugin, and the only
"Value Test" / "Standard Thought Leadership Structure" term-hits were the two SSOT spots being edited — no
hidden same-class instances.
S29e filename locked (operator, this session): thought-leadership-angles.md → content-angles.md.
The canonical file's in-file title/headers were therefore scrubbed now for consistency (H1 →
"# Content Angles"; "## The Authority Value Test"; "### Step 3: Test For Authority Value"); the file
rename + all 20 pointers remain S29e (atomic).
HARDEN (34 edits, 15 files — 1:1). Vocabulary consistent with S29a/S29b: "thought leadership angle(s)" → "content angle(s)"; "thought leadership" (positioning/practice) → "authority …"; content-type labels (lists/tables) → "authority content / authority posts"; the "Value Test" family → "Authority Value Test".
- Established cross-pass equivalents closed:
glossary.md:229"### Thought Leadership Value Test" → "### Authority Value Test" (closes the S29b cross-directory naming gap);glossary.md:29"8 universal thought leadership angles" → "content angles";engagement-frameworks.md:137"Standard Thought Leadership Structure" → "Standard Post Structure" (matches S29apost:98). thought-leadership-angles.md(6 edits / 7 instances): H1 → "# Content Angles"; :3 "identifying thought leadership angles" → "content angles"; :7 (×2) "Thought leadership isn't about…/can become thought leadership" → "Authority isn't about…/can build authority"; :92 "Test For Thought Leadership Value" → "Test For Authority Value"; :212 "Marketing disguised as thought leadership" → "expertise"; :215 "## The Thought Leadership Test" → "## The Authority Value Test".linkedin-formats.md(5): :24/:79/:272/:309 content-type labels → "authority content/posts"; :295 "Text-based thought leadership often outperforms…" → "Text-based content …" (avoids authority…authority echo).linkedin-visual-style.md(4): :3 "For thought leadership," → "For building authority,"; :7 "thought leadership niche" → "authority niche"; :82 label → "authority content"; :123 "myth for thought leadership content" → "authority content".trajectory-strategy-adjustments.md(3): :167 "Shift to thought leadership" → "authority content"; :202 "100% thought leadership and signature content" → "100% authority and signature content"; :217 "thought leadership deepening" → "authority deepening".linkedin-monetization-strategies.md(3): :285 "Inbound from thought leadership" → "authority building"; :624 "80% thought leadership" → "authority content"; :658 "Breaks the thought leadership positioning" → "authority positioning".ai-content-framework.md(2): :3 "build thought leadership in the AI space" → "authority"; :380 "main LinkedIn thought leadership skill" → "content skill" (judgment-call; avoids awkward "authority skill").- Single-edit files (8 edits / 8 files):
ab-testing-framework.md:9→ "authority building";growth-roadmaps.md:222"Thought leadership pieces" → "Authority pieces";linkedin-growth-playbook-2025-2026.md:822→ "Reflective authority content";algorithm-signals-reference.md:158(SSOT) "Text for thought leadership" → "Text for authority" (phrase only; magnitudes = S30);scheduling-strategy.md:35→ "Mid-week authority content";poll-strategy-guide.md:179"thought leadership angle" → "content angle";video-strategy-guide.md:3→ "authority content";video-strategy-guide.md:580"8 thought leadership angles" → "8 content angles".
KEPT BY DESIGN (operator-approved). video-strategy-guide.md:429 ironic quote "Your 'thought
leadership' content isn't leading anyone's thoughts." — scrubbing destroys the point.
video-strategy-guide.md:532 "TL;DW" = false positive (too long, didn't watch).
VERIFY.
- Re-grep final FORM A
thought leadership(space) inreferences/→ only the kept ironic quote (video-strategy-guide.md:429); canonical-file in-file FORM A → NONE. - FORM B in
references/= 4, unchanged (collaborations-guide.md:211,analytics-tools-guide.md:227,opportunity-generation.md:81,linkedin-visual-style.md:134). - Filename pointers
thought-leadership-angles.mdinreferences/= 3, unchanged (S29e). - New terms present: "Authority Value Test" (
glossary.md:229+thought-leadership-angles.md:215, consistent), "Standard Post Structure" (engagement-frameworks.md:137). bash scripts/test-runner.sh→Passed: 81 · Failed: 0 · Warnings: 0, exit 0; counts 29/19/26/6 + v0.5.0 unchanged.- Disposition: FIXED (34 edits, 15 files). Commit
b9b769c(local; push parked per policy until operator OK).
SURFACED (queued, not swept). Remaining S29 queue: S29d skills/ + config/ + assets/ +
README.md + CLAUDE.md + hooks/prompts/ + forward-looking docs + test .mjs · S29e rename
thought-leadership-angles.md → content-angles.md + all 20 pointers (atomic; filename locked). The
canonical file's in-file phrase scrub is done, so S29e is now a pure rename + pointer-update with no
remaining FORM A inside the file.