linkedin-studio/docs/second-brain/plan-sb-s3d.md
Kjell Tore Guttormsen 0061bf2bb5 docs(linkedin-studio): SB-S3d brief + plan — ops centre (operations.md reader, light-Voyage hardened)
Splits the old S3d charter: S3d = ops centre ONLY (operations.md becomes a
read tributary; strategy-advisor honours the dated frozen-past-self anchor
that deprecates older inferences — advisory/reader-side). The hygiene +
triple-post reconciliation half (dead content-history.md retirement +
post-tracking↔published↔analytics) moves to a new SB-S3e (the last S3 slice).

Light-Voyage hardening: scope-guardian ALIGNED (0 creep/gap); brief-reviewer
REVISE (5 FIX folded); plan-critic 3 major + 3 minor folded. Baselines
verified live: gate 95→97, brain 113→114, ASSERT floor 80→82. The RED-bearing
brain-test literal is pinned to the dated-anchor convention (_As of YYYY-MM-DD:_,
verified absent) — NOT 'deprecates older inferences', which already ships in
the seed comment and would make the RED gate vacuous.

Go-before-code gate pending (forks: Option B enrich seed · advisory deprecation
· one reader · doc home).

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

16 KiB
Raw Blame History

Plan — SB-S3d: wire the operations centre (operations.md READER + dated anchor)

Brief: docs/second-brain/brief-sb-s3d.md. Slice: SB-S3d (ops centre only; hygiene+reconciliation → SB-S3e). Operator confirmed (2026-06-23): Split, ops-centre first. Recommendations pending the go-gate: Option B (enrich seed) + advisory deprecation + one reader (strategy-advisor). Order is TDD: the failing lint/seed checks land BEFORE the agent/seed edits (iron law).

Goal

strategy-advisor reads brain/operations.md and honours the dated frozen-past-self anchor — preferring it over older/contradicting profile facts (the guard, advisory) — guarded by a deterministic wiring lint, with an enriched seed that ships the dated-anchor convention. No engine write, no post-silo contact, no parser.

Files touched (exhaustive — for scope-guardian)

File Change Why
scripts/test-runner.sh NEW Section 16e (2 unconditional checks) + bump ASSERT_BASELINE_FLOOR 80→82 + extend the Section-18 history comment + header enumeration (:33-36) SC1/SC2/SC5 — the TDD anchor
scripts/brain/tests/scaffold.test.ts NEW test() asserting the dated-anchor seed convention (Option B) SC3 — fails first (RED)
scripts/brain/src/scaffold.ts enrich operationsSeed() (:52-64): dated-anchor convention + light Plans/Ideas guidance SC3 — makes the guard operational
agents/strategy-advisor.md add brain/operations.md to Step 0 Load-Context (:41-48) + a consumption subsection after :63 (anchor authoritative + deprecates older inferences literal + graceful absence) SC1/SC2/SC6/SC7 — the wiring
docs/second-brain/architecture.md edit the SB-S3 build-row (:80) to the post-split truth (S3d ops · S3e remains hygiene+reconciliation) doc reconciliation

Not touched (scope fence): any post silo (hooks/scripts/state-updater.mjs, ## Recent Posts, content-history*, analytics, tributary JSON) — that is S3e · consolidate.ts/assemble.ts/ingest.ts/cli.ts (no engine/graph change; advisory guard only) · consolidation-loop.md (profile-motor contract, not this loop) · content-planner.md (second reader, not S3d) · CLAUDE.md agent table (count/model lint unaffected — no new agent, frontmatter unchanged) · Section 16d (the profile reader stays exactly as-is).

Step 1 — (RED) Lint: Section 16e + floor bump

Insert a new section after Section 16d (test-runner.sh:833, before Section 17 at :834), modelled byte-for-byte on 16d's idiom (two exact literals + *_wired() + non-vacuity self-test + real-file grep with grep -qF):

  • Literals: OPS_LIT='brain/operations.md', ANCHOR_LIT='deprecates older inferences'.
  • ops_reader_wired() — wired iff BOTH literals present. Pin the body VERBATIM from 16d (test-runner.sh:802), grep -qF (fixed-string — OPS_LIT contains .//, so -F is mandatory or the . is a regex wildcard): echo "$1" | grep -qF "$OPS_LIT" && echo "$1" | grep -qF "$ANCHOR_LIT" (echo twice — grep consumes stdin).
  • Check A (self-test, unconditional): a fully-wired probe ("reads brain/operations.md; the anchor deprecates older inferences") MUST be detected; three under-wired probes MUST be rejected:
    1. reads brain/operations.md but never says the anchor outranks anything (file lit, missing anchor lit)
    2. the anchor deprecates older inferences but names no source file (anchor lit, missing file lit)
    3. reads brain/profile.md and tests the evidence (sibling-file decoy — names the OTHER brain file + no anchor lit; must NOT match either operations literal) → pass/fail "ops-reader self-test: full wiring detected; 3 under-wired forms rejected (incl. sibling-file brain/profile.md decoy)".
  • Check B (real-file grep, unconditional): grep -qF "$OPS_LIT" agents/strategy-advisor.md && grep -qF "$ANCHOR_LIT" agents/strategy-advisor.mdpass "strategy-advisor.md wired to brain operations reader (names '…operations.md', frames 'deprecates older inferences')" else fail.
  • Header enumeration (:33-37): insert the 16e clause immediately after "…with a non-vacuity self-test) in Section 16d;" (mid-:36), BEFORE the "the assertion-count anti-erosion floor (SC6) in Section 18. All are live below (Sections 818)." tail — preserving the 16d → 16e → 18 ordering. Clause: "the brain operations-reader guard (SB-S3d: strategy-advisor names brain/operations.md AND carries the frozen-past-self literal deprecates older inferences, with a non-vacuity self-test) in Section 16e;". The "Sections 818" range is unchanged (16e is in range).
  • Floor (:905-913): ASSERT_BASELINE_FLOOR=8082; extend the history comment: "+2 for SB-S3d's two UNCONDITIONAL Section-16e checks (ops-reader self-test + strategy-advisor ops-wiring grep) = 82." Both new checks are deps-free → they lift the deps-absent minimum, so +2 is correct (NOT pinned to deps-present TOTAL).

Non-collisions (verify with plan-critic): new prose carries no algorithm-magnitude token (Section 8 stat-consistency safe) and no Significant?( column (Section 11 render-chain safe); 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; Section 16d's two literals remain present in the (unchanged) profile subsection.

Step 2 — (RED) Brain seed test (Option B)

In scripts/brain/tests/scaffold.test.ts, add ONE new test() (bumps the suite count → floor +1) asserting the enriched seed — e.g. test("operations.md ships a dated frozen-past-self anchor convention", ...):

  • initBrain(), read brain/operations.md.
  • The single RED-bearing assertion is the date convention, which is verified ABSENT from the current seed (grep "As of" scaffold.ts = 0 → the test fails first): assert.match(ops, /_As of YYYY-MM-DD:_/) (or /As of/ — but the underscore form is the exact seed literal).
  • Do NOT assert deprecates older inferences as the failing literal — it ALREADY ships in the current seed comment (scaffold.ts:58, verified grep -c = 1), so it passes pre-enrichment and would make the RED gate vacuous. It may be asserted only as an explicit non-RED companion (documented as such), or omitted.
  • Keep matching the existing Who I am now / ## Plans / ## Ideas anchors so the new case is a strict superset of the old guarantee.
  • Leave the existing 5 tests untouched (the no-clobber test at :70-77 already proves idempotency of the new seed).
  • Baseline (verified live, 2026-06-23): brain suite reports tests 113 and the gate reports 95 checks — so the floor becomes recorded + 1 = 114 (not a hardcoded guess) and the gate goes 95→97.

RED proof (recorded): (cd scripts/brain && npm test) against the un-enriched seed → the new test FAILS (no _As of in the seed yet). bash scripts/test-runner.sh → Section 16e Check A passes, Check B FAILS (agent not yet wired), floor self-count passes (TOTAL 96 ≥ 82). Capture this failing output in STATE/changelog as the iron-law artifact. This is the required failing state.

Step 3 — (GREEN) Enrich the seed

In scripts/brain/src/scaffold.ts, rewrite operationsSeed() (:52-64, the full function incl. the closing brace at :64 — body string is :53-63) to ship the dated-anchor convention + light guidance. Load-bearing: the rewrite MUST retain ## Who I am now, ## Plans, and ## Ideas verbatim — the existing anchor test scaffold.test.ts:48-58 asserts all three, so dropping one regresses that test. Idempotency is untouched: initBrain existence-skips (writes a seed only when the file is absent, scaffold.ts:105-113), so the new seed string never reaches an already-created operations.md. Sketch:

function operationsSeed(): string {
  return `# Operations

> The operations centre — where you're headed now, what you're working on, what you might do next.
> User-authored: the brain motor never writes here (a \`brain init\` re-run never clobbers your edits).

## Who I am now (anchor)

<!-- Frozen-past-self guard: a DATED, user-authored "where I'm headed now" statement.
     It DEPRECATES older inferences — when a profile.md fact predates or contradicts this
     anchor, the anchor wins. Re-date it when your direction shifts. -->

_As of YYYY-MM-DD:_ <one or two sentences on your current direction>

## Plans

<!-- Active commitments — what you're working toward now. One per line. -->

## Ideas

<!-- Parking lot — possible content/strategy ideas, not yet commitments. One per line. -->
`;
}

GREEN gate (brain): (cd scripts/brain && npm test) → new test passes; suite reports tests 114 (verified baseline 113 + 1); bump BRAIN_TESTS_FLOOR 113→114 (test-runner.sh:716) + extend its inline breakdown comment ("+ SB-S3d 1 [scaffold dated-anchor seed]"). The no-clobber test (scaffold.test.ts:70-77) runs in this same gate and must stay green.

Step 4 — (GREEN) Wire strategy-advisor.md

  1. Step 0 Load Context (strategy-advisor.md:41-48): insert one line INSIDE the fenced block, immediately before the closing ``` fence (:48), after the profile line (:47): ${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}/brain/operations.md → the operations centre: dated "who I am now" anchor + plans + ideas (user-authored)
  2. New subsection immediately after the profile subsection's graceful-absence line (:63), e.g. ### Consuming the operations centre (brain/operations.md):
    • Anchor is authoritative: "The ## Who I am now anchor is the user's own dated declaration of current direction. It is authoritative and deprecates older inferences: when a brain/profile.md Dynamic fact predates the anchor's date or contradicts its stated direction, prefer the anchor and flag the older fact as possibly-stale — do not parrot it." ← carries the exact literal deprecates older inferences.
    • Inversion (make the contrast explicit): "Unlike profile facts, which you treat as evidence to TEST, the anchor is user-declared direction, not an inference to challenge — honour it. (It is direction, not praise; honouring it never licenses flattery.)"
    • Plans / Ideas: "## Plans are active commitments (current intent); ## Ideas are a parking lot (suggestions, not commitments) — weigh accordingly."
    • Graceful absence: "If brain/operations.md (or its anchor) is missing or empty, proceed silently on the other context sources — no error, no note about a missing ops centre."

GREEN gate (lint): bash scripts/test-runner.sh → Section 16e Check A + Check B pass, FAIL=0, 97/0/0, ASSERT floor 82 honoured. (16d still green — profile literals untouched.)

Step 5 — Doc reconciliation

Edit architecture.md:80 (the SB-S3 build-row) so the post-split status is true: S3a/b/c as today, then "S3d ops centreoperations.md is a read tributary; strategy-advisor honours the dated anchor that deprecates older inferences (advisory). S3e remains — dead content-history.md retirement + triple-post (post-tracking↔published↔analytics) reconciliation." No other architecture edit (the §59 guard spec already stands; the §80 row was the stale claim).

Step 6 — Behavioural verification (manual, recorded — SC6/SC7)

Agent-prompt behaviour is not unit-testable (operator-accepted). Honest procedure, result recorded in STATE/changelog at land:

  • SC6 (graceful absence): with no brain/operations.md at the data-root, the wiring degrades silently — inspect the subsection's graceful-absence clause + (best-effort) a strategy-advisor run on an empty root → no missing-file noise.
  • SC7 (guard fires): seed a temp root (LINKEDIN_STUDIO_DATA=<tmp> brain init), write a dated anchor (_As of 2026-06-20:_ pivoting from X to Z) and a contradicting older profile fact (leans toward X, last_seen < 2026-06-20) → run the agent → confirm it prefers the anchor (Z) and flags the older X fact as deprecated, not parroted. If the harness cannot exercise a per-call data-root, record that honestly and fall back to inspection of the wiring + framing (no overclaim).

Step 7 — Land

STATE "Telling" + "👉 NESTE" updated (S3d done → S3e is the new last slice); commit. Mixed change: the seed/agent/lint are code → [skip-docs] judged per the repo convention; brief+plan+architecture are docs. Push only inside the window (date '+%u %H:%M' first; origin = PUBLIC open/ → confirm before push). No version bump (S3d additive within v0.5.2 dev; release is a separate decision).

Verification (testable)

SC Check Command Expected
SC1+SC2 ops reader wired + literal bash scripts/test-runner.sh Section 16e Check B passes
SC3 seed convention (cd scripts/brain && npm test) new test passes; floor 114
SC4 gate green bash scripts/test-runner.sh 97/0/0; 16d still green; hook suite (separate runner) untouched
SC5 assertion floor same run "anti-erosion: 97 … >= floor 82" passes
(red proof) failing-test-first gate run BETWEEN Step 1/2 and Step 3/4 exit 1: scaffold test fails (Step 2), 16e Check B fails (Step 1)
SC6 graceful absence manual, empty root clean output, no missing-file noise
SC7 guard fires manual, seeded anchor+stale fact anchor wins, older fact flagged (or honest fallback recorded)

Risks

  • R1 — vacuous lint. Mitigated by the 16d-style non-vacuity self-test with the sibling-file (brain/profile.md) + "outranks anything" decoys.
  • R2 — floor false-fail on fresh clone. Both new lint checks are deps-free (lift the deps-absent minimum) → +2 → 82 correct, not pinned to deps-present TOTAL. The brain floor (114) only checked when the brain suite runs (deps-present); a fresh clone warn-skips it (unchanged mechanism).
  • R3 — behavioural overclaim. Step 6 honest-fallback clause (verifiseringsplikt): never report a guard-fires pass not actually run.
  • R4 — anti-sycophancy weakening. The anchor's "authoritative" stance must not read as "flatter the user." Mitigated by the explicit "direction, not praise" clause + the profile evidence to TEST stance staying verbatim (Section 16d unchanged, still grepped).
  • R5 — seed breaks idempotency. Mitigated: the enriched seed is still a static string; scaffold.test.ts:70-77 (no-clobber) stays green and is run in Step 3's GREEN gate.
  • R6 — stale §80 doc. The build-row claim "S3d remains (ops + hygiene + reconciliation)" becomes false at land; mitigated by EDITING :80 to the split truth (no automated guard covers architecture.md; Section 11 scans non-docs dirs only).

Plan-critic — folded

voyage:plan-critic (no blockers; 3 major + 3 minor) folded above:

  • Major-1 — vacuous brain RED: the seed already ships deprecates older inferences (scaffold.ts:58), so the RED-bearing literal must be the date convention _As of YYYY-MM-DD:_ (verified absent). Folded into Step 2.
  • Major-2 — unverified brain floor: recorded the live count (tests 113) → floor = recorded + 1 = 114, not a hardcoded guess. Folded into Step 2/3.
  • Major-3 — grep -qF fixed-string: pinned the ops_reader_wired() body verbatim from test-runner.sh:802 (-F mandatory — OPS_LIT has .//). Folded into Step 1.
  • Minor-1 — header range: corrected to :33-37; the 16e clause inserts after "…in Section 16d;", before the SC6/Section-18 tail. Folded into Step 1.
  • Minor-2 — function range: cite operationsSeed() as :52-64 incl. the closing brace (body :53-63). Folded into Step 3.
  • Minor-3 — retained anchors: the three ## anchors are load-bearing for scaffold.test.ts:48-58; the rewrite retains them verbatim. Folded into Step 3.

Cross-checks the critic confirmed sound: floor arithmetic (ASSERT 80→82, BRAIN 113→114), the 3 decoys each miss ≥1 literal, the sibling-file decoy brain/profile.md cannot match OPS_LIT, Section 16d stays green (profile literals untouched; the new subsection adds a second evidence to TEST occurrence, harmless), and no collision with Sections 8/11/13.