From 4109fe7fd07a939ebcd0c058095c3f2603a9f7cc Mon Sep 17 00:00:00 2001 From: Kjell Tore Guttormsen Date: Tue, 30 Jun 2026 09:58:40 +0200 Subject: [PATCH] =?UTF-8?q?docs(linkedin-studio):=20cold-review=20R4=20(Me?= =?UTF-8?q?asure=20surfaces)=20=E2=80=94=20independent=20kald-review=20of?= =?UTF-8?q?=206=20surfaces?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Independent two-lens cold review of the 6 Measure-journey surfaces (import, report, analyze, audit, ab-test, measure) on frozen HEAD 69f37ba. Largest batch + only analytics-class batch; analytics-honesty predicate carried alongside the standard intent/correctness lenses. Verdict: REWORK (0 BLOCKER · 1 MAJOR · 4 MINOR · 6 SUGGESTION). - report.md MAJOR: heatmap report type (:72) routes to a nonexistent "Step 6c"; real handler is Step 2c (:106) — provably-wrong cross-ref on a primary menu branch. Caught by the correctness lens alone (intent lens never traced step-jump arithmetic); confirmed by main grounding the step inventory. - 5 of 6 surfaces ALLOW (measure notably clean — delegate-only enforced by the allowed-tools whitelist, not just asserted). Analytics-class predicate PASSES on all 6: saves framed as manual/count-only/ no-API and never folded into engagementRate; dwell called unmeasurable; parseOptionalCount (csv-parser.ts:71) + getAnalyticsRoot seam described accurately wherever quoted; graceful degradation present everywhere. Independence: 2 convergences (import Step 6a invalid trends flags; ab-test ER-omits-clicks) + 3 divergences resolved by main grounding in both directions (intent over-rated import 6a MAJOR->MINOR; correctness uniquely caught report 6c + analyze twin severity scales). Two-lens method earned its keep again. New R4 finding clusters (operator-gated fix, not done here): sibling interface/metric drift (import stale trends flags vs report; ab-test ER vs CLI engagementRate), one true under-declaration (report Step 8b Write). No code changed; cold review finds only. Cumulative cold-review coverage: 23/29 (S1 + R2a + R2b + R3 + R4). Remaining: R5 (Grow+Router, 6 surfaces) -> 29/29. test-runner 138/0 unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_012GqEHp4uDiivfrAUjw4BdE --- docs/hardening/review-R4.md | 293 ++++++++++++++++++++++++++++++++++++ 1 file changed, 293 insertions(+) create mode 100644 docs/hardening/review-R4.md diff --git a/docs/hardening/review-R4.md b/docs/hardening/review-R4.md new file mode 100644 index 0000000..7914a9d --- /dev/null +++ b/docs/hardening/review-R4.md @@ -0,0 +1,293 @@ +--- +type: cold-review +batch: R4 +journey: "Measure — analytics & performance surfaces" +scope: "FROZEN committed files at HEAD 69f37ba (clean tree; post-hardening cold pass)" +method: "2 independent cold Opus reviewers for the round (intent + correctness), each covering all 6 surfaces, no cross-feed; every mechanical claim tool-grounded (anti-fabrication mandate); reviewers carry NO drafting-session context. Divergences re-grounded by main before registration." +surfaces: [import, report, analyze, audit, ab-test, measure] +reviewers: + - "intent-lens (conformance: intent delivery + cross-ref resolution + analytics class predicates + graceful degradation + terminology)" + - "correctness-lens (internal consistency + bound-vs-canonical + step/phase arithmetic + allowed-tools completeness + metric-definition cross-check)" +class: "analytics — extra predicate: graceful degradation present · saves/dwell honesty intact (parseOptionalCount → unknown/never 0; dwell unmeasurable; saves NOT folded into engagementRate; analytics I/O via getAnalyticsRoot seam)" +status: "COMPLETE — all 6 surfaces reviewed (import, report, analyze, audit, ab-test, measure)" +verdict: REWORK +counts: { BLOCKER: 0, MAJOR: 1, MINOR: 4, SUGGESTION: 6 } +--- + +# Cold review — R4 (Measure · analytics & performance) + +Independent post-hoc cold review of the 6 Measure-journey surfaces, on the FROZEN committed files +(HEAD `69f37ba`). Mirrors the S1 `review.md` + R2a + R2b + R3 model (the cold-review method that did **not** +fabricate): read-and-show before assert, every `file:line` tool-confirmed, reviewers carry no +drafting-session context. The per-command interactive gate (`log.md`) already passed these; this pass +adds the **independent** axis that gate never had. This is the largest batch (6 surfaces) and the only +**analytics-class** batch, so the round carries the extra class predicate (graceful degradation + +saves/dwell honesty) alongside the standard intent/correctness lenses. + +**Analytics-class predicate — PASSES across all 6 surfaces (the headline R4 result).** Both blind lenses +independently confirmed the honesty contract holds wherever a surface touches the metric: **saves** are +consistently framed as native-only / count-only / ~Sept 2025-onward / no self-serve API / manual-entry +(`report.md:143,:241`; `import.md:30,:138,:148`; matches `cli.ts:144-146` + `csv-parser.ts:71` where +`parseOptionalCount` → blank/non-numeric/negative becomes `undefined` = unknown, never 0) and are **never +folded into `engagementRate`** (`csv-parser.ts:205-208` numerator = reactions+comments+shares+clicks, no +saves); **dwell** is consistently called unmeasurable/internal-to-LinkedIn (`report.md:241`, +`import.md:30`); no surface claims to import or compute either. The `getAnalyticsRoot()` per-user data-dir +seam (`storage.ts`) is described accurately wherever quoted. **No analytics-honesty violation anywhere in +R4.** + +**Independence cross-check — both outcomes recurred this batch (the case for two lenses, again):** +1. **Convergence (×2):** both blind lenses independently surfaced (a) `import.md` Step 6a's invalid + `trends` flags (`--period 4w` / `--metric engagement_rate`) and (b) `ab-test.md:236`'s manual + engagement-rate formula excluding clicks. Two real defects, found twice without cross-feed. +2. **Divergence resolved by grounding (×3, in BOTH directions):** + - **intent over-rated, main corrected down** — on `import` the intent-lens flagged the Step 6a CLI block + **MAJOR** (→ REWORK), the correctness-lens flagged the same defect **MINOR** (→ ALLOW, "off-primary, + descriptive"). Main re-grounded `import.md:194-217`: the executable instruction is the **delegation** + (`:200` "Run /linkedin:report"); the bash block (`:207-210`) is import's *description* of report's + internals, not import's own step → latent, errors only if copy-run → **MINOR**, import = ALLOW. + - **correctness uniquely caught, main confirmed** — on `report` the correctness-lens flagged a **MAJOR** + (heatmap branch routes to a nonexistent "Step 6c"); the intent-lens was silent (its lens probes + agent/command cross-refs, not internal step-jump arithmetic). Main grounded the step inventory → no + `6c` exists, real handler is `2c` → **MAJOR confirmed**. This is the batch's load-bearing defect. + - **correctness uniquely caught, main confirmed** — on `analyze` the correctness-lens flagged a **MINOR** + (two non-reconciling severity scales); the intent-lens was silent → main grounded `:155-178` vs + `:227-231` → confirmed **MINOR**. + Both lenses earned their keep: intent over-rated one finding (corrected by grounding), correctness + uniquely caught the two structural defects intent's lens never traced. + +--- + +## Connections to existing systemic findings (no NEW ★ cross-cutting this batch) + +All connections re-grounded by main against the R4 files: + +- **★ #1 (clipboard `printf '%s'`, R2a, 10 files) — R4 adds nothing.** `grep -nE "printf '%s'|clipboard-helper"` + across all 6 R4 files → NONE. The analytics surfaces do not auto-copy to clipboard (they ingest/report + data, they don't emit post text), so this systemic pattern simply does not reach the Measure journey. +- **★ #2 (5-component scaffold band-mismatch, R2b, 3 files) — R4 adds nothing.** The length-band tokens + that appear (`analyze.md:201` "1,200-1,500", `:217` "1,500-1,800"; `report.md:331` example impressions; + `ab-test.md:80` test-variable "Short (500) vs standard (1,200-1,800) vs long (2,500+)") are + recovery-protocol guidance / illustrative numbers / a test variable — none is a component scaffold that + sums outside the standard band. No defect. +- **★ #3 (bare reference paths vs `${CLAUDE_PLUGIN_ROOT}/`, R2b+R3) — R4 connects lightly (lowest impact).** + `analyze.md:22,:23,:93,:259,:260,:261` and `report.md:241` carry bare `references/…` — but **none is + inside an executable `Read`/`cat`** (`grep -nE "(Read|cat) .*references/"` → NONE executable); all are + pointer-list entries or prose mentions, the same lowest-impact class as R3's firsthour bare paths. + Latent parity break worth catching in the same repo-wide `${CLAUDE_PLUGIN_ROOT}/` grep pass; not elevated + to a per-surface finding (neither lens raised it; cosmetic on these surfaces). + +**Recurring (SUGGESTION-class, NOT elevated to ★) — `allowed-tools` over-declaration now spans R3+R4.** +Four of six R4 surfaces declare a tool the body never invokes: `import`/`report` (`Glob` — listing done via +Bash `ls`/`find`), `audit` (`Grep` — no grep call). Combined with R3's 3-of-4, the pattern now touches ~7 +surfaces. Harmless (over-declaration widens the permission surface but breaks nothing; *under*-declaration +is the real risk and there is one true instance this batch — `report` Step 8b, recorded as MINOR below). +Optional minimal-surface trim; fold into the consolidated fix if touched. + +**New R4 cluster (not ★, analytics-specific) — sibling-command interface/metric-definition drift.** Two +of the four MINORs are the same shape: an analytics surface quotes another surface's CLI interface or a +shared metric definition and drifts from the SSOT — `import.md` Step 6a's stale `trends` flags vs +`report.md`'s correct ones, and `ab-test.md:236`'s manual engagement-rate (clicks excluded) vs the CLI's +`engagementRate` (clicks included, `csv-parser.ts:205`). Both are latent (cross-reference paths, not +primary execution) but both are real consistency debt between siblings. Worth a single reconciliation note +in the consolidated fix: pin the canonical `engagementRate` definition + CLI flag vocabulary once, and make +the descriptive blocks point at it rather than restate it. + +--- + +## import.md — VERDICT: ALLOW (0 BLOCKER/MAJOR · 1 MINOR · 1 SUGGESTION) + +Class: **analytics (import orchestrator)**. Intent delivered: primary artifact is the structured JSON batch +written by `cli.ts import` (Step 4 invokes it; output surfaced Step 5), then analysis delegated to +`/linkedin:report` (Step 6). Step inventory `1·1b·2·3·4·5·5b·6·6a·6b·7·8` sequential, no gaps; Step 1b/Step 3 +option lists each carry a Skip/Cancel disposition. `allowed-tools` (`:10-15` Bash/Read/Glob/Write/AskUserQuestion) +— Bash/Read/Write/AskUserQuestion all invoked. Cross-refs resolve (`report.md`, `setup.md`, `quick-import.mjs`, +`assets/analytics/README.md` all exist; no `subagent_type`). Degradation present (no-CSV, nothing-anywhere, +missing-deps `npm install`, skipped rows on empty-title/unparseable-date matching `csv-parser.ts:187,193`). +saves/dwell honesty intact (`:30,:138,:148`). No "thought leadership". + +### MINOR — Step 6a documents report's CLI calls with invalid period + metric, contradicting the real owner (`import.md:200, :206, :207-210`) +- **Verified by main (the intent/correctness severity divergence, re-grounded `:194-217`):** `:207-210` + shows `trends --period 4w --metric impressions` and `--metric engagement_rate` inside a bash fence. The + CLI accepts period `week|month|quarter|all` (`cli.ts:217`, validated → `process.exit(1)` `:219-221`) and + metric `…|engagementRate` camelCase (`cli.ts:202-209`, validated → `process.exit(1)` `:233-234`) — both + `4w` and `engagement_rate` would error. The real owner `report.md:153,:171` uses the correct + `--period month --metric engagementRate`. `:200` "(period: 4w)" and `:206` "Read expertise_areas" also + mis-describe report (it takes no period arg, never reads expertise_areas). +- **Why MINOR not MAJOR (intent-lens rated MAJOR; main grounds down):** the **executable** instruction on + this path is the delegation at `:200` ("Run /linkedin:report") → routes to `report.md`, which is correct. + The bash block (`:207-210`) is import's *narrative description* of report's internals ("`/linkedin:report` + will: … 2. Call `trends`…"), not a step import itself runs. Latent (errors only if a reader copy-runs the + illustrative block) and the primary delegation path is unaffected → MINOR, not MAJOR. Both lenses + converged on the defect's existence; only the severity diverged. +- **disposition:** drop the illustrative bash + the "(period: 4w)"/"expertise_areas" description, or mirror + report's real invocations (`--period month --metric engagementRate`). Fold into the sibling-drift + reconciliation note. + +### SUGGESTION — `allowed-tools` over-declares `Glob` (`:13`); directory listing uses Bash `ls`/`find` (`:37,:47`). Both lenses. See Recurring note. + +--- + +## report.md — VERDICT: REWORK (0 BLOCKER · 1 MAJOR · 1 MINOR · 1 SUGGESTION) + +Class: **analytics (report orchestrator)**. Intent delivered: produces weekly/monthly/heatmap report JSON +via `cli.ts report`/`heatmap` + a formatted presentation (Step 6) + an analytics-interpreter handoff +(`subagent_type: linkedin-studio:analytics-interpreter` `:308` → `agents/analytics-interpreter.md` ✓, `Task` +declared `:14`). Trends flags `--period month --metric engagementRate` (`:153,:171,:366`) all valid vs CLI. +Degradation present (no-data, npm install, week-not-found/empty-week/ERR_MODULE_NOT_FOUND `:387-400`). +saves/dwell honesty exemplary (`:143,:241`). No "thought leadership". + +### MAJOR — the heatmap report type routes to a nonexistent "Step 6c" (`report.md:72`) +- **Verified by main (correctness-lens caught it; intent-lens silent — lens gap, not contradiction):** the + step inventory (`grep -nE '^### Step|^## Step'`) is `1·1b·2·2b·2c·3·4·5·5b·5c·6·7·8·8b` — **there is no + Step 6c**. `:72` ("If heatmap (option 3): Run the heatmap CLI command and jump to **Step 6c**") points a + reader nowhere. The real heatmap handler is **Step 2c** (`:106`, immediately below the monthly Step 2b), + which itself "jump[s] to Step 7" (`:114`). The two sibling branches are correct (monthly `:71`→2b; + weekly→inline), so heatmap — one of three top-level report types in Step 2 — is the lone misroute. +- **Severity:** a provably-wrong cross-reference on a **primary menu branch** (top-level report-type + selection, not a deep-dive). Recoverable (`:72` also says "Run the heatmap CLI command," and 2c sits + right under 2b, so a capable agent recovers by proximity) — hence MAJOR, not BLOCKER — but it is the + batch's one load-bearing navigation defect. +- **disposition:** retarget `:72` from "Step 6c" to "Step 2c". + +### MINOR — Step 8b markdown export under-declares its write tool (`report.md:429-431` vs `:9-15`) +- **Verified by main:** Step 8b (reached via Step 8 option 4, "Export report as markdown file") instructs + "Format the data using this template and **write to file**" / "Save to: …`-report.md`" (`:429-431`). + Frontmatter `allowed-tools` (`:9-15`) = Bash/Read/Glob/AskUserQuestion/Task — **no `Write`**. This is the + one genuine *under*-declaration this batch (the real-risk class). Held at MINOR by two mitigations: the + step is an optional deep-dive (not the primary path), and the declared `Bash` can satisfy the write via a + heredoc/`cat >`. Sibling `ab-test.md:12-19` declares `Write` for the same `.md`-save, so the omission + reads as an oversight/parity break. +- **disposition:** add `Write` to `allowed-tools` (parity with ab-test) or rephrase Step 8b to write via the + declared `Bash`. + +### SUGGESTION — `allowed-tools` over-declares `Glob` (`:12`); listing uses Bash `ls` (`:30,:197`). Correctness-lens. See Recurring note. + +--- + +## analyze.md — VERDICT: ALLOW (0 BLOCKER/MAJOR · 1 MINOR · 1 SUGGESTION) + +Class: **analytics-adjacent (read-only diagnostic; no CLI)**. Intent delivered: diagnosis + recovery plan +from reference files + AskUserQuestion (Steps Load-Context·1-8). Cross-refs resolve +(`subagent_type: linkedin-studio:analytics-interpreter` `:41` → agent ✓, `Task` declared `:12`; +`/linkedin:profile` `:188` → `commands/profile.md` ✓). Degradation present (analytics delegation is +conditional `:41` with a self-report fallback; functions with zero data). No saves/dwell claims → nothing to +contradict. No "thought leadership". + +### MINOR — two non-reconciling severity scales in one command (`analyze.md:155-178` vs `:227-231`) +- **Verified by main (correctness-lens; intent-lens silent — lens gap):** Step 5 grades reach drop on four + percentage bands (`<25` / `25-50` / `50-75` / `75%+`, `:155-178`). Step 7's timeline table (`:227-231`) + uses three rows on a *different* axis — "Moderate (link/off-topic)", "Moderate (partial reach loss)", + "Severe (sharp reach loss)". The two scales share no common key, so a user holding a Step 5 result (e.g. + "Down 50-75% → algorithmic suppression likely") cannot map it to a Step 7 timeline row. Advisory/usability + inconsistency, low-confidence; nothing breaks. +- **disposition:** cross-label the Step 7 rows to the Step 5 bands, or state explicitly that they are + independent axes. + +### SUGGESTION — the `:41` existence check ("If imported analytics data exists `…/analytics/`") implies Glob/Bash, neither declared (`allowed-tools` `:9-13` = Read/AskUserQuestion/Task). Softer than report's Write gap: no explicit tool call is written at `:41` (it's a conditional prose phrase) and the real data access is delegated to `analytics-interpreter` via `Task`. Correctness-lens. + +--- + +## audit.md — VERDICT: ALLOW (0 BLOCKER/MAJOR/MINOR · 1 SUGGESTION) + +Class: **analytics-adjacent (read-only strategy auditor; no CLI)**. Intent delivered: audit report (Step 7 +template) + action items (Step 8). Steps `0·1·2·3·4·5·5.5·6·7·8` sequential. Routing resolves +(`/linkedin:strategy` → `commands/strategy.md` ✓, `/linkedin:profile` ✓; no `subagent_type`, `Task` +correctly absent from `allowed-tools`). Degradation present (Step 0 checks for analytics data + asks for +screenshots/metrics; milestone block self-skips with no data `:140`). **Correctness cross-check (both +lenses):** the state fields the milestone block reads — `follower_count`, `monthly_growth`, +`growth_rate_needed` (`:105,:109,:128`) — all exist in `config/state-file.template.md:23,26,28`, so it reads +real fields. No saves/dwell claims. No "thought leadership". + +### SUGGESTION — `allowed-tools` over-declares `Grep` (`:11`); Step 0 uses Read/Glob, no grep call in the body. Both lenses (convergence). See Recurring note. + +--- + +## ab-test.md — VERDICT: ALLOW (0 BLOCKER/MAJOR · 1 MINOR · 2 SUGGESTION) + +Class: **analytics (experiment manager; manual metric entry, no CLI)**. Intent delivered: primary artifact +is the test-plan markdown written to `analytics/ab-tests/[name].md` (Step 2a.8) + running comparison / +analysis (2b/2c). Step inventory `0·1·2a(.1-.8)·2b·2c·2d·2e·3` consistent; Step 1's 6 intents map to 2a-2e + +option 6 self-handles (`:57`). Post-count arithmetic coherent ("3 per variant / 6 total" `:127`; 6-row +execution table `:155-162`; "X of 6" `:255`). `allowed-tools` (`:12-19` +Read/Glob/Write/Bash/AskUserQuestion/Task) — Read/Write/Bash/AskUserQuestion/Task(→`content-optimizer` `:119` +✓) all invoked. Degradation present (Error Handling: No-Tests-Directory, Incomplete-Data, Missing-Analytics, +Corrupted-files `:472-493`). Statistical honesty notably correct — 2c.4/Confidence-Level (`:311,:320-331`) +explicitly demotes small-sample results to "directional, not significant." No saves/dwell claims. No +"thought leadership". + +### MINOR — manual engagement-rate formula excludes clicks, diverging from the canonical `engagementRate` (`ab-test.md:236`) +- **Verified by main (both lenses converged):** `:236` computes ER as + `(reactions + comments + reposts) / impressions * 100` — clicks excluded (and 2b.3 `:228-234` never + collects clicks). The CLI's `engagementRate` includes clicks: `totalEngagement = reactions + comments + + shares + clicks` (`csv-parser.ts:205-208`). Step 2c.3 (`:282-288`) cross-references the A/B numbers against + the CLI weekly reports, where the two rates will not match. +- **Severity:** internally consistent within a single test (same formula on both variants, and A/B is + variant-relative), so the verdict-within-a-test is unaffected → MINOR, latent on the cross-reference path. +- **disposition:** add a one-line "clicks excluded by design" caveat, or align the manual formula to the + canonical definition. Fold into the sibling-drift reconciliation note. + +### SUGGESTION — bare agent name in a user-facing suggestion (`ab-test.md:468`): "use the `content-optimizer` agent" surfaces a bare name where the canonical form (correctly used at `:119`) is the namespaced `subagent_type`. Cosmetic. Intent-lens. + +### SUGGESTION — `allowed-tools` over-declares `Glob` (`:14`); scans use Bash `ls` (`:37,:209`). 2b.4/2c.5 append/update are edit-shaped but the declared `Write` covers them via full rewrite (no `Edit` gap). Correctness-lens. See Recurring note. + +--- + +## measure.md — VERDICT: ALLOW (0 findings — clean) + +Class: **front-door router (delegate-only)**. Intent delivered **and structurally enforced** (both lenses +converged): `allowed-tools` (`:10-13`) = `Glob` + `AskUserQuestion` only — no Bash/Read/Task — so the +command *cannot* run analysis itself; it identifies intent (Step 1, 5 intents `:30-34`) and routes (Step 2 +table `:41-47`, one row per intent). All five routes — `/linkedin:import`, `/linkedin:report`, +`/linkedin:analyze`, `/linkedin:audit`, `/linkedin:ab-test` — resolve to existing command files. Degradation +present (Step 0 glob optional, "Do not block on it"; order-note `:49-50` routes to import first when nothing +imported). No dangling branch, no analysis logic to drift, no saves/dwell claims, no "thought leadership". +The thinnest, cleanest surface in the batch — the delegate-only contract is enforced by the tool whitelist, +not just asserted. + +--- + +## Gate decision — R4 COMPLETE (6 surfaces) + +| Surface | Verdict | BLOCKER | MAJOR | MINOR | SUGGESTION | +|---|---|---|---|---|---| +| import | ALLOW | 0 | 0 | 1 | 1 | +| report | REWORK | 0 | 1 | 1 | 1 | +| analyze | ALLOW | 0 | 0 | 1 | 1 | +| audit | ALLOW | 0 | 0 | 0 | 1 | +| ab-test | ALLOW | 0 | 0 | 1 | 2 | +| measure | ALLOW | 0 | 0 | 0 | 0 | +| **TOTAL** | **REWORK** | **0** | **1** | **4** | **6** | + +**Batch verdict: REWORK** — 1 of 6 surfaces (report) carries **1 MAJOR**: the heatmap report type routes to +a nonexistent "Step 6c" (real handler Step 2c) — a provably-wrong cross-reference on a primary menu branch. +**0 BLOCKER anywhere.** The other five are ALLOW (measure notably clean — its delegate-only contract is +enforced by the `allowed-tools` whitelist, not merely asserted). + +**Analytics-class predicate verdict: PASS.** The saves/dwell honesty contract holds on every surface that +touches the metric — saves framed as manual/count-only/no-API and never folded into `engagementRate`, dwell +called unmeasurable, neither claimed as imported; `parseOptionalCount` semantics (`csv-parser.ts:71`) and the +`getAnalyticsRoot` seam described accurately wherever quoted. Graceful degradation present on all six. This +was the batch-specific axis and it is clean. + +**Independence verdict:** two convergences (import Step 6a flags; ab-test ER-omits-clicks) + three +divergences resolved by main's grounding in **both directions** — intent over-rated import's Step 6a +(MAJOR→MINOR on grounding that the executable path delegates), while correctness uniquely caught report's +Step 6c misroute (MAJOR) and analyze's twin severity scales (MINOR) that intent's lens never traced. The +two-lens method earned its keep again: had only the intent-lens run, report would have shipped ALLOW with a +broken primary branch; had only the correctness-lens run, import would have over-escalated to REWORK. + +**Systemic findings now span R2a+R2b+R3+R4:** clipboard `printf` (R2a, 10 files — **R4 adds none**) · +component scaffold (R2b, 3 files — **R4 adds none**) · bare reference paths (R2b+R3+R4 — R4 adds 7 +lowest-impact pointer/prose sites in analyze/report, not executable). **New this batch:** (a) `allowed-tools` +over-declaration now spans R3+R4 (~7 surfaces, SUGGESTION-class, harmless) with one true *under*-declaration +(report Step 8b `Write`, MINOR); (b) a small **sibling interface/metric-definition drift** cluster (import's +stale `trends` flags + ab-test's clicks-excluded ER) — reconcile once against the CLI SSOT. Cold review +**finds**; it changes no code. Each fix is its own operator-gated decision. Recommended consolidated-fix +order unchanged: (1) clipboard `printf` [R2a, 10 files, highest blast radius], (2) component scaffold [3 +files], (3) bare reference paths [grep-driven], then the per-surface items — now including **report Step 6c +misroute (the one R4 MAJOR)**, report Step 8b `Write`, the sibling-drift reconciliation (import 6a + +ab-test ER), analyze severity scales, and the over-declaration trims. Local-only (hardening-class), pushed +per the 2026-06-30 operator delegation (public catalog, no secrets). + +**Cumulative cold-review coverage: 23/29** (review.md S1=4 · R2a=5 · R2b=4 · R3=4 · R4=6). Remaining: **R5 +(Grow+Router)** — strategy · competitive · monetize · outreach · profile · linkedin (6 surfaces) → 29/29.