fix(linkedin-studio): S13 — close S12 WARN ($-scalar + false-green test) + $-safety lint guard

Closes the 2 grep/Read-verified findings from the S12 cold full-brief re-review
(docs/remediation/review.md, WARN 0/1/1/0, 0 dropped) and closes the $-injection
CLASS — not the line — across the whole state-updater.mjs mutation surface.

See docs/remediation/review.md (S13 ALLOW, 0/0/0/0) for the full closure record:
replaceField -> replacement function; the 3 additive-insert sites -> functions
(m === $1, behavior-preserving); a scalar assert.match pins last_post_topic; and a
behavioral, coverage-complete, self-testing Section 12 guard (check-replace-safety.mjs)
that is mutation-proven. Docs three-doc + residuals updated. test-runner.sh 71/0/0,
node --test 98/98.
This commit is contained in:
Kjell Tore Guttormsen 2026-05-30 19:12:45 +02:00
commit 431a893f7c
10 changed files with 665 additions and 9 deletions

View file

@ -231,6 +231,14 @@ describe('updatePostTracking', () => {
assert.notEqual(result, null);
assert.ok(result.content.includes('$100 budget — $& and $1 rule'), 'topic with $-tokens must be inserted verbatim');
assert.ok(result.content.includes('"We cut $1 of $5"'), 'hook with $-tokens must be inserted verbatim');
// S13: the SCALAR path (replaceField → state-updater.mjs:58) must ALSO insert
// verbatim. The S12 test only checked the Recent Posts section entry (a function
// append), so a `$&`-corrupted `last_post_topic` scalar shipped green: a
// replacement *string* expands `$&` to the whole matched line, rewriting the
// field to `last_post_topic: "$100 budget — last_post_topic: "AI strategy" …"`.
// This assertion fails until replaceField is a replacement function.
assert.match(result.content, /^last_post_topic: "\$100 budget — \$& and \$1 rule"$/m,
'last_post_topic scalar must carry the $-bearing topic verbatim (no $&/$1 expansion)');
const headings = result.content.match(/^## Recent Posts$/gm) || [];
assert.equal(headings.length, 1, 'heading must not be re-injected by a $1/$& expansion');
});