linkedin-studio/docs/research-engine/plan-re-r3f.md
Kjell Tore Guttormsen 63745ddcab docs(linkedin-studio): RE-R3f brief + plan — unattended AI discovery (headless, slice e)
Tracked slice docs for MR-F5: the poll->score->capture->brief loop
made safe to fire with no operator present. Records the 2026-06-24
re-evaluation gate against v1.0.0 maturity and the operator's explicit
decision to open it (2026-08-10), plus the Desktop Scheduled Tasks vs.
hand-rolled cron design decision.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y2qHoS4FrkabuD1bCg8Nr2
2026-08-10 20:57:20 +02:00

113 lines
7.9 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.

# Plan — RE-R3f: unattended AI discovery (`--headless`, slice e)
> **Brief:** `docs/research-engine/brief-re-r3f.md`. **Slice:** RE-R3f (research-engine rung-2 — R3
> slice (e), the AI-capture unattended-run slice). No new source/test file: this is a prompt-file
> (`commands/trends.md`) contract change plus documentation. There is nothing here for
> `scripts/test-runner.sh` to gain a new floor for — the plan's "TDD" is a direct-read verification
> against the brief's SC1SC5, not a unit-test suite.
## Files touched (exhaustive)
| File | Change | SC |
|---|---|---|
| `commands/trends.md` | EDIT — `--headless` flag row + new **Step 0.5** contract section; Step 1's missing-profile branch forks on `--headless`; Step 2D refuses `--demand --headless`; Step 5 header states the unconditional skip | SC1, SC2 |
| `scripts/trends/README.md` | EDIT — new `## Unattended AI discovery — --headless (RE-R3f, slice e)` section: Desktop Scheduled Tasks (recommended) + the fallback `claude -p` recipe + `ANTHROPIC_API_KEY` + wait-ceiling + artifact-grounded success check + cost visibility | SC3 |
| `CLAUDE.md` | EDIT — `/linkedin:trends` command-table row gains a `--headless` clause | SC4 |
| `CHANGELOG.md` | EDIT — `[Unreleased]` entry naming MR-F5 | SC4 |
| `docs/research-engine/{brief,plan}-re-r3f.md` | NEW — tracked slice docs (mirrors R3c/R3e/etc.) | — |
| `STATE.md` | EDIT at land — Telling-block reconcile (no new counts; note MR-F5 landed) | — |
**Not touched (scope fence):** `scripts/trends/src/*.ts` (no code — Desktop Scheduled Tasks is the
mechanism, not a repo-owned wrapper); `scripts/trends/run-daily.sh` (RE-R3c stays deterministic-only,
untouched); `agents/trend-spotter.md` (the agent's own contract — poll/score — is unchanged by who
fires it; `--headless` is a command-level concern); `config/*`; `references/*`; command/agent counts
(no new command, no new agent — `--headless` is a flag on an existing command); `scripts/test-runner.sh`
(no new floor — nothing here is `tsx`-tested source).
## Step 1 — `commands/trends.md`: the `--headless` contract
Edited already this session (verify against brief SC1/SC2 by direct read):
1. Step 0 flags table gains the `--headless` row.
2. New **Step 0.5** section states the full contract: `--demand --headless` refusal, Step 1
fail-fast, Step 5 unconditional skip, Steps 24/6 unchanged, artifact-grounded success.
3. Step 1's pillar-loading paragraph forks explicitly: `--headless` → error + stop; else → ask.
4. Step 2D gains the refusal clause for `--demand --headless` before its existing demand-sweep
delegation text.
5. Step 5's header and lead line state the `--headless` skip condition (not buried only in Step 0.5
— a reader working step-by-step must see it at the step itself).
**Verification:** `grep -n -- '--headless' commands/trends.md` shows the table row + Step 0.5 + the
three per-step cross-references (≥5 matches, SC1); re-read Steps 1/2D/5 end-to-end to confirm each
fork is unambiguous (no branch left to model inference under ambiguity, SC2).
## Step 2 — `scripts/trends/README.md`: the unattended-discovery section
Edited already this session. New section placed after the existing RE-R3c ("Autonomous trigger +
headless entry") section, explicit that RE-R3f is a **different mechanism** (full agent turn, not a
bash wrapper): Desktop Scheduled Tasks recommended; the fallback `claude -p …` recipe with all four
required flags; `ANTHROPIC_API_KEY` under `--bare`; `CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS`; the
artifact-grounded success check (never trust `$?`/prose); `total_cost_usd` cost-visibility note.
**Verification:** `grep -n -- '--bare\|--permission-mode dontAsk\|--allowedTools\|ANTHROPIC_API_KEY\|Desktop Scheduled Tasks' scripts/trends/README.md` — each present (SC3).
## Step 3 — `CLAUDE.md` + `CHANGELOG.md`
- `CLAUDE.md`: append a `--headless` clause to the existing `/linkedin:trends` row (one line, no
restructuring of the table).
- `CHANGELOG.md`: `[Unreleased]` gains an entry — MR-F5 landed, the gate-opening decision named, the
scope (command contract + docs, no new code), matching this repo's existing changelog voice (see
the 0.8.0 entries for tone/format).
**Verification:** `grep -n -- '--headless' CLAUDE.md`; `grep -n 'MR-F5' CHANGELOG.md`.
## Step 4 — gate + regression sanity
`bash scripts/test-runner.sh``FAIL=0`, every existing floor unchanged (no new source/test file to
raise a floor for); Section 17 de-niche green (no vendor/sector token in any edit — the README's
`claude -p` recipe names a placeholder plugin-dir path, never an operator-specific one);
command/agent/reference counts unchanged, recounted live (`--headless` is a flag, not a new
surface).
## Step 5 — land
Recount counts live; reconcile `STATE.md`'s Telling block (no count change; note MR-F5 landed at
commit); quit the feedback register kvittering per `CLAUDE.local.md`'s protocol ("landed
feedback:MR-F5 @ `<commit>`" — Maskinrommet flips 🔵→🟢 on relay, never written here). Commit order:
**(1)** docs commit — `docs/research-engine/{brief,plan}-re-r3f.md` (tracked, no suffix); **(2)** one
code^H^H^H^Hprompt commit — `commands/trends.md` + `scripts/trends/README.md` + `CLAUDE.md` +
`CHANGELOG.md` (there is no code in this slice — "code commit" here means the prompt-file + docs
edit, landed together since it is one coherent contract change). Push after operator go (public
`open/` remote — confirm before push per the repo's own push-topology memory).
## Verification (testable)
| SC | Check | Command | Expected |
|---|---|---|---|
| SC1 | `--headless` documented | `grep -c -- '--headless' commands/trends.md` | ≥ 5 |
| SC2 | Per-step forks unambiguous | direct read of Steps 1, 2D, 5 | each states the `--headless` branch explicitly, no inference required |
| SC3 | README recipe complete | `grep` for the four flags + `ANTHROPIC_API_KEY` + `Desktop Scheduled Tasks` | all present |
| SC4 | CLAUDE.md + CHANGELOG updated | `grep -- '--headless' CLAUDE.md`; `grep 'MR-F5' CHANGELOG.md` | both present |
| SC5 | Gate green, counts unchanged | `bash scripts/test-runner.sh` | `FAIL=0`; all floors unchanged; Section 17 green |
| SC6 | (explicitly deferred) | — | consumer-side unattended proof is NOT claimed this session (`plugin-runtime-is-consumer-side`) |
## Risks
- **R1 — a scheduled task on the operator's actual machine can't reach Desktop Scheduled Tasks
(older Claude Code version, disabled feature).** *Mitigated:* the fallback `claude -p` recipe is
fully documented in the README, so the operator has a working path either way; not built as repo
code because building an unused wrapper would be speculative (brief §3 D3).
- **R2 — the `--headless` contract is a prompt, so nothing enforces it mechanically; a future edit
to `commands/trends.md` could silently reintroduce a blocking `AskUserQuestion` on the headless
path.** *Accepted, stated honestly:* there is no code-level guard here (unlike RE-R3c's
gate-tested `schedule.ts`). Claude Code's own `dontAsk` permission mode is the real backstop —
`AskUserQuestion` is auto-denied unconditionally regardless of what the command file says — so a
regression fails safe (the run aborts) rather than silently hanging on a phantom prompt.
- **R3 — unattended weekly AI research has a real, currently-uncapped per-run cost.** *Mitigated by
visibility, not a cap* (brief §3 non-goal, D2): `--output-format json`'s `total_cost_usd` is
documented as the thing to log; enforcing a hard ceiling is deferred as a real design question
rather than an arbitrary number picked under this slice.
- **R4 — the gate-reopening decision itself is contestable** (research was explicitly deferred to
v1.0.0 by a prior operator decision). *Mitigated:* the conflict was surfaced explicitly
(AskUserQuestion, 2026-08-10) rather than silently built around or silently deferred; the operator
chose to open it with the trade-off stated plainly. Recorded in the brief's header for future
sessions reading this slice cold.