feat(linkedin-studio): research-engine config layer — sources + scoring modes + MCP profile (§5 slice 2a) [skip-docs]

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
This commit is contained in:
Kjell Tore Guttormsen 2026-06-22 13:36:28 +02:00
commit b89868e3b1
6 changed files with 225 additions and 11 deletions

View file

@ -0,0 +1,100 @@
# Trend Scoring Modes Reference
**Single source of truth** for how a discovered trend/topic candidate is scored.
There are **two modes** — they share the same 110 per-dimension scale and the same
composite formula, but they weight the dimensions differently because a feed post and
a long-form chronicle reward different things. Surfaces (the `trend-spotter` agent, any
research-engine pass) **select a mode and apply the matching rubric** — they do not
restate the weights inline. Cite this file; do not duplicate it.
This file defines **methodology** (the weights), not user preference. The *source list*
a pass polls is separate and user-overridable — see
`config/trends-sources.template.md``${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}/trends/sources.md`.
## How to read this file
- Score each dimension **110** (see the bands in the per-mode tables).
- Composite = the weighted sum of the five dimension scores. Each mode's weights sum to
**100 %**, so the composite stays on the same 010 scale across modes.
- The **ordering** of the weights is the signal; the exact percentages are a deliberate,
documented choice, not a measured coefficient. (Timing grounding — why a feed post
weights recency and a chronicle does not — traces to
`references/algorithm-signals-reference.md`; this file does not restate algorithm
magnitudes.)
## Mode selection
| Mode | Use for | Driver |
|------|---------|--------|
| **kortform** | feed posts (`/linkedin:post`, `:quick`, `:react`, `:carousel`, `:video`) | timing + audience pull — a good post published early beats a perfect post published late |
| **long-form** | chronicles / newsletters / series editions (`/linkedin:newsletter`) | depth + angle — a chronicle has a longer shelf life; whether there is *enough material for a full piece* matters more than a 24-hour window |
If no mode is declared, default to **kortform** (the feed is the higher-cadence surface).
A caller may pass the mode explicitly (e.g. the long-form orchestrator requesting
`long-form`); a future slice may read a per-user default from the profile.
## Mode: kortform (LinkedIn feed post)
Tuned for the feed: timing and audience pull carry real weight because the first-mover
window is short.
| Dimension | Weight | 12 (Low) | 35 (Medium) | 68 (High) | 910 (Exceptional) |
|-----------|--------|-----------|---------------|-------------|---------------------|
| **Pillar Fit** | 30 % | Outside all 5 pillars | Tangential to one pillar | Direct hit on one pillar | Intersects 2+ pillars |
| **Audience Relevance** | 25 % | Wrong audience entirely | Some audience overlap | Core audience cares | Audience actively asking about this |
| **Timing** | 20 % | >7 days old, saturated | 37 days, moderate coverage | 2472h, early coverage | <24h, you would be among first |
| **Angle Potential** | 15 % | Only obvious take available | One good angle possible | 23 strong angles | Contrarian or unique angle clear |
| **Authority Match** | 10 % | No credibility on topic | Some related experience | Direct experience | Published authority on this |
```
Composite = (Pillar × 0.30) + (Audience × 0.25) + (Timing × 0.20) + (Angle × 0.15) + (Authority × 0.10)
```
## Mode: long-form (chronicle / newsletter / series)
Reweighted for a longer piece: **depth potential** enters at 25 %, and **timing drops to
10 %** — a chronicle is not a 24-hour reaction, so recency matters less than whether the
topic has enough substance and a differentiated angle to carry a full edition.
| Dimension | Weight | 12 (Low) | 35 (Medium) | 68 (High) | 910 (Exceptional) |
|-----------|--------|-----------|---------------|-------------|---------------------|
| **Pillar / thesis fit** | 30 % | Outside the active theses | Tangential to one thesis | Fits one thesis / series arc | Advances 2+ theses or a live series arc |
| **Depth potential** | 25 % | A single post at most | Enough for one solid post | Enough for a full chronicle | Enough for a multi-part series |
| **Angle / differentiation** | 20 % | Commodity take only | One non-obvious angle | 23 differentiated angles | Original thesis the field lacks |
| **Authority / experience** | 15 % | No credibility on topic | Some related experience | Direct lived experience | Published authority on this |
| **Currency** | 10 % | Stale / already resolved | Relevant this quarter | Relevant now, durable | Relevant now AND will compound |
```
Composite = (Pillar × 0.30) + (Depth × 0.25) + (Angle × 0.20) + (Authority × 0.15) + (Currency × 0.10)
```
## Why the two modes differ (the one delta)
The two rubrics are the same five-dimension instrument with one deliberate swap:
- **kortform:** Timing **20 %**, no depth dimension — the feed rewards being early.
- **long-form:** Timing → Currency at **10 %**, Depth potential added at **25 %** — a
chronicle rewards substance and a durable angle over speed.
Pillar fit (30 %) and authority (kortform 10 % / long-form 15 %) anchor both: an off-pillar
or low-credibility topic scores low in either mode, because topic relevance and credibility
are non-negotiable regardless of format.
## Composite → action
The same priority bands apply to both modes (the composite is on the same 010 scale):
| Composite | Priority | kortform action | long-form action |
|-----------|----------|-----------------|------------------|
| 8.010 | **Immediate** | Draft within 24h | Promote to the edition backlog now |
| 6.07.9 | **High** | Publish within 4872h | Strong edition candidate — schedule it |
| 4.05.9 | **Medium** | Add to this week's calendar | Hold as a backlog candidate, revisit |
| 2.03.9 | **Low** | Note, skip for now | Park unless the angle sharpens |
| 01.9 | **Skip** | Off positioning | Off positioning |
## Consumers
- `agents/trend-spotter.md` — reads the requested mode and applies the matching rubric
instead of inlining a matrix (wired in research-engine slice 2b).
- Any future research-engine pass that scores candidates before writing them to the trend
store (`scripts/trends/`).