From 8a3e109b3574804a457c63045229dc8ad8b505e2 Mon Sep 17 00:00:00 2001 From: Kjell Tore Guttormsen Date: Thu, 18 Jun 2026 15:29:31 +0200 Subject: [PATCH] =?UTF-8?q?fix(linkedin-studio):=20S7=20harden=20batch=20?= =?UTF-8?q?=E2=80=94=20format-aware=20length=20band=20on=20per-post=20qual?= =?UTF-8?q?ity=20check?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit S7 close-out (1 edit / 1 command-file · lint 81/0 · counts 29/19/26/6): - batch.md:95 Step-3b Quick Quality Check: replace vague "Character count in range" with a format-aware band (standard 1,200-1,800 · quick 150-500 · carousel/video caption per that format) — the old line named no band, and the 3a structure (:88-92) sums to 960-1640, under the 1,200 standard floor, so a ~1,000-char standard post passed "in range" unflagged Axis-c (length band) closed; axes a/b/d PASS. Class: hybrid guided/stateful + post-emitting per post (each of 3-5 drafts is a feed post). Buzzword (:98) + no-body-link (:97) already present — the gap S2-S6 found is already closed in batch. Wiring verified: trend-spotter + content-planner resolve; all 5 node helpers (queueUpcoming/queueAdd 8-arg/queueFormatSummary/generateIcalFromQueue/writeIcalFile) export with matching signatures. 3 deferrals (3a single-structure vs mixed-format promise · no per-post differentiation gate by design · weekly_goal-unset micro-fallback). Local-only per push policy. --- commands/batch.md | 2 +- docs/hardening/log.md | 77 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 1 deletion(-) diff --git a/commands/batch.md b/commands/batch.md index 2b1029a..b303eb1 100644 --- a/commands/batch.md +++ b/commands/batch.md @@ -92,7 +92,7 @@ Follow the standard structure: - CTA: 50-100 characters ### 3b. Quick Quality Check -- 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" - Hook works standalone - No external links in body - No corporate buzzwords diff --git a/docs/hardening/log.md b/docs/hardening/log.md index 55a5f6a..6b94eca 100644 --- a/docs/hardening/log.md +++ b/docs/hardening/log.md @@ -632,3 +632,80 @@ graceful degradation when voice samples are absent. :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. + +---