feat(linkedin-studio): N23 — positioning-brief-motor (generering + konsum) [skip-docs]

Persistert posisjonering som alle drafts bindes mot. Innplassert i
/linkedin:setup (Step 3g) etter operatør-friksjonskriteriet — setup eier
allerede ${DATA}/profile/ og har menyen; telling forblir 30.

- config/positioning-brief.template.md (NY): fire seksjoner (Who I am ·
  Who this is for · What I hold · How I differ), hver med _Evidence:_-linje.
- setup.md Step 3g: DELEGERER til linkedin-studio:strategy-advisor.
  Brain-konsum-blokken forblir i én kopi (N21-lærdommen), lint-håndhevet.
- strategy-advisor.md: distillasjonen, kildepresedens, anti-flatteri
  (What I hold må bære påstander en leser kan være UENIG i) og
  evidensgulv ([insufficient evidence] framfor plausibel oppfinnelse).
- Distillat, ikke andre profil: briefen REFERERER user-profile.md framfor
  å gjenta den. Operatørens deklarasjon og daterte anker slår maskinens
  inferens; motstrid rapporteres som spenning, aldri stille anvendt.
- Konsum: post/quick/batch + newsletter Step 1 + differentiation-checker
  (scorer originalitet mot How I differ, ikke generisk nyhet).
- Regenerering er operatør-gatet: explicit go + seksjonsvis diff + aldri
  stille overskriving av operatørens egne redigeringer.

Lint: Section 16y, 17 nye ubetingede sjekker (self-test 1 akseptert /
4 underspesifiserte avvist). Floor 251 → 268. Alle ti suiter grønne:
test-runner 270→287/0 · trends 300 · analytics 202 · hooks 191 · brain 134
· editions 72 · render 63 · specifics-bank 45 · tests 35 · contract-gate 33.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AbwkH8phPsgv9xFd8Qbq7E
This commit is contained in:
Kjell Tore Guttormsen 2026-07-31 21:01:55 +02:00
commit af80150019
10 changed files with 304 additions and 3 deletions

View file

@ -2930,6 +2930,155 @@ fi
echo ""
# --- Section 16y: Positioning Brief - generation, consumption, operator gate (N23 / E#4) ---
echo "--- Positioning Brief: distillation + create-surface consumption + regeneration gate (N23) ---"
# A draft is only as anchored as the positioning it is written against. The brief is a
# DISTILLATE of the second brain, not a second copy of the declared profile, and three
# disciplines carry the whole feature - each of which fails silently if eroded:
# (E#4 separation) user-profile.md stays the operator's DECLARED identity; the brief is
# the evidence-weighted distillate. Two files restating the same claim
# is the N22 defect class (conflicting numbers across surfaces), so the
# brief must DEFER to the profile and to the operations anchor.
# (E#4 consumption) a brief nothing reads is a file, not an engine. The create surfaces
# and newsletter Step 1 must read it the way they read voice-samples.
# (E#4 gate) positioning is the operator's own. Regeneration is operator-gated:
# an explicit go, a visible diff, and never a silent overwrite. This is
# the check most likely to be "simplified" away, because a confirmation
# prompt reads as friction rather than the guarantee it is.
# (anti-drift) the brain-consumption rules stay in ONE file (strategy-advisor). The
# hosting command DELEGATES; it does not copy the block. Six copies of
# the standard skeleton (N21) is exactly what that copy would become.
BRIEF_PATH_N23="profile/positioning-brief.md"
SETUP_N23="commands/setup.md"
ADVISOR_N23="agents/strategy-advisor.md"
TMPL_N23="config/positioning-brief.template.md"
DIFFCHK_N23="agents/differentiation-checker.md"
NEWS_N23="commands/newsletter.md"
gate_honest() { # $1 = text; honest iff it REQUIRES a go, SHOWS the change, and FORBIDS a silent overwrite
# -qiF, not -qF: these are concepts in running prose, where sentence position decides the
# casing. Case-pinning would force the prose to fit the lint instead of the other way round.
echo "$1" | grep -qiF "explicit go" \
&& echo "$1" | grep -qiF "never overwrite" \
&& echo "$1" | grep -qiF "diff"
}
GATE_SELFTEST_N23=1
if ! gate_honest "regeneration requires an explicit go: show the diff first and never overwrite the existing brief without it"; then
GATE_SELFTEST_N23=0; echo " non-vacuity FAIL: a fully-gated regeneration probe was not detected"
fi
while IFS= read -r probe; do
[ -z "$probe" ] && continue
if gate_honest "$probe"; then
GATE_SELFTEST_N23=0; echo " false-positive FAIL: under-specified gate probe accepted -> $probe"
fi
done <<'NEGATIVE16Y'
regenerate the brief from the brain and overwrite it with the new distillation
ask the operator before regenerating, then write the new brief over the old one
show the diff and regenerate on confirmation, replacing the previous brief
an explicit go is required before regenerating the positioning brief
NEGATIVE16Y
if [ "$GATE_SELFTEST_N23" -eq 1 ]; then
pass "regeneration-gate self-test: predicate needs explicit-go + diff + no-silent-overwrite (1 accepted, 4 under-specified rejected)"
else
fail "regeneration-gate self-test failed - the N23 gate lint is vacuous or over-eager"
fi
# (E#4 generation) the template exists and carries the four positioning questions
if [ -f "$TMPL_N23" ] \
&& grep -qF "## Who I am" "$TMPL_N23" 2>/dev/null \
&& grep -qF "## Who this is for" "$TMPL_N23" 2>/dev/null \
&& grep -qF "## What I hold" "$TMPL_N23" 2>/dev/null \
&& grep -qF "## How I differ" "$TMPL_N23" 2>/dev/null; then
pass "positioning-brief template carries all four positioning sections (E#4)"
else
fail "$TMPL_N23 missing or incomplete - the brief has no declared shape (E#4)"
fi
# (E#4 separation) the template states it is a distillate that defers, not a second profile
if grep -qF "does not restate" "$TMPL_N23" 2>/dev/null \
&& grep -qF "user-profile.md" "$TMPL_N23" 2>/dev/null; then
pass "template records that the brief defers to the declared profile instead of restating it"
else
fail "$TMPL_N23 does not separate distillate from declared profile - two sources of positioning truth (N22 class)"
fi
# (E#4 generation) setup hosts the generator as its own step and names the target path
if grep -qF "## Step 3g: Positioning Brief" "$SETUP_N23" 2>/dev/null \
&& grep -qF "$BRIEF_PATH_N23" "$SETUP_N23" 2>/dev/null; then
pass "setup Step 3g generates the brief to the per-user data dir (E#4)"
else
fail "$SETUP_N23 has no Step 3g writing $BRIEF_PATH_N23 - the generator has no surface (E#4)"
fi
# (E#4 generation) the step is reachable: the Step 2 menu offers it
if grep -qF "Positioning brief" "$SETUP_N23" 2>/dev/null \
&& grep -qF "always show all 8" "$SETUP_N23" 2>/dev/null; then
pass "setup Step 2 menu offers the positioning brief (8 options) - the step is reachable"
else
fail "$SETUP_N23 Step 2 menu does not offer the brief - Step 3g is unreachable (E#4)"
fi
# (anti-drift) setup DELEGATES the distillation instead of copying the brain-consumption block
if grep -qF "linkedin-studio:strategy-advisor" "$SETUP_N23" 2>/dev/null; then
pass "setup delegates the distillation to the namespaced strategy-advisor (no copied brain block)"
else
fail "$SETUP_N23 does not delegate to linkedin-studio:strategy-advisor - the brain rules will be copied (N21 class)"
fi
# (anti-drift) the brain-consumption rules stay in exactly one file
BRAINDOC_N23=$(grep -lF "Consuming the evolving profile" agents/*.md commands/*.md 2>/dev/null | wc -l | tr -d ' ')
if [ "$BRAINDOC_N23" = "1" ]; then
pass "brain-consumption rules live in exactly 1 file - no second copy to drift (SB-S3a)"
else
fail "brain-consumption rules found in $BRAINDOC_N23 files - a copy will drift from the original (N21 class)"
fi
# (E#4 generation) the advisor owns the distillation and writes the four sections
if grep -qF "Distilling the positioning brief" "$ADVISOR_N23" 2>/dev/null \
&& grep -qF "$BRIEF_PATH_N23" "$ADVISOR_N23" 2>/dev/null; then
pass "strategy-advisor owns the positioning distillation (reuses its brain readers)"
else
fail "$ADVISOR_N23 has no positioning-brief distillation - setup would have to reimplement it (E#4)"
fi
# (E#4 separation) the distillation defers to the operator's own anchor over an older inference
if grep -qF "Who I am now" "$ADVISOR_N23" 2>/dev/null \
&& grep -qiF "operator has declared is never overridden by a distilled inference" "$ADVISOR_N23" 2>/dev/null; then
pass "distillation subordinates itself to the operator's dated anchor (frozen-past-self guard extends to positioning)"
else
fail "$ADVISOR_N23 may let a machine distillate outrank the operator's own declaration (E#4)"
fi
# (E#4 gate) regeneration is operator-gated on BOTH surfaces that can trigger it
for f_n23 in "$SETUP_N23" "$ADVISOR_N23"; do
if gate_honest "$(cat "$f_n23" 2>/dev/null)"; then
pass "$(basename "$f_n23"): regeneration is gated (explicit go + diff + no silent overwrite)"
else
fail "$f_n23 may regenerate the brief without an explicit go, a diff, or without preserving the old one (E#4)"
fi
done
# (E#4 consumption) the create surfaces and newsletter Step 1 read the brief, traceably
for f_n23 in commands/post.md commands/quick.md commands/batch.md "$NEWS_N23" "$DIFFCHK_N23"; do
if grep -qF "$BRIEF_PATH_N23" "$f_n23" 2>/dev/null; then
pass "$(basename "$f_n23") reads the positioning brief (E#4 consumption)"
else
fail "$f_n23 does not read $BRIEF_PATH_N23 - the brief steers nothing there (E#4)"
fi
done
# (E#4 consumption) absence is graceful: a fresh install has no brain and no brief
if grep -qF "no brief yet" "$ADVISOR_N23" 2>/dev/null \
|| grep -qF "no brief yet" "$SETUP_N23" 2>/dev/null; then
pass "an absent brief degrades silently (fresh installs have no brain to distil)"
else
fail "absent-brief handling is undocumented - a fresh install would error or nag (E#4)"
fi
echo ""
# --- Section 18: Assertion-Count Anti-Erosion (SC6) ---
# The lint self-modifies its own checks, so a green run could mask a silently dropped
# assertion. Pin the total pass()+fail() invocations as a monotonic floor; the count
@ -3015,7 +3164,7 @@ echo ""
# 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
# clone). Runs last so TOTAL_CHECKS sees every prior check.
ASSERT_BASELINE_FLOOR=251
ASSERT_BASELINE_FLOOR=268
TOTAL_CHECKS=$((PASS + FAIL))
if [ "$TOTAL_CHECKS" -ge "$ASSERT_BASELINE_FLOOR" ]; then
pass "assertion-count anti-erosion: $TOTAL_CHECKS checks >= baseline floor $ASSERT_BASELINE_FLOOR"