feat: move stats footer into Python engine, harden synthesis voice contract
DO NOT MERGE until local validation passes on 3+ golden topics. Problem: the magic footer (✅ All agents reported back!, emoji tree, Top voices, Raw results saved) was composed by the synthesizer model following a "Copy this EXACTLY" template buried 1150 lines into SKILL.md. Under context pressure, Opus 4.7 dropped it. Three recent /last30days runs (Opus 4.7, programming language for AI agents, Kanye West) produced clean prose with no footer and used AI-slop section headers (## The launch, ## Where it disappoints) instead of flowing paragraphs. Fix: 1. render.py: new _render_emoji_footer() emits the deterministic footer as the final block of every compact output. Zero-count sources are omitted. Tree characters (├─ / └─) computed from populated-line count. The model no longer assembles the tree from text instructions. 2. render.py: new _site_name_for_url() and _format_web_line_sources() map URLs to clean publication names (Later, Buffer, CNN, etc.) so the 🌐 Web line is pre-assembled by Python. 3. last30days.py: compute_save_path_display() turns the save path into a ~/-relative string that the engine puts in the footer. Signature change: emit_output() and render_compact() both accept save_path. 4. SKILL.md synthesis contract rewritten: - Footer template DELETED. Replaced with instruction to include the engine footer block verbatim. - URL-to-site-name sub-block DELETED. Engine does this. - "Calculate actual totals" paragraph DELETED. Engine does this. - All em-dashes in the synthesis section replaced with ` - ` (single hyphen with spaces). Em-dashes are the most reliable AI-slop tell. - New rules: no ## markdown section headers in response body, no invented title line like "{Topic}: last 30 days", no bold section labels acting as headers. Bold-lead-in paragraph shape stays. - SELF-CHECK updated to verify footer presence, no em-dashes, no body-level headers. Tests: 15 new tests covering footer emission, zero-source omission, tree character placement, save-path threading, URL-to-name helper, Web line formatting, Top voices combination, Polymarket line. All 127 tests pass across render, rerank, cluster, briefing, CLI, internals, fun-scoring. Plan: docs/plans/2026-04-17-003-feat-deterministic-footer-plan.md Local validation protocol (blocks merge): - Run /last30days in a fresh Claude Code window on 5 golden topics - Verify each output contains the footer block verbatim - Verify zero ## body headers, zero em-dashes/en-dashes, zero invented title lines - Report 5x8 pass/fail matrix; all 40 cells must be green before merge 🤖 Generated with Claude Opus 4.7 (1M context) via [Claude Code](https://claude.com/claude-code) + Compound Engineering v2.63.1 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+28
-3
@@ -112,16 +112,36 @@ def save_output(report: schema.Report, emit: str, save_dir: str, suffix: str = "
|
||||
return out_path
|
||||
|
||||
|
||||
def emit_output(report: schema.Report, emit: str, fun_level: str = "medium") -> str:
|
||||
def emit_output(report: schema.Report, emit: str, fun_level: str = "medium", save_path: str | None = None) -> str:
|
||||
if emit == "json":
|
||||
return json.dumps(schema.to_dict(report), indent=2, sort_keys=True)
|
||||
if emit in {"compact", "md"}:
|
||||
return render.render_compact(report, fun_level=fun_level)
|
||||
return render.render_compact(report, fun_level=fun_level, save_path=save_path)
|
||||
if emit == "context":
|
||||
return render.render_context(report)
|
||||
raise SystemExit(f"Unsupported emit mode: {emit}")
|
||||
|
||||
|
||||
def compute_save_path_display(save_dir: str, topic: str, suffix: str, emit: str) -> str:
|
||||
"""Compute the user-friendly save path string that will be shown in the footer.
|
||||
|
||||
Uses ~ for the home directory so the footer reads "~/Documents/Last30Days/slug-raw.md"
|
||||
instead of an absolute machine-local path.
|
||||
"""
|
||||
from pathlib import Path as _Path
|
||||
path = _Path(save_dir).expanduser().resolve()
|
||||
slug = slugify(topic)
|
||||
extension = "json" if emit == "json" else "md"
|
||||
suffix_part = f"-{suffix}" if suffix else ""
|
||||
raw = path / f"{slug}-raw{suffix_part}.{extension}"
|
||||
try:
|
||||
home = _Path.home().resolve()
|
||||
relative = raw.relative_to(home)
|
||||
return f"~/{relative}"
|
||||
except ValueError:
|
||||
return str(raw)
|
||||
|
||||
|
||||
def persist_report(report: schema.Report) -> dict[str, int]:
|
||||
import store
|
||||
|
||||
@@ -373,7 +393,12 @@ def main() -> int:
|
||||
pass
|
||||
|
||||
fun_level = config.get("FUN_LEVEL", "medium").lower()
|
||||
rendered = emit_output(report, args.emit, fun_level=fun_level)
|
||||
footer_save_path = None
|
||||
if args.save_dir:
|
||||
footer_save_path = compute_save_path_display(
|
||||
args.save_dir, report.topic, args.save_suffix or "", args.emit
|
||||
)
|
||||
rendered = emit_output(report, args.emit, fun_level=fun_level, save_path=footer_save_path)
|
||||
if args.save_dir:
|
||||
save_path = save_output(report, args.emit, args.save_dir, suffix=args.save_suffix or "")
|
||||
sys.stderr.write(f"[last30days] Saved output to {save_path}\n")
|
||||
|
||||
Reference in New Issue
Block a user