ktg-plugin-marketplace/plugins/linkedin-studio/docs/remediation/review.md
Kjell Tore Guttormsen 431a893f7c 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.
2026-05-30 19:12:45 +02:00

166 lines
9.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
type: trekreview
review_version: "1.0"
task: "Remediate linkedin-studio from the baseline audit — correctness, honesty, generalization, and the highest-leverage 2026 coverage gaps (full Phase 03 roadmap, phased)"
slug: remediation
project_dir: docs/remediation/
brief_path: docs/remediation/brief.md
scope_sha_start: c5b4c58f4f390aca83c8937880c5fd0bcc983e44
scope_sha_end: 36f79dd702b9315a0cd9100c3a8dd6dd81b3797f
reviewed_files_count: 50
verdict: ALLOW
mode: default
effort: high
profile: premium
findings: []
---
# Review — linkedin-studio audit-remediation (S13 re-review: `$`-class closure + scalar-test fix)
## Executive Summary
**Verdict: ALLOW** — 0 BLOCKER, 0 MAJOR, 0 MINOR, 0 SUGGESTION.
This is the **S13 re-review** — the **seventh** full-brief sweep
(`c5b4c58..36f79dd` + the uncommitted S13 working-tree delta), run COLD and
high-effort. S13 was commissioned to close the two findings the S12 re-review
left open (verdict WARN, 0/1/1/0): the MAJOR `MISSING_TEST` (the S12 `$`-bearing
test asserted the Recent Posts section but never the `last_post_topic` scalar, so
the corruption shipped green) and the MINOR `MISSING_ERROR_HANDLING` (the
`last_post_topic` scalar was still `$`-unsafe because `replaceField` used a
replacement *string* for untrusted content). Two independent reviewers
(brief-conformance, code-correctness) ran without cross-feeding; the coordinator
applied bounded dedup + the HubSpot Judge filters + verdict (high-effort →
Cloudflare reasonableness filter skipped; the operator weighs borderline findings).
**Both reviewers returned empty finding sets.**
**Both S12 findings are CLOSED at the reviewed (uncommitted) state:**
- `replaceField` (`hooks/scripts/state-updater.mjs:14-24`) now uses a replacement
**function** (`() => \`${field}: ${value}\``), so the untrusted `last_post_topic`
at the `:64`-equivalent call site is inserted verbatim — no `$&`/`$1`/`` $` ``
expansion. The MINOR is closed.
- The existing `$`-bearing test (`hooks/scripts/__tests__/state-updater.test.mjs`)
now carries `assert.match(result.content, /^last_post_topic: "\$100 budget — \$&
and \$1 rule"$/m, …)`, distinct from the section-entry `includes()` it already
had. This assertion **fails on the old string-`replaceField` and passes on the
function form** (orchestrator-verified by reverting the fix: the test went
40 pass / 1 fail). The false-green MAJOR is closed.
**The class — not just the line — is closed.** The recurring S9→S12 lesson is
"close the class, not the line"; the class here is "untrusted user content reaching
ANY `String.replace` replacement *string*". Beyond the `replaceField` scalar, S13
also converted the three remaining additive-insert sites (`recordFirstHourPlan`
`:246`-equiv; `recordOutreachContact` `:305/:308`-equiv) from a string replacement
carrying an intentional `$1` backref + interpolated date to a replacement function
(`(m) => \`${m}\n…\``). The code-correctness reviewer verified rigorously that this
is **behavior-preserving**: each regex's capture group spans the *entire* match (the
only chars outside the group are the zero-width `^`/`$` anchors), so the full match
`m` is character-identical to the old `$1`. After S13, **every `.replace()` in
`state-updater.mjs` uses a replacement function or a `$`-free literal** — the class
is closed by construction, not by per-line patch.
**A structural guard replaces the per-line proof.** New
`scripts/check-replace-safety.mjs` (wired as `test-runner.sh` Section 12) proves the
property behaviorally: it drives every exported mutator with an adversarial payload
of every special replacement token (`$&`, `` $` ``, `$'`, `$$`, `$n`) in every
free-text *and* date field and asserts the payload survives verbatim. Two structural
backstops run on every invocation — **coverage-completeness** (a newly-exported
mutator without `$`-coverage fails the guard) and a **non-vacuity self-test** (a
naive string-replace MUST corrupt the payload and a function MUST preserve it, else a
PASS is meaningless), mirroring the Section 8/10/11 self-tests. The orchestrator
mutation-proved it end-to-end: reverting `replaceField` to a string makes the guard
exit 1 with two findings; restoring it returns exit 0.
**No Phase-03 Success Criterion regressed.** The brief-conformance reviewer traced
each S13 clause to delivered code and confirmed the counts (19 agents / 27 commands /
25 references / 6 skills), the version (4.0.0), the single-source algorithm-signal,
the model-consistency guard, and the render-chain-propagation guard all still hold;
S13 touched no command/agent/reference file. The two Non-Goals the brief amendment
re-opens (the command invocation surface for S14; saves manual-entry for S16) trace
to **explicit operator decisions** in the brief amendment, and S13 itself did not
touch either surface — no `SCOPE_CREEP_BUILT`.
**Push decision: ALLOW.** The two S12 findings are closed, the class is closed
structurally, the lint is non-vacuous and mutation-proven, all suites are green
(`scripts/test-runner.sh` → 71/0/0; `node --test` → 98/98), and no SC regressed. The
ORIGINAL remediation brief now closes clean. Per `feedback_trekreview_always_last` +
Handover 6, this review is the gate; with ALLOW, S13 may push.
## Coverage
Scope SHA range: `c5b4c58` (= `origin/main`, parent of remediation Steg 1) →
`36f79dd` (HEAD, the S12 commit) **plus the uncommitted S13 working-tree delta**
(annotated `[uncommitted]` — a brief-level contract; the brief's Assumptions allow
uncommitted review). The committed range (47 files) was already deep-reviewed and
cleared at S12 except the 2 WARN findings; the active S13 delta is the 9 working-tree
files below. **No silent skips.**
| Treatment | Count | Notes |
|-----------|-------|-------|
| `deep-review` (hooks/** + the new guard) | 4 | `state-updater.mjs`, `state-updater.test.mjs` `[uncommitted]`; `scripts/check-replace-safety.mjs` `[uncommitted, new]`; `scripts/test-runner.sh` `[uncommitted]` |
| `summary-only` | 46 | the committed `c5b4c58..36f79dd` range (already cleared at S12) + the S13 doc edits `CLAUDE.md`/`README.md`/`docs/integration-test-guide.md` `[uncommitted]` + `docs/remediation/{brief.md (amendment), finish-plan.md}` `[uncommitted]` |
| `skip` | 0 | no lockfiles / svg / generated / dist |
**Cross-cutting execution criteria (run by orchestrator):**
`scripts/test-runner.sh` → 71 passed / 0 failed / 0 warnings, exit 0 (was 70;
+1 — Section 12 `$`-safety guard).
`node --test hooks/scripts/__tests__/*.test.mjs` → 98 tests, 98 pass, 0 fail (the
S13 scalar assertion was added to an existing test, not a new test).
`node scripts/check-replace-safety.mjs` → exit 0 (8 adversarial cases / 5 mutators,
coverage-complete, self-test non-vacuous); mutation-proven (reverting the fix → exit 1).
**S12 findings — both confirmed CLOSED:**
`replaceField` (`state-updater.mjs:14-24`) → replacement function; the `$`-bearing
test now pins the `last_post_topic` scalar (`state-updater.test.mjs`); the three
remaining additive-insert string-replacements (`:246/:305/:308`) → functions; the
class is closed and guarded structurally (Section 12).
## Findings
None. Both independent reviewers returned empty finding sets; the coordinator's
bounded passes (dedup, HubSpot Judge, verdict) on an empty set yield ALLOW.
## Remediation Summary
**Gate: ALLOW.** The S12 WARN is fully resolved: the `replaceField` scalar
`$`-corruption (MINOR) and the false-green test (MAJOR) are both closed; the
`$`-injection class is closed across the whole `state-updater.mjs` mutation surface;
and a behavioral, coverage-complete, self-testing Section-12 lint guards it
structurally against future regressions. All suites green; no Phase-03 SC regressed;
the two re-opened Non-Goals trace to explicit operator decisions and S13 stayed in its
lane.
**Two non-blocking observations, recorded by both reviewers, neither rising to a
catalogue finding:**
1. The S13 dead binding both reviewers named (`check-replace-safety.mjs` `HERE` +
its now-unused `node:url`/`node:path` imports) was removed during this review
pass; the guard remains green (exit 0) after removal.
2. The behavioral guard catches a new *unguarded exported mutator* (coverage
backstop) but not a new unsafe `String.replace` added *inside* an existing
battery-covered mutator on a field the battery does not fuzz. This is a documented,
deliberate limit of the behavioral proxy (vs a per-`.replace()` AST enumeration)
and is **moot today** — every `.replace()` in `state-updater.mjs` is already a
function. Recorded as a known boundary, not a defect; closing it further is out of
S13 scope (no real `$`-unsafe site exists to catch).
The two adjacent machine-value `.replace()` sites the correctness reviewer probed —
`session-start.mjs:396` (`${actualWeek}`, a computed ISO week) and `week-rollover.mjs`
(computed week / literal int) — carry no untrusted content and are therefore not
members of the defect class, consistent with how the S12 review itself classified the
date/integer `replaceField` call sites. No finding.
Per Handover 6, this `review.md` is consumable by
`/trekplan --brief docs/remediation/review.md`; the trailing JSON block is the machine
contract for that handover. With an ALLOW verdict and no BLOCKER/MAJOR findings, no
follow-up remediation plan is required — the ORIGINAL brief is closed clean and the
finish-plan continues at S14.
```json
{
"verdict": "ALLOW",
"scope": { "sha_start": "c5b4c58f4f390aca83c8937880c5fd0bcc983e44", "sha_end": "36f79dd702b9315a0cd9100c3a8dd6dd81b3797f", "reviewed_files_count": 50, "uncommitted_delta": true },
"counts": { "BLOCKER": 0, "MAJOR": 0, "MINOR": 0, "SUGGESTION": 0 },
"findings": [],
"dropped_findings": []
}
```