Step-3 optimize gate (:79) carried the buzzword line but as a bare '- [ ] No corporate buzzwords' — not self-contained, leaning on the quality-scorecard.md reference rather than the inline gate the AI executes. Enumerated the banned list inline to match every other post-emitting gate (post :134 / react :131 / carousel :123 / video :129 / scorecard :132), removing pipeline as the odd-one-out. Recorded deferral: Step-2 component structure (:58-62) sums 960-1640, floor below the Step-3 band floor 1,200 — identical to batch's untouched 3a; the gate (:77) already names the band and catches a minimum-path undershoot, so no edit (editing Step 2 would exceed S7 precedent). Gate: test-runner 81/0/0 · counts 29/19 unchanged · only .md touched. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016qgzo6rxthw7KuxHjn5vyE
787 lines
58 KiB
Markdown
787 lines
58 KiB
Markdown
# 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** (lint `Failed: 0` + counts
|
||
> + the failing axis now passes). The cold `/trekreview` reviewer 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; promised `subagent_type` targets 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" in `quick`, (3) `onboarding`/`first-post` edits 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
|
||
> `/trekreview` oracle 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.md` the
|
||
command reads at runtime). `recent_posts: []` → no rotation conflict. *Fresh-adopter
|
||
path (no voice samples) reasoned, not separately re-drafted: `quick` reads 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.md` **as 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:post` upgrade 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).** `quick` **conditionally**
|
||
delegates to `differentiation-checker` via `Task` (`quick.md:151`,
|
||
`subagent_type: linkedin-studio:differentiation-checker`) — only when the take is commodity,
|
||
preserving the 5-minute promise by default. `Task` in `allowed-tools` is 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.md` Step 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 `Task` in `allowed-tools` — onboarding
|
||
inlines every step (Phase 2 "delegate to setup" = inline its logic; commands aren't subagents,
|
||
so no broken `subagent_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 real `agents/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.md`
|
||
> header). 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 to
|
||
`quality-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.md` itself 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 with `algorithm-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 correctly
|
||
`subagent_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` (Notes `Mobile 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 `post` is
|
||
hardened this session — `react/batch/video/pipeline` get 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 char` hook bound remains in the scorecard (`110-140` at
|
||
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.md` lines BEFORE talk
|
||
> (jerndisiplin: assert-after-read). Field-notes inbox **absent** at S3 → graceful no-op (SC-I).
|
||
> All `file:line` below 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. `react` auto-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 in `post`.**
|
||
- **Second friction (axis d, URL-pipeline-specific):** `grep` for 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 with `references/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-checker`
|
||
resolves, 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.md` already clean post-S2 (`110-140` at `:32/:114/:128` +
|
||
buzzword `:132`) — `react`'s referenced asset (`react.md:270`) is good; the gap was `react`'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.md` only, +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.md` lines
|
||
> BEFORE talk (jerndisiplin: assert-after-read). Field-notes inbox **absent** at S4 → graceful
|
||
> no-op (SC-I). All `file:line` below 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 from `drafts/` + state → Step 1 (`:31`) AskUserQuestion pick
|
||
Twitter → Twitter template (`:53`, hook ≤**280** + 🧵 + one-idea tweets + CTA) → Step 2 (`:115`) save
|
||
`drafts/multiplatform/twitter-[slug].md` (`:118`) + clipboard, "Copied" (`:123`). **Promised artifact
|
||
produced.**
|
||
- **CONCRETE friction (axis d, adapter-specific — anchored, not a generated post):** `grep` for 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`); **no** `110`/`140` hook 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 real `commands/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, but `clipboard-helper.mjs` is 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.md` only, +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.md` lines BEFORE
|
||
> talk (jerndisiplin: assert-after-read). Field-notes inbox **absent** at S5 → graceful no-op (SC-I).
|
||
> All `file:line` below 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 in `post`/`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-checker` resolves, 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-updater` exports `updatePostTracking` (`: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–77` and `:87`; both
|
||
are NICE-only, below the stopping-rule's axis-pass bar).
|
||
- **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.md` only, 1 line changed). Only `.md` touched → hooks/analytics `node --test` not 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.md` lines BEFORE
|
||
> talk (jerndisiplin: assert-after-read). Field-notes inbox **absent** at S6 → graceful no-op (SC-I).
|
||
> All `file:line` below 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-scripter` generates → **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 in `post`/`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).
|
||
|
||
**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 SSOT `algorithm-signals-reference.md:56` (no 30 %, confidence
|
||
*medium*); it is consistent with `linkedin-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 real `agents/*.md`, both
|
||
`subagent_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: *"if `voice-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.md` only, +4/−2). Only `.md` touched → hooks/analytics `node --test` not 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.md` lines BEFORE
|
||
> talk (jerndisiplin: assert-after-read). Field-notes inbox **absent** at S7 → graceful no-op (SC-I).
|
||
> All `file:line` below 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-spotter`
|
||
for timely angles) → Step 2 (`:45`) `content-planner` plan + schedule (slot template by `weekly_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
|
||
`:95` read **"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` + `:97` already present — the
|
||
hole S2–S6 kept finding is already closed in `batch`).
|
||
|
||
**EVALUATE (4 axes).**
|
||
- **(a) intention fidelity — PASS.** Theme→plan→schedule→per-post draft/check/save/queue→review→finalize+
|
||
`.ics` delivers the week-of-content promise. *Tension (deferred):* Step 3a imposes one "standard structure"
|
||
though Step 2 (`:76`) promises format variety — `batch` is 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`). `batch` uses a deliberately lighter "Quick Quality
|
||
Check" (no per-post `differentiation-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 real `agents/*.md`, both `subagent_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→`:181` guard.
|
||
*Minor (deferred):* no fallback if `weekly_goal` is unset (`:52` slot-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.md` only,
|
||
1 insertion / 1 deletion). Only `.md` touched → hooks/analytics `node --test` not 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.md` lines BEFORE
|
||
> talk (jerndisiplin: assert-after-read). Field-notes inbox **absent** at S8 → graceful no-op (SC-I).
|
||
> All `file:line` below 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 `:129` all 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 ✓ (`:77` names 1,200–1,800) · no-body-link ✓ (`:78`) · topic→pillars ✓
|
||
(`:80` + `:49` content-planner pillar-situating) · subagent resolves ✓ (`:49`) · **buzzword
|
||
present-but-not-self-contained ✗→fixed** (`:79` bare → enumerated inline).
|
||
- **(d) agent-wiring + graceful degradation — PASS.** `content-planner` + `trend-spotter` (`:49`) resolve
|
||
to real `agents/*.md`, both `subagent_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.md` only,
|
||
1 insertion / 1 deletion). Only `.md` touched → hooks/analytics `node --test` not 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.
|
||
|
||
---
|