# Brief — SB-S3a: the first profile.md READER

> **Slice:** SB-S3a (first sub-slice of SB-S3, the cross-silo + ops-centre arc step).
> **Status:** LANDED `4fa411f` (2026-06-23) — gate 95/0/0, `ASSERT_BASELINE_FLOOR` 80. Light-Voyage-hardened (brief-review APPROVE · scope-guardian ALIGNED · plan-critic REVISE→folded). SC1/2/3/6 gate-proven; SC4 inspection-pass; SC5 (read-back) deferred to a reloaded session.
> **Predecessors:** SB-S0 (id/profile substrate) · SB-S1 (published-gold ingest) · SB-S2 (consolidation motor — *motor-only, no reader*).

## 1. Operator decision (2026-06-23)

SB-S3 is the arc's largest slice and was decomposed into four sub-slices (value-first / risk-managed): **S3a reader · S3b supersede · S3c cross-silo id-threading · S3d hygiene+ops**. The operator picked **S3a — the profile.md reader — first**, and within S3a the first reader is **one agent: `strategy-advisor`**, wired **READ-only**.

## 2. Why a reader, and why first

The whole arc was built *"so S3's reader inherits rich data"* (`consolidation-loop.md:67`). S2 grows `brain/profile.md` but **no agent or command consumes it today** — verified: 0 references to `brain/profile.md` in `agents/`/`commands/`; every "profile" hit points at the *legacy* flat `profile/user-profile.md`, not the SB-S0 two-layer brain profile. The reader is the deferred payoff of S0→S2: it turns a motor-only system into one that **feeds content generation** — the first end-to-end proof of capture → consolidate → read-back-into-generation.

It is first because it has **no dependency on id-threading** (it reads the profile *facts*, not the cross-silo graph), it is **additive / non-breaking**, and it is the **lowest-risk** of the four (read-only consumption of an existing file).

## 3. Scope — what is IN (S3a)

1. **Wire `strategy-advisor` to read `brain/profile.md`.** Add the brain profile to the agent's existing **Step 0: Load Context** list:
   `${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}/brain/profile.md`
   The agent reads the markdown in-context and reasons over it — no parser, consistent with the arc thesis (Claude *is* the retrieval engine; `architecture.md:14`).

2. **Consumption contract (how the agent uses it).** A short subsection in the agent prompt that tells it:
   - The profile has two layers — `## Static` (stable, high-confidence) and `## Dynamic` (emerging) — and each fact line carries `evidence_count` + `last_seen`. Higher `evidence_count` / more recent `last_seen` = stronger/fresher signal; weight accordingly.
   - **Anti-sycophancy (binding, `architecture.md:58`):** treat every profile fact as *evidence to TEST, not flatter*. Counter-pressure it against analytics/state each time it is used (e.g. "the profile says you lean X, but your last imports show Y — test that"). The profile informs, it never dictates or flatters.

3. **Graceful absence.** `brain/profile.md` does not exist until `brain init` runs (fresh installs have no brain). The agent must **degrade silently** when the file is missing or empty — no error, no "I couldn't find your profile" noise; it simply proceeds on its other context sources.

4. **A deterministic wiring test** in the structure-lint / `test-runner.sh` gate: two UNCONDITIONAL assertions — (a) `strategy-advisor.md`'s context-load declares `brain/profile.md`; (b) the agent carries the anti-sycophancy sentinel **literal `evidence to TEST`** (exact-literal grep + a non-vacuity self-test, per the repo lint idiom in `test-runner.sh` Sections 13/16c — loose patterns match vacuously). This is the TDD anchor (see §6) and protects the wiring against future agent-file edits.
   - **Assertion-floor lockstep (binding):** the two new checks are UNCONDITIONAL, so `ASSERT_BASELINE_FLOOR` in `test-runner.sh` (Section 18; currently **78** — verify at plan time) must be bumped by exactly +2 → **80** in the same change, per the assertion-erosion guard. Do NOT pin to a deps-present TOTAL.

5. **Doc/count reconciliation.** Update the binding counts/docs touched (CLAUDE.md agent table note if needed, STATE telling, `consolidation-loop.md` reader-status line: "S3a wires the first reader — `strategy-advisor`").

## 4. Non-goals — what is OUT (deferred to later S3 sub-slices)

- **More than one reader.** `content-optimizer` is the obvious second reader and the pattern generalizes trivially, but S3a wires **exactly one** agent — the smallest valuable proof. Follow-on readers are separate work.
- **A hook-level / `user-prompt-context.mjs` digest reader.** A broad "inject a profile digest into every prompt" reader is attractive but carries a twin `.mjs` parser (twin-sync with `profile.ts`) + per-prompt context cost — *not* a good first proof. Deferred.
- **Cross-silo id-threading (S3c).** The reader consumes profile facts, not the post↔specific↔trend↔analytics graph. No `mintEntityId` threading here.
- **Supersede arm (S3b)**, **content-history retirement / triple-post reconciliation + operations.md (S3d)** — separate sub-slices.
- **Any WRITE to `brain/profile.md`.** The profile is mutated ONLY via `brain consolidate --apply --confirm` (operator-gated). S3a is strictly read-only; it adds no write path.
- **A new parser or new `.mjs`.** S3a is markdown-agent edits + a lint assertion only.

## 5. Boundaries / invariants (must hold)

- **READ-only** — S3a never writes the profile; the `--apply --confirm` gate stays the sole writer.
- **Anti-sycophancy is a built-in default, not a toggle** (`architecture.md:58`).
- **Provenance spine intact** — the profile already encodes provenance; the reader must not undermine the published-only learning guard.
- **No tributary schema changes** (that's S3c).
- **Fresh-clone safe** — missing brain → silent degrade, no crash, no nag from the agent.
- **TDD iron law** — the failing wiring test lands before the agent edit.

## 6. Success criteria (testable)

- **SC1 — wired:** `strategy-advisor.md` Step 0 context-load includes `brain/profile.md`. *(lint assertion, deterministic)*
- **SC2 — anti-sycophancy framed:** `strategy-advisor.md`'s profile-consumption subsection contains the exact durable sentinel literal **`evidence to TEST`**, asserted by an exact-literal grep + a non-vacuity self-test (repo idiom, `test-runner.sh` §§13/16c). *(lint assertion)*
- **SC3 — gate green:** `scripts/test-runner.sh` (the structure lint) stays green with the new assertions; its `BRAIN_TESTS_FLOOR` (82) is unchanged — no brain TS is touched. The hook suite (~136) runs under the **separate** `node --test hooks/scripts/__tests__/*.test.mjs` runner (NOT part of `test-runner.sh`) and is untouched because no hook code path changes.
- **SC6 — assertion floor honoured:** `ASSERT_BASELINE_FLOOR` bumped by exactly the number of new unconditional checks (+2 → 80); the gate's self-count check passes.
- **SC4 — graceful absence (manual/behavioural):** running `strategy-advisor` with **no** `brain/profile.md` produces normal output, no error/noise about the missing file.
- **SC5 — read-back works (manual/behavioural):** running `strategy-advisor` with a **populated** `brain/profile.md` surfaces ≥1 profile fact as *evidence-to-test* in its recommendation, counter-pressured against analytics/state — not parroted.

## 7. Verification

- **Deterministic (gate):** SC1–SC3 via the structure-lint assertion in `test-runner.sh`. `cd scripts/brain` not required — this is an agent-file + lint change; brain TS is untouched.
- **Behavioural (manual, documented):** SC4 + SC5 — the honest limit. Agent-prompt behaviour is not unit-testable (the plugin's command-testing workstream is still open). The plan must include a documented manual run: (a) empty-brain run → clean output; (b) populated-brain run (seed via `brain init` + a `--apply --confirm` cycle, or a fixture profile) → confirm a profile fact appears as tested evidence. Record the result in STATE/changelog at land.

## 8. Open questions for brief-review / the operator

1. **Agent choice:** `strategy-advisor` recommended; operator may redirect to `content-optimizer` (post-level grounding) — confirm at the brief gate.
2. **Lint location:** which existing lint file in the `test-runner.sh` gate hosts the SC1/SC2 assertion (plan resolves precisely).
3. **Behavioural test honesty:** is the documented manual verification (SC4/SC5) acceptable for S3a's land, given agent-behaviour is not unit-testable — or does the operator want a fixture-driven harness scoped in (larger)?

## 9. Brief-review (light-Voyage) — folded

`voyage:brief-reviewer` verdict: **APPROVE** (scope crisp, non-goals correct, invariants inherited, deterministic-vs-behavioural split honest). Three [FIX]es folded above:
- SC3 no longer conflates two runners (brain-82 floor in `test-runner.sh` vs the separate hook runner). ✅
- `ASSERT_BASELINE_FLOOR` lockstep bump (+2 → 80) made binding in §3.4 + SC6. ✅
- SC2 pinned to the exact literal `evidence to TEST` + non-vacuity self-test (anti-vacuity idiom). ✅

Reviewer confirmed: `strategy-advisor` is the better first reader than `content-optimizer`; SC4/SC5 manual split is correct; do NOT scope a behavioural harness into S3a (keeps "smallest valuable proof").
