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

9.6 KiB
Raw Permalink Blame History

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.mdpass "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=7880; 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.