feat: vs mode N full passes + --competitors auto-discovery + (/Last30Days) title (#312)
* feat: vs mode runs N full passes; --competitors wraps vs with auto-discovery
Unifies vs-mode and --competitors onto one fanout architecture. A topic
containing "vs" / "versus" now runs N full pipeline.run() calls in parallel
(reverting the one-pass latency optimization that removed per-entity
depth); --competitors becomes a SKILL.md-level shortcut where the hosting
reasoning model (Claude Code, Codex, Hermes, Gemini) discovers N peers via
its own WebSearch, runs Step 0.55 per entity, and invokes the engine with
a vs-topic + --competitors-plan JSON.
Changed:
- vs-mode: N full passes in parallel via fanout (was 1 merged pass).
- --competitors: SKILL.md shortcut for vs-mode-with-discovery. Engine flag
kept for headless/cron use. LAW 7-style stderr reframed to lead with the
hosting-model path (use WebSearch + --competitors-plan) instead of
BRAVE_API_KEY. Footer BRAVE/SERPER nudge suppressed when --plan or
--competitors-plan present (hosting model already has WebSearch).
Added:
- --competitors-plan JSON flag: per-entity {x_handle, x_related, subreddits,
github_user, github_repos, context}. Accepts inline JSON or file path.
subrun_kwargs_for helper is the single source of truth for per-entity
kwargs — no closure-default fallthrough from main scope.
- Per-entity save files: each entity's sub-run produces its own
{slug}-raw.md with a single-row Resolved Entities block.
- --polymarket-keywords filter for ambiguous single-token topics.
Fixed:
- test_competitor_subrun_isolation regression suite locks in 3.0.12's
no-leak invariant (main flags do not inherit into peer sub-runs).
- Updates test_regression.py for the new comparison-mode payload shape.
Bumps plugin.json to 3.0.13. 1,219 tests passing.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: comparison title attribution — (Last 30 Days) → (/Last30Days)
User feedback on 3.0.13 dogfood runs (Kanye vs Drake, Mercer Island,
Figma): the comparison-mode synthesis title should attribute to the
slash command rather than restate the date range.
Three SKILL.md occurrences updated. Pure documentation change. Bumps to
3.0.14.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
# ruff: noqa: E402
|
||||
"""Tests for the BRAVE/SERPER web-promo suppression when hosting-model-driven."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parents[1]
|
||||
sys.path.insert(0, str(REPO_ROOT / "scripts"))
|
||||
|
||||
|
||||
def _engine() -> Path:
|
||||
return REPO_ROOT / "scripts" / "last30days.py"
|
||||
|
||||
|
||||
class FooterNudgeSuppressionTests(unittest.TestCase):
|
||||
def _run(self, *argv: str, topic: str) -> subprocess.CompletedProcess:
|
||||
cmd = [
|
||||
sys.executable,
|
||||
str(_engine()),
|
||||
topic,
|
||||
"--mock",
|
||||
"--emit=md",
|
||||
*argv,
|
||||
]
|
||||
env = {**os.environ, "LAST30DAYS_SKIP_PREFLIGHT": "1"}
|
||||
# Strip any grounded-web keys the host might have so the promo path
|
||||
# triggers deterministically in mock + no-backend.
|
||||
for key in ("BRAVE_API_KEY", "EXA_API_KEY", "SERPER_API_KEY",
|
||||
"PARALLEL_API_KEY", "OPENROUTER_API_KEY"):
|
||||
env.pop(key, None)
|
||||
return subprocess.run(cmd, capture_output=True, text=True, env=env)
|
||||
|
||||
def test_bare_run_emits_web_promo(self):
|
||||
result = self._run(topic="OpenAI")
|
||||
combined = result.stdout + result.stderr
|
||||
# Mock mode still shows the promo when nothing indicates a hosting
|
||||
# model is driving. Check both streams since the UI may emit to stderr.
|
||||
self.assertIn("BRAVE_API_KEY", combined)
|
||||
|
||||
def test_competitors_plan_suppresses_web_promo(self):
|
||||
result = self._run(
|
||||
"--competitors-list", "Anthropic",
|
||||
"--competitors-plan",
|
||||
'{"Anthropic":{"x_handle":"AnthropicAI","subreddits":["ClaudeAI"]}}',
|
||||
topic="OpenAI",
|
||||
)
|
||||
combined = result.stdout + result.stderr
|
||||
self.assertNotIn(
|
||||
"unlock native grounded web search",
|
||||
combined,
|
||||
msg="web promo should be suppressed when --competitors-plan is passed",
|
||||
)
|
||||
|
||||
def test_plan_suppresses_web_promo(self):
|
||||
plan = (
|
||||
'{"intent":"concept","freshness_mode":"balanced_recent",'
|
||||
'"cluster_mode":"none","subqueries":[{"label":"primary",'
|
||||
'"search_query":"OpenAI","ranking_query":"OpenAI",'
|
||||
'"sources":["grounding"]}],"source_weights":{"grounding":1.0}}'
|
||||
)
|
||||
result = self._run("--plan", plan, topic="OpenAI")
|
||||
combined = result.stdout + result.stderr
|
||||
self.assertNotIn(
|
||||
"unlock native grounded web search",
|
||||
combined,
|
||||
msg="web promo should be suppressed when --plan is passed",
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user