From 8d1ef43801a95031db5adad48ed4d2c268acedaa Mon Sep 17 00:00:00 2001 From: Kjell Tore Guttormsen Date: Fri, 19 Jun 2026 21:38:02 +0200 Subject: [PATCH] =?UTF-8?q?fix(linkedin-studio):=20S25=20harden=20measure?= =?UTF-8?q?=20=E2=80=94=20explicit=20Glob,=20drop=20Read=20from=20routing?= =?UTF-8?q?=20front-door?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit measure is the Measure-journey routing front-door (v4.1): guided "how am I doing?" -> routes to the analytics command that owns the work; delegates only, never crunches numbers. Routing axis is clean — all 5 emitted targets (import/report/analyze/audit/ab-test) resolve to commands/Y.md. Delegates-only holds: the 3 crunch/analysis mentions (:7/:20/:40) are all no-do promises, no leak. Grant-hygiene was the one finding, and it differs from S24 create. There Glob was a pure orphan (no filesystem check at all). Here measure HAS an optional Step 0 ("if .../analytics/ holds imported data, note last import") that gives Glob a real home — but the grant<->use link was implicit (body named no tool), and Read hung on the same vague Step 0. Operator chose: make Glob explicit, drop Read as redundant (the import-date need is met by a Glob listing). 2 edits, commands/measure.md only: - allowed-tools :11: drop Read; net = {Glob, AskUserQuestion}. - Step 0 :23: "You may Glob .../analytics/; if it holds imported data, note last import" — gives the retained Glob grant a named body home. Verify: re-grep final — Read as tool name NONE, allowed-tools = Glob + AskUserQuestion (:11-12), Glob now in body :23; routing unchanged (5/5); git diff --stat = 1 file +1/-2; test-runner 81/0/0 exit 0; counts 29/19 unchanged (.md-only). FIXED, 0 deferrals. Scope note: Glob-orphan question now resolved for measure (it had a home via Step 0; create did not); linkedin (S26) still to check independently. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_016qgzo6rxthw7KuxHjn5vyE --- commands/measure.md | 3 +-- docs/hardening/log.md | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/commands/measure.md b/commands/measure.md index f1961a6..995417e 100644 --- a/commands/measure.md +++ b/commands/measure.md @@ -8,7 +8,6 @@ description: | Triggers on: "measure", "how am I doing", "my performance", "show my analytics", "performance overview", "how are my posts doing", "linkedin measure". allowed-tools: - - Read - Glob - AskUserQuestion --- @@ -21,7 +20,7 @@ intent in one question and route. **You do not run the analysis here.** ## Step 0: Quick context (optional) -If `${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}/analytics/` holds imported data, you may note "last import: [date]" in one +You may `Glob` `${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}/analytics/`; if it holds imported data, note "last import: [date]" in one line so the user knows whether a fresh import is needed first. Do not block on it. ## Step 1: Identify what they need diff --git a/docs/hardening/log.md b/docs/hardening/log.md index 406b649..43d22c5 100644 --- a/docs/hardening/log.md +++ b/docs/hardening/log.md @@ -1723,3 +1723,42 @@ read, pattern greps) from a tool, never by reasoning. expanded (one command per session); each catches its own. --- + +### /linkedin:measure — performance front-door (guided "how am I doing?" → routes to the owning analytics command); delegates only, no number-crunching (S25) + +**CLASS: routing front-door** (Measure-journey, v4.1). Predicate: every emitted `/linkedin:Y` resolves to +`commands/Y.md`; bidirectional grant-hygiene; "delegates only" (never crunches numbers). + +**TEST (tool-grounded).** +- Routing (main axis): **5/5 targets resolve** — `commands/{import,report,analyze,audit,ab-test}.md` all + present (menu `:31-35` / table `:44-48` / order-note `:51`). +- Grant-hygiene (bidirectional): `AskUserQuestion` (`:13`) used at `:29`; `Glob` (`:12`) + `Read` (`:11`) — + neither named a tool in body, both hung only on the **optional Step 0** filesystem glance (`:22-25`, + pre-edit). UNLIKE `create` (Glob a pure orphan, no fs-check at all), measure HAS a Step 0 ("if + `…/analytics/` holds imported data, note last import"), giving `Glob` a real home — but the grant↔use + link was implicit (body named no tool). +- Delegates-only: 3 no-do promises (`:7`, `:20`, `:40`); all crunch/analysis hits are negations — no leak. +- Persona (ICP author, "how am I doing?"): Step 0 optional analytics glance → Step 1 AskUserQuestion (5 + opts) `:29` → Step 2 route into target workflow `:37-48`; order-note `:50-51` (no data → import first). ✓ +- No fixture (pure routing prose). + +**HARDEN (operator-chosen — explicit `Glob`, drop `Read`; 2 edits, 1 file — `commands/measure.md`).** +1. [REWORK · grant-hygiene] dropped `Read` from `allowed-tools` (`:11`, pre-edit) — redundant; the Step 0 + import-date need is met by a `Glob` listing of the analytics dir. +2. [REWORK · grant↔use traceability] made Step 0 explicit: "You may `Glob` `…/analytics/`; if it holds + imported data, note last import" (`:23`), giving the retained `Glob` grant a named body home. + Net grants = {Glob, AskUserQuestion}. + +**VERIFY.** +- Re-grep final: `Read` as a tool name → **NONE**; `allowed-tools` = Glob + AskUserQuestion (`:11-12`); + `Glob` now in body `:23`. +- Routing unchanged: 5 distinct targets, all present. +- `git diff --stat` = 1 file, **+1/−2**. +- `bash scripts/test-runner.sh` → `Passed: 81 · Failed: 0 · Warnings: 0`, **exit 0**; counts **29/19** + unchanged (.md-only edit). +- Disposition: **FIXED** (2 edits, 1 file) · 0 deferrals · routing axis **PASS**, delegates-only **PASS**, + grant-hygiene **FIXED** (Glob retained + made explicit, Read dropped). +- Scope note: the `Glob`-orphan question is now resolved for `measure` (it had a home via Step 0; `create` + did not). `linkedin` (S26) still to check independently. + +---