feat(linkedin-studio): N8 — stemme-kjeden (chronicle-voice-profile + drift-logg + language-resolve + auto-gull) [skip-docs]

Bind the long-form VOICE before prose — the discipline the line already
applies to SOURCES (validate-binding), its strongest link.

- C-1/A2-F1: voice-trainer distils a chronicle-voice-profile from the
  published gold corpus (per language/format); newsletter Step 0/3a/3b bind
  drafting to it, with an explicit never-silent fallback to the short-form
  corpus (which the engine itself calls degrading for chronicle voice).
- C-2: Step 3a Pass 0 READS the chronicle-voice-drift-log as a negative list
  (it was append-only, never consumed); Step 3b re-reads it in expansion.
- C-3: Step 1 resolves + persists the top-level edition-state.language, making
  the template doc-string's "Resolved at Step 1" claim true; the Norwegian
  review axis (language-reviewer / voice-scrubber) now fires when the edition
  IS Norwegian instead of being silently off by default. Step 6.5 already
  consumed the field — resolving it closes the axis end-to-end.
- A2-F2: Step 8 lock appends the locked edition to ingest/published
  (provenance=published), so the gold corpus the profile distils from grows
  one edition at a time — never the engine's drafts.

Domain-general throughout (languages/formats from the user's own corpus).
test-runner 140 -> 146 (Section 16o: 6 unconditional voice-chain greps +
non-vacuity self-test; anti-erosion floor 123 -> 129). All six suites green
(trends 300, brain 134, hooks 140, tests 35, render 60).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014bE7VbkmR3cqHFEeGfzgwb
This commit is contained in:
Kjell Tore Guttormsen 2026-07-23 22:58:38 +02:00
commit b30b0e208f
4 changed files with 197 additions and 13 deletions

View file

@ -1512,6 +1512,88 @@ fi
echo ""
# --- Section 16o: Voice Chain — chronicle-voice-profile binding (N8 / C-1,C-2,C-3,A2-F1,A2-F2) ---
echo "--- Voice Chain (N8) ---"
# N8 binds the long-form VOICE before prose — the same discipline the line already applies to
# SOURCES (validate-binding), its strongest link. Five invariants must hold in the .md/.json surfaces:
# (C-1/A2-F1) voice-trainer.md distils a chronicle-voice-profile from the PUBLISHED gold corpus, and
# newsletter.md binds drafting (Step 0/3a/3b) to THAT profile — not to the English short-form
# authentic-voice-samples corpus the engine itself calls degrading for chronicle voice.
# (C-2) Step 3a READS the chronicle-voice-drift-log as a Pass-0 negative list (today write-only).
# (C-3) Step 1 RESOLVES + persists the review `language`, making the edition-state doc-string's
# "Resolved at Step 1" claim true, so the Norwegian axis fires when content IS Norwegian.
# (A2-F2) Step 8 lock appends the locked edition to the gold corpus (ingest/published,
# provenance=published) so the corpus the profile distils from grows automatically.
# All are UNCONDITIONAL .md/.json greps (no TS deps → they raise the deps-absent floor). Auto-gull needs
# BOTH gold-corpus literals; a non-vacuity self-test guards that compound predicate (mirrors Section 16c).
CVP_LIT='chronicle-voice-profile'
DRIFTLOG_LIT='chronicle-voice-drift-log'
LANG_RESOLVE_LIT='Resolve the review language'
GOLD_PATH_LIT='ingest/published'
GOLD_PROV_LIT='provenance=published'
autogull_wired() { # $1 = text; wired iff BOTH gold-corpus literals present (echo twice — grep consumes stdin)
echo "$1" | grep -qF "$GOLD_PATH_LIT" && echo "$1" | grep -qF "$GOLD_PROV_LIT"
}
VC_SELFTEST_OK=1
if ! autogull_wired "lock appends the edition to ingest/published with provenance=published"; then
VC_SELFTEST_OK=0; echo " non-vacuity FAIL: a fully-wired auto-gull probe was not detected"
fi
while IFS= read -r probe; do
[ -z "$probe" ] && continue
if autogull_wired "$probe"; then
VC_SELFTEST_OK=0; echo " false-positive FAIL: under-wired auto-gull probe accepted -> $probe"
fi
done <<'NEGATIVE16O'
lock appends the edition to ingest/published/ but never tags provenance
marks provenance=published but never names the gold-corpus path
NEGATIVE16O
if [ "$VC_SELFTEST_OK" -eq 1 ]; then
pass "voice-chain self-test: auto-gull predicate needs BOTH gold-corpus literals (1 accepted, 2 under-wired rejected)"
else
fail "voice-chain self-test failed — the auto-gull lint is vacuous or over-eager"
fi
NL="commands/newsletter.md"
VT_N8="agents/voice-trainer.md"
# (C-1/A2-F1) chronicle-voice-profile artifact generated + bound
if grep -qF "$CVP_LIT" "$VT_N8"; then
pass "voice-trainer.md distils the $CVP_LIT (per-language gold-corpus voice artifact)"
else
fail "voice-trainer.md missing '$CVP_LIT' — the chronicle voice artifact is never generated (C-1/A2-F1)"
fi
if grep -qF "$CVP_LIT" "$NL"; then
pass "newsletter.md binds long-form drafting to the $CVP_LIT (C-1)"
else
fail "newsletter.md missing '$CVP_LIT' — drafting still binds only to the short-form corpus (C-1)"
fi
# (C-2) drift-log READ (Pass 0 negative list), not just written
if grep -qF "$DRIFTLOG_LIT" "$NL"; then
pass "newsletter.md reads the $DRIFTLOG_LIT as a Pass-0 negative list (C-2)"
else
fail "newsletter.md missing '$DRIFTLOG_LIT' — the drift log is still write-only (C-2)"
fi
# (C-3) language resolved + persisted at Step 1
if grep -qF "$LANG_RESOLVE_LIT" "$NL"; then
pass "newsletter.md Step 1 resolves + persists the review language ('$LANG_RESOLVE_LIT', C-3)"
else
fail "newsletter.md missing the Step 1 language-resolution instruction ('$LANG_RESOLVE_LIT', C-3)"
fi
# (A2-F2) auto-gull at Step 8 lock — the gold corpus grows on its own
if autogull_wired "$(cat "$NL")"; then
pass "newsletter.md Step 8 auto-gull: locked edition appended to the gold corpus ('$GOLD_PATH_LIT' + '$GOLD_PROV_LIT', A2-F2)"
else
fail "newsletter.md missing auto-gull — lock does not grow the gold corpus (needs '$GOLD_PATH_LIT' + '$GOLD_PROV_LIT', A2-F2)"
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
@ -1540,12 +1622,15 @@ echo ""
# cli.ts saturation-at flag grep) = 117; +6 for RE-R3e's six UNCONDITIONAL Section-16n checks
# (brief-diff self-test + brief.ts diffSurfaced grep + brief.ts parseSurfacedFrontmatter grep +
# brief.ts 'Nytt siden sist' section grep + cli.ts selectPriorBriefFile wiring grep + brief.ts
# 'surfaced: ' frontmatter grep) = 123.
# 'surfaced: ' frontmatter grep) = 123; +6 for N8's six UNCONDITIONAL Section-16o checks (voice-chain
# self-test + voice-trainer chronicle-voice-profile grep + newsletter chronicle-voice-profile grep +
# newsletter chronicle-voice-drift-log read grep + newsletter Step-1 language-resolve grep + newsletter
# Step-8 auto-gull compound grep) = 129.
# 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
# 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=123
ASSERT_BASELINE_FLOOR=129
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"