S3 close-out (3 edits / 1 file · lint 81/0 · counts 29/19/26/6): - react.md:131 Step 6: add no-buzzword checklist line (was missing; banned list = content rule #4; covers Step 6b via "Same as Step 6") - react.md:60 Step 2: WebFetch-failure fallback (paywall/JS/YouTube-no-transcript -> ask user to paste or pick another; never fabricate) - react.md:194 Step 2b: same fallback pointer for the multi-URL comparison path Axis-c (buzzword) + axis-d (graceful degradation) closed on both paths; axes a/b PASS. Shared scorecard already clean post-S2. Local-only per push policy.
27 KiB
LinkedIn Studio — Command Hardening Log
Per-command audit trail for the hardening phase (
docs/hardening/brief.md+plan.md). One anchored entry per command surface. The operator's parallel live-testing cross-references every change here.Entry contract (SC-A…SC-E). Each entry begins with the UNIQUE anchored header
### /linkedin:<command-name> — <one-line intent>(coverage greps^### /linkedin:<name>, never the bare word). Every entry carries: INTENT · SIMULATE (persona + the CONCRETE before-output + friction log) · EVALUATE (4 axes, with the per-type mechanical predicate — never "N/A → judgment") · HARDEN (surgical diff + concrete after-output, or "no edit — passes") · VERIFY (lintFailed: 0+ counts
- the failing axis now passes). The cold
/trekreviewreviewer adjudicates every hardened command's before/after — the author does not self-certify.Mechanical-predicate classes: post-emitting (hook 110–140 · length band · no body link · no banned buzzword · topic→5 pillars) · routing (every emitted target resolves to a real
commands/<x>.md) · analytics (graceful-degradation present + saves/dwell honesty intact) · guided/stateful (primary promised artifact actually produced; promisedsubagent_typetargets resolve).Stopping rule (anti-gold-plating): harden until every axis returns pass OR a recorded deferral; no NICE-only polish beyond axis-pass.
Method discipline (learned the hard way in the S1 calibration — three stumbles). Write the HARDEN / after-output section only from the applied + re-grepped diff, and assert a gap only after reading the actual file line. Every number (char counts, edit counts) must come from a tool, not from memory. The S1 calibration produced three assert-before-verify errors — (1) a non-existent inline buzzword list in
quick, (2) a non-existent "unused Task" inquick, (3)onboarding/first-postedits asserted as landed when the Edits had failed on wrong strings, plus a false "25 commands → stale" claim (the file already said 29). All were caught by failed Edits / empty greps / the git status, and corrected here. This is exactly the failure mode the independent/trekrevieworacle exists to catch — verify-before-assert is part of the method, not optional.
Session 1 — Method calibration (quick) + Start journey
S1 status: calibration corrected + method locked (operator, 2026-05-31). onboarding / first-post / setup follow below under the same entry shape. Field-notes inbox: absent at S1 start → graceful no-op (SC-I).
/linkedin:quick — 5-minute 3-line post from a topic, ≤1 question, clipboard-ready
INTENT. quick is the Create journey's speed path: a topic in → a publishable
150–500-char post out in ~5 minutes, max one question, auto-copied to clipboard. It must
honor the content-quality bar mechanically (hook 110–140, length 150–500, no body
links, no banned buzzword, topic maps to one of the 5 pillars, exactly one CTA) and the
algorithm bar (hook decisive before the mobile fold; links to first comment not body;
native; a CTA that invites comments without manufactured engagement-bait). Its defining
constraint is speed — "skip interrogation, generate immediately."
SIMULATE.
-
Persona (ICP): the author — 1048 followers, "Validation", 5 pillars; voice = direct/technical/low-formality, NO/EN mix, short sentences, contrarian openings (grounded in the state file + the gitignored
authentic-voice-samples.local.mdthe command reads at runtime).recent_posts: []→ no rotation conflict. Fresh-adopter path (no voice samples) reasoned, not separately re-drafted:quickreads voice from SKILL.md and falls back to defaults; the personalization score is hidden < 3 posts and the voice guardian is suppressed < 5 samples — degrades cleanly, no block, no dead-end. -
Invocation:
/linkedin:quick AI-kodeassistenter i offentlig sektor(pillars "AI-rådgivning i offentlig sektor" / "Claude Code / agentisk koding"). -
Walk: topic from
$ARGUMENTS(no question) → load voice + pillars → infer type (HOT TAKE — contrarian) → 3-line formula → auto-CTA → quality check → de-AI/differentiation gate (skip unless commodity) → clipboard → present. -
CONCRETE before-output (produced under
quick.mdas written, pre-fix):Alle vil ha AI-kodeassistenter i staten. Men hvem tar ansvaret når koden tar feil i produksjon?
Verktøyet skriver koden på sekunder. Ansvaret for at den er riktig flyttes ikke — det blir ditt, raskere enn før.
Hvordan kvalitetssikrer dere AI-generert kode hos dere?
(Pillar: Claude Code / agentisk koding · type: HOT TAKE · hook = 95 chars (node-verified) · body has 0 links / 0 buzzwords.)
-
Friction log: the 95-char hook passes
quick.md's own checks — Step 2 said "Hook (under 140 characters)" and the Step 5 checklist asked "Hook works in 140 chars?", both upper-bound only — yet it breaks the canonical 110 floor (the PreToolUse gate: "under 110: wasting prime real estate"). Same one-sidedness on length ("Under 500?" vs the 150–500 band). The Step 5 checklist also had no buzzword line, and a quick post is auto-copied to clipboard (no file Write), so the PreToolUse file gate may not fire — the checklist is the load-bearing surface. No dead-ends.
EVALUATE (4 axes).
- (a) intention fidelity — PASS. One-question speed path, 3-line formula, 8 templates,
auto-CTA, clipboard, why-hook/reach tips,
/linkedin:postupgrade path — delivers the promise. - (b) algorithm bar — PASS. No body link (links → first comment); native; CTA invites
comments (comments > reactions) without bait; de-AI gate cites the confirmed low-substance
down-rank. Consistent with
references/algorithm-signals-reference.md. - (c) MECHANICAL predicate (post-emitting) — GAP → fixed. no body link ✓ · topic→pillar ✓ · hook band ✗ (spec + checklist enforced ≤140, omitted the 110 floor; the 95-char before-hook is the live proof) · length band ✗ (checklist enforced <500, omitted the 150 floor) · buzzword ✗ (no checklist line; clipboard path bypasses the file gate).
- (d) agent-wiring + graceful degradation — PASS (verified).
quickconditionally delegates todifferentiation-checkerviaTask(quick.md:151,subagent_type: linkedin-studio:differentiation-checker) — only when the take is commodity, preserving the 5-minute promise by default.Taskinallowed-toolsis therefore used, not vestigial. Fresh-adopter degradation works (defaults; guardian suppressed < 5 samples).
HARDEN (surgical — 2 edits, axis-c only — both grep-confirmed landed).
-
commands/quick.md:68—**Line 1: Hook (under 140 characters)**→**Line 1: Hook (110-140 characters)**. -
commands/quick.mdStep 5 checklist — hook check"Hook works in 140 chars?"→"Hook in the 110-140 band (not just under 140)?"; length check"Under 500 characters?"→"In the 150-500 band (not just under 500)?"; added"No corporate buzzwords?"; count**All 6 = Yes?**→**All 7 = Yes?**. -
Deferrals: none (the earlier "incomplete buzzword list" and "unused Task" findings were file-misreads, struck — see Method discipline).
-
CONCRETE after-output (under the hardened spec — hook expanded into the 110–140 band):
Alle vil ha AI-kodeassistenter i staten. Få spør hvem som tar ansvaret når assistenten foreslår noe ingen kan forklare etterpå.
Verktøyet skriver koden på sekunder. Ansvaret for at den er riktig flyttes ikke — det blir ditt, raskere enn før.
Hvordan kvalitetssikrer dere AI-generert kode hos dere?
(hook = 127 chars (node-verified, in band) · 0 body links · 0 buzzwords · same pillar.)
VERIFY.
bash scripts/test-runner.sh→Failed: 0+ exit 0 + counts 29/19/25/6 unchanged (re-run AFTER the real edits; recorded at the session gate).- Before/after delta: axis (c) failing sub-checks (hook 110 floor, length 150 floor,
buzzword) now pass — the 95-char before-hook slips
quick.md's old checks; the hardened checklist catches it and the after-hook is 127 chars, buzzword-clean. The two edits are the cause. - Disposition: HARDENED (2 edits, axis-c) · 0 deferrals · axes a/b/d PASS.
/linkedin:onboarding — zero→published first post as one guided wizard (Start front-door)
INTENT. Multi-phase wizard taking a brand-new user from zero to a published first post as one cohesive flow (profile → personalization → first-post), so they don't navigate the full command surface alone. Primary artifacts: a saved profile + a drafted first post (the S15-B1 inline-draft). Guided/stateful; inlines rather than spawning subagents.
SIMULATE.
- Persona (fresh adopter — the right persona here): just installed, no profile, no voice
samples,
recent_posts: []. - Invocation:
/linkedin:onboarding. - Walk: Phase 0 already-onboarded check → Phase 1 profile/topic-relevance checklist → Phase 2 personalization (voice + user profile, or defaults when < 3 posts) → Phase 3 first post (3.1 topic → 3.2 3-line draft → 3.3 quality check → 3.4 present+clipboard → 3.5 record) → Phase 4 summary. CONCRETE artifact produced: a refined first-post inline draft (S15-B1 path — spot-confirmed still delivers: Phase 3.2 "Draft the post… Line 1/2/3", 3.4 "present and copy").
- Friction log: Phase 3.2 said "Line 1 — Hook (under 140 chars)" and the Phase 3.3 check asked "Hook works in 140 chars?" — both upper-bound only, so a 95-char hook would pass while breaking the 110 floor. (Phase 3.2 line 204 already states "150-500 characters" + "No external links in the post body", so length + links were NOT gaps — only the hook floor.) The description + Phase-4 tip hardcode "29 commands" — accurate today, not stale (an earlier "25 commands" claim was a misread, struck).
EVALUATE (4 axes).
- (a) intention fidelity — PASS. Cohesive zero→post wizard; S15-B1 inline draft holds (Phase 3).
- (b) algorithm bar — GAP → fixed. Phase 3 emitted a post but enforced only the hook upper bound; now the full 110–140 band (length 150–500 + no-body-links were already present).
- (c) MECHANICAL predicate (guided/stateful) — PASS; one post-emitting sub-check fixed. Primary artifact (first-post draft) produced ✓; the one-sided hook bound in Phase 3.2 + 3.3 closed.
- (d) agent-wiring + graceful degradation — PASS. No
Taskinallowed-tools— onboarding inlines every step (Phase 2 "delegate to setup" = inline its logic; commands aren't subagents, so no brokensubagent_type). Built for the no-profile path; degrades cleanly.
HARDEN (surgical — 2 edits, hook floor — both grep-confirmed landed).
commands/onboarding.md:200—**Line 1 — Hook (under 140 chars):**→**Line 1 — Hook (110-140 chars):**.commands/onboarding.md:209(Phase 3.3 check) —Hook works in 140 chars?→Hook in the 110-140 band (not just under 140)?.- Deferred (NICE-only, stopping rule): the hardcoded "29 commands" (description + Phase-4 tip) is correct now; making it count-free is drift-proofing, not an axis fix → recorded, not edited.
VERIFY. lint Failed: 0 + counts unchanged (recorded at gate); S15-B1 inline-draft
spot-confirmed; hook floor now enforced in Phase 3.2 + 3.3. Disposition: HARDENED (2 edits) ·
1 recorded deferral.
/linkedin:first-post — zero→published in <10 min, maximum hand-holding
INTENT. First-post accelerator: from "never posted" to "just published" in <10 min, breaking the blank-page barrier. Produces one published first post. Guided/stateful; inlines.
SIMULATE.
- Persona (fresh adopter): no profile (Step 2 offers a voice quick-setup or 5-question calibration; proceeds either way — momentum over completeness).
- Invocation:
/linkedin:first-post. - Walk: Step 1 welcome → Step 2 voice setup (samples or 5 Qs; graceful if none) → Step 3 topic (5 angles) → Step 4 write (3-line formula) → Step 5 simplified quality check → Step 6 present + clipboard → Step 7 record → Step 8 first-hour engagement guidance.
- CONCRETE before (the gap): Step 4 "Line 1: Hook (under 140 characters)" and the Step 5 check "Hook works in 140 chars?" were both upper-bound only — a 95-char hook would pass. (Step 4 already states "Target: 150-500 characters" and "No external links in the post body", so length + links were NOT gaps — only the hook floor.)
- Friction log: the hook bound was one-sided in Step 4 + Step 5; length + no-links already covered.
EVALUATE (4 axes).
- (a) intention fidelity — PASS. Delivers zero→published with hand-holding; first-hour guidance present.
- (b) algorithm bar — PASS. First-hour engagement window cited; no-body-links already in Step 4 tips.
- (c) MECHANICAL predicate (post-emitting) — GAP → fixed. Hook bound was upper-only in Step 4 + Step 5; now the full 110–140 band (length 150–500 + no-body-links already present).
- (d) agent-wiring + graceful degradation — PASS. No
Task; inlines; no-profile/no-samples path graceful. Differentiation-checker deliberately skipped (a first post optimizes for momentum).
HARDEN (surgical — 2 edits, hook floor — both grep-confirmed landed).
commands/first-post.md:101—**Line 1: Hook (under 140 characters)**→**Line 1: Hook (110-140 characters)**.commands/first-post.md:125(Step 5 check) —Hook works in 140 chars?→Hook in the 110-140 band (not just under 140)?.- Deferrals: none.
VERIFY. lint Failed: 0 + counts unchanged; Step 4 ↔ Step 5 hook bound now consistent (both 110-140).
Disposition: HARDENED (2 edits) · 0 deferrals.
/linkedin:setup — guided personalization (5 pillars + voice profile + prefs)
INTENT. Build the user's voice profile, expertise pillars, and content preferences into the state/asset files so every post sounds like them. Primary artifact: a populated voice profile + populated asset templates (8-category personalization score). Guided/stateful; delegates voice to an agent.
SIMULATE.
- Persona (fresh adopter): no existing data (all templates at placeholder).
- Invocation:
/linkedin:setup. - Walk: Step 0 calculate score → Step 1 dashboard → Step 2 choose what to set up → Step 3a–3f
sub-workflows (voice / case study / framework / post analysis / demographics / user profile) →
Step 4 recalculate → Step 5 continue or exit. CONCRETE artifact: e.g. Step 3a writes a real
voice profile to
assets/voice-samples/authentic-voice-samples.md(placeholder sentinel removed). - Friction log: none — no dead-ends, no ambiguous steps.
EVALUATE (4 axes).
- (a) intention fidelity — PASS. Delivers the personalization the description promises (score + 6 sub-flows).
- (b) algorithm bar — PASS (n/a-direct). Emits no post; the expertise/pillar capture is the topic-relevance foundation the bar depends on.
- (c) MECHANICAL predicate (guided/stateful) — PASS. Primary artifact (populated profile/assets)
produced ✓; the promised
subagent_type: linkedin-studio:voice-trainer(setup.md:86) resolves to a realagents/voice-trainer.md(verified). - (d) agent-wiring + graceful degradation — PASS. voice-trainer invoked via
Task(correct namespaced type); the placeholder-sentinel logic is explicit; samples optional → degrades if none.
HARDEN. No edit — passes all four axes. (Demonstrates a legitimate zero-edit pass; per the
plan, "command file modified" is not a coverage predicate — the log.md entry + /trekreview are.)
VERIFY. lint Failed: 0 + counts unchanged; voice-trainer target resolves.
Disposition: PASS, no edit · 0 deferrals.
Session 2 — Create I (post)
S2 status: the v1 autonomous attempt fabricated and was reverted (→ v2 method; see
plan.mdheader). This is the v2 re-run: parked at step 5 across a/clear, re-grounded from STATE.md's two P4 findings against the actual file lines before talking (jerndisiplin: assert-after-read). Field-notes inbox absent at S2 → graceful no-op (SC-I).
/linkedin:post — interactive full-workflow post (angle→write→quality→refine→publish), 1200–1800 chars
INTENT. post is the Create journey's full path: from raw material (data / article / experience /
observation / opinion / question) to a publishable 1,200–1,800-char thought-leadership post via an
8-step workflow — angle → format → structure+write → quality check → present → refine → pre-publish
→ deterministic state update. Post-emitting, so it must honor the content bar mechanically (hook
110–140, length 1,200–1,800, no body links, no banned buzzword, topic→5 pillars) and the
algorithm bar (hook decisive before the mobile fold, links→first comment, native, comment-inviting
CTA without bait, de-AI substance signals).
SIMULATE.
- Persona (ICP): the author — 1048 followers, "Validation", 5 pillars; direct/technical NO/EN voice.
- Invocation:
/linkedin:post about AI-kodeassistenter i offentlig sektor. - Walk: Step 0 load state/SKILL → Step 1 type=Opinion → Step 2 angle (contrarian) → Step 3 medium text → Step 4 structure (hook 110–140 ✓ internally) → Step 5 quality check (the gap) → Step 6 present+clipboard → Step 7 refine → Step 8 pre-publish + state.
- CONCRETE friction (spec-level, the live proof — anchored, not a generated post): at Step 5
the quality checklist (
post.md:127–135, 9 items) had no buzzword line, so a draft opening "How to leverage AI to drive synergy in the public sector…" would pass Step 5 unflagged — the banned-list (content rule #4,CLAUDE.md:124) was never enforced at the gate. Step 5 also routes toquality-scorecard.md(post.md:125), which self-contradicted on the hook bound: l.32 "Works in 140 characters" + l.114 "Hook works in 140 chars?" (upper-only) vs l.128 "110-140" — the same one-sided bound S1 fixed in the command files, surviving in the shared asset. - Friction log:
post.mditself is internally consistent on the hook (110–140 at l.100/113/127); the only command-side gap is the missing Step-5 buzzword line. The shared scorecard carried both gaps (buzzword absent + two one-sided hook bounds). Scorecard is shared by 8 surfaces (pipeline · video · post · react · batch+ 3 skills) — fixing it is high-leverage, operator-approved.
EVALUATE (4 axes).
- (a) intention fidelity — PASS. Full 8-step workflow delivers the description's promise.
- (b) algorithm bar — PASS. No body link (
post.md:133/176); comment-inviting CTA; de-AI gate cites the confirmed reach-suppression (post.md:137–141). Consistent withalgorithm-signals-reference.md. - (c) MECHANICAL predicate (post-emitting) — GAP → fixed. hook band ✓ · length band ✓ · no-body-link ✓ · topic→pillars ✓ · subagent resolves ✓ · buzzword ✗ (Step-5 checklist had no line; grep NONE). Shared scorecard added two sub-gaps: hook one-sided at l.32 + l.114.
- (d) agent-wiring + graceful degradation — PASS.
differentiation-checker(post.md:141, conditional) +content-optimizer(post.md:166, conditional) both resolve, both correctlysubagent_type: linkedin-studio:-namespaced. Voice→defaults; fresh-adopter path graceful.
HARDEN (surgical — 4 edits across 2 files, all grep-confirmed landed).
commands/post.md:134— added Step-5 checklist line:- [ ] No corporate buzzwords (leverage, synergy, paradigm shift, thought leader, disruptive, value proposition, ecosystem, holistic approach).assets/checklists/quality-scorecard.md:32—Works in 140 characters→Works in 110-140 characters(NotesMobile threshold→Mobile band (floor + ceiling)).assets/checklists/quality-scorecard.md:114—Hook works in 140 chars?→Hook works in 110-140 chars?.assets/checklists/quality-scorecard.md:132— added Pre-Publish Basic Checklist line:- [ ] No corporate buzzwords (…)(same banned list).- Deferrals: none. Scope note: the 3 scorecard edits improve all 8 consumers; only
postis hardened this session —react/batch/video/pipelineget their own EVALUATE in S3/S5/S6/S8.
VERIFY.
bash scripts/test-runner.sh→Passed: 81 · Failed: 0 · Warnings: 0; counts 29/19/26/6 unchanged.- Anti-check grep: no one-sided bare
140 charhook bound remains in the scorecard (110-140at l.32/114/128). Buzzword line present in both files (post.md:134,quality-scorecard.md:132). - Before/after delta: axis (c) buzzword sub-check now enforced at the load-bearing Step-5 gate; the scorecard hook self-contradiction is resolved (all three mentions banded). The 4 edits are the cause.
- Disposition: HARDENED (4 edits, axis-c + shared-asset consistency) · 0 deferrals · axes a/b/d PASS.
Session 3 — Create I (react)
S3 status: re-grounded STATE's S3 predicate against the actual
react.mdlines BEFORE talk (jerndisiplin: assert-after-read). Field-notes inbox absent at S3 → graceful no-op (SC-I). Allfile:linebelow are tool-grounded against the FINAL (post-edit) file.
/linkedin:react — URL-to-post pipeline (single + comparison), your-take-as-hook, 1,200–1,800 chars
INTENT. react is the Create journey's URL→post path: fetch external content
(article / news / research / YouTube), extract the key points, pick an angle, and draft in the
author's voice. Post-emitting (medium 1,200–1,800), two paths — single-URL (Steps 1–8) +
comparison/multi-URL (Steps 1b–8b). Must honor the content bar mechanically (hook 110–140,
length 1,200–1,800, no body link, no banned buzzword, topic→5 pillars) and the algorithm bar
(URL→first comment not body, post stands alone, your reaction is the hook not a summary,
comment-inviting CTA, de-AI substance). Distinct from post/quick: the value-add is YOUR
perspective extending the source, not echoing it — the commodity-reaction guard (differentiation-checker).
SIMULATE.
- Persona (ICP): the author — 1048 followers, "Validation", 5 pillars; direct/technical NO/EN voice.
- Invocation:
/linkedin:react <public-sector-AI news URL>. - Walk: Step 0 load → Step 1 single URL → Step 2 WebFetch extract → Step 3 classify (Product Launch) → Step 4 angle (First-Take Analysis) → Step 5 draft (hook 110–140 ✓) → Step 6 quality check (the gap) → Step 7 present+clipboard → Step 8 state.
- CONCRETE friction (spec-level, anchored — not a generated post): at Step 6 the quality
checklist (pre-edit
react.md:122–128, 7 items) enforced hook/links/standalone/voice/charcount/ topic/CTA but had no buzzword line, so a draft opening "This launch lets agencies leverage AI to unlock synergy across the value proposition…" passes unflagged — the banned-list (content rule #4,CLAUDE.md:124) was never enforced at the gate. Step 6b (:237"Same as Step 6, plus") inherits the hole.reactauto-copies to clipboard (:144–148, no file Write) → the PreToolUse file gate may not fire → Step 6 is the load-bearing surface. Same gap S2 fixed inpost. - Second friction (axis d, URL-pipeline-specific):
grepfor fetch-failure/paywall/transcript/ fallback → NONE. Step 2 (:54) "Use WebFetch to extract" had no fallback when extraction yields nothing (paywall / JS-heavy SPA / YouTube-no-transcript — an explicitly accepted input,:37/:71); Step 2b (:185) same. Risk: proceed on a thin/empty extraction or fabricate from the URL string.
EVALUATE (4 axes).
- (a) intention fidelity — PASS. Both paths, angle selection, your-take-not-summary, commodity guard, clipboard, URL→first comment — delivers the description's promise.
- (b) algorithm bar — PASS. No body link (
react.md:115/125/235); URL→first comment (:116/:144/:253); stands alone (:118/:126); take-as-hook (:101/:118); de-AI gate bans mechanical engagement-bait (:135–137). Consistent withreferences/algorithm-signals-reference.md. - (c) MECHANICAL predicate (post-emitting) — GAP → fixed. hook band ✓ (
:101/:124/:221) · length band ✓ (:119/:128/:239) · no-body-link ✓ (:115/:125/:235) · topic→pillars ✓ (:129) · subagent resolves ✓ (:137→agents/differentiation-checker.md) · buzzword ✗ (grep NONE; no inline line in Step 6/6b). - (d) agent-wiring + graceful degradation — wiring PASS; degradation GAP → fixed.
differentiation-checkerresolves, namespaced, conditional (:137). Graceful degradation: no WebFetch-failure/empty-extraction fallback on EITHER path (grep NONE) — YouTube-no-transcript the sharpest, since it is a stated accepted input. - Shared asset:
quality-scorecard.mdalready clean post-S2 (110-140at:32/:114/:128+ buzzword:132) —react's referenced asset (react.md:270) is good; the gap wasreact's OWN inline Step 6.
HARDEN (surgical — 3 edits, 1 file, all grep-confirmed landed).
commands/react.md:131— added Step-6 checklist line:- [ ] No corporate buzzwords (leverage, synergy, paradigm shift, thought leader, disruptive, value proposition, ecosystem, holistic approach). Covers Step 6b via "Same as Step 6".commands/react.md:60— added Step-2 WebFetch fallback: "If WebFetch can't extract usable content (paywall / JS-heavy / YouTube-no-transcript): say so, ask the user to paste the key points or choose another URL; never fabricate from the URL string or title."commands/react.md:194— added Step-2b pointer: "If a source can't be extracted: apply the Step 2 fallback — drop it if 2+ usable sources remain, else ask the user; never fabricate."- Deferrals: none.
- CONCRETE after: the "leverage…synergy…value proposition" draft now trips the Step-6 buzzword line; a YouTube-no-transcript invocation now degrades to "paste the key points / pick another URL" instead of a fabricated reaction.
VERIFY.
bash scripts/test-runner.sh→Passed: 81 · Failed: 0 · Warnings: 0; counts 29/19/26/6 unchanged (ls commands/*.md | wc -l== 29;git diff --stat=react.mdonly, +5 insertions, 0 deletions).- Before/after delta: axis (c) buzzword sub-check now enforced at the load-bearing Step-6 gate (both paths via "Same as Step 6"); axis (d) WebFetch-failure now has a sensible fallback on both paths. The 3 edits are the cause.
- Disposition: HARDENED (3 edits, axis-c + axis-d) · 0 deferrals · axes a/b PASS.