Commit graph

7 commits

Author SHA1 Message Date
6ed3e2f5a6 fix(linkedin-studio): honest saves/dwell wording, no false tracking claim
Wave 2 / Step 7 of the remediation plan (research/02 D2/D4).

The tool parses the LinkedIn analytics CSV export, which has no saves/dwell — and
there is no self-serve API to pull them. Stop implying it tracks them:
- report.md: replace "Saves (10x weight) and expert comments (7-9x) are the
  highest-impact signals" with honest wording — saves rank highest in the
  engagement ORDER (cite references/algorithm-signals-reference.md, not a restated
  coefficient), but are visible only in native LinkedIn post analytics (count-only,
  ~Sept 2025+) with no self-serve API, so this tool does not auto-track them; dwell
  is internal to LinkedIn for organic posts.
- types.ts: document why PostMetrics intentionally omits saves/dwell (no ingest
  source) so a future contributor does not "add the missing fields".
- strategy.md: reconcile two saves references (signature-content criterion +
  authority scorecard) to say the count is read from native LinkedIn analytics, not
  captured by this tool.

No new metric field, no manual-entry feature (operator Q3).

Verify: report.md has no "Saves (10x"/"highest-impact signals" and does say "no
self-serve API"; tsc --noEmit clean; analytics suite 106/106; structural lint
0 failed (report.md cites the reference, so stat-consistency stays green).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 00:28:23 +02:00
55bfe309eb fix(linkedin-studio): downgrade A/B significance claim to directional
Wave 2 / Step 6 of the remediation plan.

Organic personal-post A/B tests gather a handful of posts per variant — far below
the volume a significance test needs — so the tool must not imply statistical
significance:
- Rename the results-table "Significant?" column to "Directional?" and define it
  as "clears the ~20% minimum-meaningful-difference AND points the same way across
  most posts" — a direction to test further, not a significant result.
- Reword the "20% significance rule" to a minimum-meaningful-difference effect-size
  heuristic (explicitly NOT statistical significance).
- Replace the "3 = Medium, 5+ = High" confidence ladder with a directional-only
  confidence section: treat every result as directional (not significant) given
  realistic volume is well under ~50 conversions/variant; name a direction, not a
  winner.

The 20% minimum-meaningful-difference threshold itself stays — it is a legitimate
effect-size heuristic; only the significance framing was the false claim.

Verify: no "Significant?"/"20% significance" remain; "directional" present;
structural lint 0 failed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 00:25:26 +02:00
911871ff53 fix(linkedin-studio): ship placeholder voice profile, gitignore real, sentinel detection
Wave 2 / Step 5 of the remediation plan (coupled criticals: voice-leak +
placeholder-detection).

Voice profile (the adopter-default leak):
- Ship a PII-free placeholder at authentic-voice-samples.md carrying a
  <!-- VOICE_PLACEHOLDER --> sentinel + neutral default voice principles.
- Migrate the author's real profile to gitignored authentic-voice-samples.local.md
  (already matched by *.local.md; added an explicit, commented .gitignore entry so
  the intent is unmissable). NO git-history rewrite — the historical file is
  attributed authorship, not a secret (per the plan threat model).
- Add authentic-voice-samples.template.md — a clean fill-in template for adopters.
- personalization-score.mjs: detect the sentinel (deterministic) instead of the
  unreliable `[Your Name]` heuristic, so the placeholder scores 0 voice points and
  a populated profile (sentinel removed) earns the 25.
- Both voice writers replace-not-append on the placeholder: setup.md (merge ->
  replace-if-placeholder) and onboarding.md (append -> replace-if-placeholder), so
  populating removes the sentinel; updated setup.md's stale heuristic table.

Operator decisions (deviations from plan-literal, approved this session):
- KEEP the plugin.json author name. The plan said scrub author -> neutral/org, but
  that contradicts its own LICENSE reasoning (intentional MIT attribution) and all
  5 sibling plugins keep author = the author; scrubbing only this one would create
  inconsistency for zero security gain (the name is public-by-design). The voice
  placeholder fully fixes the adopter-inheritance bug.
- Scrub the stale "January 2026 360Brew" brand from the plugin.json description and
  the "360brew" keyword (locked decision: no publishable model name/date). This is
  a Wave-1 propagation miss surfaced here because plugin.json was in Step 5's
  touch-scope.

Flagged for follow-up (NOT done here — out of Session 2 scope):
- The lint's stat-consistency grep (scripts/test-runner.sh) scans references/,
  commands/, skills/, hooks/prompts/, CLAUDE.md, README.md — but NOT
  .claude-plugin/plugin.json, which is why the 360Brew brand slipped Wave 1.
  Needs a Session-1-scoped lint extension to add plugin.json to the scan set.
- Readers (user-prompt-context.mjs, voice-guardian.md, state-update-reminder.md)
  read the tracked .md (placeholder), per the plan. The operator's real voice now
  lives in the gitignored .local.md, which nothing reads. To use it, readers + the
  voice score should prefer .local.md (matching the user-profile.local.md
  precedent). Deferred as a coherence follow-up for operator review.

Test-first: hooks/scripts/__tests__/personalization-score.test.mjs (red on the
placeholder scoring 25 under the old heuristic, green after the sentinel fix). Hook
suite 62/62, structural lint 0 failed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 00:23:32 +02:00
798484bf0c fix(linkedin-studio): anchor analytics root on plugin marker + surface npm install
Wave 2 / Step 4 of the remediation plan (docs/remediation/plan.md).

PRIMARY (the real fresh-clone failure):
- scripts/analytics/node_modules is gitignored, so a fresh clone has neither
  tsx nor csv-parse. Surface an idempotent `npm install --silent` prerequisite
  at point-of-use in report.md (Step 1b) and import.md (Step 4).

DEVIATION FROM PLAN (correction-in-scope, to satisfy the plan's own Verify gate):
- The plan assumed prepending `npm install` was sufficient. Verified it is NOT:
  the commands invoke the CLI with an absolute src/cli.ts path but from the
  user's arbitrary CWD, and `node --import tsx` resolves the `tsx` specifier
  relative to CWD, not the script. There is no global tsx, so the call still
  fails with ERR_MODULE_NOT_FOUND from any CWD other than scripts/analytics.
- Complete fix: invoke the locally-installed tsx by its absolute
  node_modules/.bin/tsx path in all CLI calls (report.md x10, import.md x3), so
  they resolve from any working directory once the install above has run.
  Verified: 0 ERR_MODULE_NOT_FOUND running `report` from /tmp.

SECONDARY (latent correctness / hardening):
- Add findPluginRoot(): walks up to the dir holding .claude-plugin/plugin.json
  and anchors getAnalyticsRoot() on it, falling back to the legacy 4-up count.
  MEASURED that ../../../../ already resolved to the plugin root from BOTH
  src/utils and build/utils (both 4 levels deep), so the plan's "src-vs-build
  depth miscalibration" premise was false — this is correct-by-construction
  hardening (survives a future source move), not a live-bug fix.
- Reconcile cli.ts usage/help text: `node build/cli.js` -> `node --import tsx
  src/cli.ts` (the real runtime).
- Fix report.md troubleshooting: "Verify tsx is available" -> the actual
  install command on ERR_MODULE_NOT_FOUND.

Test-first: scripts/analytics/tests/storage-root.test.ts (red on missing
findPluginRoot export, green after). Full suite 106/106, tsc --noEmit clean,
structural lint 0 failed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29 21:18:33 +02:00
4700248cc4 fix(linkedin-studio): propagate reconciled algorithm numbers, cite-not-restate
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29 20:32:17 +02:00
e69ea1f4c9 feat(linkedin-studio): v3.1.0 — Endring 9 adversarial review-pakke + per-artefakt personas
Cold, adversarial review package for the long-form pipeline + configurable
per-edition personas. Motivated by Del 4 (Security Champions pivot): the
in-session editor + persona sweep shared the drafting session's framing-bias,
so the shipped version was never independently re-reviewed.

Headless package (9a/9b):
- New Step 6.5 (headless-review) in /linkedin:newsletter, after the persona
  sweep, before lock — the independence layer the in-session gates can't be.
- New standalone /linkedin:headless-review command (run in a fresh session for
  maximum isolation; reconstructs frozen draft + contract + personas from disk).
- 3 new Opus archetypes, each with a cardinal context-isolation block that
  refuses drafting-session framing as "context pollution":
  - content-reviewer (argument integrity C1–C5, ≤8 flags)
  - language-reviewer (Norwegian language L1–L5, ≤10 flags)
  - fact-reviewer (cold re-verification F1–F4, risk-sort + pivot-risk, WebSearch)
- Deliberate redundancy with fact-checker / editorial-reviewer documented so
  the pairs are never de-duplicated.

Pivot-reopen (9c):
- New /linkedin:pivot command: logs articles.NN.pivots[], resets currentPhase,
  un-locks, marks gates to re-run.
- Pivot-detection gate in Step 8 lock precondition (>20% word-count change or
  >2 new sections re-opens cleared gates). Del 4 v8→v11 worked example.

Per-artifact personas (new requirement):
- articles.NN.personas with resolution order (edition-state → series file →
  plugin library → interactive). One or more readers configurable per edition.

Schema/docs:
- edition-state.template.json: additive personas[], pivots[], headlessReview,
  headless-review phase (16 phases); personaSweep.resonance.wordCount baseline.
- 3 fasit fixtures + 3 structural lint tests (Del 4 worked cases).
- Counts: 24→26 commands, 16→19 agents, 15→16 newsletter phases.
- README + CLAUDE.md (plugin + root) + CHANGELOG synced.

Verification: 35 agent-fixture + 59 hook + 20 render tests green. Backward-
compatible (additive state); reload required before the 3 new agents resolve.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29 13:01:24 +02:00
b6bb61246b refactor(linkedin)!: rename plugin linkedin-thought-leadership → linkedin-studio (v3.0.0)
BREAKING CHANGE: the marketplace slug, the agent namespace
(linkedin-studio:<agent>), and the runtime state-file path
(~/.claude/linkedin-studio.local.md) all change. Reinstall required;
existing state migrated in place (post metrics, streak, history preserved).
The /linkedin:* commands are unchanged — the command namespace is set
per-command in frontmatter and was always independent of the plugin slug.
Functionality is byte-identical to v2.4.0; this release is pure identity.

- dir + manifests: plugins/linkedin-studio + plugin.json + root marketplace.json
- agent namespace updated in commands/newsletter.md (only functional invoker)
- state path updated in 4 hook scripts + topic-rotation prompt + state template
- catch-all skill dir renamed skills/linkedin-studio (5 functional skills unchanged)
- docs + version bump to 3.0.0 across README badge, CHANGELOG, root README/CLAUDE.md
- historical records (CHANGELOG past entries, docs/ build artifacts,
  config-audit v5.0.0 snapshots) intentionally retain the old slug

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-29 11:32:02 +02:00