feat: make every scenario arena-grade with a competition contract
agharsallah+1: Codex
0d0c561
Add a validated `competition` block (versus|judged|none) to scenarios,
stamped onto run.started so runs are self-describing and winners attribute
to models. Winners become data, not prose: judges emit a `winner` field
that the reusable JudgedCompetition handler validates against the live cast
(repairing deterministically so the offline stub always names a real
player); ground-truth judges (SpyHost, SproutJudge) decide in code.
Audit the five existing scenarios (The Steeped versus+teams with code-scored
winner; Mystery Roots judged; Open Table gains a table-judge; Thousand Token
Wood and Oracle Grove marked none) and add three competitive scenarios:
Debate Duel and Beat Battle (symmetric seats, different models) and Twenty
Sprouts (code-dealt secret word, deterministic win).
Surface a winner ribbon in the verdict banner only when a winner exists, so
none-kind and legacy runs render byte-identically. Enforce the authoring
checklist in tests/test_scenario_contract.py and document the co…
Refactor code structure for improved readability and maintainability
Engine additions (zero scenario edits required):
- EpisodicMemory: per-agent filtered view over the ledger; agents see only their
own actions and globally-visible event kinds, capped at 8 events for small-model
context windows
- ContextBuilder: single point of prompt assembly (persona → scene → memory →
visitor disturbances); changing prompt strategy is now a one-file edit
- Governor: enforces max_turns / max_calls_per_turn / max_total_calls; raises
BudgetExceeded before a runaway cascade can burn quota
Model provider:
- OpenAICompatProvider: works with any OpenAI-compatible endpoint; config via
OPENAI_API_KEY / OPENAI_BASE_URL / MODEL_NAME; falls back to deterministic stub
when no key is present
Agents + scenarios:
- All four Tiny Wood agents use ContextBuilder with rich personas and episodic memory
- New EchoAgent transforms visitor injections through the wood's logic
- Mystery Roots (src/scenarios/mystery_roots.py): convergent blackboard swarm with
ClueGatherer / Hyp…