fix(linkedin-studio): S17 harden audit — drop orphan WebFetch grant + re-source carousel save-rate claim to SSOT

This commit is contained in:
Kjell Tore Guttormsen 2026-06-19 13:24:43 +02:00
commit 52e39d18a9
2 changed files with 57 additions and 2 deletions

View file

@ -9,7 +9,6 @@ allowed-tools:
- Read
- Glob
- Grep
- WebFetch
- AskUserQuestion
---
@ -90,7 +89,7 @@ Carousels: ████░░░░░░░░░░░░ 15%
Video: █░░░░░░░░░░░░░░░ 5%
Polls: ░░░░░░░░░░░░░░░░ 0%
Recommendation: Increase carousel content (highest save rate)
Recommendation: Increase carousel content (top organic format)
```
## Step 5: Engagement Trends

View file

@ -1288,3 +1288,59 @@ source, so the real fix belongs to the reference-consistency pass.
- Disposition: **FIXED** (1 edit, `commands/analyze.md`) · 0 deferrals · axes a/c/d PASS, b PASS post-fix.
---
### /linkedin:audit — quarterly content-strategy audit (top/bottom posts · topic & format mix · trends · milestone) → report + routes to strategy/profile
**INTENT.** Prose-heavy, self-contained quarterly audit — **NOT CLI-backed, NOT agent-delegated**
(`allowed-tools: Read, Glob, Grep, AskUserQuestion` post-fix, no Bash, no Task, `audit.md:812`).
Measure-journey (reachable via `/linkedin:measure`). The 8 steps (08 + 5.5) faithfully cover the
description scope: top/bottom performers, topic distribution, format mix, engagement trends, milestone
progress, profile alignment — quarterly cadence. Names the gap; routes the fix to `/linkedin:strategy`
(trajectory) + `/linkedin:profile` (profile audit).
**SIMULATE.** ICP author, scenario A (partial data). Step 0 reads state + `plans/` + checks `analytics/`
+ audience-insights/examples, asks user for top-5/bottom-5 + screenshot; Steps 12 tabulate vs 7 factors
(`:4149`); Step 3 topic-mix vs pillars (`:6981`); Step 4 format mix → emits "Increase carousel content
(**highest save rate**)" (`:93`, before fix); Step 5 trends; Step 5.5 milestone if `follower_count>0`;
Step 6 routes to `/linkedin:profile` (`:151`); Step 7 report; Step 8 AskUserQuestion. Scenario B (fresh
adopter, no data): Step 0 `:26` "Check for any" = soft, audience files absent → degrades to user-provided
data; Step 5.5 `:141` `follower_count` not >0 → "Skip this step. Add note: …not configured" — no crash.
Friction: one orphan tool-grant + one unsourced format-claim.
**EVALUATE (4 axes; analytics-class predicate = graceful degradation + saves/dwell honesty).**
- **axis-a (intent): PASS** — 8 steps faithfully cover the description scope; routing-by-delegation (not
agent delegation) is honest ("names the gap, strategy/profile prescribe the fix", `:145156`).
- **axis-b (algorithm/format claim vs SSOT): 1 FUNN.** `:93` "(highest save rate)" — the specific
metric-attribution is absent from the SSOT (which sources "carousels = **top organic format**",
`algorithm-signals-reference.md:55`, and "**saves** = top engagement signal", `:42`, but never
"carousels = highest *save rate*") AND from the cited refs (playbook `:248` "Carousels: 1.6x", `:192`
"6070 % reduced reach"; no save-rate superlative). Postulated mechanic embedded in an example block.
- **axis-c (quality rules): PASS** — emits no content; no format/length advice contradicting CLAUDE.md.
- **axis-d (wiring + degradation): 1 FUNN.** No Task → claims no agent delegation (`grep
subagent_type|Task` = NONE) ✅; `/linkedin:strategy` + `/linkedin:profile` resolve ✅; graceful
degradation present (Step 5.5 explicit skip + user-provided-data primary path) ✅; data-seam consistent
(`${LINKEDIN_STUDIO_DATA:-…}/` data, `~/.claude/linkedin-studio.local.md` state, `${CLAUDE_PLUGIN_ROOT}/`
refs) ✅; saves/dwell not over-promised (no Bash; never claims auto-track) ✅. **FUNN: WebFetch orphan
tool-grant** — `:12` granted it; body `:20234` never fetches (grep = declaration line only).
**HARDEN (2 surgical edits, `commands/audit.md`).**
1. [REWORK · axis-d] Dropped `WebFetch` from allowed-tools — granted but never invoked; audit reads local
files + asks user + routes, fetches no URL. Tool-surface now matches behavior (5 → 4 tools).
2. [REWORK · axis-b] `:93``:92` "(highest save rate)" → "(top organic format)" — aligned to the SSOT's
sourced framing; dropped the unsourced save-rate superlative.
**Out-of-scope (logged, NOT touched in S17).** `:61` "off-topic (topic-relevance penalty)" — SSOT frames
topic-relevance as a positive distribution driver (`:30,89`, high), not a named penalty; but off-topic →
weaker relevance match → less reach is defensible and "topic-relevance signal" is plugin convention
(CLAUDE.md rule #5). Left as-is (NICE, directionally correct diagnostic parenthesis).
**VERIFY.**
- Re-grepped final file: `grep WebFetch commands/audit.md`**NONE** (allowed-tools now
Read/Glob/Grep/AskUserQuestion, `:912`); `grep "highest save rate"`**NONE**; `:92` = "Increase
carousel content (top organic format)".
- `git diff --stat` = 1 file, **+1 / 2**.
- `bash scripts/test-runner.sh``Passed: 81 · Failed: 0 · Warnings: 0`, **exit 0**; counts **29/19**
unchanged (.md-only edit).
- Disposition: **FIXED** (2 edits, `commands/audit.md`) · 0 deferrals · axes a/c PASS, b + d PASS post-fix.
---