The de-niche sweep (B-S1/B-S2) stripped the hardcoded KTG beat
(Microsoft|Azure|Copilot|public sector|offentlig sektor) from three surfaces,
but §17 only locked agents/trend-spotter.md against its return. Generalize the
guard to the full de-niched set so a beat token cannot creep back into the
other two:
- agents/trend-spotter.md (B-S1)
- agents/content-planner.md (B-S2a)
- references/content-framework.md (B-S2a)
Single shared NICHE_TOKENS criterion + non-vacuity/false-positive self-test
(unchanged shape), then a per-file grep loop over the explicit allowlist.
Scoped per file BY DESIGN, not tree-wide: references/content-angles.md keeps
"Public Sector" as 1 of 6 example industry tables (a KEEP surface — generic
illustration, not a beat) and is deliberately NOT guarded; "AI" is the plugin's
own subject, not a niche token. Added an "AI-driven content planning ..."
negative probe to lock that in (self-test now 5 caught / 6 ignored).
Non-vacuity proven by injection: a beat token appended to each new file makes
the guard fail naming the file+line; reverts clean. Gate 87→89/0/0 (+2 file
checks; assertion-count floor §18 still satisfied).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RigJBiRFNtFZKCz21qNbQ4
The last de-niche slice: recast the 10 sites where the vendor/sector beat
(Microsoft|Azure|Copilot|public sector) sat as the PRIVILEGED/default example,
varying each to a concrete cross-domain example instead of sterilizing
(plugin-is-domain-general — domain comes from user config, never hardcoded).
Recast (10): url-processing-templates (news worked-example Copilot->Figma),
opportunity-generation (3 headline examples + About block -> varied/ops persona),
profile (3 "good example" headlines/impact -> healthcare/e-commerce/support),
first-comment-strategy (drop "Microsoft" from research-paper example),
poll-strategy-guide (Copilot option -> generic AI assistants),
engagement-frameworks (1 of 3 direct-address audiences -> RevOps/SaaS),
setup (audience e.g. -> two varied examples), post (invocation e.g. -> SaaS pricing),
network-builder (tagline example -> ops/manufacturing),
video-scripter (2 filename slugs -> neutral topics).
Kept as false positives (would sterilize): content-angles.md (Public Sector is
1 of 6 balanced industry tables + Industry-Agnostic section), outreach.md
(Microsoft Build/Ignite/Azure UG = 3 of ~20 varied real conferences),
linkedin-growth-playbook (biographical fact in a real case study), the
Gemini/Tavily/Perplexity MCP tool-name examples, and the algorithm-signals
"Gemini provenance" SSOT citation. AI-as-topic kept (not a niche token; the
de-AI/AI-slop mechanic is the plugin's legit subject).
Gate scripts/test-runner.sh 87/0/0 (no lint touches these files yet; §17-guard
extension to content-planner is the deferred next step). 10 files, 26/26.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RBMKqPSVbvSZHtQ4heM1UY
B-S2a, the constraining-first slice of the de-niche sweep: kill the niche at
its source. B-S1 made trend-spotter pillar-driven, but the agent still READ
references/ai-content-framework.md (and so did differentiation-checker,
voice-trainer, and the content-creation skill) — an AI/Microsoft-specific file
whose very name baked in the niche. So the niche leaked back regardless of how
clean the agents were. This recasts that file domain-general and de-niches the
content-planner seasonal calendar (the other hardcoded beat: MS Build/Ignite as
THE anchors). The principle: vary concreteness, don't sterilize
(plugin-is-domain-general).
- Recast + rename references/ai-content-framework.md -> references/content-framework.md:
title "AI Content Framework" -> "Content Framework"; the 4 pillars kept as a
domain-general pattern (News/Implementation/Strategy/Tools) with examples now
spanning multiple fields instead of AI-only; AI-specific placeholders
([AI announcement], [AI system], GPT-X/Claude X) generalized to neutral
brackets; anti-patterns "AI will change everything" -> "[Field] will change
everything". The "News Monitoring / Sources by Priority" section (AI sources:
The Batch, ArXiv, r/MachineLearning, OpenAI/Anthropic blogs) — now duplicated
by the trend engine's config source-list — is thinned to point at
config/trends-sources.template.md + the data-dir override, keeping the
daily/weekly RHYTHM (general) and dropping the baked source list.
- Rename ripple, 6 referrers repointed: trend-spotter, differentiation-checker,
voice-trainer (reference lines, + dropped "AI" from descriptions), glossary
(Used-in + de-niched the "Example for AI content" pillar illustration),
linkedin-content-creation SKILL ("AI-specific angles" -> "Domain content
pillars + angles"), and test-runner §17 (NEGATIVE17 probe path + comment).
docs/hardening/log.md left intact — historical record, not a live pointer.
- content-planner.md seasonal calendar de-niched: header "Nordic/Tech Focus" ->
"rhythm, adapt to your field & region" + intro prompt; Microsoft Build,
Ignite (x2), Apple/Microsoft launches, NDC, EU AI Act, "Azure AI" example
pillar, "AI predictions", Nordic/17.mai locale anchors -> domain/region-
neutral prompts. Global anchors kept (New Year, IWD, Halloween, Black Friday,
year-end).
Deferred to after the full sweep (per STATE): extending the §17 de-niche guard
to content-planner (and content-framework) — the guard's token set + agent
scope is best designed once the sweep (B-S2b) reflects the final clean surface.
ref count unchanged (27; rename is 1->1). Gate 87/0/0 (§17 self-test green).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RBMKqPSVbvSZHtQ4heM1UY
The trend-spotter agent stated its own contract — "the niche lives in the
source list and the user's pillars, never in this agent" — yet contradicted it
by hardcoding the Microsoft/public-sector beat in four surfaces. Resolve the
contradiction so the file is genuinely domain-general (plugin-is-domain-general):
the domain comes from the user's profile/pillars at runtime, never baked in.
- Description: "trending topics in AI, Microsoft, and public sector" ->
"across the user's content pillars and domain"; trigger phrases "what's
happening in AI" -> "in my field"/"in my space".
- Mission: drop "intersection of AI, Microsoft technology, and public sector
digitalization" -> "within the creator's own domain, defined entirely by
their content pillars and expertise areas, never by a beat baked into this
agent".
- Content Trigger Classification: "Microsoft platform changes" -> "platform
changes in the user's stack"; "public sector milestones" -> "sector
milestones in the user's domain".
- 4-Question Relevance Filter: "Public sector leaders or enterprise AI
implementers" -> "the user's target audience (per their profile)".
- Anti-pattern example: "AI is changing everything" -> "[topic] is changing
everything".
- CI: new test-runner Section 17 (trend-spotter de-niche guard) forbids the
KTG-beat proper nouns (Microsoft|Azure|Copilot|public sector|offentlig
sektor, case-insensitive) from returning to agents/trend-spotter.md, with a
non-vacuity self-test mirroring Sections 8/13. Scoped to this one agent
(B-S1); the wider sweep (B-S2) owns the other surfaces + the
ai-content-framework.md reference filename. Assertion-count renumbered to
Section 18. Gate 85 -> 87/0/0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RBMKqPSVbvSZHtQ4heM1UY
Bind the layers slices 1 (store) and 2a (config) built: trend-spotter goes from
an amnesiac, niche-hardcoded scanner to a persistent, generic engine.
- Tools: drop the `tools:` allowlist (inherit all session tools incl. any
research MCP) + `disallowedTools: Write, Edit, NotebookEdit`. An explicit
allowlist would block every MCP unless its mcp__server__tool name were
hardcoded — which breaks "prefer whatever MCP the user connected, hardcode
nothing". WebSearch+WebFetch stay as the always-available floor; Bash runs
the deterministic store CLI. (CC mechanic verified vs code.claude.com/docs.)
- Store-wiring (de-amnesia): query prior history before polling; persist every
kept trend through scripts/trends `add` (dedup/union preserved — a raw Write
would bypass it). Mirrors how specifics-bank is wired from the command layer.
- MCP-first routing: read the profile's "### Research Tooling" declaration,
prefer a declared MCP, fall back to the floor, fail soft. No hardcoded names.
- Scoring -> SSOT: replace the inline matrix/composite/bands with a pointer to
references/trend-scoring-modes.md (kortform default, long-form on request).
- Sources from config: replace the hardcoded vendor/outlet list + query bank
with a read of trends/sources.md (user override) -> trends-sources.template.md
(shipped default).
- CI: new test-runner Section 16 (trends-store binding guard, floor 21,
KTG-only skip) mirroring the specifics-bank guard; assertion-count renumbered
to Section 17. Gate 84 -> 85/0/0. model-consistency green (model unchanged).
Reload required: the tools-grant change takes effect only after a session reload.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RBMKqPSVbvSZHtQ4heM1UY
Declaration/config groundwork that slice 2b's trend-spotter upgrade reads.
Standalone (no agent wiring yet — that's 2b), mirroring slice 1's pattern;
[skip-docs] for the same reason slice 1 was — user-facing docs land when 2b
wires the engine live.
- references/trend-scoring-modes.md: methodology SSOT for two rubrics —
kortform (feed post, timing 20%) + long-form (chronicle, depth 25% / timing 10%,
per tema-research-motor-spec §4.2). Both sum to 100%. trend-spotter renders from
this in 2b instead of inlining a matrix (S12-consistent).
- config/trends-sources.template.md: shipped generic source-list defaults →
user override at ${LINKEDIN_STUDIO_DATA}/trends/sources.md (data-dir, survives
reinstall; same template->data-dir pattern as user-profile).
- user-profile.template.md: new "Research Tooling" section — declared research MCPs
(Tavily/Gemini/Perplexity/Other) + WebSearch/WebFetch floor. 2b routes MCP-first.
- setup.md Step 3f + onboarding.md Phase 2: ask "which research MCPs?" -> profile.
Store only what the user declares; no hard-coded MCP names.
- test-runner.sh: EXPECT_REFS 26->27; generalized the M0 +1 delta-guard into a
named-post-M0-additions guard (POSTM0_REFS) so a legit later ref doc passes while
the anti-masking intent holds. Gate green 84/0/0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RBMKqPSVbvSZHtQ4heM1UY
[skip-docs] internal plumbing — standalone store, no command/agent/pipeline
surface change until slice 2 wiring (mirrors specifics-bank slice 2). CLAUDE.md
"Telling"/counts untouched; lint stays 84/0/0.
Research-engine §5 (foundation layer) slice 1: the deterministic STORE half of
the persistent trend store — a topic-tagged, provenance-bearing inventory of
trend signals captured over time, so the research engine accumulates HISTORY
instead of starting amnesiac each session. Trend-side twin of the lived-specifics
bank (same store/dedup/query discipline; dedupe key is normalized title+URL, not
free-text content). Generic by architecture: nothing niche-specific lives here —
topics and source are free-form, decided upstream via config/profile.
scripts/trends/ (sibling to specifics-bank, same tsx convention):
- src/types.ts — TrendRecord/TrendStore schema (schemaVersion 1), minimal
generic core: title, url, source, capturedAt, topics[], optional summary
- src/store.ts — pure store: normalizeField, title+url-hash id (= dedupe key),
load/save, addTrend (dedupe + topic union on re-capture; first-sighting
source/capturedAt kept), queryByTopic (overlap-ranked then recency), history
(time-scoped, since/limit)
- src/cli.ts — add / query / list; default store under
${LINKEDIN_STUDIO_DATA:-~/.claude/linkedin-studio}/trends/ so trend history
survives plugin upgrades/reinstalls (M0 data-path seam)
- tests/store.test.ts — 21/21 green; tsc clean
- README + .gitignore for node_modules/build
Capture/scoring agent + MCP-first routing land in slice 2; the CI binding guard
is deferred to wiring, mirroring the specifics-bank timeline.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Wire the kilde-så-draft binding (slices 1–2) into the live /linkedin:newsletter
pipeline so a draft is grounded in the operator's real material BEFORE any prose.
- New Step 1.5 "Lived-specifics extraction" BETWEEN brief (1) and research (2):
query the bank → 3–5 sharp elicitation questions (vagueness refused, never
fabricated — invariant 3) → `add` to the specifics-bank → populate the
articles.NN.livedSpecifics slot-map → render the NN-kilder.md ledger. First
phase to write machine state (persists brief + personas + binding).
- Deterministic binding-gate (`validate-binding`, exit 1 = BLOCK) wired as a new
step 5 of the Step 2.5 skeleton-gate (renumbered 5→9): no prose is written on
an unresolved load-bearing claim; livedSpecifics → "bound" on pass.
- Step 2 re-scoped BY the binding: research fills the ekstern/unresolved slots +
verifies the operator's own numbers (regel 6/7) → flips bank unverified→verified
→ re-renders NN-kilder.md, instead of re-sourcing what is already grounded.
- Pipeline 17 → 18 phases: new `lived-specifics` phase id in edition-state
_doc.phases; resumption table + pipeline overview + CLAUDE.md + README updated.
- Lint: new Section 15 "Specifics-Bank Binding" wires the specifics-bank suite
into CI (suite green + case-count floor 28, KTG-only/adopter-skip); the
assertion-count anti-erosion floor moves to Section 16.
Verification: structure gate 84/0/0 (was 83), specifics-bank 28/28, contract-gate
ratify 1:1, edition-state template valid JSON (18 phases), gitleaks clean on all
5 files. Design record: docs/fix2/slice2-binding.md.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Slice 2 of fix#2 (kilde-så-draft): the per-edition bridge between the global
specifics-bank (slice 1) and a draft. In scripts/specifics-bank:
- binding.ts — livedSpecifics slot-map model + validateBinding, the «vaghet
avvises» gate (G4). BLOCK on unresolved / dangling specific-id / unjustified
abstrakt; WARN on an unverified-number-backed slot (regel 6/7); PASS otherwise.
- kilder.ts — renderKilder, the read-only NN-kilder.md sources ledger, rendered
deterministically from the slot-map + bank (coverage via validateBinding, so
the artifact and the skeleton-gate cannot disagree).
- cli.ts — validate-binding (exit 1 = BLOCK) + render-kilder subcommands.
edition-state schema gains articles.NN.livedSpecifics ({ slots, status }) + _doc.
Design record + the Step 2 research re-scope spec: docs/fix2/slice2-binding.md.
Wiring into newsletter.md (Step 1.5 elicitation + Step 2.5 gate + pipeline 17->18)
is slice 3 — not in this commit.
Tests 28/28 (specifics-bank; +9 binding +4 kilder), tsc clean, plugin gate 83/0/0
unaffected, gitleaks clean on all 8 files.
[skip-docs] internal plumbing — no command/agent/pipeline surface change until
slice 3 wires it; documenting it in the user-facing root CLAUDE.md/README now would
overclaim unreachable functionality. Docs ARE updated where they belong: the design
record docs/fix2/slice2-binding.md, scripts/specifics-bank/README.md, and the
edition-state _doc. Root-doc update lands with the slice-3 wiring feat.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fix#2 (kilde-så-draft) slice 1: the deterministic STORE half of the
lived-specifics bank — the operator's real, un-generatable raw material
(measured number / named-but-real case / what broke / contrarian opinion /
mind-change), so drafts start grounded instead of hollow (retning §3;
dream-spec "Lived-Specifics Extraction", the single biggest missing upstream
piece for the authenticity thesis).
scripts/specifics-bank/ (sibling to contract-gate, same tsx convention):
- src/types.ts — Specific/Bank schema (schemaVersion 1), un-generatable taxonomy
- src/bank.ts — pure store: normalizeContent, content-hash id (= dedupe key),
load/save, addSpecific (dedupe + topicTag union on re-capture), queryByTopic
(active-only, ranked by tag overlap then recency)
- src/cli.ts — query / add / list; default bank under
${LINKEDIN_STUDIO_DATA:-~/.claude/linkedin-studio}/specifics-bank/ so it
survives plugin upgrades/reinstalls (M0 data-path seam)
- tests/bank.test.ts — 15/15 green; tsc clean
- README + .gitignore for node_modules/build
Content is stored verbatim; never AI-generated. The elicitation interview
(refuses vague answers; abstrakt/ekstern escape hatches) lands in slice 3
(/linkedin:newsletter Step 1.5). Forward-compatible with the profile-evolution
/ "second brain" architecture.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Slice 3 of fix#1 (§C2 bindende + akkumulerende): wire the deterministic
§B/§C1 contract-gate into the long-form pipeline as a pre-handoff step, so
mechanical violations die deterministically BEFORE the costly AI gates and
never reach the operator at a judgment gate ("rettelser fester seg").
Newsletter pipeline:
- New Step 4.5 (between Step 4 consistency/quality and Step 5 fact-check):
(1) ratify the gate (rules.ts <-> §E-manifest 1:1; DRIFT escalates to
operator, not a draft fix) and (2) gate the draft (exit 0 PASS / exit 1
BLOCK -> fix by tightening + re-run; WARN = direction, never blocks).
Adopter-safe: no-op when contract-gate deps / the maskinrommet contract
are absent.
- Pipeline phase count 16 -> 17 across every LIVE surface (overview table +
build-status + narrative + banner + schema pointer in newsletter.md;
command-table rows in CLAUDE.md and README). Historical version-narrative
entries left untouched.
- edition-state.template.json: new "contract-gate" phase string (Step 4.5),
between consistency-quality and factcheck-sweep. JSON valid; phases 16->17.
CI integration (test-runner.sh, Section 14 — new):
- 14a: contract-gate suite stays green (npm test exit 0) with a 33-test
case-count floor (anti-erosion).
- 14b: ratify invariant — rules.ts bound 1:1 to the §E-manifest.
- Both KTG-internal and adopter-safe (warn/skip, never fail, when deps or the
contract are absent). set +e inside the test command-substitution keeps a
red suite from aborting the runner; ratify exit 1 captured via if-subshell.
- SC6 anti-erosion section renumbered 14 -> 15; header comment updated.
Verification:
- Structure lint 81 -> 83/0/0 (contract-gate suite + ratify both green).
- Documented Step 4.5 command smoke-tested on a real draft
(serier/silvija-seres-motsvar/utkast/04-utkast.md): 0 BLOCK / 2 WARN ->
"Gate passert", exit 0.
- edition-state.template.json valid JSON; phases array = 17.
foldIns capture into the pipeline phases deferred to a later slice (scope A).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Slice 2 av fix#1 («rettelser fester seg»): binder rules.ts til den menneskelige
sannhetskilden (skrivekontrakt §E), så en korreksjon gjort én gang håndheves for
alltid i stedet for å gjenoppdages hver utgave (diagnose-gap 2).
- ratify.ts: importerer RULES direkte (ingen skjør tekst-parsing), krever en
bijeksjon mot §E gate-bindings-manifestet (id ↔ ref ↔ severity) + dangling-
§-anker-sjekk. CLI: `--ratify [kontrakt]` / `npm run ratify`. Sti: arg > env
MASKINROMMET_CONTRACT > default (relativt til modulen).
- edition-state.template: foldIns[] fangst-kø (per-artikkel proveniens,
pending|promoted|rejected, mekanisk→rules.ts / dømmekraft→§C2).
- 12 nye tester (33 totalt), tsc rent. Live-kontrakt-integrasjonstest ratify-er
det ekte §E-manifestet rent (10 regler bundet 1:1).
Companion: skrivekontrakt §E (JA-promoter-prosedyre + manifest) i maskinrommet.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds scripts/contract-gate/ — a deterministic, AI-free gate that enforces the
mechanical half of the Maskinrommet writing contract (§B red flags + §C1
regelsjekk) BEFORE operator handoff, so the same mechanical correction never
reaches KTG twice. First slice of fix#1 (binding + accumulating); target
re-scoped to close all 4 diagnosis gaps = sustainable newsletter workflow.
- Structured ruleset as DATA (src/rules.ts) so accumulation (slice 2) appends.
- 3 BLOCK (modell-strawman, series-thesis "er ikke modellen", _underscore_)
+ 7 WARN (judgment-needed). Block only on provable, ~zero-FP matches.
- Code/frontmatter masking; line-accurate reporting; CLI receipt + exit code.
- 21/21 tests (node:test), tsc clean.
- Validated on 6 real editions: 0 BLOCK on published Del 2-5; caught a real
Rule-10 violation in Del 6 (WIP) automatically. Versal-tic uses an
emphasis-word denylist after real-data FPs (NAV/DFØ/NPM).
Finding: the plugin already mirrors §A + §C2; §C1 was the unhomed gap this fills.
Plugin structure lint unchanged (81/0/0); no new agents/commands/refs/skills.
assets/examples/high-engagement-posts.md restored as the generic placeholder
example. STATE.md is now gitignored (local-only): there is no private remote,
and STATE must not reach the public mirror.
The reviews-line used the (await parallel(...)).filter(...) pattern but had
only 3 closing parens before .filter, leaving the wrapper paren unbalanced.
Added the missing close paren so the script parses.
Post-hardening. Two jobs queued for next session (operator: work starts next session):
JOB 1 = run the dream-spec expert panel (docs/expert-review/dream-spec-panel.md, launch-ready
Workflow script; supersedes plan.md critique-of-current direction). Operator twist: a world-class
LinkedIn-growth panel defines the IDEAL plugin (north-star), then reviews the current plugin against
it (informational, not a plan). Mission clarified: followers of an account using this plugin recruit
NEW LinkedIn users to the account because the account is so good. JOB 2 = push everything EXCEPT
STATE.md to public open/ (STATE woven into 8/18 parked commits -> strip via filter-repo, backup first,
re-gitignore STATE local-only; open/ already public = low risk; check Ralph-Wiggum history item).
STATE.md updated with full mechanics for both. Nothing started this session per operator.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016qgzo6rxthw7KuxHjn5vyE
S31c descriptive-% log entry (full A/B/C/straggler breakdown + VERIFY). STATE: the Nx-multiplier
+ descriptive-% platform-norm class is now fully SSOT-reconciled; next phase = post-hardening
expert panel (operator-triggered), then command testing + GUI. Push parked (ahead 17; open/ is
public, STATE must not be published).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016qgzo6rxthw7KuxHjn5vyE
Log entries for the two multiplier-scrub batches (S31a reference-docs 35ed480,
S31b commands/agents c850352) with full TEST/HARDEN/KEPT/VERIFY/SURFACED, and
STATE.md overwritten for session-end.
Captures the new measured-data-class rule (S31b): "Nx"/"N%" that reports or
hypothesizes from the user's OWN measured analytics — or a pure placeholder
[X]x — is not a platform claim and stays (the ab-test:418 "your data shows ...
test whether this holds" pattern); distinguish from generic-claim TARGET. S31c
must apply it to the descriptive-% sub-class (some bands are unsourced platform
norms to scrub, some are sourced benchmarks / user-measured % to keep).
Also records the jerndisiplin reminder that grep output does not count as a
Read for the Edit safety check (three S31b edits were correctly blocked until
re-read with the Read tool).
Push held: origin = open/ (public), STATE.md must not go there; ahead 14 parked.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016qgzo6rxthw7KuxHjn5vyE
Hardening, multiplier class (S31, batch b). SSOT-reconciliation of unsourced
generic "Nx" reach/growth multipliers asserted as platform fact across commands
and agents. Same discipline as S31a: read-and-show (Read tool, not Bash-tail) ->
edit -> re-grep final; 8-step gate.
5 edits / 5 files (+5/-5):
- report:249 (PDF/Carousels 3.4x reach multiplier) -> top organic format, no
reliable multiplier.
- outreach:652 (collab content 2-3x reach, ref collaborations-guide) -> above-
baseline reach, aligned with the S31a collab scrub.
- engagement-coach:120 (2-3 touchpoints = 3.6x more likely) -> far more likely
(figure unverified).
- strategy-advisor:241 (saves drive 3x faster audience growth) -> faster growth
(figure unverified).
- content-repurposer:591 (Expected reach multiplier: [2-5x original]) -> Expected
reach: above the original (no reliable multiplier).
KEPT (operator-ruled measured-data class — report/hypothesize from the USER's own
analytics, not a platform norm; the number is an illustrative-computed example or
a pure placeholder, and removing it adds no honesty): report:303 ("[format] ...
2x more shares" example), report:335 ("your one carousel got 3x" rendered
example), ab-test:418 ("Your data shows ... 2x ... test whether this holds"),
outreach:1234 ("Average reach multiplier (collab vs solo): [X]x" output field).
KEPT INTACT: engagement-coach:148 SSOT comment ~= 2x a like. OUT (untouched):
strategy-advisor:239 4-5x/week frequency.
VERIFY: re-grep generic-claim targets in the 5 files -> 0; measured-data class +
KEEP/OUT intact; gate scripts/test-runner.sh = 81/0/0 exit 0, counts 29/19/26
+ v0.5.0 unchanged.
Push held: origin = open/ (public namespace), STATE.md must not go there.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016qgzo6rxthw7KuxHjn5vyE
Appends the S30 row to the hardening journal (FIXED, 20 edits/7 files, commit 1bab1d6) and
catalogs the surfaced S31 multiplier-scrub class (~50 unsourced "Nx" instances across ~15 files,
with the SSOT-backed-vs-unsourced and coefficient-vs-frequency distinctions the next pass must make).
New entry only — prior entries untouched.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016qgzo6rxthw7KuxHjn5vyE
Appends the S29e row to the hardening journal, closing the per-step gap (S29a-d were logged;
S29e was not). New entry only — existing S29a-d entries untouched (history content URØRT).
Documents: pure rename + 17 pointer files (29 occurrences), the history-URØRT categorisation,
and VERIFY (no old file remains; residual confined to STATE+CHANGELOG+plan+log; gate 81/0/0).
Marks S29 complete (a-e); next is S30 magnitude-scrub.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016qgzo6rxthw7KuxHjn5vyE
Final sub-pass of the S29 plugin-wide terminology scrub. The canonical reference file is
renamed and every functional pointer updated atomically in one commit. The file's in-file
title/headers were already FORM A-scrubbed in S29c (H1 reads "Content Angles"), so S29e is a
pure rename + pointer update — no FORM A remained in the file.
Rename: references/thought-leadership-angles.md -> references/content-angles.md (git mv).
Pointers updated (17 files, 29 occurrences) — token "thought-leadership-angles" -> "content-angles":
- references/ (2): ai-content-framework, glossary
- agents/ (7): content-repurposer, strategy-advisor, network-builder, content-planner,
trend-spotter, video-scripter, differentiation-checker
- commands/ (6): pipeline, video, post, competitive, react, batch
- skills/ (1): linkedin-content-creation/SKILL
- docs/ (1, forward-looking): integration-test-guide
Left URØRT per the standing S29 decision (history = honest record of a past state, not a
runtime load): CHANGELOG.md, docs/hardening/log.md, docs/hardening/plan.md. STATE.md untouched
here (rewritten at session end).
Verify: no thought-leadership-angles* file remains; references/content-angles.md present; zero
residual "thought-leadership-angles" in commands/agents/references/skills/integration-test-guide;
structure gate scripts/test-runner.sh 81/0/0 exit 0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016qgzo6rxthw7KuxHjn5vyE
Append the S29d verification record to docs/hardening/log.md (anchored
"### S29d terminology-scrub" entry, matching S29a-S29c format): the 8-edit replacement map
across 6 files (skills/linkedin-content-creation x3, linkedin-strategy, config template, two
shipped assets, the clipboard test fixture), the 4 judgment-calls, the FORM B = 8 kept-by-design
list (buzzword denylists + role usages), the broad anchor-link check (none break), and the
verify block (FORM A in scope = NONE; FORM B unchanged 8; filename pointers unchanged 21;
clipboard test 13/0; gate 81/0/0; counts 29/19/26/6 unchanged). Documents fix commit d15ffa4.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016qgzo6rxthw7KuxHjn5vyE
Fourth sub-pass of the S29 plugin-wide terminology scrub: the banned brand phrase
"thought leadership" (FORM A) removed from the remaining surfaces — skills, a config template,
shipped assets, and a test fixture. 8 edits across 6 files. Vocabulary consistent with
S29a-S29c: "thought leadership angle(s)" -> "content angle(s)"; the "Value Test" family ->
"Authority Value Test"; "Standard Thought Leadership Post" -> "Standard Post" (matches the
S29a/S29c "Standard Post Structure" equivalent).
Edits: skills/linkedin-content-creation (3) "Identify Thought Leadership Angles" -> "Content
Angles", "Standard Thought Leadership Post" -> "Standard Post", "The 8 Thought Leadership
Angles" -> "The 8 Content Angles"; skills/linkedin-strategy:176 phase-focus cell "Thought
leadership, cross-platform" -> "Signature content, ..." (avoids the Authority-phase column
echo); config/user-profile.template:35 "Build thought leadership & authority" -> "Build
authority & influence"; assets/checklists/quality-scorecard:136 "Passes thought leadership
test" -> "Passes Authority Value Test"; assets/case-studies/case-study-template:173 "Best for:
Thought leadership" -> "Authority content"; hooks/scripts/__tests__/clipboard-helper.test:61
unicode fixture "Thought leadership" -> "Authority" (emoji + arrow retained; coverage unchanged).
Scope (operator-locked, inherits S29a-S29c): FORM A only. FORM B = 8 untouched -- the 5
buzzword-denylist entries MUST list the banned word ("thought leader"), plus 3 role usages
(linkedin-networking x2, README "niche thought leaders"). The 21 thought-leadership-angles.md
filename pointers deferred to S29e. No anchor links to the changed headers anywhere in the
plugin. Forward-looking docs already clean.
Verify: FORM A in scope = NONE; FORM B unchanged (8); filename pointers unchanged (21);
clipboard-helper test 13/0; gate 81/0/0; counts 29/19/26/6 + v0.5.0 unchanged.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016qgzo6rxthw7KuxHjn5vyE
The global continuity rule supersedes the old polyrepo convention: STATE.md is now
tracked and committed per repo (never gitignored). Remove STATE.md from .gitignore; the
other session-local entries (REMEMBER/ROADMAP/TODO/NEXT-SESSION/*.local.md) stay ignored
as deprecated local mechanisms. STATE.md content reflects current state-of-play (S29c
done/pushed; S29d next).
NOT pushed: held local pending the config-audit plugin's cross-repo brief that will
standardize STATE + per-repo conventions (operator: "kommer tilbake til det"). The remote
is an "open/" namespace — public/private to be confirmed before STATE is ever pushed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016qgzo6rxthw7KuxHjn5vyE
Append the S29c verification record to docs/hardening/log.md (anchored
"### S29c terminology-scrub" entry, matching S29a/S29b format): the 34-edit replacement map
across 15 reference files, the S29e filename lock (thought-leadership-angles.md ->
content-angles.md) with the canonical file's in-file title/headers scrubbed now, the
KEPT-BY-DESIGN items (ironic quote, TL;DW false positive), and the verify block (FORM A in
references/ = only the kept ironic quote; canonical in-file FORM A = NONE; FORM B unchanged 4;
filename pointers unchanged 3; gate 81/0/0; counts 29/19/26/6 unchanged). Documents fix commit
25b356f.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016qgzo6rxthw7KuxHjn5vyE
Third sub-pass of the S29 plugin-wide terminology scrub: the banned brand phrase
"thought leadership" (FORM A) removed from the reference-doc surface — the largest pass
(2x S29a/S29b). 34 edits across 15 reference files. Vocabulary consistent with S29a/S29b:
"thought leadership angle(s)" -> "content angle(s)"; "thought leadership" (positioning/practice)
-> "authority ..."; content-type labels -> "authority content / authority posts"; the whole
"Value Test" family -> "Authority Value Test".
Established cross-pass equivalents closed: glossary:229 "Thought Leadership Value Test" ->
"Authority Value Test" (closes the S29b cross-directory naming gap); glossary:29 "8 universal
thought leadership angles" -> "content angles"; engagement-frameworks:137 "Standard Thought
Leadership Structure" -> "Standard Post Structure" (matches S29a post:98).
S29e filename locked this session: thought-leadership-angles.md -> content-angles.md (operator-
chosen). The canonical file's in-file title/headers scrubbed now for consistency (H1 ->
"# Content Angles"; "## The Authority Value Test"; "### Step 3: Test For Authority Value");
the file rename + all 20 pointers remain S29e (atomic).
Judgment-calls (operator-approved): thought-leadership-angles:212 "disguised as thought
leadership" -> "expertise" (S29b vocab); linkedin-formats:295 -> "Text-based content" (avoids
authority...authority echo); linkedin-visual-style:3 -> "For building authority,"; ai-content-
framework:380 "main LinkedIn thought leadership skill" -> "content skill" (avoids awkward
"authority skill"). Kept by design: video-strategy-guide:429 ironic quote; video-strategy-
guide:532 "TL;DW" false positive (too long, didn't watch).
Scope (operator-locked, inherits S29a/S29b): FORM A only. FORM B ("thought leader(s)" as role,
references = 4) untouched. The 3 thought-leadership-angles.md filename pointers in references/
deferred to S29e.
Verify: FORM A in references/ = only the kept ironic quote (video:429); canonical file in-file
FORM A = NONE; FORM B unchanged (4); filename pointers unchanged (3); no anchor links to changed
headers; gate 81/0/0; counts 29/19/26/6 + v0.5.0 unchanged.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016qgzo6rxthw7KuxHjn5vyE
Append the S29b verification record to docs/hardening/log.md (anchored
"### S29b terminology-scrub" entry, matching S29a format): the 17-edit replacement
map, the abbreviated-"TL" discovery during the header anchor-check + operator-approved
addendum (#16–#17), and the verify block (FORM A in agents/ = NONE; abbreviated TL =
NONE; FORM B unchanged 2; filename pointers unchanged 11; gate 81/0/0; counts
29/19/26/6 unchanged). Documents fix commit b6ba826.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016qgzo6rxthw7KuxHjn5vyE
Second sub-pass of the S29 plugin-wide terminology scrub: the banned brand phrase
"thought leadership" (FORM A) removed from the agent surface. 17 edits across 6 agents
(strategy-advisor, content-planner, voice-trainer, network-builder, differentiation-checker,
trend-spotter). Vocabulary consistent with S29a: "thought leadership angle(s)" → "content
angle(s)"; "thought leadership" (positioning/practice) → "authority …"; the whole "Value Test"
family → "Authority Value Test".
15 in-file phrase occurrences (space-grep) + 2 abbreviated "TL Value Test" instances found
during the header anchor-check (trend-spotter:192/:257, TL = Thought Leadership) — surfaced as
an addendum and operator-approved before edit, scope not expanded silently. The
differentiation-checker:47 web-search query thought leadership → expert insights
(functional-keyword judgment-call, operator option b).
Scope (operator-locked, inherits S29a): FORM A only. FORM B ("thought leader(s)" as role,
agents = 2) untouched. The 11 thought-leadership-angles.md filename pointers deferred to S29e.
Verify: FORM A in agents/ = NONE; abbreviated TL = NONE; FORM B unchanged (2); filename
pointers unchanged (11); diff 6 files 1:1; gate 81/0/0; counts 29/19/26/6 + v0.5.0 unchanged.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016qgzo6rxthw7KuxHjn5vyE
Append the S29a verification record to docs/hardening/log.md (anchored
"### S29a terminology-scrub" entry, matching S27/S28 format): scope decisions
locked for all S29 sub-passes a–e (FORM A only; surface + forward-docs; history
untouched; per-directory sub-passes), the 15-edit replacement map, and the
verify block (assertive non-filename FORM-A in commands/ = NONE; FORM B
unchanged; gate 81/0/0; counts 29/19/26/6 unchanged). Documents fix commit
9d83dbc.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016qgzo6rxthw7KuxHjn5vyE
First sub-pass of the S29 plugin-wide terminology scrub: the banned brand phrase
"thought leadership" (FORM A) removed from the user-facing command surface. 15 in-file
phrase occurrences across 9 commands re-sourced to neutral wording (post, video, strategy,
batch, setup, react, outreach, onboarding, monetize) — e.g. "thought leadership content
creator" → "content creator", "Select Thought Leadership Angle" → "Select Content Angle",
"Build thought leadership & authority" → "Build authority & influence", onboarding guide
→ "LinkedIn Studio onboarding guide".
Scope (operator-set): FORM A only. FORM B ("thought leader" as role, incl. the buzzword
denylist at post.md:134) left untouched. The 11 filename pointers to
references/thought-leadership-angles.md deferred to S29e (atomic rename + pointer update);
competitive.md/pipeline.md carry only pointers and are untouched here. Pure history
(CHANGELOG, docs/**) left intact per "history → git".
Verify: assertive non-filename FORM-A in commands/ = NONE; FORM B count unchanged (15);
diff +15/-15 across 9 files (1:1); gate 81/0/0; counts 29/19/26/6 + v0.5.0 unchanged.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016qgzo6rxthw7KuxHjn5vyE
Reconcile commands/video.md + references/linkedin-formats.md to the algorithm-signals SSOT
in one pass (20 edits/2 files). The unsourced "30% completion rate or zero distribution"
gate (7x) → "completion/dwell is a ranking input; shorter completes better; no published
hard completion gate". The 6 S27-folded link-penalty lines → "correlate with lower reach"
(incl. heading "The External Link Penalty" → "External Links and Lower Reach"). Six other
unsourced format magnitudes softened to direction-without-number (video 5.60% ER, Live
12-24x, polls 1.64x, 3x shares, Creator-Mode 35%). One internal contradiction fixed (3-sec
= 70% retention contradicted the already-reconciled three-second-folklore note).
Bucket D (this file's non-format coefficients: 47-50% reach-decline, AI-comment -30%/-55%,
hashtag -68%) left intact and deferred to S30, which is re-scoped to cover them + the other
files. Gate 81/0/0; counts 29/19 unchanged.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016qgzo6rxthw7KuxHjn5vyE
Reconcile external-link and topic-relevance reach-loss framing to the algorithm-signals
SSOT across 6 files (10 edits): body links "correlate with lower reach" (LinkedIn denies
an intentional penalty), topic relevance is a positive ranking input with no quantified
off-topic figure. 3 plan-cited lines + 7 same-class siblings surfaced during verify.
Bucket B (link-penalty lines in linkedin-formats.md) folded into S28; Bucket D (other
unsourced reach-coefficients: -68%/-25%/-15-25%/-30-50%/55%) queued as new S30. Engagement-
pod + AI-slop "penalized" framing left intact (officially confirmed). Gate 81/0/0; counts
29/19 unchanged.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016qgzo6rxthw7KuxHjn5vyE
Router hardening (routing/agent/grant axes all PASS). Operator terminology rule: the "thought leadership" phrase must not appear in the plugin. Re-sourced the 2 occurrences in commands/linkedin.md (:4 frontmatter description, :16 body) to "LinkedIn Studio". Routing 28/28 + agent-pointers 10/10 resolve; grant-hygiene clean (no Glob orphan — third front-door). Surfaced plugin-wide (~85 lines / ~45 files) and promoted to S29 terminology-scrub in docs/hardening/plan.md.
measure is the Measure-journey routing front-door (v4.1): guided "how am I
doing?" -> routes to the analytics command that owns the work; delegates only,
never crunches numbers. Routing axis is clean — all 5 emitted targets
(import/report/analyze/audit/ab-test) resolve to commands/Y.md. Delegates-only
holds: the 3 crunch/analysis mentions (:7/:20/:40) are all no-do promises, no
leak.
Grant-hygiene was the one finding, and it differs from S24 create. There Glob
was a pure orphan (no filesystem check at all). Here measure HAS an optional
Step 0 ("if .../analytics/ holds imported data, note last import") that gives
Glob a real home — but the grant<->use link was implicit (body named no tool),
and Read hung on the same vague Step 0. Operator chose: make Glob explicit,
drop Read as redundant (the import-date need is met by a Glob listing).
2 edits, commands/measure.md only:
- allowed-tools :11: drop Read; net = {Glob, AskUserQuestion}.
- Step 0 :23: "You may Glob .../analytics/; if it holds imported data, note last
import" — gives the retained Glob grant a named body home.
Verify: re-grep final — Read as tool name NONE, allowed-tools = Glob +
AskUserQuestion (:11-12), Glob now in body :23; routing unchanged (5/5);
git diff --stat = 1 file +1/-2; test-runner 81/0/0 exit 0; counts 29/19
unchanged (.md-only). FIXED, 0 deferrals. Scope note: Glob-orphan question now
resolved for measure (it had a home via Step 0; create did not); linkedin (S26)
still to check independently.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016qgzo6rxthw7KuxHjn5vyE
create is the Create-journey routing front-door (v4.1): guided "what to make?"
-> routes to the command that owns the format; delegates only, never drafts.
Routing axis is clean — all 8 emitted targets (post/quick/react/carousel/video/
multiplatform/batch/newsletter) resolve to commands/Y.md. Delegates-only holds:
every "draft" mention is the no-draft promise (:7/:22, long-form lock :66) or a
target-description (:38), no leak. The one finding was grant-hygiene: Glob was
declared (:14) but never used — the only file access is a fixed-path Read of the
state file (:26), which needs no pattern-matching. Same orphan-grant pattern as
S17-S22.
1 edit, commands/create.md only:
- allowed-tools :14: drop orphan Glob; net = {Read, AskUserQuestion}.
Verify: re-grep final — Glob NONE, allowed-tools = Read + AskUserQuestion;
git diff --stat = 1 file -1; test-runner 81/0/0 exit 0; counts 29/19 unchanged
(.md-only). FIXED, 0 deferrals. Scope note: Glob-orphan may recur in sibling
front-doors (measure S25, linkedin S26) — not expanded; each catches its own.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016qgzo6rxthw7KuxHjn5vyE
Operator promoted open follow-up #1 (reference-consistency) to scheduled work —
all SSOT divergences must be fixed, planned across sessions rather than crammed.
Added two sessions to the queue, run after S26:
- S27 (A): "penalty/penalizes" framing -> SSOT (troubleshooting-guide.md:127,
analyze.md:102, audit.md:61 "topic-relevance penalty").
- S28 (B): format magnitudes -> SSOT (video.md:69, linkedin-formats.md
"30% zero-distribution").
Surgical SSOT-reconciliation of already-hardened files, NOT full re-hardening;
hardening-class (commit local, no push).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016qgzo6rxthw7KuxHjn5vyE
Profile is a self-contained, prose-heavy Grow-tier audit command (no agent, no
routing, no state). Grant-hygiene was already clean (Read + AskUserQuestion, both
used, no orphans/missing). The one real axis was b': the file repeatedly framed
the relevance model as reading and VALIDATING your profile and gating distribution
on it — contradicting the SSOT (algorithm-signals-reference.md), which confirms
only topic/interest relevance as a ranking input (content matched to a viewer's
interests, incl. beyond your network) with no off-topic magnitude figure and no
weighted profile criteria. The file was internally inconsistent — its own soft,
SSOT-true framing already sat at :17/:25/:27.
12 edits, commands/profile.md only:
- desc :5: drop "validates your profile BEFORE distributing content".
- :31 + table: drop "the model evaluates five criteria (see SSOT)" false
attribution + HIGH/MEDIUM "Impact if Missing" postulated weights -> "LinkedIn
does not publish a profile-scoring breakdown ... practitioner heuristics",
column -> "Priority (heuristic)".
- :99/:161/:173/:230: reframe "first signal telling ... qualified" / "relevance
validation" / "checks if you're connected" / "if LinkedIn's AI read my profile,
would it believe" away from the profile-read-by-model mechanic.
- :25/:27/:51/:67: conflation fix — "your demonstrated expertise" / "tell the
relevance model what you're expert in" -> "a viewer's interests" / "topic-
relevance distribution" (SSOT wording) + no-percentage honesty.
- :24 (B2): "Goes to 10% of audience" -> "a slice of your network".
- :52/:61 (P3): "highest-weight search field" -> "highest-leverage" (self-
justified rest kept).
Verify: re-grep final file — all overclaim/conflation patterns NONE, new SSOT
text in place; grant-hygiene unchanged; test-runner 81/0/0 exit 0; counts 29/19
unchanged (.md-only). FIXED, 0 deferrals.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016qgzo6rxthw7KuxHjn5vyE
Outreach is the first command in the hardening queue that both delegates to an
agent (network-builder) and mutates real state (recordOutreachContact), so the
weight fell on axis-d. Five fixes across two files (operator-approved scope
extension to the SSOT-diverging guide source):
- allowed-tools: ADD Bash (Step 8c runs `node state-updater.mjs --record-outreach`
and needs it — firsthour precedent grants Bash for the same pattern; the command
promised a mutation it couldn't execute), DROP orphan WebFetch + Write grants
(zero body use; :410/:1040 "Write a post" is prose). Now
Read·Glob·WebSearch·AskUserQuestion·Task·Bash.
- Step 7 pod-warning (axis-b'): replaced fabricated magnitudes ("30-55% reach
reduction", "shadow suppression", "credibility score", "penalizes",
"Post-March 2025", "low dwell") with the SSOT statement
(algorithm-signals-reference.md:98 — demote out of "Most Relevant" / scope to
own network / restrict repeat offenders) + cite.
- :652 DM-amplification "2-3x first-hour" (axis-b'): re-attributed 2-3x to collab
reach (where SSOT places it), kept the first-hour effect qualitative.
- collaborations-guide.md:349-370 (axis-b', scope extension): same SSOT rewrite of
the "March 2025 Crackdown" section so the Step 7 fix can't be re-rendered from a
stale reference (dropped "shadow banning ALL future content / 90+ days / 6+
months / permanent penalty" + speculative detection methods).
Verify: re-grep both files clean (orphans/fabricated stats NONE, Bash :21, SSOT
text in place); recordOutreachContact throwaway-fixture 10/10 PASS (additive,
$-safe, newest-first, untouched undeclared fields); test-runner 81/0/0 exit 0;
counts 29/19 unchanged (.md-only).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016qgzo6rxthw7KuxHjn5vyE
Dynamic Workflow (6 expert archetypes, distinct lenses) that evaluates the whole
plugin after herding (S26) and consolidates findings into docs/expert-review/roadmap.md.
Operator-triggered, Opus, schema-forced. STATE.md points to it under the v1.0.0 path.
docs/-placed (not root ROADMAP.md) per the global no-local-mechanisms rule.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016qgzo6rxthw7KuxHjn5vyE
S16 analyze through the v2 interactive quality gate (analytics/diagnostic class —
prose-diagnosis + conditional agent-delegation, NOT CLI-backed: allowed-tools
Read/AskUserQuestion/Task, no Bash). 1 finding, 1 surgical edit in
commands/analyze.md, grep-confirmed + grounded persona sim (scenario 1, reach -50%):
- FUNN (axis-b'): Step 4 penalty checklist asked 'Did you use 5+ hashtags in posts?'
— a concrete-number penalty absent from BOTH the SSOT
(algorithm-signals-reference.md: no hashtag claim, deliberately omitted) AND the
cited troubleshooting-guide.md (its own checklist is 6 items, no hashtag).
Command-only unsourced folklore. Dropped analyze.md:149; kept :150 'tag unrelated
people for reach' (defensible — aligns with SSOT bait/pod-suppression direction,
no numeric claim).
Verified clean: interpret-mode wiring (analytics-interpreter resolves, real default
mode agent:6,39,141), shared data-dir seam (analyze:41 <-> agent:49),
/linkedin:profile cross-ref, graceful-degradation IF, saves/dwell honesty (no Bash,
no over-promise). External-link hard-penalty framing in troubleshooting-guide.md:127
vs SSOT logged as reference-pass follow-up (out of S16 scope — not touched).
Gate: test-runner 81/0/0 exit 0; counts 29/19 unchanged (.md-only).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016qgzo6rxthw7KuxHjn5vyE