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
9.6 KiB
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 -qFeach; 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:"reads brain/profile.md but never frames how to weigh it"(has reader lit, missing anti-syc)"treats facts as evidence to TEST but names no source file"(has anti-syc, missing reader lit)"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')" elsefail. -
Header enumeration (
:19-35): add a sentence — "the brain profile-reader guard (SB-S3a:strategy-advisornamesbrain/profile.mdAND carries the anti-sycophancy literalevidence to TEST, with a non-vacuity self-test) in Section 16d". Range "Sections 8–18" 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);brainis absent from Section 13'sBARE_DATAregex (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-advisormodel/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
- 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:47and 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) - 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 carriesevidence_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.mdis missing or empty (fresh installs have no brain yet), proceed silently on the other context sources — no error, no note about a missing profile."
- Two layers:
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.mdat 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 protectsdocs/(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.