linkedin-studio/docs/second-brain/plan-sb-s3a.md
Kjell Tore Guttormsen fbfbf71cdd docs(linkedin-studio): SB-S3a brief + plan — first profile.md reader (light-Voyage hardened)
SB-S3 decomposed into 4 sub-slices; operator picked S3a (profile.md reader)
first: wire strategy-advisor to consume brain/profile.md as evidence-to-test,
READ-only, guarded by a deterministic wiring lint (new test-runner.sh
Section 16d + ASSERT_BASELINE_FLOOR 78->80). Light-Voyage hardened:
brief-review APPROVE, scope-guardian ALIGNED, plan-critic REVISE (all 3 FIX
folded — incl. consolidation-loop.md:67 reconciliation, since no lint guards
docs/). No code yet — parked at the final go-before-code gate.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RigJBiRFNtFZKCz21qNbQ4
2026-06-23 18:09:54 +02:00

83 lines
9.6 KiB
Markdown
Raw Permalink 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 — SB-S3a: wire the first profile.md READER (`strategy-advisor`)
> Brief: `docs/second-brain/brief-sb-s3a.md` (APPROVE, FIXes folded). Slice: SB-S3a.
> Operator confirmed: **`strategy-advisor`**, READ-only, **manual SC4/SC5** (no behavioural harness).
> Order is TDD: the failing lint check lands BEFORE the agent edit (iron law).
## Goal
`strategy-advisor` consumes `brain/profile.md` as *evidence-to-test*, guarded by a deterministic wiring lint. No write path, no parser, no tributary/hook change. Smallest end-to-end proof that the second brain feeds generation.
## Files touched (exhaustive — for scope-guardian)
| File | Change | Why |
|------|--------|-----|
| `scripts/test-runner.sh` | **NEW Section 16d** (2 unconditional checks) + bump `ASSERT_BASELINE_FLOOR` 78→80 + extend floor-history comment + header enumeration | SC1/SC2/SC6 — the TDD anchor |
| `agents/strategy-advisor.md` | add `brain/profile.md` to Step 0 Load Context + a short consumption subsection (anti-sycophancy literal + graceful-absence) | SC1/SC2/SC5 — the wiring itself |
| `docs/second-brain/consolidation-loop.md` | **append** an "SB-S3a landed" reader-status line (do NOT rewrite the existing :67 contract prose) | doc reconciliation |
**Not touched (scope fence):** any `scripts/brain/**` TS · any `hooks/scripts/**` · any tributary JSON · `architecture.md`/`brief.md` (arc-level "motor-only until S3" stays true until all of S3 lands) · `content-optimizer.md` (second reader, not S3a) · CLAUDE.md agent table (responsibility text unchanged — the count/model lint is unaffected; a note is optional and deferred to avoid churn).
## Step 1 — (RED) Lint: Section 16d + floor bump
Insert a new section after Section 16c (`test-runner.sh:780`, before Section 17 at `:782`), modelled byte-for-byte on 16c's idiom (literals + `*_wired()` + non-vacuity self-test + real-file grep with `grep -qF`):
- **Literals:** `READER_LIT='brain/profile.md'`, `ANTISYC_LIT='evidence to TEST'`.
- **`reader_wired()`** — text wired iff BOTH literals present (`grep -qF` each; echo twice as 16c does).
- **Check A (self-test, unconditional):** a fully-wired probe (`"reads brain/profile.md as evidence to TEST"`) MUST be detected; three under-wired probes MUST be rejected:
1. `"reads brain/profile.md but never frames how to weigh it"` (has reader lit, missing anti-syc)
2. `"treats facts as evidence to TEST but names no source file"` (has anti-syc, missing reader lit)
3. `"reads profile/user-profile.md and tests the evidence"` (decoy: legacy path + lowercase "evidence" — must NOT match either exact literal)
`pass`/`fail` "profile-reader self-test: full wiring detected; 3 under-wired forms rejected".
- **Check B (real-file grep, unconditional):** `grep -qF "$READER_LIT" agents/strategy-advisor.md && grep -qF "$ANTISYC_LIT" agents/strategy-advisor.md``pass` "strategy-advisor.md wired to brain profile reader (names '…profile.md', frames 'evidence to TEST')" else `fail`.
- **Header enumeration (`:19-35`):** add a sentence — "the brain profile-reader guard (SB-S3a: `strategy-advisor` names `brain/profile.md` AND carries the anti-sycophancy literal `evidence to TEST`, with a non-vacuity self-test) in Section 16d". Range "Sections 818" unchanged (16d is in range).
- **Floor (`:849-865`):** `ASSERT_BASELINE_FLOOR=78``80`; extend the history comment: "+2 for SB-S3a's two UNCONDITIONAL Section-16d checks (profile-reader self-test + strategy-advisor wiring grep) = 80." Both new checks are deps-free → they lift the deps-absent minimum, so the +2 bump is correct (NOT pinned to deps-present TOTAL).
- **Non-collisions (verified by plan-critic):** the new prose carries no algorithm-magnitude token (Section 8 stat-consistency safe) and no `Significant?(` column (Section 11 render-chain safe); `brain` is absent from Section 13's `BARE_DATA` regex (`test-runner.sh:514`) AND the edit uses the exempt `${LINKEDIN_STUDIO_DATA:-…}` external form → Section 13 data-dir guard safe. Agent count (19) + `strategy-advisor` model/frontmatter unchanged → Sections 2/9/10 unaffected.
**RED gate:** `bash scripts/test-runner.sh` → Check A passes, **Check B FAILS** (agent not yet wired), floor check passes (TOTAL 95 ≥ 80) → exit 1. This is the required failing test.
## Step 2 — (GREEN) Wire `strategy-advisor.md`
1. **Step 0 Load Context** (`strategy-advisor.md:41-47`): insert one line **inside** the fenced code block, immediately BEFORE the closing ``` fence (currently `:47`) — i.e. the new path becomes `:47` and the fence shifts to `:48`. Do NOT place it after the fence (that breaks the code block). The line:
`${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}/brain/profile.md → evolving second-brain profile (consolidated, evidence-weighted facts about the user)`
2. **New subsection** immediately after the Load Context block (after `:49`), e.g. `### Consuming the evolving profile (brain/profile.md)`:
- Two layers: `## Static` (stable, high-confidence) vs `## Dynamic` (emerging); each fact carries `evidence_count` + `last_seen` — weight by strength/recency.
- **Anti-sycophancy (binding):** "Treat every profile fact as **evidence to TEST**, not flatter — counter-pressure it against analytics/state each time (e.g. *the profile says you lean X, but your imports show Y — test that*). The profile informs; it never dictates or flatters." ← carries the exact literal `evidence to TEST`.
- **Graceful absence:** "If `brain/profile.md` is missing or empty (fresh installs have no brain yet), proceed silently on the other context sources — no error, no note about a missing profile."
**GREEN gate:** `bash scripts/test-runner.sh` → Check A + Check B pass, FAIL=0, **95/0/0**, brain floor 82 untouched.
## Step 3 — Doc reconciliation
`consolidation-loop.md:67-68` currently reads *"`brain/profile.md` has no reader yet … wiring content agents/commands to consume it is SB-S3."* — which becomes **false** the moment S3a lands a reader. **No lint guards `docs/`** (Section 11 scans `references/ commands/ skills/ hooks/prompts/ agents/ assets/` only, and `PROP_FORBIDDEN` matches only the significance-verdict column — verified by plan-critic; `grep consolidation-loop test-runner.sh` = 0 hits). So **EDIT the bullet** (it lives under "## Honest limits" — keep it a limit) to the true partial state, e.g.:
"**`brain/profile.md` has one reader as of SB-S3a.** S2 evolved the profile motor-only; SB-S3a wired the first consumer — `strategy-advisor` reads it as *evidence-to-test*. Broader consumption (more content agents, a hook-level digest) remains later S3 work, and the profile is still mutated only via `brain consolidate --apply --confirm`."
This removes the stale claim rather than appending a self-contradicting line beneath it.
## Step 4 — Behavioural verification (manual, recorded — SC4/SC5)
Agent-prompt behaviour is not unit-testable (operator-accepted). Honest procedure, result recorded in STATE/changelog at land:
- **SC4 (graceful absence):** with no/empty `brain/profile.md` at the data-root, the wiring degrades silently — verified by inspection of the subsection's graceful-absence clause + (best-effort) a strategy-advisor run on the empty real root → no missing-file noise.
- **SC5 (read-back works):** seed a temp profile (e.g. `LINKEDIN_STUDIO_DATA=<tmp> brain init` + a couple of hand-written facts) and run the agent → confirm ≥1 fact surfaces as tested evidence, counter-pressured, not parroted. If the harness cannot fully exercise a per-call data-root, record that honestly and fall back to inspection of the wiring + framing (do NOT overclaim a behavioural pass we did not run).
## Step 5 — Land
STATE "Telling" + "👉 NESTE" updated (S3a done → S3b/c/d remain); commit (Conventional, `[skip-docs]` on the code/feat parts; brief+plan+consolidation-loop are docs → judge suffix per the mixed change); **push only inside the window** (`date '+%u %H:%M'` first; `origin` is the PUBLIC `open/` remote → confirm before push). No version bump (S3a is additive within v0.5.2 dev; a release bump is a separate decision).
## Verification (testable)
| SC | Check | Command | Expected |
|----|-------|---------|----------|
| SC1+SC2 | reader wired + literal | `bash scripts/test-runner.sh` | Section 16d Check B passes |
| SC3 | gate green, brain floor intact | same run | 95/0/0; `BRAIN_TESTS_FLOOR=82` unchanged; hook suite (separate runner) untouched |
| SC6 | assertion floor honoured | same run | "assertion-count anti-erosion: 95 … >= floor 80" passes |
| (red proof) | failing-test-first | gate run BETWEEN Step 1 and Step 2 | exit 1, exactly Check B fails |
| SC4 | graceful absence | manual run, empty root | clean output, no missing-file noise |
| SC5 | read-back | manual run, seeded profile | ≥1 fact surfaced as evidence-to-test (or honest fallback recorded) |
## Risks
- **R1 — vacuous lint.** Mitigated by the 16c-style non-vacuity self-test with the legacy-path/lowercase decoy.
- **R2 — floor false-fail on fresh clone.** Mitigated: both new checks are deps-free (lift the deps-absent minimum), so +2 → 80 is the correct floor; not pinned to deps-present TOTAL.
- **R3 — behavioural overclaim.** Mitigated by Step 4's honest-fallback clause (verifiseringsplikt): never report a behavioural pass we did not run.
- **R4 — stale doc claim.** `consolidation-loop.md:67` ("no reader yet") becomes false once S3a lands; **no automated guard protects `docs/`** (Section 11 scans non-docs dirs + only the significance column — verified). Mitigated by EDITING :67 to the true partial state (one reader, broader consumption deferred) within the "Honest limits" framing — by discipline, not by a blind append.