fix(linkedin-studio): S10 — generalize stale-stat lint to the pattern class + permanent non-vacuity self-test

Closes the S9 re-review (1 BLOCKER + 2 MAJOR, all grep-verified). The survivor
set converged 8 -> 6 -> 2; this closes the meta-problem behind the convergence,
not just the two lines.

BLOCKER — references/glossary.md:10: drop the fabricated "150-parameter
foundation model" (a garbled 150B that the S9 enumerative grep/lint, requiring a
"B"/"billion", could not match). Reframe to "a real input to LinkedIn's 2026
relevance-ranking model" with no parameter count, citing
algorithm-signals-reference.md inline — which makes the :12 "Used in" provenance
accurate (the reference does state the relevance-ranking framing; it never stated
"150-parameter").

MAJOR — CHANGELOG.md:308: de-brand "360Brew profile optimization (January 2026
algorithm update)" -> "Profile/topic-relevance optimization". Removes the
unpublishable brand + asserted Jan-2026 date, honouring v4.0.0's "removed
everywhere" claim. It was the only STALE_STATS hit in CHANGELOG.

MAJOR — scripts/test-runner.sh: the rebuilt lint was enumerative on surface form.
Generalize it to the PATTERN CLASS so the same grep that defines the SC fails on
any surface form, present or future:
  - STALE_STATS model token: "150 ?B param|150 billion param"
      -> "[0-9]+[ -]?(B|billion)?[ -]?param"
    (covers 150-parameter / 150B param / 150 billion param). This robustifies the
    review's literal suggestion "[0-9]+[ -]?(B|billion )?param", which missed the
    space form "150B param"; the separator is moved out of the group.
  - STAT_HITS grep scope += CHANGELOG.md (the 360Brew survivor lived outside it).
  - Permanent non-vacuity SELF-TEST before the real scan: 13 forbidden probes must
    match (incl. the exact "150-parameter" survivor), 8 legitimate probes must not
    ("Language parameter", "parameterized", "different parameters",
    "175-milliarders parametermodell", 5x5x5, cadence, pixel dims, "10x your
    reach"). S7->S9 each shipped a green lint because the proof was run by hand and
    never committed; this makes narrowing STALE_STATS fail the suite.

Verification: test-runner.sh 67/0/0 exit 0 (was 66/0/0; +1 self-test);
node --test 94/94; broadened exhaustive grep across the tree -> zero survivors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-05-30 13:48:37 +02:00
commit 853cad3ade
3 changed files with 70 additions and 7 deletions

View file

@ -202,19 +202,82 @@ echo "--- Algorithm-Stat Consistency ---"
# - Video-multiplier folklore: "5x more conversations" → reference: video declining, no multiplier
# - Engagement-coefficient system: 7-9x, 2.5x, 0.2x, (10x), (8x), "10x weight"
# → reference: "never hard coefficients to optimize against"
# - Model params/brand/date: 150B param / 150 billion param / 360Brew / January 2026
# - Model params/brand/date: the PATTERN CLASS [0-9]+[ -]?(B|billion)?[ -]?param
# (covers 150-parameter / 150B param / 150 billion param) / 360Brew / January 2026
# → reference: "Not publishable as fact"
#
# S10: the model-precision token is now the pattern CLASS, not a literal-token
# list. S9 forbade only "150 ?B param|150 billion param"; a hyphenated
# "150-parameter" (no "B") slipped both the discovery grep and the lint, surviving
# in glossary.md:10. The criterion is "no asserted model precision in ANY surface
# form", so the lint now enforces the shape (a number adjacent to "param"), not an
# enumeration. An adjacent digit is REQUIRED, so legitimate "param" uses with no
# leading number — "Language parameter", "parameterized", "different parameters",
# "«parametere»", "175-milliarders parametermodell" — do not match.
# Bare "10x"/"15x"/"5x" are deliberately NOT forbidden — they carry legitimate
# uses (collaboration "10x your reach" hyperbole, "5x5x5", posting cadence, pixel
# dims like 1080x1350), so each token targets the retired *phrasing*, not the bare
# number.
#
# Scope covers every dir the criterion's grep covers, including assets/checklists/
# (the 360Brew survivor lived there, outside the S8 scan) and assets/templates/.
# assets/{templates,checklists}/ — not all of assets/ — keeps the scan off
# (the 360Brew survivor lived there, outside the S8 scan), assets/templates/, and
# CHANGELOG.md (S10: the 360Brew/January-2026 survivor lived there, outside the S9
# scope). assets/{templates,checklists}/ — not all of assets/ — keeps the scan off
# gitignored runtime data (assets/analytics/, assets/drafts/, voice-samples/).
STALE_STATS='40-50%|25-40%|6\.6%|6\.60%|1\.92%|15x more reach|15x more algorithmic|5x more effective|5x less valuable|5x more reach than|5x more conversations|7-9x|2\.5x|0\.2x|\(10x\)|\(8x\)|10x weight|-40-60%|150 ?B param|150 billion param|360Brew|January 2026'
STAT_HITS=$(grep -rnE "$STALE_STATS" references/ commands/ skills/ hooks/prompts/ agents/ assets/templates/ assets/checklists/ CLAUDE.md README.md .claude-plugin/plugin.json 2>/dev/null | grep -v 'algorithm-signals-reference' || true)
STALE_STATS='40-50%|25-40%|6\.6%|6\.60%|1\.92%|15x more reach|15x more algorithmic|5x more effective|5x less valuable|5x more reach than|5x more conversations|7-9x|2\.5x|0\.2x|\(10x\)|\(8x\)|10x weight|-40-60%|[0-9]+[ -]?(B|billion)?[ -]?param|360Brew|January 2026'
# Non-vacuity self-test (S10). A grep criterion is only meaningful if it actually
# MATCHES the forbidden forms and does NOT match legitimate ones. S7→S9 each
# shipped a lint that passed green while a survivor slipped, because the proof was
# run once by hand and never committed — so a hyphenated "150-parameter" form was
# never re-checked. This makes the proof PERMANENT: it runs on every invocation
# BEFORE the real scan, so narrowing STALE_STATS back to a literal-token list fails
# the suite instead of silently certifying an unenforced criterion. The positive
# set covers all three model-precision surface forms (incl. the exact S10
# "150-parameter" survivor); the negative set covers the legitimate "param"/x uses
# that live in the tree today.
SELFTEST_OK=1
while IFS= read -r probe; do
[ -z "$probe" ] && continue
if ! echo "$probe" | grep -qE "$STALE_STATS"; then
SELFTEST_OK=0; echo " non-vacuity FAIL: forbidden form not caught -> $probe"
fi
done <<'POSITIVE'
40-50% link penalty
6.6% carousel rate
1.92% reach
15x more reach
5x more conversations
7-9x weight
(10x) coefficient
10x weight
150-parameter foundation model
150B parameter foundation model
150 billion parameter model
360Brew
January 2026 algorithm update
POSITIVE
while IFS= read -r probe; do
[ -z "$probe" ] && continue
if echo "$probe" | grep -qE "$STALE_STATS"; then
SELFTEST_OK=0; echo " false-positive FAIL: legitimate form caught -> $probe"
fi
done <<'NEGATIVE'
5x5x5 pre-posting method
post 3x per week
1080x1350 pixels
10x your reach
Language parameter (configurable)
parameterized content-gatekeeper
Start over with different parameters
175-milliarders parametermodell
NEGATIVE
if [ "$SELFTEST_OK" -eq 1 ]; then
pass "STALE_STATS self-test: 13 forbidden forms caught, 8 legitimate forms ignored"
else
fail "STALE_STATS self-test failed — the lint no longer enforces the full criterion"
fi
STAT_HITS=$(grep -rnE "$STALE_STATS" references/ commands/ skills/ hooks/prompts/ agents/ assets/templates/ assets/checklists/ CLAUDE.md README.md CHANGELOG.md .claude-plugin/plugin.json 2>/dev/null | grep -v 'algorithm-signals-reference' || true)
if [ -z "$STAT_HITS" ]; then
pass "no stale algorithm magnitudes / model brand outside the canonical reference"
else