Reproduces the S1/R2a non-fabricating method: 2 blind cold Opus lenses per
surface (intent + correctness), no cross-feed, every mechanical claim
tool-grounded. Surfaces: create, batch, pipeline, newsletter.
Verdict REWORK — 3 of 4 surfaces, each 1 MAJOR; 0 BLOCKER:
- batch: 3a/3b component scaffold (format-blind) contradicts the format-aware
band gate
- pipeline: Step 2 scaffold (960-1640) cannot satisfy Step 3 total band
(1200-1800)
- newsletter: resumption table omits the contract-gate phase (Step 4.5) ->
breaks deterministic resume between Step 4 and Step 5
- create: ALLOW (1 MINOR, 8-option AskUserQuestion vs documented 2-4 cap)
Two systemic patterns surfaced (main-grounded, not single-reviewer):
- 5-component draft scaffold 960-1640 != 1200-1800 band, in exactly 3 files
(post.md [R2a], batch.md, pipeline.md)
- bare reference paths vs ${CLAUDE_PLUGIN_ROOT}/ in batch + pipeline
Independence axis earned its keep: on newsletter the intent-lens asserted the
resumption table complete; the correctness-lens counted the gap; main confirmed
the correctness-lens (a divergence resolved by grounding, not just convergence).
Review finds; changes no code. Fixes are separate operator-gated decisions.
test-runner 138/0 unchanged. Hardening-class artifact.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012GqEHp4uDiivfrAUjw4BdE
21 KiB
| type | batch | journey | scope | method | surfaces | reviewers | status | verdict | counts | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| cold-review | R2b | Create — orchestrators & front-door | FROZEN committed files at HEAD 5474df5 (clean tree; post-hardening cold pass) |
2 independent cold Opus reviewers per surface (intent + correctness), no cross-feed; every mechanical claim tool-grounded (anti-fabrication mandate); reviewers carry NO drafting-session context |
|
|
COMPLETE — all 4 surfaces reviewed (create, batch, pipeline, newsletter) | REWORK |
|
Cold review — R2b (Create · orchestrators & front-door)
Independent post-hoc cold review of the 4 Create-journey orchestrators/front-door, on the FROZEN
committed files (HEAD 5474df5). Mirrors the S1 review.md + R2a model (the cold-review method that
did not fabricate): read-and-show before assert, every file:line tool-confirmed, reviewers carry
no drafting-session context. The per-command interactive gate (log.md) already passed these; this
pass adds the independent axis that gate never had.
Independence cross-check — two outcomes worth noting this batch:
- Convergence (the R2a pattern): both blind lenses independently surfaced the same real defect on
several surfaces — batch's bare-vs-prefixed reference path, batch's 3a/3b component-band tension,
newsletter's
allowed-toolsomission, create's 8-optionAskUserQuestion. - Divergence resolved by grounding (new this batch, the strongest argument FOR the two-lens
method): on
newsletterthe intent-lens asserted the resumption table "maps every currentPhase to the correct resume step"; the correctness-lens counted the rows (17) against the canonical_doc.phases(18) and found thecontract-gaterow missing. Main re-grounded it independently (below) → the correctness-lens is right. The independence axis caught a real MAJOR that one lens had asserted away.
★ Cross-cutting finding #1 (systemic) — 5-component draft scaffold (960–1,640) cannot satisfy the 1,200–1,800 standard band it is gated against
- Pattern (verified by main, independent of reviewers —
grepblast radius): the identical 5-component "standard post" breakdown —Hook 110-140+Context 200-300+Insight 400-800+Implication 200-300+CTA 50-100— appears in exactly 3 files:post.md:100-104,batch.md:88-92,pipeline.md:58-62. (grep -rln "Insight.*400" commands/→ those three only;quick/first-post/reactcarry the loneHook 110-140line, NOT the full scaffold, so are unaffected.) - Grounded arithmetic: component min-sum = 110+200+400+200+50 = 960 · max-sum =
140+300+800+300+100 = 1,640. Each file then gates the SAME post against the canonical standard band
1,200–1,800 (
content-quality-gate.md:17;post.md:128,batch.md:95,pipeline.md:77). - Mechanism (two-sided): (a) a draft built at the component minimums is 960 chars — 240 below
the 1,200 floor enforced by the next step AND the live PreToolUse
content-quality-gatehook; (b) the component maximums sum to 1,640 — 160 below the 1,800 ceiling, so the scaffold literally cannot reach the upper half of its own target band. - Why it matters: on the most common path (drafting a standard text post) the drafting recipe and
the acceptance test are mutually incompatible, with no transition/connective slack to close the
960→1,200 gap. In
batchthe defect is sharper: the 3a scaffold is format-blind (always the 5-component standard layout) while the 3b gate is format-aware (batch.md:114format: [text/carousel/video], rotation:76), so aquick-format post built from the scaffold (960–1,640) also blows the quick band (150–500). Inpipelinethe contradiction is between two adjacent steps (Step 2 draft → Step 3 scorecard). - Severity: recorded MAJOR in
batchandpipeline(real adjacent-step / gate contradiction on every standard post). Reconciliation note for R2a: R2a recorded the same scaffold inpost.mdat MINOR ("component minimums sum below the 1,200 optimal floor") and flagged only the min-side. The batch/pipeline analysis shows it is a two-sided, gate-hitting contradiction, not merely loose guidance — the post.md instance is arguably under-rated and should be reconciled in the same fix. - Disposition (NOT fixed here — review finds, operator decides; 3-file change = own go): one
consolidated fix across all 3 files — raise the component floors so min-sum ≥ 1,200 (e.g. widen
Context/Insight) AND either lift the ceiling or accept ~1,640, AND scope the standard 5-component
scaffold explicitly to standard-format posts where the command is format-aware (
batch), adding per-format draft guidance for quick/carousel/video. Recommend treating this as the second consolidated fix out of the sweep, after the R2a clipboard fix.
★ Cross-cutting finding #2 (recurring) — bare relative reference paths vs ${CLAUDE_PLUGIN_ROOT}/
- Pattern: several
Read/reference paths are written bare (resolved against the runtime cwd) while the same file's appendix and most other sites prefix${CLAUDE_PLUGIN_ROOT}/.batch.md:43(references/content-angles.md) vsbatch.md:206(prefixed, same file) — flagged by both batch lenses.pipeline.md:31,55,70,75bare vspipeline.md:28,64,107+ appendix:204-209prefixed —content-angles.mdis bare at:55but prefixed at:204. - Impact: the files exist (not dead refs), but a bare path fails the
Readwhen cwd ≠ plugin root, on real paths run every invocation (angle-select, optimize). Self-recoverable via Glob, latent. - Disposition: normalize all bare reference/asset paths to
${CLAUDE_PLUGIN_ROOT}/. Cheap, mechanical; fold into the consolidated fix pass. (Worth a repo-wide grep for the same pattern in the other 25 commands during the eventual fix.)
create.md — VERDICT: ALLOW (0 BLOCKER/MAJOR · 1 MINOR · 0 SUGGESTION)
Class: routing (pure delegating front-door). Both lenses confirm intent delivered: Step 0 context →
Step 1 intent-ID → Step 2 route, with explicit "you do not draft here / do NOT inline the target's
steps" (create.md:49-51,64-65) — delegation purity intact, single source of truth preserved. All 8
routed targets resolve (post/quick/react/carousel/video/multiplatform/batch/newsletter, :37-44 +
:55-62, ls-confirmed); the three enumerations (description :7, menu :37-44, route table
:55-62) are mutually consistent (8/8/8, same order); no subagent_type refs (correct — it routes to
commands); no "thought leadership". Correctness-lens: 0 findings.
MINOR — Step 1 directs one AskUserQuestion carrying 8 options; documented support is 2–4
create.md:35-44— "useAskUserQuestion" immediately followed by 8 numbered options (grep -cE "^[0-9]+\. \*\*"→ 8). Grounded against the plugin-dev referencecommand-development/.../interactive-commands.md:469("2-4 options per question") +:906.- impact: on the PRIMARY interactive path (user names no format) the front-door instructs a single question with double the documented option range.
- anti-fabrication caveat (carried from the reviewer, honestly): grounded = (a) 8 options
instructed, (b) the documented 2–4 range. NOT grounded = whether the live
AskUserQuestionruntime hard-rejects >4 vs silently truncates/degrades. If the runtime hard-rejects, this escalates to MAJOR/BLOCKER on the no-format-named path; if it only degrades, the picker is over-long. Worth a runtime check before the fix. - disposition: group the 8 intents into ≤4 options (e.g. Short-form / Reaction / Visual / Long-form & batch) with a drill-down, or split into two questions.
batch.md — VERDICT: REWORK (0 BLOCKER · 1 MAJOR · 3 MINOR · 2 SUGGESTION)
Class: guided/stateful + routing ("create a full week of content"). Intent delivered: the Step 0→5
flow traces the frontmatter promise; all cross-refs resolve (trend-spotter, content-planner →
agents/; /linkedin:calendar → commands/; queue-manager.mjs + ical-generator.mjs exports +
the 8-arg queueAdd call/signature match; all 6 reference/asset paths + SKILL.md); graceful
degradation present; no "thought leadership".
MAJOR — Step 3a component scaffold contradicts the Step 3b band gate → see ★ cross-cutting #1 (batch.md:88-92 vs :95)
Sharper here than elsewhere: 3a is format-blind (always the 5-component standard layout, 960–1,640)
while 3b is format-aware (:114 format:[text/carousel/video], rotation :76), so a quick-format
post built from 3a also blows the quick band 150–500. Both lenses flagged this (intent-lens MINOR,
correctness-lens MAJOR — recorded at the higher severity: it hits a real gate on every standard post).
MINOR — bare reference path → see ★ cross-cutting #2 (batch.md:43 vs :206). Both lenses.
MINOR — weekly_goal cadence decoupled from the fixed "3–5 posts" headline
batch.md:5,65fix the output at "3–5 posts";batch.md:52schedules againstweekly_goalslot templates (2x/3x/4x/5x). Atweekly_goal=2x, 3–5 posts against 2 weekly slots overflow into the next week (:53"next available slot after today") — ~2.5 weeks of content under a "full week" label.- impact: non-breaking (scheduling rolls forward), but "full week" + "3–5" is internally inconsistent with the 2x cadence.
- disposition: tie post count to
weekly_goal, or note that overflow rolls into following weeks.
MINOR — orphan sub-step marker 5b with no 5a
batch.md:172### 5b. Generate Calendar File;grep -n "5a" batch.md→ no match (exit 1). Step 3 has 3a/3b/3c/3d; Step 5 jumps straight to 5b.- disposition: renumber to
5a, or drop the letter.
SUGGESTION — weekly_goal default (3x) lives only in the referenced scheduling-strategy.md:15, never stated in batch.md. Optional one-line "default 3x" for self-evident degradation.
SUGGESTION — planned_date metadata never computed
batch.md:109writesplanned_date: YYYY-MM-DDinto each draft header, but Step 2 only computesscheduled_date/scheduled_time(:54);planned_dateis introduced nowhere upstream.- disposition: drop
planned_date, or define where it is derived.
pipeline.md — VERDICT: REWORK (0 BLOCKER · 1 MAJOR · 4 MINOR · 2 SUGGESTION + clipboard pointer)
Class: post-emitting + guided/stateful + routing ("full end-to-end pipeline"). Intent delivered:
Steps 0–8 map to every named stage. All post-emitting predicates present (hook 110–140 :58,:76 ·
length band :77 · no-body-link :78 · buzzword check :79 · topic→expertise :49,:55,:80); all
cross-refs + function signatures resolve (content-planner, trend-spotter; /linkedin:calendar,
/linkedin:analyze; queueAdd 8-arg call/signature; writeState/updatePostTracking); no "thought
leadership".
MAJOR — Step 2 component scaffold cannot satisfy the Step 3 total-length gate → see ★ cross-cutting #1 (pipeline.md:58-62 vs :77)
Adjacent-step contradiction: Step 2 partitions into 960–1,640; the very next step's scorecard asserts "Total 1,200–1,800". Correctness-lens, grounded arithmetic.
MINOR — inline buzzword checklist enumerates 8, canonical gate enumerates 10
pipeline.md:79lists 8 terms (= CLAUDE.md rule 4); SSOTcontent-quality-gate.md:13adds 'actionable insights' + 'best practices' = 10. A draft passing the inline list can still trip the Write hook. (Gate-vs-rule divergence, not unique to this file — also noted on carousel in R2a.)- disposition: align to the 10-term canonical list, or reference the gate instead of duplicating.
MINOR — bare reference paths → see ★ cross-cutting #2 (pipeline.md:31,55,70,75). Intent-lens.
MINOR — Step 4 deferred/queued path falls through into the immediate Publish steps
pipeline.md:97-101offers "Schedule / Add to queue / Save as draft (no schedule)"; Steps 5–8 (:120"15-20 min BEFORE posting",:135Publish,:158first-hour,:171post-analysis) then run with no branch. A user who queued/deferred is marched through Pre-Engagement → Publish → Monitoring, contradicting the just-made defer decision.- disposition: add an early-exit after Step 4 for options 2–4 ("if scheduled/queued, end here; Steps 5–8 run at publish time").
MINOR — Step 7 inlines a static first-hour checklist instead of routing to the stateful surface
pipeline.md:158-169inlines a 5-item plan; the dedicated/linkedin:firsthourdelegates toengagement-coach, persists viarecordFirstHourPlan, hands off topost-feedback-monitor— strictly richer (Step 8 already routes to/linkedin:analyze, so the inline first-hour is the inconsistent one).- disposition: route to
/linkedin:firsthour.
SUGGESTION — over-provisioned allowed-tools: :13 declares WebFetch but no body step fetches (trend-spotter does its own). Drop unless a URL-ingest step is intended.
SUGGESTION — hardcoded Norwegian peak times: :92-95 bakes "European/Norwegian audience" peak windows into the body while scheduling-strategy.md (read at :107) is the SSOT for slots; conflicts with the domain/audience-general principle. Source from the reference/config.
(pointer) clipboard printf '%s' systemic bug — pipeline.md:139 confirmed present (the only R2b surface in the 10-content-command set). Folds into the R2a ★ cross-cutting clipboard finding; no new derivation.
newsletter.md — VERDICT: REWORK (0 BLOCKER · 1 MAJOR · 2 MINOR · 2 SUGGESTION)
Class: guided/stateful + routing + heavy subagent orchestration (long-form 18-phase pipeline,
~110 KB). Intent delivered: all 18 phases present, ordered, [GATE]/[OPERATØR]-marked. 18-phase
count confirmed by both lenses (0,1,1.5,2,2.5,3a,3b,4,4.5,5,5.5,6,6.5,7,7.5,8,9,10; headline :25
matches body + template _doc.phases + build-status). All 7 longform agents (fact-checker,
editorial-reviewer, persona-reviewer, voice-scrubber, content-reviewer, language-reviewer, fact-reviewer)
present in agents/ AND invoked; gate sequence ordered before lock (:1570): skeleton 2.5 → spine 3a →
fact-check 5 → editorial 5.5 → persona 6 → headless 6.5 → visual 7.5 → LOCK 8 → hook 9. All subagent_type
carry the linkedin-studio: namespace (the 5 prefix-less grep hits are line-wraps). All ~25 cross-refs
(agents, commands, scripts, configs, render, docs) resolve. Pivot heuristic, flag caps, step-label
5.5/6.5 consistency all clean. No "thought leadership".
MAJOR — deterministic resumption table omits the contract-gate phase (Step 4.5) → breaks resume between Step 4 and Step 5
- Verified by main (independent re-grounding of a lens disagreement): the resumption table
newsletter.md:209-228has nocontract-gaterow (grep contract-gateover the table region → none). The canonical_doc.phasesit claims to mirror (:230-231) does define it —config/edition-state.template.jsonlists"contract-gate — … (Step 4.5)"betweenconsistency-quality(Step 4) andfactcheck-sweep(Step 5). Step 4.5 actually writes it:newsletter.md:988"SetcurrentPhase: "contract-gate"". - Two concrete breakages on the multi-session resume path (the file's core premise,
:200-204):- Gate skipped on resume. The rule (
:203-204) is "run the step AFTER the recorded phase." Row:219mapsconsistency-quality → Step 5(Fact-check), but the step after Step 4 is Step 4.5 (contract-gate), not Step 5. A session aborting after Step 4 resumes past the deterministic contract-gate, never running it. - Unrecognized phase on resume. A session aborting after Step 4.5 has
currentPhase: "contract-gate", absent from the table → falls into the:232-234fallback ("missing or unrecognized → do NOT guess … confirm with the operator"), defeating the deterministic-resumption guarantee the section is built on.
- Gate skipped on resume. The rule (
- Note: the linear next-pointers are correct (
:918"next: contract-gate",:989"next: fact-check"); only the resume table is short one row — the defect surfaces solely on abort/resume between Step 4 and Step 5. - Independence note: the intent-lens asserted this table "maps every currentPhase to the correct resume step"; the correctness-lens counted (17 rows vs 18 phases) and found the gap. Main confirmed the correctness-lens. Two-lens method earned its keep here.
- disposition: insert a
contract-gate → Step 5 — Fact-check sweeprow, and repointconsistency-quality → Step 4.5 — Contract-gate.
MINOR — Step 1 says the brief is first persisted "in Step 2"; the rest of the file says Step 1.5
newsletter.md:303"Record the resolved brief inline (you will persist it to edition-state in Step 2)" contradicts:287-289,:412-418,:494-496(all: first durable write is the Step 1.5 checkpoint). Stale "Step 2" — almost certainly predates the Fix #2 Step 1.5 insertion; non-breaking (Step 1 only records inline either way).- disposition: change
:303"in Step 2" → "at the Step 1.5 checkpoint".
MINOR — allowed-tools omits SendUserFile (body-primary operator gate) + mcp__mcp-image__generate_image (default image route)
newsletter.md:11-19declaresRead, Glob, Grep, WebFetch, Bash, AskUserQuestion, Task, Write. The body namesSendUserFileas the primary operator gate at Steps 5.5/6.5/7.5 (13 uses, e.g.:1138) and mcp-image as the default image route (:1471); neither is declared. Both lenses flagged this (intent-lens MINOR, correctness-lens SUGGESTION — recorded at the higher: the declared "default" path can't execute under the frontmatter as written). Every use guards with a fallback ("SendUserFileif available, else a markdownfile://link"), so it degrades gracefully → not load-bearing.- disposition: add
SendUserFile(+ optionally mcp-image) toallowed-tools, or downgrade the body wording from "default/primary" to "if permitted".
SUGGESTION — undefined "LTL plugin" acronym: newsletter.md:36,725 ("the LTL plugin" / "the LTL rule"); repo-wide the bare phrase appears only here, no expansion; the plugin is canonically "LinkedIn Studio". (The env vars LTL_SERIES_ROOT/LTL_BRAND :48,154-156 ARE a legit convention consumed by render/build-*.mjs — not a defect.) Rename to "LinkedIn Studio plugin", or define once.
SUGGESTION — "leveraged" in doc prose (newsletter.md:1785, note-only): ordinary verb in the command's own explanatory prose, not generated post content; CLAUDE.md rule 4 targets generated posts. Not a real violation; optionally swap to "drew on / built on".
Gate decision — R2b COMPLETE (4 surfaces)
| Surface | Verdict | BLOCKER | MAJOR | MINOR | SUGGESTION |
|---|---|---|---|---|---|
| create | ALLOW | 0 | 0 | 1 | 0 |
| batch | REWORK | 0 | 1 | 3 | 2 |
| pipeline | REWORK | 0 | 1 | 4 | 2 |
| newsletter | REWORK | 0 | 1 | 2 | 2 |
| ★ cross-cutting #1 (scaffold, 3 files) | — | 0 | (counted in batch + pipeline; spans post.md from R2a) | — | — |
| ★ cross-cutting #2 (bare paths) | — | 0 | 0 | (counted in batch + pipeline) | — |
Batch verdict: REWORK — 3 of 4 surfaces (batch, pipeline, newsletter), each with 1 MAJOR:
(1) the systemic 5-component scaffold contradicting the 1,200–1,800 band (batch + pipeline; spans
post.md from R2a), and (2) newsletter's resumption table missing the contract-gate phase. 0 BLOCKER
anywhere. create is ALLOW (one option-count MINOR with a runtime caveat).
Independence verdict: convergence on batch path-prefix / batch 3a-3b band / newsletter allowed-tools / create 8-option (both lenses) — plus one divergence resolved by main's grounding (newsletter resumption table: intent-lens asserted complete, correctness-lens counted the gap, main confirmed). Both the convergence and the resolved divergence are signals these are real defects, not single-reviewer framing.
Systemic findings now span R2a+R2b: clipboard printf (R2a, 10 files) · component scaffold (R2b, 3
files incl. post.md from R2a) · bare reference paths (R2b, 2 files, worth a repo-wide grep). Cold review
finds; it changes no code. Each fix is its own operator-gated decision. Recommended consolidated-fix
order out of the sweep so far: (1) clipboard printf [R2a, 10 files, highest blast radius], (2)
component scaffold [3 files], (3) bare reference paths [grep-driven], then the per-surface items.
Local-only (hardening-class), not pushed.