diff --git a/cron/evolution/hydra.yaml b/cron/evolution/hydra.yaml index 9547cac1ca..401a953622 100644 --- a/cron/evolution/hydra.yaml +++ b/cron/evolution/hydra.yaml @@ -26,6 +26,12 @@ prompt: | 2. DECIDE which stages have fresh upstream output newer than their consumer. 3. DISPATCH up to 3 subagents per tick, upstream stages first. 4. APPEND a brief record to KNOWLEDGE/hydra-dispatch-{date}.jsonl. + NAMING CONVENTION (#120): tick1 IS the base file hydra-dispatch-{date}.jsonl — + there is no separate hydra-dispatch-{date}-tick1.json(l). Per-tick snapshots + are named hydra-dispatch-{date}-tickN.jsonl for N >= 2 ONLY. Before reading a + dispatch artifact, list KNOWLEDGE/hydra-dispatch-* and read the newest existing + file; never guess a tickN path (that File-not-found breaks the pre-run gate). + Canonical templates live in ONE place: scripts/evolution_dispatch_paths.py. ## Stage definitions (delegate_task goal only) research – scan for new AI agent frameworks/papers/trends. diff --git a/scripts/evolution_dispatch_paths.py b/scripts/evolution_dispatch_paths.py new file mode 100644 index 0000000000..e743d1a163 --- /dev/null +++ b/scripts/evolution_dispatch_paths.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python3 +"""Canonical Hydra dispatch artifact path templates (issue #120). + +Single source of truth for the dispatch-file naming convention so the +reader and writer can never drift: + + * tick1 == the base file: hydra-dispatch-{date}.jsonl + * per-tick snapshots: hydra-dispatch-{date}-tickN.jsonl (N >= 2) + +Usage: + python scripts/evolution_dispatch_paths.py base 2026-08-26 + python scripts/evolution_dispatch_paths.py tick 2026-08-26 7 + python scripts/evolution_dispatch_paths.py latest [KNOWLEDGE_DIR] +""" +from __future__ import annotations + +import sys +from pathlib import Path + +DISPATCH_BASE_TEMPLATE = "hydra-dispatch-{date}.jsonl" + + +def base_path(date: str) -> str: + """tick1 — the base dispatch file for ``date``.""" + return DISPATCH_BASE_TEMPLATE.format(date=date) + + +def tick_path(date: str, tick: int) -> str: + """Per-tick snapshot path. tick 1 is the base file, NOT a tick1 file.""" + if tick <= 1: + return base_path(date) + return f"hydra-dispatch-{date}-tick{tick}.jsonl" + + +def latest(known: Path) -> Path | None: + """Newest existing hydra-dispatch-*.jsonl under ``known`` (or None).""" + matches = sorted(known.glob("hydra-dispatch-*.jsonl"), key=lambda p: p.name) + return matches[-1] if matches else None + + +def main(argv: list[str]) -> int: + if len(argv) < 2: + print(__doc__) + return 2 + cmd = argv[1] + if cmd == "base" and len(argv) >= 3: + print(base_path(argv[2])) + return 0 + if cmd == "tick" and len(argv) >= 4: + print(tick_path(argv[2], int(argv[3]))) + return 0 + if cmd == "latest": + known = Path(argv[2]) if len(argv) >= 3 else Path.home() / ".hermes" / "knowledge" + hit = latest(known) + print(hit if hit else "") + return 0 if hit else 1 + print(__doc__) + return 2 + + +if __name__ == "__main__": + raise SystemExit(main(sys.argv))