fix(linkedin-studio): S9 — full algorithm-magnitude sweep + lint rebuilt to the criterion

Closes the S8 re-review (BLOCK 3/4/1). The S8 fix patched only the 2 strings S7 named; the re-review found 6 more same-class survivors. Per the systemic read, this is a comprehensive sweep, not a per-line patch.

Reconciled every retired engagement-coefficient + model-fact survivor against the canonical references/algorithm-signals-reference.md (order, not coefficients; comment ≈ 2x a like; no model name/params):
- glossary.md: coefficient table + Save-Signal '10x weight' → canonical ordering (citation now true)
- engagement-frameworks.md, analytics-interpreter.md, content-optimizer.md, pipeline.md, engagement-coach.md: the 10x/8x/7-9x/2.5x/0.2x system (incl. 4 survivors the re-review did not cite) → ordering
- playbook: '15x more algorithmic boost' + video '5x more conversations' → directional, sourced
- profile.md + linkedin-voice/SKILL.md: '150B parameter foundation model' → '2026 relevance-ranking model'
- quality-scorecard.md: '360Brew Validation' → topic-relevance framing
- setup.md: 'thought leadership plugin' → 'LinkedIn Studio plugin'

Lint (MAJOR 4): rebuilt scripts/test-runner.sh STALE_STATS to forbid EVERY retired-class phrasing (not the 2 S7 strings) + widened scope to assets/checklists/. Targets retired phrasings (7-9x, (10x), '10x weight', '5x more conversations'), NOT bare 10x/15x/5x (legit 5x5x5 / cadence / pixel-dims / '10x your reach' hyperbole). Proven non-vacuous: catches all 10 retired strings, ignores all 10 legit uses.

Tests (MAJOR 7): added no-anchor fall-through tests for recordFirstHourPlan + recordOutreachContact (date scalar not written/reported, section still appended). MINOR 8: reflowed newsletter.md content-repurposer wiring onto one line.

test-runner.sh 66/0/0; node --test 94/94 (was 92, +2). NO push until /trekreview re-clears the gate.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-05-30 09:56:49 +02:00
commit 0c9c02a2b1
14 changed files with 115 additions and 40 deletions

View file

@ -72,6 +72,29 @@ target_date: "2026-12-31"
<!-- Format: ### [YYYY-MM-DD HH:MM] partner track -->
`;
// A hand-corrupted / pre-migration state missing EVERY date anchor
// (last_post_date, last_firsthour_date, last_outreach_date). No production
// template ships like this — every template carries last_post_date — but it is
// the exact else-fall-through the S8 date-scalar gate protects: the scalar must
// NOT be inserted and must NOT be reported in `changes`, while the section append
// still runs and the function still returns non-null (log-accuracy branch).
const NO_ANCHOR_STATE = `---
first_post_date: "2026-01-15"
last_post_topic: "AI strategy"
posts_this_week: 2
weekly_goal: 3
follower_count: 850
follower_target: 10000
target_date: "2026-12-31"
---
# LinkedIn Session State
## Recent Posts
- [2026-04-05] "AI governance is not about..." (1450) - AI strategy
`;
describe('updatePostTracking', () => {
test('sets last_post_date to provided date', () => {
const result = updatePostTracking(SAMPLE_STATE, {
@ -422,6 +445,25 @@ describe('recordFirstHourPlan', () => {
assert.ok(section.includes('[2026-05-30 09:00]'), 'entry must land inside the First-Hour Plans section');
assert.ok(section.includes('AI governance'));
});
test('no-anchor fall-through: neither last_firsthour_date nor last_post_date — scalar not written, not reported; section still appended', () => {
// Exercises the else-fall-through of the date-scalar gate
// (state-updater.mjs:225-231): with NO anchor field, the scalar cannot be
// inserted and must NOT be reported in `changes` (the exact branch the S8
// fix protects) — yet the section append always runs, so result is non-null.
assert.ok(!/^last_firsthour_date:/m.test(NO_ANCHOR_STATE));
assert.ok(!/^last_post_date:/m.test(NO_ANCHOR_STATE));
const result = recordFirstHourPlan(NO_ANCHOR_STATE, PLAN_OPTS);
assert.notEqual(result, null);
// Scalar NOT inserted (no anchor to insert after)
assert.ok(!/^last_firsthour_date:/m.test(result.content), 'scalar must not be inserted without an anchor');
// ...and NOT reported as changed
assert.ok(!result.changes.some((c) => /last_firsthour_date/.test(c)), 'no date-scalar change entry without an anchor');
// The section entry IS still written
assert.ok(result.changes.some((c) => /^First-Hour Plans \+=/.test(c)), 'section entry must still be recorded');
assert.ok(result.content.includes('## First-Hour Plans'));
assert.ok(result.content.includes('[2026-05-30 09:00]'));
});
});
describe('recordOutreachContact', () => {
@ -514,4 +556,21 @@ describe('recordOutreachContact', () => {
assert.ok(section.includes('[2026-05-30 14:00]'), 'entry must land inside the Outreach Pipeline section');
assert.ok(section.includes('@bigvoice'));
});
test('no-anchor fall-through: none of last_outreach_date/last_firsthour_date/last_post_date — scalar not written, not reported; section still appended', () => {
// Exercises the else-fall-through of the date-scalar gate
// (state-updater.mjs:284-293): with NONE of the three anchors, the scalar
// cannot be inserted and must NOT be reported — the section append still
// runs, so result is non-null.
assert.ok(!/^last_outreach_date:/m.test(NO_ANCHOR_STATE));
assert.ok(!/^last_firsthour_date:/m.test(NO_ANCHOR_STATE));
assert.ok(!/^last_post_date:/m.test(NO_ANCHOR_STATE));
const result = recordOutreachContact(NO_ANCHOR_STATE, CONTACT_OPTS);
assert.notEqual(result, null);
assert.ok(!/^last_outreach_date:/m.test(result.content), 'scalar must not be inserted without an anchor');
assert.ok(!result.changes.some((c) => /last_outreach_date/.test(c)), 'no date-scalar change entry without an anchor');
assert.ok(result.changes.some((c) => /^Outreach Pipeline \+=/.test(c)), 'section entry must still be recorded');
assert.ok(result.content.includes('## Outreach Pipeline'));
assert.ok(result.content.includes('[2026-05-30 14:00]'));
});
});