linkedin-studio/docs/hardening/review-R5.md
Kjell Tore Guttormsen 4fd038ad1d docs(linkedin-studio): cold-review R5 (Grow+Router) — independent kald-review of 6 surfaces -> 29/29 coverage
Final cold-review round: strategy, competitive, monetize, outreach, profile, linkedin.
2 independent cold Opus reviewers (intent + correctness), no cross-feed, every claim
tool-grounded; divergences re-grounded by main before registration.

Result: verdict MINOR, 0 MAJOR (cleanest batch of the sweep). Resolution integrity
PASS across all 6 (2/2 subagent_type, 28/28 routes, 11/11 router-suggested agents,
helper-script exports all resolve; 0 under-declared tools; 0 dead executable refs).

Findings (all advisory, no REWORK): thought-leader terminology cluster (5 surfaces,
9 instances; profile :79/:101 are correct negative examples, NOT violations);
monetize :6 description<->body scope self-contradiction; bare ref-paths in
strategy+profile (folds into systemic #3); monetize Audience-Size scorecard +40 vs
/25 cap (suggestion).

Cold-review sweep COMPLETE: 29/29 coverage (S1 + R2a + R2b + R3 + R4 + R5).
v1.0.0 review-blocker lifted. test-runner 138/0 unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012GqEHp4uDiivfrAUjw4BdE
2026-06-30 10:28:57 +02:00

18 KiB
Raw Blame History

type batch journey scope method surfaces reviewers class status verdict counts
cold-review R5 Grow + Router — growth/authority surfaces + the command router (FINAL round) FROZEN committed files at HEAD 4109fe7 (clean tree; post-hardening cold pass) 2 independent cold Opus reviewers for the round (intent + correctness), each covering all 6 surfaces, no cross-feed; every mechanical claim tool-grounded (anti-fabrication mandate); reviewers carry NO drafting-session context. Divergences re-grounded by main before registration.
strategy
competitive
monetize
outreach
profile
linkedin
intent-lens (conformance: intent delivery + cross-ref resolution + class predicates + graceful degradation + thought-leadership terminology ban)
correctness-lens (internal consistency + bound-vs-canonical + step/phase arithmetic + allowed-tools completeness + dead-ref / executable-path checks)
guided/stateful (strategy·competitive·monetize·outreach·profile — primary artifact produced · subagent targets resolve · graceful degradation) + routing (linkedin — every emitted /linkedin:Y resolves) COMPLETE — all 6 surfaces reviewed (strategy, competitive, monetize, outreach, profile, linkedin). R5 completes 29/29 cold-review coverage. MINOR
BLOCKER MAJOR MINOR SUGGESTION
0 0 3 2

Cold review — R5 (Grow + Router) · FINAL round → 29/29 coverage

Independent post-hoc cold review of the 6 remaining surfaces — the five Grow-journey guided/stateful commands (strategy, competitive, monetize, outreach, profile) plus the linkedin router — on the FROZEN committed files (HEAD 4109fe7). Mirrors the S1 review.md + R2a + R2b + R3 + R4 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. R5 completes the sweep: 23/29 + 6 = 29/29 cold-review coverage.

Resolution integrity — PASS across all 6 surfaces (the headline R5 result). Both blind lenses independently confirmed, target-by-target against their own ls/test -f:

  • 2/2 subagent_type: linkedin-studio:X refs resolve — strategy-advisor (strategy.md:153), network-builder (outreach.md:171).
  • 28/28 unique /linkedin:Y route tokens resolve to commands/Y.md (router + cross-command suggestions).
  • 11/11 router-suggested agents (named in linkedin.md) resolve to agents/*.md.
  • 2/2 helper-script invocations resolve: outreach.md's state-updater.mjs --record-outreach (flags --date/--track/--partner/--stage/--next/--due match state-updater.mjs:394-411 byte-for-byte) and linkedin.md's queue-manager.mjs import (queueUpcoming/queueOverdue/ queueFormatSummary exist at queue-manager.mjs:52,94,112).
  • 0 under-declared tools — every body-invoked tool (Task/Read/Write/Edit/Bash/WebSearch/ AskUserQuestion) is in the surface's allowed-tools; only harmless Glob/Grep over-declarations.
  • 0 dead executable Read/Bash targets — every references/*, ${CLAUDE_PLUGIN_ROOT}/skills/…, and script path on an executable path verified present.

No broken invocation, no missing primary artifact, no failing gate, no runtime-breaking contradiction anywhere in R5 → 0 MAJOR, verdict MINOR (advisory, not REWORK). This is the cleanest batch of the sweep.

Independence cross-check — both outcomes recurred (the case for two lenses, again):

  1. Convergence: both blind lenses independently surfaced the same monetize.md description↔body scope mismatch and the same thought leader terminology cluster — high confidence these are real.
  2. Divergence (re-grounded by main):
    • Terminology severity — intent-lens called the thought leader hits MINOR (it owns the conformity predicate; memory no-thought-leadership-phrase makes this a standing plugin rule, not a nicety), correctness-lens called them SUGGESTION (no runtime break). Main ruling: MINOR — a direct violation of an explicit plugin terminology rule in user-facing strings is a conformity defect; it is not MAJOR (no runtime break).
    • monetize scope mismatch severity — intent-lens SUGGESTION ("description under-claims body"), correctness-lens MINOR ("description contradicts its own 0-1K Stage 1"). Main ruling: MINOR — it is a genuine self-contradiction about the command's scope, not a mere under-claim.
    • Lens-unique: correctness-lens alone caught the monetize Audience-Size scorecard arithmetic; intent-lens alone caught the bare-relative-path robustness gap. Both re-grounded by main below and kept.

strategy.md — VERDICT: MINOR

  • Intent delivered: yes. Phase auto-detect from state (:32-44), phase strategy + delegation to strategy-advisor (:153), trajectory overlay (:250-284), authority building Phase 2+ (:286-419), stall points (Step 4), 90-day plan (Step 5), metrics (Step 6).
  • Resolution: all resolve — subagent_type: linkedin-studio:strategy-advisor (:153) → agents/strategy-advisor.md ✓; routes /linkedin:profile (:292,:360) ✓; Task declared.
  • Class predicate (guided/stateful): growth-plan artifact produced ✓; subagent resolves ✓; graceful degradation present ✓ (follower_count 0/missing handled :42; "If no milestone data: Skip this step" :284; authority skipped in Phase 0-1 :290).
  • Arithmetic (correctness-lens, grounded): 5 phases (04) consistent between Step 0.5 auto-detect ranges and Step 2 headers; step numbering monotonic (0.5,1,2,3,3.5,3.6,4,5,6), no gaps/dupes. PASS.
  • allowed-tools: declared {Read, Glob, Grep, AskUserQuestion, Task}; under-declared {} ✓; over {Glob, Grep} (harmless).
  • Findings:
    1. [MINOR] strategy.md:371 "Engaging with other thought leaders" — thought leader terminology-ban hit (off-primary checklist label). Part of the cross-cutting cluster.
    2. [MINOR] bare relative paths for all file loads; 0× ${CLAUDE_PLUGIN_ROOT} (grounded grep -c = 0, vs 110× in competitive/monetize/outreach/linkedin) → Read resolves against cwd, not plugin root. Has Glob in allowed-tools as a fallback so it degrades, not fatal. Folds into systemic finding #3 (bare ref-paths).

competitive.md — VERDICT: MINOR

  • Intent delivered: yes. Competitor analysis template (Step 2), landscape map (Step 3), gap/opportunity matrix (Step 4), differentiation plan (Step 5), inspired takeaways (Step 6), ethics note.
  • Resolution: fully self-contained — no subagent_type, no /linkedin: routes; allowed-tools (Read/Glob/WebSearch/AskUserQuestion) correctly omits Task. ✓
  • Class predicate (guided/stateful): competitive-analysis artifact produced ✓; no subagents to resolve ✓; graceful degradation ✓ (Step 1 user-input/WebSearch-driven, runs with no state).
  • Arithmetic: Steps 06 linear/monotonic; no stated totals to miscount. PASS.
  • allowed-tools: declared {Read, Glob, WebSearch, AskUserQuestion}; under {} ✓; over {Glob}.
  • Findings:
    1. [MINOR] thought leader(s) appears 4× — including the frontmatter description (:4, user-facing, shows in command listings) and the opening promise (:17), plus :31,:34. Worst terminology offender of the six. Conformity defect, no runtime break.

monetize.md — VERDICT: MINOR

  • Intent delivered: yes. All 8 steps present: scorecard (1), stage strategy (2), lead-magnet blueprint (3), funnel calendar (4), CTA + A/B variants (5), Featured optimization (6), revenue model (7), tracking dashboard (8).
  • Resolution: all resolve — no subagent_type; routes /linkedin:post + /linkedin:pipeline (:367) both exist. ✓
  • Class predicate (guided/stateful): monetization-plan artifact produced ✓; no subagents ✓; graceful degradation ✓ ("Stage 1: Visibility (0-1K followers)" :92 serves brand-new users).
  • Gating honesty: does NOT hard-gate; serves 0-1K. The real state-read gate is the router's soft prepend (linkedin.md:175, <1000 → prepend, continue anyway) — consistent with outreach.
  • Findings:
    1. [MINOR] description↔body scope self-contradictionmonetize.md:6 "Works from 1K+ followers" contradicts its own Stage 1 "Visibility (0-1K followers, score 0-30)" (:92, :81) and the router's "they work at any follower count" (linkedin.md:126). The body genuinely covers sub-1K; the description misstates scope. Off-primary (a frontmatter string) but user-facing. Strongest non-terminology R5 finding. Fix: align :6 to "any follower count (compounds at 1K+)".
    2. [MINOR] thought leaders in the frontmatter description (:4, user-facing). Part of the cross-cutting cluster.
    3. [SUGGESTION] Audience-Size scorecard arithmetic (:51-56): sub-items +5/+10/+15/+5/+5 sum to +40 against a /25 cap if read additively, whereas the other three categories each sum to exactly 25 (e.g. Engagement Quality 5+5+10+3+2=25). The follower tiers (1K/5K/10K) are clearly intended mutually-exclusive (one tier) but aren't marked as such → a literal additive read overflows. AI-interpreted (not machine-summed) so intent is recoverable; cosmetic, but it feeds the band that selects the stage. Fix: mark the three follower tiers "(pick one)".

outreach.md — VERDICT: PASS

  • Intent delivered: yes, thoroughly. Two-track (collab + speaking) orchestrator with a Capability Checklist mapping every predecessor function to a step (:31-62) + 10 steps + state persistence.
  • Resolution: all resolve — subagent_type: linkedin-studio:network-builder (:171) ✓; routes /linkedin:strategy (:112), /linkedin:firsthour+/linkedin:outreach (:1078), /linkedin:calendar (:1097) all exist ✓; Bash executable path sound — Step 8c's state-updater.mjs --record-outreach (:1084-1092) matches the script's handler (state-updater.mjs:294,:394-411) byte-for-byte. ✓
  • Class predicate (guided/stateful): outreach-plan + persisted pipeline produced ✓; subagent + script resolve ✓; graceful degradation ✓ (Step 2a "Not ready: <3 met → build foundation first" + recommend /linkedin:strategy :112).
  • Arithmetic (correctness-lens, grounded): "12 collab formats" → 12 (FORMAT 112); "4 talk templates" → AD; "5 phases" → PHASE 15; scorecards 4×/25=/100 and 5×/5=/25 check out; step numbering monotonic. PASS.
  • allowed-tools: declared {Read, Glob, WebSearch, AskUserQuestion, Task, Bash}; under {} ✓; over {Glob}.
  • Gating honesty: "1K+ followers" self-report (:100,:143) consistent with router's ~1K soft gate (linkedin.md:120,:176) and monetize's 1K. ✓
  • Findings:
    1. [SUGGESTION] thought leader inside a WebSearch query template (:229, "[your niche] linkedin thought leader"). It is a search string targeting how others self-label (intentional — to find such profiles), so the lowest-priority instance of the terminology cluster — but the literal string is still in the plugin.

profile.md — VERDICT: PASS

  • Intent delivered: yes. Relevance-model context (:20-44), Profile SEO + per-section keyword targets (:46-79), 7-section audit walkthrough (:82-199), profile-content alignment check (:200-212), prioritized action plan (:214-231), alignment test (:232-238).
  • Resolution: self-contained — no subagent_type, no /linkedin: routes; allowed-tools Read/AskUserQuestion (tightest frontmatter of the six). ✓
  • Class predicate (guided/stateful + topic-relevance-audit): the topic-relevance audit is actually performed (the body is that audit) ✓; artifact (audit + action plan) produced ✓; graceful degradation ✓ (every step AskUserQuestion-driven, runs with zero state). Notable verification discipline: explicitly refuses to fabricate a scoring breakdown (:28,:32-36,:179).
  • Arithmetic: Sections 17 monotonic; profile-field limits (headline 220, About 2,600) are LinkedIn field limits, NOT post hook/length bounds — no canonical contradiction. PASS.
  • Terminology — IMPORTANT NON-VIOLATION: the two thought leader hits (:79,:101) are legitimate negative examples — the command explicitly tells the user to AVOID the phrase (:79 lists it with "guru"/"ninja" as keyword-wasters; :101 is a "Weak example"). Both lenses agree; main confirmed by reading both lines. profile.md models the correct behavior.
  • Findings: none of defect class.
    1. [Note — systemic #3] bare relative paths; 0× ${CLAUDE_PLUGIN_ROOT} and no Glob fallback → most-exposed instance of the bare-path robustness item. BUT correctness-lens verified all three referenced files exist (test -f OK), so this is a cwd-robustness concern, not a dead ref. Folds into systemic #3; profile.md is otherwise the cleanest surface of R5.

linkedin.md (router) — VERDICT: MINOR

  • Intent delivered: yes. Status line (:19-29), upcoming/overdue posts via queue (:31-57), five-journey menu with front-doors (:59-127), gating rule (:122-127), interactive menu (:129-146), direct-routing table (:156-198).
  • Resolution (routing class): all 28 unique route tokens resolve to commands/*.md (verified token-by-token vs ls commands/); all 11 suggested agents resolve; queue-manager.mjs node call (:35-42) uses exports that all exist (:52,:94,:112). The router advertises nothing that doesn't exist. ✓ Correctly has no Task (delegate-only).
  • Class predicate (routing): every route resolves ✓; graceful degradation ✓ (missing state "No LinkedIn state tracked yet" :28; empty queue :57; follower segment only if follower_count > 0 :30).
  • Gating honesty/consistency: :175-176 give monetize + outreach the same soft state-read gate (<1000 → prepend, continue anyway); :122-127 document the soft-gate design honestly ("they work at any follower count… competitive is not gated"). Consistent with both command bodies. ✓
  • Findings:
    1. [MINOR] linkedin.md:118 "Competitive analysis of other thought leaders" — thought leader terminology-ban hit in the user-facing routing-menu table. Part of the cluster.

Summary table

Surface Verdict MAJOR MINOR SUGGESTION
strategy.md MINOR 0 2 0
competitive.md MINOR 0 1 0
monetize.md MINOR 0 2 1
outreach.md PASS 0 0 1
profile.md PASS 0 0 0 (1 systemic-#3 note)
linkedin.md MINOR 0 1 0
R5 total MINOR 0 3 distinct 2 distinct

(Per-surface MINOR counts include shared cross-cutting findings; the 3 distinct R5 MINOR findings are: the terminology cluster, the monetize scope contradiction, and the bare-path robustness item.)

Cross-cutting findings (for the consolidated fix-pass)

  1. [MINOR · NEW R5 systemic] thought leader terminology cluster — 5 surfaces, 9 instances. competitive :4(description, user-facing)/:17/:31/:34 · monetize :4(description, user-facing) · linkedin :118(menu, user-facing) · strategy :371(checklist) · outreach :229(WebSearch string, lowest priority). profile :79,:101 are NON-violations (correct negative examples — do not "fix" them). Memory no-thought-leadership-phrase confirms this is a standing plugin terminology rule. Recommended fix: one terminology sweep replacing the user-facing instances first ("thought leaders" → "creators"/"experts"/"voices in your niche"), leaving profile's avoid-list intact and the outreach search-string as lowest priority. No runtime risk — the buzzword gate scopes to post content, not command markdown.

  2. [MINOR · per-flate] monetize.md:6 description↔body scope self-contradiction. "Works from 1K+ followers" vs the body's own 0-1K Stage 1 (:92) and the router's "any follower count" (linkedin.md:126). Fix: align the description to the body's actual sub-1K-onward range.

  3. [MINOR · folds into existing systemic #3] bare ref-paths — strategy + profile (0× ${CLAUDE_PLUGIN_ROOT}). profile most exposed (no Glob fallback). Refs verified to exist, so cwd-robustness not a dead ref. Reconcile in the repo-wide path-style pass already scoped by systemic #3 (R3/R4 found the same pattern in batch/pipeline/firsthour/analyze/report).

  4. [SUGGESTION · per-flate] monetize.md:51-56 Audience-Size scorecard sums to +40 vs /25 cap. Follower tiers intended mutually-exclusive but unmarked. Fix: annotate "(pick one)".

R5 adds NO new ★ systemic finding to the existing three (clipboard, scaffold-band, bare-paths) — the only genuinely new cross-cutting item is the terminology cluster, which is a conformity sweep, not a code-behavior defect.

Verification

  • Spot-checks re-grounded by main (this file): grep -rniE 'thought.?leader' over the 6 (9 hits, classifications above); sed -n '1,8p'/'92p'/'48,64p' monetize.md (scope + scorecard); grep -c CLAUDE_PLUGIN_ROOT per surface (strategy 0, competitive 4, monetize 10, outreach 10, profile 0, linkedin 1).
  • bash scripts/test-runner.sh → see STATE telling (expected 138 passed / 0 failed, floor 123) — unchanged by this review (review is read-only; no command edits).

Sweep status after R5

29/29 cold-review coverage reached (S1 review.md + R2a + R2b + R3 + R4 + R5). The independent cold-review phase is COMPLETE; the v1.0.0 review blocker is lifted. Remaining v1.0.0 work: the consolidated fix-pass (operator-gated — review FINDS, fix is a separate decision) and the GUI.