diff --git a/scripts/test-runner.sh b/scripts/test-runner.sh index 4651a0d..c8727e7 100755 --- a/scripts/test-runner.sh +++ b/scripts/test-runner.sh @@ -695,23 +695,28 @@ fi echo "" -# --- Section 17: Trend-Spotter De-Niche Guard (B-S1) --- -echo "--- Trend-Spotter De-Niche ---" +# --- Section 17: De-Niche Guard (B-S1 + B-S2) --- +echo "--- De-Niche Guard ---" -# The trend-spotter agent states its own contract — "the niche lives in the source -# list and the user's pillars, never in this agent" (Source Scanning Framework). For -# that to be true the agent file must name NO specific vendor or sector beat: the -# domain comes from the user's profile/pillars at runtime, never hardcoded here -# (plugin-is-domain-general). Pre-B-S1 the file contradicted itself, hardcoding the -# Microsoft/public-sector beat in its description, mission, trigger table and -# relevance filter. This guard forbids those KTG-beat proper nouns from returning to -# agents/trend-spotter.md. Scoped to this one agent by design (B-S1); the wider -# de-niche sweep (B-S2) covers the other surfaces. Non-vacuity self-test mirrors -# Sections 8/13: the criterion must catch the beat tokens and ignore generic prose -# (incl. the content-framework.md reference filename — B-S2a recast + renamed it -# from ai-content-framework.md, de-nicheing the file the agent reads). -# Case-insensitive: "Public sector" and "public sector" name the same beat, and a -# future reintroduction could use either case — the positive set locks that in. +# The de-niche sweep removed the hardcoded KTG beat (Microsoft / public-sector) from +# three surfaces so the domain comes from the user's profile/pillars at runtime, never +# baked in (plugin-is-domain-general): +# - agents/trend-spotter.md (B-S1: pillar-driven scanning; the agent's own +# contract says "the niche lives in the source +# list and the user's pillars, never in this agent") +# - agents/content-planner.md (B-S2a: planner calendar recast off the beat) +# - references/content-framework.md (B-S2a: recast + renamed from ai-content-framework.md) +# Each must name NO specific vendor or sector beat; this guard forbids those KTG-beat +# proper nouns from returning to any of them. Scoped per file BY DESIGN: the check runs +# against this explicit allowlist, NOT the whole tree, because references/content-angles.md +# legitimately lists "Public Sector" as one of six example industry tables (a KEEP surface, +# generic illustration — not a hardcoded beat), and "AI" is the plugin's own subject, not a +# niche token. Non-vacuity self-test mirrors Sections 8/13: the criterion must catch the beat +# tokens and ignore generic prose (incl. the content-framework.md reference filename — B-S2a +# recast + renamed it from ai-content-framework.md — and "AI"-flavoured planner prose, locking +# in that "AI" is never treated as a beat). Case-insensitive: "Public sector" and "public +# sector" name the same beat, and a future reintroduction could use either case — the +# positive set locks that in. NICHE_TOKENS='Microsoft|Azure|Copilot|public sector|offentlig sektor' TS_SELFTEST_OK=1 while IFS= read -r probe; do @@ -737,20 +742,23 @@ sector milestones in the user's domain the user's content pillars and expertise areas references/content-framework.md major product/model releases +AI-driven content planning across the user's pillars NEGATIVE17 if [ "$TS_SELFTEST_OK" -eq 1 ]; then - pass "trend-spotter de-niche self-test: 5 beat tokens caught (case-insensitive), 5 generic forms ignored" + pass "de-niche self-test: 5 beat tokens caught (case-insensitive), 6 generic forms ignored (incl. 'AI' kept as the plugin's own subject)" else - fail "trend-spotter de-niche self-test failed — the guard no longer enforces the no-beat criterion" + fail "de-niche self-test failed — the guard no longer enforces the no-beat criterion" fi -TS_NICHE_HITS=$(grep -niE "$NICHE_TOKENS" agents/trend-spotter.md 2>/dev/null || true) -if [ -z "$TS_NICHE_HITS" ]; then - pass "trend-spotter names no hardcoded vendor/sector beat (domain comes from pillars)" -else - fail "trend-spotter hardcodes a vendor/sector beat — generalize to pillar-driven prose:" - echo "$TS_NICHE_HITS" -fi +for guarded in agents/trend-spotter.md agents/content-planner.md references/content-framework.md; do + NICHE_HITS=$(grep -niE "$NICHE_TOKENS" "$guarded" 2>/dev/null || true) + if [ -z "$NICHE_HITS" ]; then + pass "$guarded names no hardcoded vendor/sector beat (domain comes from pillars)" + else + fail "$guarded hardcodes a vendor/sector beat — generalize to pillar-driven prose:" + echo "$NICHE_HITS" + fi +done echo ""