linkedin-studio/docs/hardening/review-R4.md
Kjell Tore Guttormsen 4109fe7fd0 docs(linkedin-studio): cold-review R4 (Measure surfaces) — independent kald-review of 6 surfaces
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) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012GqEHp4uDiivfrAUjw4BdE
2026-06-30 09:58:40 +02:00

293 lines
23 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: 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.