feat(linkedin-studio): SB-S3a — wire strategy-advisor as first brain/profile.md reader [skip-docs]
The second brain now feeds generation: strategy-advisor reads brain/profile.md as evidence-to-test (anti-sycophancy default, graceful absence on fresh installs). First end-to-end proof of capture → consolidate → read-back-into-generation. - agents/strategy-advisor.md: brain/profile.md added to Step 0 Load Context + a consumption subsection (Static/Dynamic layers, evidence_count/last_seen weighting, anti-sycophancy counter-pressure, silent degrade when the file is absent). - scripts/test-runner.sh: new Section 16d (Brain Profile Reader) — 2 UNCONDITIONAL checks (non-vacuity self-test with legacy-path/lowercase decoy + exact-literal wiring grep on strategy-advisor.md), ASSERT_BASELINE_FLOOR 78→80, header enumeration extended. Gate 93→95/0/0; brain floor 82 untouched. - docs/second-brain/consolidation-loop.md: reconciled the stale "no reader yet" honest-limit to the true partial state (one reader; broader consumption deferred). TDD: RED (only the wiring grep failed, exit 1) → GREEN (95/0/0). READ-only — the brain consolidate --apply --confirm gate stays the sole writer. SC4 (graceful absence) verified by inspection; SC5 (read-back) deferred to a reloaded session (honest — agent prompts load at session start). S3a scope held: one reader, no parser, no id-threading. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RigJBiRFNtFZKCz21qNbQ4
This commit is contained in:
parent
fbfbf71cdd
commit
4fa411f13c
3 changed files with 76 additions and 6 deletions
|
|
@ -44,10 +44,24 @@ ${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}/audience-insights/engagem
|
||||||
${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}/examples/high-engagement-posts.md → proven patterns from top posts
|
${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}/examples/high-engagement-posts.md → proven patterns from top posts
|
||||||
${CLAUDE_PLUGIN_ROOT}/references/trajectory-strategy-adjustments.md → trajectory-to-action mappings
|
${CLAUDE_PLUGIN_ROOT}/references/trajectory-strategy-adjustments.md → trajectory-to-action mappings
|
||||||
~/.claude/linkedin-studio.local.md → user state + posting history
|
~/.claude/linkedin-studio.local.md → user state + posting history
|
||||||
|
${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}/brain/profile.md → evolving second-brain profile (consolidated, evidence-weighted facts about the user)
|
||||||
```
|
```
|
||||||
|
|
||||||
Use demographics data to compare the user's **intended** audience vs **actual** engagers when making strategic recommendations.
|
Use demographics data to compare the user's **intended** audience vs **actual** engagers when making strategic recommendations.
|
||||||
|
|
||||||
|
### Consuming the evolving profile (brain/profile.md)
|
||||||
|
|
||||||
|
The second-brain profile is a consolidated, evidence-weighted picture of the user, grown over time by the brain motor (mutated ONLY via `brain consolidate --apply --confirm` — you never write it). It has two layers:
|
||||||
|
|
||||||
|
- **`## Static`** — stable, high-confidence facts about the user.
|
||||||
|
- **`## Dynamic`** — emerging facts still accruing evidence.
|
||||||
|
|
||||||
|
Each fact line carries `evidence_count` and `last_seen`. Weight by strength and recency: a higher `evidence_count` and a more recent `last_seen` are a stronger, fresher signal than a thin or stale one.
|
||||||
|
|
||||||
|
**Anti-sycophancy (binding):** Treat every profile fact as **evidence to TEST**, not flattery — counter-pressure it against the analytics and state each time you use it (e.g. *the profile says you lean toward X, but your recent imports show Y — test that before recommending*). The profile informs your recommendations; it never dictates them and never flatters the user.
|
||||||
|
|
||||||
|
**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, and no note about a missing profile.
|
||||||
|
|
||||||
### New Creator Advantage Detection
|
### New Creator Advantage Detection
|
||||||
|
|
||||||
From the state file, extract `first_post_date`. Calculate the creator window status:
|
From the state file, extract `first_post_date`. Calculate the creator window status:
|
||||||
|
|
|
||||||
|
|
@ -64,8 +64,10 @@ Defaults: `promoteThreshold = 3`, `decayDays = 90` (operator-confirmed).
|
||||||
- **The loop's value depends on the session's extraction.** The engine only guarantees threshold/conflict/
|
- **The loop's value depends on the session's extraction.** The engine only guarantees threshold/conflict/
|
||||||
decay/provenance mechanics. Garbage candidates → a garbage diff. The operator gate + candidate-shape
|
decay/provenance mechanics. Garbage candidates → a garbage diff. The operator gate + candidate-shape
|
||||||
validation catch shape errors, not insight quality.
|
validation catch shape errors, not insight quality.
|
||||||
- **`brain/profile.md` has no reader yet.** S2 evolves the profile; wiring content agents/commands to
|
- **`brain/profile.md` has one reader as of SB-S3a.** S2 evolved the profile motor-only; SB-S3a wired the
|
||||||
*consume* it is SB-S3. The value is deferred: the profile compounds now so S3's reader inherits rich data.
|
first consumer — `strategy-advisor` reads it as *evidence-to-test* (anti-sycophancy: counter-pressured, never
|
||||||
|
parroted). Broader consumption (more content agents, a hook-level prompt digest) remains later S3 work, and
|
||||||
|
the profile is still mutated ONLY via `brain consolidate --apply --confirm`.
|
||||||
- **No supersede / no auto-demotion.** Conflicts keep both; stale facts are flagged, never auto-removed —
|
- **No supersede / no auto-demotion.** Conflicts keep both; stale facts are flagged, never auto-removed —
|
||||||
the operator (or S3) reconciles. Conflict alt facts persist until then.
|
the operator (or S3) reconciles. Conflict alt facts persist until then.
|
||||||
- **No AI at session-start.** The nudge is a deterministic file-count + sidecar read; the consolidation
|
- **No AI at session-start.** The nudge is a deterministic file-count + sidecar read; the consolidation
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,10 @@
|
||||||
# findings through it — KTG-only, skipped for an adopter shipping no deps) in Section
|
# findings through it — KTG-only, skipped for an adopter shipping no deps) in Section
|
||||||
# 16; the trend-spotter de-niche guard (B-S1: agents/trend-spotter.md names no
|
# 16; the trend-spotter de-niche guard (B-S1: agents/trend-spotter.md names no
|
||||||
# hardcoded vendor/sector beat — the domain comes from the user's pillars at runtime,
|
# hardcoded vendor/sector beat — the domain comes from the user's pillars at runtime,
|
||||||
# never baked into the agent — with a non-vacuity self-test) in Section 17; the
|
# never baked into the agent — with a non-vacuity self-test) in Section 17; the brain
|
||||||
# assertion-count anti-erosion floor (SC6) in Section 18. All are live below
|
# 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; the assertion-count anti-erosion floor (SC6) in Section 18. All are live below
|
||||||
# (Sections 8–18).
|
# (Sections 8–18).
|
||||||
#
|
#
|
||||||
# Usage: bash scripts/test-runner.sh
|
# Usage: bash scripts/test-runner.sh
|
||||||
|
|
@ -779,6 +781,56 @@ fi
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
|
# --- Section 16d: Brain Profile Reader (SB-S3a) ---
|
||||||
|
echo "--- Brain Profile Reader ---"
|
||||||
|
|
||||||
|
# SB-S3a wires the FIRST reader of the evolving second-brain profile: strategy-advisor
|
||||||
|
# must (a) name brain/profile.md as a context source AND (b) carry the anti-sycophancy
|
||||||
|
# literal 'evidence to TEST' (architecture.md:58 — the profile informs, it never dictates
|
||||||
|
# or flatters; every fact is counter-pressured against analytics/state). Both literals
|
||||||
|
# are required, grepped EXACT with grep -F: a loose 'profile' pattern would match the
|
||||||
|
# legacy flat profile/user-profile.md vacuously, and a loose lowercase 'evidence' would
|
||||||
|
# match generic prose. Non-vacuity self-test mirrors Sections 8/13/16c/17: a probe counts
|
||||||
|
# as "wired" iff it carries BOTH exact literals; probes missing either (incl. a decoy
|
||||||
|
# naming the legacy path + lowercase "evidence") must NOT count as wired. The wiring is
|
||||||
|
# gate-enforced; the agent's runtime OBEDIENCE is verified manually (SC4/SC5 at land —
|
||||||
|
# agent-prompt behaviour is not unit-testable; the brief states this honestly).
|
||||||
|
READER_LIT='brain/profile.md'
|
||||||
|
ANTISYC_LIT='evidence to TEST'
|
||||||
|
|
||||||
|
reader_wired() { # $1 = text; wired iff BOTH literals present (echo twice — grep consumes stdin)
|
||||||
|
echo "$1" | grep -qF "$READER_LIT" && echo "$1" | grep -qF "$ANTISYC_LIT"
|
||||||
|
}
|
||||||
|
|
||||||
|
READER_SELFTEST_OK=1
|
||||||
|
if ! reader_wired "reads brain/profile.md as evidence to TEST"; then
|
||||||
|
READER_SELFTEST_OK=0; echo " non-vacuity FAIL: a fully-wired probe was not detected"
|
||||||
|
fi
|
||||||
|
while IFS= read -r probe; do
|
||||||
|
[ -z "$probe" ] && continue
|
||||||
|
if reader_wired "$probe"; then
|
||||||
|
READER_SELFTEST_OK=0; echo " false-positive FAIL: under-wired probe accepted -> $probe"
|
||||||
|
fi
|
||||||
|
done <<'NEGATIVE16D'
|
||||||
|
reads brain/profile.md but never frames how to weigh it
|
||||||
|
treats facts as evidence to TEST but names no source file
|
||||||
|
reads profile/user-profile.md and tests the evidence
|
||||||
|
NEGATIVE16D
|
||||||
|
if [ "$READER_SELFTEST_OK" -eq 1 ]; then
|
||||||
|
pass "profile-reader self-test: full wiring detected; 3 under-wired forms rejected (incl. legacy-path + lowercase 'evidence' decoy)"
|
||||||
|
else
|
||||||
|
fail "profile-reader self-test failed — the reader-wiring lint is vacuous or over-eager"
|
||||||
|
fi
|
||||||
|
|
||||||
|
SA="agents/strategy-advisor.md"
|
||||||
|
if grep -qF "$READER_LIT" "$SA" && grep -qF "$ANTISYC_LIT" "$SA"; then
|
||||||
|
pass "strategy-advisor.md wired to brain profile reader (names '$READER_LIT', frames '$ANTISYC_LIT')"
|
||||||
|
else
|
||||||
|
fail "strategy-advisor.md missing brain profile reader wiring — needs both '$READER_LIT' and '$ANTISYC_LIT'"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
# --- Section 17: De-Niche Guard (B-S1 + B-S2) ---
|
# --- Section 17: De-Niche Guard (B-S1 + B-S2) ---
|
||||||
echo "--- De-Niche Guard ---"
|
echo "--- De-Niche Guard ---"
|
||||||
|
|
||||||
|
|
@ -851,12 +903,14 @@ echo ""
|
||||||
# assertion. Pin the total pass()+fail() invocations as a monotonic floor; the count
|
# assertion. Pin the total pass()+fail() invocations as a monotonic floor; the count
|
||||||
# may only grow (brief-reviewer assumption 3). History: 74 pre-M0; +1 for the SB-S0
|
# may only grow (brief-reviewer assumption 3). History: 74 pre-M0; +1 for the SB-S0
|
||||||
# brain-suite floor (Section 16b) = 75; +3 for SB-S1's three UNCONDITIONAL Section-16c
|
# brain-suite floor (Section 16b) = 75; +3 for SB-S1's three UNCONDITIONAL Section-16c
|
||||||
# checks (published-only self-test + voice-trainer grep + contract-doc grep) = 78.
|
# checks (published-only self-test + voice-trainer grep + contract-doc grep) = 78;
|
||||||
|
# +2 for SB-S3a's two UNCONDITIONAL Section-16d checks (profile-reader self-test +
|
||||||
|
# strategy-advisor wiring grep) = 80.
|
||||||
# NB: the floor tracks the deps-absent MINIMUM (conditional TS suites warn-skip and drop
|
# NB: the floor tracks the deps-absent MINIMUM (conditional TS suites warn-skip and drop
|
||||||
# the count), so it is bumped only by UNCONDITIONAL new checks — NOT pinned to the
|
# the count), so it is bumped only by UNCONDITIONAL new checks — NOT pinned to the
|
||||||
# deps-present TOTAL_CHECKS (that would zero the warn-skip margin and false-fail a fresh
|
# deps-present TOTAL_CHECKS (that would zero the warn-skip margin and false-fail a fresh
|
||||||
# clone). Runs last so TOTAL_CHECKS sees every prior check.
|
# clone). Runs last so TOTAL_CHECKS sees every prior check.
|
||||||
ASSERT_BASELINE_FLOOR=78
|
ASSERT_BASELINE_FLOOR=80
|
||||||
TOTAL_CHECKS=$((PASS + FAIL))
|
TOTAL_CHECKS=$((PASS + FAIL))
|
||||||
if [ "$TOTAL_CHECKS" -ge "$ASSERT_BASELINE_FLOOR" ]; then
|
if [ "$TOTAL_CHECKS" -ge "$ASSERT_BASELINE_FLOOR" ]; then
|
||||||
pass "assertion-count anti-erosion: $TOTAL_CHECKS checks >= baseline floor $ASSERT_BASELINE_FLOOR"
|
pass "assertion-count anti-erosion: $TOTAL_CHECKS checks >= baseline floor $ASSERT_BASELINE_FLOOR"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue