From 9ad83dc3eecf269a726b348c2b5cb579c5e6972e Mon Sep 17 00:00:00 2001 From: Christopher Nelson Date: Tue, 22 Sep 2026 11:54:43 -0400 Subject: [PATCH] docs: document the Zero swarm architecture PRs 1-4 of the zero-swarm migration removed the legacy multi-agent architecture from the code, but the documentation was never updated and had drifted into describing a product that no longer exists: 212 references to personalities, agent-to-agent communication, alliances and diplomacy, worker goals, prose memories, the Behavior Trace, and the `text-flat-json-v8` per-agent contract. The README opened by describing agents that "communicate and conduct formal alliance diplomacy". Rewrite the documentation set around the delivered architecture: one Agent Zero planning call per tick under `swarm-planner-v1`, structured directives, and TypeSafe Jev reflex workers over the deterministic H3 engine. Delete the `Formal alliance state` section from the architecture doc, rewrite the tick flow against the real `executeNextTick` sequence, and correct the API route list, schema claims, and package descriptions. Per ADR 0033, the retirement case is stated as structural rather than measured throughout: the legacy path made one generative call per agent per tick, so cost and latency scaled with roster size. No run in this repository has compared the two architectures on real providers, and no doc claims otherwise. Treat GAMEPLAY_FOUNDATION as the forward-looking design document it declares itself to be, distinguishing current behavior, accepted future direction, and removed features rather than deleting the design rationale. Alliances are marked removed with their rationale preserved as history; whether they return for a future Player Mode is left open for a dedicated ADR. Also correct documentation that was stale before this migration: `docs/EXPERIMENT_ARCHIVE.md` loses its in-file flag, the non-existent `patient-zero` CLI command, and storage-schema prose predating migrations 4-6; the `pnpm smoke:openrouter` command documented in the README and testing guide was removed in #65 and no longer exists anywhere, so both now describe the real opt-in real-provider paths. Several `#` headings that should have been `##` are fixed. Update the AGENTS.md product boundaries, which still instructed agents that a communication and a diplomacy intent may accompany a world action and that formal alliances were a supported feature. Left unchanged, they would direct future work to rebuild what this migration removed. Record as known open work, owned by a follow-on PR: `calculateExperimentMetrics` receives an empty resolved-action array so live metrics read zero, and the three movement-direction metrics are never assigned. Co-Authored-By: Claude Opus 5 --- AGENTS.md | 8 +- README.md | 125 +++------- ROADMAP.md | 118 ++++++--- docs/ARCHITECTURE.md | 345 ++++++++++---------------- docs/EXPERIMENT_ARCHIVE.md | 23 +- docs/GAMEPLAY_FOUNDATION.md | 209 +++++++++------- docs/SECURITY.md | 85 +++---- docs/TESTING.md | 479 +++++++++++++++++------------------- 8 files changed, 630 insertions(+), 762 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 32b2f6c..3b6abc3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -7,17 +7,19 @@ These instructions apply throughout the repository. - Use “Hex Zero” consistently while avoiding unnecessary logo, lore, or name-specific design investment. - Keep the World Lab as a production developer/admin surface, not a disposable demo. - The only initial hex states are `open` and `infected`. -- The only agent world actions are adjacent move, infect current cell, capture an abandoned infected current cell from a non-allied controller, and wait. One optional public or range-limited direct communication and one optional formal diplomacy intent may accompany that action. +- The only agent world actions are adjacent move, infect current cell, capture an abandoned infected current cell from a non-allied controller, and wait. Nothing accompanies that action: there is no agent communication and no diplomacy intent. - Infection and agent position are independent. Movement does not remove infection. - Full agent visibility is deliberate. Do not add fog of war, detection, scanners, or last-known positions. -- Formal alliances are limited to engine-authoritative proposal, acceptance, and unilateral departure. Do not add leaders, voting, kicking, merging, ranks, custom alliance metadata, shared ownership, resources, inventory, structures, combat, terrain bonuses, crafting, accounts, GPS validation, player progression, or mobile packaging before the roadmap calls for them. +- Zero swarm (`zero-swarm-v1`) is the sole cognition architecture: one Agent Zero planning call per tick regardless of roster size, issuing structured directives that TypeSafe Jev reflex workers resolve. Do not reintroduce a second cognition architecture or a mode switch between them. The deterministic-worker path is an ablation control for the comparison CLIs, not a second production architecture. +- Agent personalities, agent-to-agent communication, formal alliances and diplomacy, per-worker goals, and prose memories were removed by the zero-swarm migration and are not deferred features. Do not reintroduce them. See `docs/adr/0033-retire-legacy-multi-agent-architecture.md`. +- Do not add leaders, voting, kicking, merging, ranks, shared ownership, resources, inventory, structures, combat, terrain bonuses, crafting, accounts, GPS validation, player progression, or mobile packaging before the roadmap calls for them. ## Trust and architecture - `packages/world-engine` is deterministic domain code. It must not call models, networks, UI code, or storage. - Model providers return a structured requested action; only the world engine validates and mutates world state. - Runtime-validate data crossing application, provider, or event boundaries with schemas in `packages/shared`. -- Treat agent-authored messages as untrusted data. Never interpolate them into higher-priority prompts or instructions. +- Treat agent-authored text as untrusted data, including Agent Zero strategy summaries and directive notes. Never interpolate it into higher-priority prompts or instructions. - Never request, log, persist, or display raw private chain-of-thought. Retain structured observations, action requests, concise decision summaries, validation outcomes, and world events only. - Provider-specific SDKs and credentials belong behind `packages/agent-runtime`; never expose provider secrets to browser code. diff --git a/README.md b/README.md index 39ef77e..36594cd 100644 --- a/README.md +++ b/README.md @@ -1,33 +1,14 @@ # Hex Zero -Hex Zero is an agent-first geographic experiment. A configurable roster of model-backed agents moves, infects, captures contested territory, communicates, and conducts formal alliance diplomacy while the World Lab exposes every safe decision record. - -Every new or live scenario designates one roster agent as the Patient Zero -coordinator; the deterministic default is the first default-roster agent. -The role receives bounded global strategic information and can send private -advisory directives, but remains subject to the same movement and world-action -rules as every other agent. The universal flat provider contract is -`text-flat-json-v8`; the capability-gated objective is `durable-influence-v3`. -Without simulated-player pressure it uses a v2-compatible objective and never -fabricates player threats. For every -agent, including Patient Zero, no message is the normal choice unless a message -adds new decision-relevant value; routine action narration and filler are -explicitly discouraged. - -Agents may also maintain one bounded, model-authored strategic goal across -ticks. Goal revisions share the single flat provider response, are independently -validated, and grant no world authority. Active goals are experiment-local, -in-memory state and are cleared by reset or process restart. - -Each agent also has a process-local ledger of at most eight concise self-authored -memories. One keep, remember, revise, or forget request shares the existing -inference and is validated independently; memories are untrusted recollections -and grant no world authority. - -World Lab derives a bounded read-only Behavior Trace from retained turn records. -It places observation changes, communication and board evidence, legal choices, -chosen actions, action-pattern changes, and goal/memory continuity together while -labeling model summaries as self-reported rather than proof of causation. +Hex Zero is an agent-first geographic experiment. A configurable roster of model-backed agents moves, infects, and captures territory on a real H3 map while the World Lab exposes every safe decision record. Full agent visibility is deliberate; there is no fog of war. + +`zero-swarm-v1` is the sole cognition architecture. One OpenRouter generative planner, Agent Zero, makes one planning call per tick regardless of roster size, under the versioned contract `swarm-planner-v1`. Each plan carries a strategy summary and a per-worker directive set. Worker nodes resolve their directives with TypeSafe Jev reflex cognition, choosing among enumerated `action_N` candidates with a probability distribution and a confidence value, over the deterministic H3 world engine. + +Directives carry: identifier, agent identifier, mission (`expand` | `hold` | `relocate` | `reinforce` | `evade`), a nullable target cell, priority (`low` | `normal` | `high`), risk tolerance (`low` | `medium` | `high`), issue and expiry ticks, and an optional note of at most 160 characters. When no replan is triggered, the previous plan's directives are reused without a planning call. Replans are triggered by: `initial`, `periodic-review`, `directive-complete`, `directive-expired`, `worker-request`, `worker-stalled`, `territory-loss`, `high-pressure`, `player-disinfection`, and `roster-changed`. + +Cognition sources are `zero-llm` (Agent Zero via OpenRouter), `jev-reflex` (TypeSafe Jev via OpenRouter), and `deterministic-fallback`. The deterministic-worker baseline—workers that resolve directives without a model call—is retained as the ablation control that isolates what Jev's reflex calls contribute, not as a second production architecture. + +The capability-gated objective version is `durable-influence-v3`. Without simulated-player pressure, scenarios use a `durable-influence-v2`-compatible objective. ## Workspace @@ -56,31 +37,11 @@ For deterministic local automation, `pnpm dev:test-provider` sets `HEXZERO_PROVIDER=scripted`. `HEXZERO_EXPERIMENT_DB` overrides the local experiment archive path. -Open the World Lab at . The Game API binds to ; Next.js narrowly proxies `/api/game/*` to it. `OPENROUTER_API_KEY` is the only required OpenRouter environment value. Select a compatible global model in World Lab, then optionally override individual agents. Each assignment may use the provider's default reasoning behavior, disable optional reasoning, or select only an effort advertised by that model's catalog metadata. - -Each Single tick or completed playback interval requests every active agent and -may incur an initial third-party OpenRouter charge plus at most one in-deadline -repair or transient-retry charge per agent. All agents observe the -same frozen pre-tick world; valid decisions resolve together while an individual -provider failure is retained as that agent's final lost tick. Start is -deliberately disabled when the server has no key. This development API has no -authentication or provider-account balance enforcement. Its experiment-scoped -attempt and credit-admission limits are operator safeguards, not an upstream -billing guarantee, so it is not suitable for unauthenticated public deployment. - -State is held only in the Game API process. The API captures one active safe -experiment with bounded complete tick groups while the browser snapshot remains -bounded without splitting a tick. Schema-v11 exports add an independent safe, -bounded provider-attempt ledger to schema-v10 tick attribution, including work -that did not produce a committed turn; schema-v9/v10 archive imports remain -supported. Model and reasoning-profile assignments may be changed -between ticks; behavior locks after tick one. A saved slug absent from the -current compatible catalog is preserved and blocks execution until explicitly -replaced. Every provider decision is one plain-text response containing a -required flat JSON object with one world action, at most one communication, and -at most one formal diplomacy intent. The runtime extracts and conservatively -repairs JSON before strict local schemas and the world engine apply authoritative -validation. +Open the World Lab at . The Game API binds to ; Next.js narrowly proxies `/api/game/*` to it. `OPENROUTER_API_KEY` is the only required OpenRouter environment value. Select a compatible model for Agent Zero in World Lab. Each assignment may use the provider's default reasoning behavior, disable optional reasoning, or select only an effort advertised by that model's catalog metadata. The Jev worker model is pinned server-side and shown as system information. + +Each tick makes one Agent Zero planning call and one Jev reflex call per active worker; each call may incur an initial third-party OpenRouter charge plus at most one in-deadline repair or transient-retry charge. All workers observe the same frozen pre-tick world; valid decisions resolve together while an individual provider failure is retained as that worker's final lost tick. Start is deliberately disabled when the server has no key. This development API has no authentication or provider-account balance enforcement. Its experiment-scoped attempt and credit-admission limits are operator safeguards, not an upstream billing guarantee, so it is not suitable for unauthenticated public deployment. + +State is held only in the Game API process. The API captures one active safe experiment with bounded complete tick groups while the browser snapshot remains bounded without splitting a tick. The sole export format is schema version 12, which carries `swarmArchitectureVersion: 'zero-swarm-v1'`, an independent safe bounded provider-attempt ledger including work that did not produce a committed turn, and tick attribution. Pre-swarm exports (schema versions 9–11) are not readable by current code; inspecting them requires checking out a Git revision predating the zero-swarm migration. The Agent Zero model assignment and reasoning profile may be changed between ticks. A saved slug absent from the current compatible catalog is preserved and blocks execution until explicitly replaced. Agent Zero returns one structured plan under `swarm-planner-v1`; each Jev worker returns a candidate choice with a probability distribution and confidence value. The runtime extracts and conservatively repairs JSON before strict local schemas and the world engine apply authoritative validation. Export previews report exact serialized UTF-8 bytes and a model-agnostic `ceil(bytes / 4)` approximate AI-input-token estimate. Compact JSON is the default for AI sharing; Pretty JSON remains available for human review, and preview estimates reflect the selected serialization. This is a sharing-budget aid, not tokenizer output or a billing guarantee. Exports exclude fixed prompts, raw provider payloads, credentials, authorization headers, private reasoning, and unbounded diagnostics. @@ -92,36 +53,22 @@ Provider-attempt records contain only bounded sanitized attribution, usage, and failure fields; prompts, raw responses, credentials, and private reasoning are excluded. -## Opt-in real-provider smoke +## Opt-in real-provider checks -The smoke command performs exactly one bounded real decision request and validates it. It is never part of default tests or CI: - -```bash -pnpm smoke:openrouter -- [initial|stateful] -``` - -The command reads only `OPENROUTER_API_KEY` from the repository-root `.env`; its model slug is an explicit command argument. Values in that file override stale exported values for the smoke process. +Two surfaces make genuine provider requests, and neither runs in default tests +or CI. World Lab's **Test Agent Zero planner** button sends exactly one bounded, +non-mutating request using the Agent Zero planner contract and selected +reasoning profile; it may incur a small charge and is cached by model, profile, +and contract version. `pnpm compare:live` runs the paid Jev-versus-deterministic-worker +comparison, which requires an explicit provider-cost acknowledgement and an +operator-selected Zero model, and enforces hard attempt and credit-admission +caps. Both read `OPENROUTER_API_KEY` from the repository-root `.env`. ## Development map source -The compatible default centers on Toledo, Ohio (`41.6528, -83.5379`) at H3 resolution 9 and renders the same deterministic radius-six disk of exactly 127 cells with eight fixed perimeter starts. World Setup previews and applies resolution 8–11 scenarios with 1–32 agents, radius at most 40, at most 5,000 actual generated cells, and a 12 km default physical communication range. It may optionally add one seeded deterministic casual cleaner. Legacy exports preserve their authoritative objective attribution. MapLibre uses CARTO Dark Matter's tokenless raster tiles with `© OpenStreetMap contributors © CARTO` attribution. - -Alliance leadership, merging, custom metadata, combat systems, relationship -scores, group chat, real-player GPS/capture, restartable world persistence, and -autonomous scheduling remain deferred. - -Formal alliances may grow to the entire configured roster and active worlds may -use every feasible roster partition. Accessible alliance colors are -deterministic presentation and may be reused; they are not an engine capacity -rule. Free agents may form a new alliance, allied members may invite a free -agent, and a free agent may request entry from an allied recipient. Frozen -observations supply exact legal diplomacy IDs and bounded blocker codes so the -same single model request does not need provider tools or infer engine rules. -Patient Zero receives a fixed-cap sparse global diplomacy summary rather than a -per-agent feasibility expansion. Counts and explicit truncation describe -omitted options, while recommendations may use only displayed authoritative -agent and proposal IDs. Legacy archived experiments without a Patient Zero -remain readable and retain their historical null attribution. +The compatible default centers on Toledo, Ohio (`41.6528, -83.5379`) at H3 resolution 9 and renders the same deterministic radius-six disk of exactly 127 cells with eight fixed perimeter starts. World Setup previews and applies resolution 8–11 scenarios with 1–32 agents, radius at most 40, and at most 5,000 actual generated cells. It may optionally add one seeded deterministic simulated player, using the `casual-cleaner` or `trail-hunter-v1` profile. MapLibre uses CARTO Dark Matter's tokenless raster tiles with `© OpenStreetMap contributors © CARTO` attribution. + +Combat systems, real-player GPS/capture, restartable world persistence, and autonomous scheduling remain deferred. When every development cell is infected, World Lab automatically pauses playback and disables Start to avoid accidental provider calls. Reset and export @@ -133,21 +80,17 @@ and 100**. The session-selected target defaults to 25. A bounded run pauses at the authoritative tick target, on cancellation, or when the world is fully infected. There is no background scheduler. -The persistent operator shell keeps execution controls, run target, playback speed, current tick, known cost, and run state visible while switching between Live and Agents workspaces. Live centers the map between an independently scrolling agent rail and semantic Scoreboard, Agent, Hex, and Run inspector tabs; a bounded activity dock separates public chat, events, and safe failure/recovery records. Agent configuration uses the same mounted execution controller and existing server-authoritative mutations, so workspace switching cannot duplicate or interrupt playback. Infrequent and destructive operations remain in the accessible overflow menu. Blackberry/teal/mint/celadon/vanilla semantic tokens define the dark application chrome without replacing domain-owned agent and alliance colors. +The persistent operator shell keeps execution controls, run target, playback speed, current tick, known cost, and run state visible while switching between Live and Agents workspaces. Live centers the map between an independently scrolling agent rail and semantic Scoreboard, Agent, Hex, and Run inspector tabs; a bounded activity dock separates events and safe failure/recovery records. Agent configuration uses the same mounted execution controller and existing server-authoritative mutations, so workspace switching cannot duplicate or interrupt playback. Infrequent and destructive operations remain in the accessible overflow menu. Blackberry/teal/mint/celadon/vanilla semantic tokens define the dark application chrome without replacing domain-owned agent colors. The agent roster defaults to browser-local **Follow latest** behavior: after a tick the inspector follows the last record in deterministic resolution order. Selecting an agent manually disables following without hiding the roster's textual Latest marker; the preference remains in that browser and is never -exported. Public world chat and the event log are newest-first bounded feeds, -and the shared Model and Export dialogs keep their headers/actions fixed while -their bodies scroll within the viewport. +exported. The event log is a newest-first bounded feed, and the shared Model and Export dialogs keep their headers/actions fixed while their bodies scroll within the viewport. See [Testing](docs/TESTING.md), [Architecture](docs/ARCHITECTURE.md), [Security](docs/SECURITY.md), the accepted future [Gameplay Foundation](docs/GAMEPLAY_FOUNDATION.md), and the [Roadmap](ROADMAP.md). -Completed schema-v10 exports and legacy schema-v9 exports can be imported into -an ignored local SQLite archive and queried without repeatedly loading full JSON -artifacts. See [Local experiment archive](docs/EXPERIMENT_ARCHIVE.md). +Schema-v12 exports can be imported into an ignored local SQLite archive and queried without repeatedly loading full JSON artifacts. See [Local experiment archive](docs/EXPERIMENT_ARCHIVE.md). After Generate export, World Lab can also save that exact current validated artifact to the configured local archive with **Save to SQLite**. Preview remains an optional estimate and does not gate generation or saving. @@ -169,7 +112,9 @@ migrate manually, stop every Hex Zero process, create `.hexzero`, copy the legacy database (including any `-wal` and `-shm` sidecars if present), verify the copy opens, and only then remove the legacy files if desired. -New downloads use `hexzero-experiment-`. Existing -`agentborne-experiment-*.json` files and their schema-v9 contents remain -importable unchanged. Browser-owned settings stored under legacy `agentborne` -keys are schema-validated and copied once to the new `hexzero` keys. +New downloads use `hexzero-experiment-`. A legacy +`agentborne-experiment-*.json` filename is not itself a barrier to import, but +its contents must be schema version 12; the schema-v9 artifacts that name +generally accompanies are rejected like any other pre-swarm export. Browser-owned +settings stored under legacy `agentborne` keys are schema-validated and copied +once to the new `hexzero` keys. diff --git a/ROADMAP.md b/ROADMAP.md index 9cb6ba9..cc3b097 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,37 +1,79 @@ # Roadmap -## Active migration: one intelligence, many bodies - -The active zero-swarm sequence supersedes the earlier social-agent direction -for new experiments while retaining `legacy-multi-agent` as a comparison mode. -PRs A-C established the Jev reflex seam, Agent Zero planner/tick, and World Lab -presentation. PR D makes directives persistent across ticks and wakes Zero on -fixed review and material events. PR E added optional deterministic -`trail-hunter-v1` capture pressure while retaining `casual-cleaner`. PR F adds -seeded offline comparisons of zero-swarm, legacy, and deterministic worker -policies. The first comparison retains legacy mode pending real-provider trials; -see `docs/ZERO_SWARM_COMPARISON.md`. See ADRs 0028-0032. Historical milestones -below remain as implementation history. - -PR #58 closes the pre-live Jev capture-context and Agent Zero cost-accounting -gaps. PR #59 adds an explicitly opted-in live comparison of Jev workers against -deterministic workers while holding the Zero model and scenario inputs constant. -Legacy retirement remains a later decision after measured live results. - -## Experimental Patient Zero coordinator - -The current focused slice requires one normal physical agent, provides a -bounded global strategic summary, and adds private advisory Zero broadcasts -plus direct replies. It intentionally excludes extra movement/actions, -numerical bonuses, forced compliance, live player GPS, capture succession, -and simulated players. The coordinator participates in the same frozen-world, -simultaneous tick transaction as every other active agent. - -Post-foundation milestone 0024 makes the designation mandatory for every new -or live scenario and replaces the roster-sized Patient Zero diplomacy expansion -with a deterministic fixed-cap sparse summary. Historical null attribution -remains readable. Proposal-outcome memory, Patient Zero analytics corrections, -and further communication tuning remain separate milestones. +## Active migration: one intelligence, many bodies — delivered + +PRs A–F of the zero-swarm sequence established the architecture: the Jev reflex +seam, Agent Zero planner/tick, World Lab presentation, persistent directives +with material-event replanning, the `trail-hunter-v1` simulated-player profile, +and offline swarm comparisons. PRs #58–#59 closed the pre-live Jev +capture-context and Agent Zero cost-accounting gaps and added the explicitly +opted-in live Jev-vs-deterministic-worker comparison. See ADRs 0028–0032. + +The subsequent retirement sequence made zero-swarm the sole cognition +architecture and removed all legacy infrastructure: + +- **PR #65** (`refactor: make zero swarm the sole cognition architecture`): + removed `legacy-multi-agent` as a runnable mode, leaving zero-swarm as the + only path a tick can take. +- **PR #66** (`refactor: remove legacy social agent systems`): deleted the + machinery that mode had required — personalities, agent-to-agent + communication, alliances and diplomacy, worker goals, prose memories, the + `text-flat-json-v8` per-agent decision contract, observation history, the + Behavior Trace, and the legacy experiment-import route. +- **PR #67** (`refactor: make experiment telemetry swarm-native`): advanced + export schema to version 12 with `swarmArchitectureVersion: 'zero-swarm-v1'` + always present; removed compatibility branches for schema versions 9–11. +- **PR #68** (`refactor(world-lab): remove legacy agent controls`): removed + per-agent model selectors and the legacy World Lab UI controls tied to the old + architecture. +- **Documentation pass** (`docs: document the Zero swarm architecture`): + brought README, this roadmap, architecture, gameplay foundation, security, + testing, and the experiment-archive guide in line with the delivered + architecture. See ADR 0033. + +The retirement case is structural rather than measured: the legacy path made one +full generative provider call per active agent per tick, so provider attempts, +cost, and tick latency all scaled linearly with roster size. The zero-swarm path +makes one Agent Zero planning call per tick regardless of roster size. No run in +this repository has compared legacy cognition against zero-swarm cognition on +real providers for cost, latency, or quality; that difference follows from the +call pattern itself. See ADR 0033 for the full record. + +The deterministic-worker baseline (workers resolving directives without a model +call) is retained as the ablation control for the swarm comparisons, not as a +second production architecture. Historical milestones below remain as +implementation history. + +## Known open work + +The following issues are known and owned by a follow-on pull request: + +- `simulation-service.ts` passes an empty resolved-action array to + `calculateExperimentMetrics`, so all live World Lab experiment metrics read + zero even though `swarmTicks` now carries the data needed to populate them. +- `movementDirectionDistribution`, `longestRepeatedDirectionStreak`, and + `recentCellRevisits` are declared in the shared metrics schema but nothing + ever assigns them, so they always fall back to their schema defaults. The + direction helper itself already exists + (`geographicDirectionBetweenCells` in `apps/game-api/src/geographic-direction.ts`, + used by swarm pressure and reflex execution); what is missing is the + originating cell on the resolved-action record — which carries only the move + target — and the metric computation itself. + +## Agent Zero planner + +Agent Zero is the sole generative planner. It makes one OpenRouter call per +tick regardless of roster size, under the versioned contract `swarm-planner-v1`. +Each plan carries a strategy summary and one directive per active worker; +directives persist across ticks and are reused when no replan is triggered. +Agent Zero participates in the same frozen-world, simultaneous-tick transaction +as the workers whose directives it issues. The Jev worker model is pinned +server-side and is not a configurable per-worker selector. + +_The legacy "Experimental Patient Zero coordinator" role described here before +PR #65 — which provided bounded global strategic information and sent private +advisory directives while remaining subject to normal world-action rules — is +superseded. See ADR 0033._ Player development begins only after the agent milestones below demonstrate compelling behavior. Each milestone is intended to remain a focused pull request; do not implement ahead of the current milestone. @@ -60,6 +102,8 @@ By the end of PR 2, a human must be able to watch real agents independently move Implementation scope: six fixed agent profiles, a 61-cell Toledo development world, server-owned in-memory round-robin turns, OpenRouter strict structured decisions, live World Lab controls/markers/inspector, and deterministic offline automation. Persistence, autonomous scheduling, messaging, and player systems remain explicitly out of scope. +_Note: agent personalities and the per-agent inspector personality display introduced here were subsequently removed. See ADR 0033._ + ## PR 3 — Personality Lab Prompt/personality editing, presets, cloning, respawning, reproducible starting worlds, provider/model configuration, and cost visibility. @@ -68,6 +112,8 @@ First focused slice: server-owned session personality editing for the six existi Second focused slice: server-owned safe experiment telemetry, actual OpenRouter usage/cost visibility, filtered tiered JSON export, and automatic browser playback pause when all 61 development cells are infected. The active experiment retains 5,000 complete safe records independently of the 120-turn browser snapshot; reset creates a new experiment and process restart still loses all telemetry. Persistence, multiple stored experiments, upload/sharing, provider configuration, and budget enforcement remain deferred. +_Note: personality editing, presets, and all per-agent prompt configuration introduced in this milestone were subsequently removed. See ADR 0033._ + ## PR 4 — Social agents Range-limited messages, agent inboxes, relationship memories, communication visualization, cooperation, refusal, deception, and betrayal emerging through prompts rather than a large formal rules system. @@ -98,6 +144,8 @@ Eleventh focused slice: redesign World Lab as a persistent long-running experime Twelfth focused slice: add scenario-owned physical communication range, private alliance communications, bounded nearby awareness, deterministic legal-move ordering variety, neutral unaffiliated presentation, and operator-only private-communication observability without adding world actions or player mechanics. +_Note: agent-to-agent messaging, public world chat, formal alliances and diplomacy, per-agent model overrides, communication range, and all agent personality and strategy configuration introduced across these slices were subsequently removed. The individual-hex controller and territory scoreboard mechanics (second focused slice) remain current. See ADR 0033._ + ## Pre-PR 5 — Simultaneous tick experiment foundation Replace sequential agent turns with operator-driven simultaneous ticks. Every @@ -123,13 +171,17 @@ paths or SQL, recovery, scheduling, MCP, and archive authority remain deferred. Persistent short- and long-term objectives, compact memories, plan revision, summaries, and longer simulation runs. +_Note: per-agent strategic goals, the compact memory ledger, and the Behavior Trace introduced in this milestone were subsequently removed. The SQLite experiment archive (pre-PR-5 observability slice) remains current, updated to schema version 12. See ADR 0033._ + ## PR 6 — Persistent autonomous world Scheduled turns, snapshots, replay, retries, idempotency, durable budget/attempt ledgers, failure recovery, and operation without the World Lab browser being open. The current process-local attempt and credit-admission ceilings are an -operator safety boundary, and their schema-v11 safe ledger can be exported to +operator safety boundary, and their schema-v12 safe ledger can be exported to the analysis archive even when no turn committed. This is not active runtime persistence, restart recovery, or provider-account balance enforcement. +This milestone also owns the two known open metrics defects noted above. + Player development begins only after these agent milestones demonstrate compelling behavior. diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index aa619ed..d0cc2ba 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -2,9 +2,8 @@ ## Zero-swarm execution -`cognitionMode` distinguishes `legacy-multi-agent` from `zero-swarm-v1` in -scenarios, snapshots, and exports. Legacy ticks retain their original path. -For a zero-swarm tick, the service first advances deterministic player pressure +`zero-swarm-v1` is the sole cognition architecture. The service first advances +deterministic player pressure into an uncommitted world candidate. Agent Zero plans on the first tick, every five ticks, and when an expiry or material event requires review. Other ticks reuse committed unexpired worker directives and compile a fresh legal Zero wait @@ -48,10 +47,10 @@ open cell, relocation/reinforcement/evasion cannot target the worker's current cell, and reinforcement needs an infected or adjacent frontier target. An invalid plan falls back safely. A completed prior directive is not reused during that fallback. -Zero planning uses the same provider-reported OpenRouter usage normalization as -legacy turns, including actual `usage.cost` when returned, and preserves that -metadata when a returned plan is rejected or a bounded non-success response -contains usage. Missing provider cost remains unknown. +Zero planning follows provider-reported OpenRouter usage normalization, +including actual `usage.cost` when returned, and preserves that metadata when a +returned plan is rejected or a bounded non-success response contains usage. +Missing provider cost remains unknown. World Lab distinguishes provider-reported cost from admission exposure. Each attempt with unknown monetary cost, including TypeSafe Jev, retains its configured per-attempt credit reserve in admission exposure. That reserve is @@ -69,13 +68,10 @@ gives that worker engine-legal deterministic local expansion without a Jev call. This prevents repeated billed Jev waits under a failed planner while retaining planner attempt telemetry. -Swarm tick records are separate from legacy agent turn records. Full all-agent -exports and the archive retain safe plans, directives, action choices, and -factual provider usage; selective legacy turn filters do not export partial -swarm plans. World Lab selects a dedicated swarm presentation from the -scenario mode. It shows Zero strategy, worker directives and Jev decisions, -progress, replanning signals, and provider usage while omitting irrelevant legacy social cognition -controls. See ADR 0030. +Full all-agent exports and the archive retain safe plans, directives, action +choices, and factual provider usage. World Lab presents the swarm view: Zero +strategy, worker directives and Jev decisions, progress, replanning signals, +and provider usage. See ADR 0030. Provider-attempt and credit-exposure admission are owned by `SimulationService`. Its ledger is deliberately separate from deterministic world state and committed-turn @@ -86,14 +82,13 @@ unknown or cancelled calls retain exposure, and a reported reservation overage stops future admission when a credit ceiling is enabled. These decimal-string totals are server authority, but they do not enforce the upstream account balance. See ADRs 0025 and 0026. -PR F supplies a separate offline comparison harness. It runs legacy, -zero-swarm, and deterministic-worker fixtures against the same seeded scenario -and player pressure, then emits JSON per-tick samples and aggregates. It is a -read-only research runner: it creates no live providers, reads no provider key, -and does not write to the experiment archive. Archive comparison remains useful -for safe completed exports, but is legacy-turn-centric and does not substitute -for the same-scenario swarm harness. See -[Zero-swarm offline comparison](ZERO_SWARM_COMPARISON.md). +The offline comparison harness runs zero-swarm (Jev workers) and +deterministic-worker fixtures against the same seeded scenario and player +pressure, then emits JSON per-tick samples and aggregates. It is a read-only +research runner: it creates no live providers, reads no provider key, and does +not write to the experiment archive. Archive comparison remains useful for safe +completed exports, but does not substitute for the same-scenario swarm harness. +See [Zero-swarm offline comparison](ZERO_SWARM_COMPARISON.md). The separately opted-in live comparison runs real OpenRouter Agent Zero with either Jev workers or a deterministic legal-candidate worker policy, using @@ -110,59 +105,46 @@ advances one deterministic virtual interval in the world engine. The baseline `trail-hunter-v1` routes from visible infection and can capture an agent only when they share a cell. Capture removes the agent, leaves its infected cells abandoned, and changes the active roster before provider dispatch. If no agents -remain, or Patient Zero is captured in zero-swarm mode, the player-only tick +remain, or Agent Zero is captured, the player-only tick commits a terminal outcome. Player events remain an uncommitted candidate until the tick commits, so cancellation cannot partially advance pressure. -Ordinary agents retain bounded own/nearby successful-clean evidence. The one -configured Patient Zero additionally receives a deterministic, current-interval +Ordinary workers retain bounded own/nearby successful-clean evidence. Agent +Zero additionally receives a deterministic, current-interval feed of successful cleans and occupied-cell blocks, capped at 128 entries with truthful total/truncation metadata; overflow retains the most recent entries in chronological order. Event cells are intentional historical clean/block locations. The feed excludes movement and the cleaner's live/current position, route, target, identity, and future-timing data. Each displayed event carries a fixed six-tick, engine-derived pressure context -for its subject: subject totals/category counts/consecutive affected ticks and, -when currently allied, aggregate counts across the alliance's current members. -The event list remains current-interval-only; no historical event array or -historical membership inference is added. +for its subject: subject totals/category counts/consecutive affected ticks. +The event list remains current-interval-only; no historical event array is added. The rollup reads committed prior intervals from the dedicated simulated-player event history and combines them with only the current tick's uncommitted candidate cleaner events. It does not depend on the smaller general world-event display buffer, and candidate events enter dedicated history only when the whole tick commits. -The Game API owns an operator-triggered tick transaction. It freezes the world -and builds every observation before dispatching any model request. A -provider-neutral runtime dispatcher starts jobs concurrently with bounded -concurrency, resolved model/reasoning identity, immutable per-agent observation, -and one shared absolute deadline. Provider completion order is never resolution -order. +The Game API owns an operator-triggered tick transaction. It builds Zero's +strategic observation from the frozen candidate world and dispatches the single +planning call; worker reflex calls follow sequentially, each receiving an +immutable compiled local observation. All calls share one absolute deadline. The simulation derives a reproducible per-tick agent order from the scenario -seed. The world engine then resolves all world actions, all communications using -the frozen pre-tick eligibility state, all diplomacy, and one proposal-expiration -pass. Only the complete candidate state and complete record group commit. -Cancellation aborts outstanding jobs and commits neither records, events, tick, -nor virtual time. The browser accelerates explicit tick requests; it does not -schedule authoritative work in the background. +seed. The world engine then resolves all world actions in that order. Only the +complete candidate state and complete record group commit. Cancellation aborts +outstanding jobs and commits neither records, events, tick, nor virtual time. +The browser accelerates explicit tick requests; it does not schedule +authoritative work in the background. ## Persistent World Lab operator shell World Lab owns one browser execution controller at the root of its client component. The controller centralizes authoritative snapshot reconciliation, mutation IDs, playback timing, bounded tick targets, and cancellation. Switching between the Live and Agents workspaces changes only the presented workspace; it does not unmount or duplicate the controller, its timer, or its in-flight request state. -The Live workspace is a grid of independently scrolling agent rail, map, contextual inspector, and bounded activity dock. Agent and hex selections select the corresponding semantic inspector tab, while Scoreboard and Run remain directly reachable. The Agents workspace reuses the same snapshot and existing server mutations for model, reasoning, personality, and strategy assignment. Roster replacement remains a World Setup operation that creates a replacement experiment rather than mutating the active roster mid-run. +The Live workspace is a grid of independently scrolling agent rail, map, contextual inspector, and bounded activity dock. Agent and hex selections select the corresponding semantic inspector tab, while Scoreboard and Run remain directly reachable. The Agents workspace selects the Agent Zero model and reasoning profile; the server-pinned Jev model is shown as runtime information. Roster replacement remains a World Setup operation that creates a replacement experiment rather than mutating the active roster mid-run. -Formal alliance experimentation preserves the existing one-way trust boundary: +The Game API also owns one process-local experiment record. Each completed safe swarm tick is captured once, independently from the browser snapshot, and server-side export filters apply without affecting provider requests. -```text -World Lab → Game API / simulation service → agent runtime → one decision - ↓ - snapshot / turn record ← independent world + communication + diplomacy validation -``` - -The Game API also owns one process-local experiment record. Each completed safe turn is captured once, independently from the browser snapshot, and server-side export levels filter that record without affecting provider requests. - -Completed schema-v10 exports and compatible schema-v9 exports may cross a separate offline archive boundary into `packages/experiment-archive`. Node's built-in SQLite stores normalized immutable research records through versioned migrations, foreign keys, prepared statements, and transactional idempotent imports. This downstream observability archive is never consulted by tick execution and cannot recover, resume, or mutate the active world. Its bounded query service is application-independent so a future read-only MCP adapter can reuse it without exposing arbitrary SQL. +Schema-v12 exports may cross a separate offline archive boundary into `packages/experiment-archive`. Node's built-in SQLite stores normalized immutable research records through versioned migrations, foreign keys, prepared statements, and transactional idempotent imports. This downstream observability archive is never consulted by tick execution and cannot recover, resume, or mutate the active world. Its bounded query service is application-independent so a future read-only MCP adapter can reuse it without exposing arbitrary SQL. World Setup uses `world-scenario-v1`. Pure preview computes the actual H3 disk, exact count, summed cell area, deterministic roster/spawns, feasibility, and warnings. Apply recomputes and atomically replaces world and experiment state. Reset reconstructs the current scenario; the Toledo default preserves legacy starts. Explicit location search crosses a replaceable server-owned adapter with no autocomplete, a one-request-per-second Nominatim limit, bounded cache/timeout, normalized results, and OpenStreetMap attribution. Manual coordinates bypass that network boundary. @@ -172,166 +154,99 @@ World Lab issues explicit ticks while Start or a bounded run is active. Provider `apps/world-lab` is a Next.js App Router developer/admin surface. It fetches runtime-validated simulation snapshots through a local rewrite, controls one tick at a time, and updates MapLibre's existing H3 GeoJSON source without recreating the map. Agent markers are fully visible and use deterministic offsets when sharing cells. -Its command navbar is the single persistent application-control row. Browser-session run-target selection remains client orchestration and preserves absolute tick semantics; execution and reconciliation still consume authoritative API snapshots. Global and per-agent selectors share one deduplicating, case-insensitive model-option builder. Current alliance membership is the first UI color authority for map, roster, chat, and log accents, followed by retained effective color, base agent color, and a neutral fallback. +Its command navbar is the single persistent application-control row. Browser-session run-target selection remains client orchestration and preserves absolute tick semantics; execution and reconciliation still consume authoritative API snapshots. Agent color uses retained effective color, base agent color, and a neutral fallback. The default basemap is tokenless CARTO Dark Matter with OpenStreetMap and CARTO attribution. Deterministic tests inspect its configuration and mocked MapLibre H3 sources without requesting external tiles. -World Lab derives a six-record, newest-first Behavior Trace entirely from the -bounded `AgentTurnRecord` snapshot already returned by the Game API. The trace -compares consecutive observations for the selected agent, separates newly -retained communication and board evidence, displays legal action affordances -beside the selected action, and labels repeated or changed action patterns. -Model summaries remain explicitly self-reported evidence rather than causal -proof. Cell highlighting reuses browser selection state and creates no server -mutation, new telemetry, retention, provider field, or world authority. +Equivalent legal moves are ordered reproducibly from world seed, stable agent ID, and logical turn without process randomness. Their six-value compass labels are derived independently from the geographic initial bearing between H3 cell centers using equal 60-degree sectors; H3 traversal order never determines direction. -Communication resolves against the authoritative pre-action snapshot. Public chat is globally observable and future-player-visible. Direct messages use H3-center great-circle distance and the scenario's bounded kilometer range. Alliance messages are private to current members regardless of distance. World Lab may inspect private traffic; player-facing contracts must not include that omniscient feed. Equivalent legal moves are ordered reproducibly from world seed, stable agent ID, and logical turn without process randomness. Their six-value compass labels are derived independently from the geographic initial bearing between H3 cell centers using equal 60-degree sectors; H3 traversal order never determines direction. - -`apps/game-api` is a Hono service bound conservatively to loopback. Its single in-memory `SimulationService` owns the development session, monotonic completed-turn count, turn cursor, bounded histories, per-agent strategic goals and compact memory ledgers, and overlap lock. Goals and memories are not part of world-engine `Agent` ownership and grant no engine authority. It exposes: +`apps/game-api` is a Hono service bound conservatively to loopback. Its single in-memory `SimulationService` owns the development session, monotonic completed-tick count, bounded histories, and overlap lock. It exposes: - `GET /api/simulation` — current authoritative snapshot -- `POST /api/simulation/tick` — one simultaneous decision opportunity for every active roster agent +- `POST /api/simulation/tick` — one atomic swarm tick: plan, dispatch directives, resolve via Jev, apply world actions - `POST /api/simulation/tick/cancel` — atomically abort the active tick -- `POST /api/simulation/turn`, `/turn/retry`, `/turn/skip`, and unattended turn variants — legacy sequential/schema-v9 compatibility only; they cannot mix with committed ticks -- `POST /api/simulation/turn/cancel` — legacy cancellation alias -- `POST /api/simulation/reset` — deterministic reset, rejected while a turn is active -- `POST /api/simulation/agents/:agentId/personality` — trim, validate, and replace one active personality -- `POST /api/simulation/personalities/restore-defaults` — restore all eight milestone personality directives without resetting progress -- `POST /api/simulation/experiment/export/preview` — validate filters and report subset size, retention, cost, and approximate sharing tokens -- `POST /api/simulation/experiment/export` — construct one schema-versioned safe JSON document -- `POST /api/simulation/experiment/export/archive` — manually import the exact - generated safe document into the configured local SQLite archive +- `POST /api/simulation/reset` — deterministic reset, rejected while a tick is active +- `POST /api/simulation/experiment/setup/preview` — compute H3 disk, roster/spawns, feasibility, and warnings without applying +- `GET /api/simulation/experiment/setup/default` — return the default world-setup request +- `POST /api/simulation/experiment/setup` — atomically replace world and experiment state +- `POST /api/simulation/experiment/setup/roster/generate` — generate a deterministic roster +- `POST /api/simulation/experiment/setup/location-search` — resolve a location query via the Nominatim adapter +- `POST /api/simulation/experiment/export/preview` — validate filters and report subset size, retention, and cost +- `POST /api/simulation/experiment/export` — construct one schema-v12 safe JSON document +- `POST /api/simulation/experiment/export/archive` — import the exact generated safe document into the configured local SQLite archive - `GET /api/simulation/models` — return the cached, sanitized compatible model catalog - `POST /api/simulation/models/refresh` — explicitly refresh that catalog -- `POST /api/simulation/models/verify` — make one explicit, non-mutating compatibility probe -- `POST /api/simulation/experiment/models` — replace the unlocked global/per-agent assignment -- `POST /api/simulation/experiment/import` — restore model assignments from a validated export +- `POST /api/simulation/models/verify` — make one explicit, non-mutating compatibility probe against `swarm-planner-v1` +- `POST /api/simulation/experiment/models` — replace the Agent Zero model assignment -The legacy `GET /api/development-world` and `GET /health` endpoints remain for low-level diagnostics. +The `GET /api/development-world` and `GET /health` endpoints remain for low-level diagnostics. -The Game API is authoritative for session personality configuration. World reset reconstructs deterministic positions, 127 open cells, empty alliances/proposals/events/metrics, cursor, and completed-turn count, then reapplies the eight current personality values. Restoring defaults changes only those values. Both personality mutations are rejected while the service's turn lock is active. +World reset reconstructs deterministic positions, 127 open cells, empty events and metrics, and a new experiment, and is rejected while a tick is active. ## Tick flow -Every current applied scenario designates one Patient Zero coordinator. The service -adds a bounded global strategic view only to that agent's immutable -observation; other observations retain their local/alliance bounds. The engine -alone authorizes player-hidden Zero broadcasts and Patient-Zero-endpoint direct -range bypass. Patient Zero receives no extra movement, action, infection, -capture, ownership, or alliance authority. Every agent observation is built -from one frozen pre-tick snapshot. +Agent Zero is the generative planner for the roster; every applied scenario +designates one roster agent for the role through `patientZeroAgentId`, which +World Lab badges HEX-0. One OpenRouter call per +tick, under the `swarm-planner-v1` contract, produces a strategy summary, +per-worker directives, and Agent Zero's own action candidate. Workers resolve +their directives with TypeSafe Jev reflex cognition; Agent Zero receives no +extra movement, action, infection, capture, or ownership authority beyond the +action candidate it selects like any other agent. The authoritative world's newest 120 events remain a bounded operator/display feed. Agent observations do not depend on that mixed feed for their promised factual windows. The Game API separately retains bounded movement, action, -communication, control-change, alliance-lifecycle, and capture ledgers, -including participant-specific private-message histories. These ledgers accept -only newly committed engine events: simultaneous ticks carry the complete -untrimmed event batch into commit and ingest it once after the final -cancellation check while separately capping the display feed; legacy turns -ingest only successful committed events, and provider failures, retries awaiting resolution, skips, and -cancellations add no facts. World reset and applied World Setup reinitialize -the ledgers; model, personality, and behavior configuration changes preserve -them. - -Patient Zero's global diplomacy context is a fixed-cap sparse summary of -authoritative eligible pairs, acceptable proposals, leave availability, -aggregate blocker counts, and prioritized blocker examples. Deterministic -counts and truncation flags preserve global shape without a roster-sized -feasibility expansion. Historical exports may retain a null designation, but -that read compatibility never creates a coordinator-free live scenario. - -The universal `text-flat-json-v8` prompt makes `communicationType: "none"` the -normal choice for ordinary agents and Patient Zero unless a message adds new -decision-relevant value. Concrete requests or replies, negotiation, -observed-fact warnings, changed plans, border/conflict coordination, and -coordinated targets or routes are useful categories. Routine action narration, -motivational filler, observation/summary restatement, and unchanged-plan -repetition are prohibited prompt behaviors. Messages accompanying formal -diplomacy add terms or context instead of duplicating the formal intent. Useful -messages retain the assigned personality and style, and all existing channel, -trust, privacy, and Patient Zero authority rules remain unchanged. This is -provider guidance, not engine semantic classification, rejection, or throttling. - -Recoverable provider, parsing, and schema failures may consume the one automatic -retry inside the shared deadline. An unresolved decision becomes an attributed -final lost tick. Ordinary engine-authoritative action rejection remains a -completed `rejected` outcome and does not affect sibling components. - -For a new logical turn, the service owns one 75-second deadline and permits at -most two provider calls: initial plus either one contract repair or one transient -transport retry. Both calls receive the same immutable observation, resolved -model, and reasoning profile. Repair prompts are fresh universal flat-JSON -requests containing only allowlisted validation codes; raw invalid output is -discarded. Structurally normalized decisions enter the normal engine path once, -and engine rejection is never an automatic retry condition. +control-change, and capture ledgers. These ledgers accept only newly committed +engine events: ticks carry the complete untrimmed event batch into commit and +ingest it once after the final cancellation check while separately capping the +display feed. World reset and applied World Setup reinitialize the ledgers; +model configuration changes preserve them. The development world is a deterministic H3 resolution-nine radius-six disk (127 cells) around Toledo with eight fixed profiles and unique perimeter starts. -Every active agent receives one decision opportunity per tick. Each provider -call asks for one flat JSON object containing a required world action, zero or -one communication, and zero or one diplomacy intent (`propose-alliance`, -`accept-alliance`, or `leave-alliance`). Required sentinel-bearing fields -normalize into the internal unions before existing Zod and engine validation. -There are no background inference calls or automatic replies. - -Names, colors, stable IDs, and starting cells remain fixed. Personality text is mutable session configuration, but each observation copies the active value at turn start. Completed observations and turn records remain immutable, so a newly edited active personality can intentionally differ from the latest historical observation until that agent acts again. - -The engine alone accepts or rejects all components and creates events. The -service applies every world action, then every communication using frozen -pre-tick eligibility, then diplomacy, then one proposal-expiry pass. Each -rejected component leaves the others intact. Missing text, unusable JSON, -contradictory fields, timeouts, and truncated output produce a lost tick for -that agent while valid siblings resolve. Operator cancellation aborts all -active requests and commits no world, events, records, tick, or virtual time. - -## Formal alliance state - -World state supports every feasible partition of the active roster into -alliances and bounded pending proposals. Alliance and proposal IDs are -system-generated typed UUIDs. Each alliance contains two agents through the -entire active roster, and each agent belongs to at most one alliance. The engine -uses deterministic accessible display colors and may reuse the palette; display -identity is never a gameplay capacity rule. A proposal records proposer, -recipient, both participants' alliance attribution at creation, -the globally unique originating record ordinal, and tick authority. Created at -tick `N`, it expires at tick `N + 2` without inference; legacy schema-v9 turn -fields retain their two-roster-round lifetime. The one expiry pass is attributed -to the final record in deterministic resolution order so its safe telemetry is -not lost. - -Free agents may form an alliance with another free agent or request entry by -proposing to a member of an existing alliance. Allied agents may invite a free -agent. Recipient-only acceptance either forms a two-agent alliance or admits -the unaffiliated participant into the recorded unchanged alliance. -Alliance-to-alliance merging remains invalid. Membership changes invalidate -impossible proposals. Departure is unilateral; an agent may later request or -accept membership elsewhere. Individual hex control never changes, and an -alliance dissolves below two members. - -Each frozen observation contains engine-/service-authored diplomacy affordances: -exact proposal recipient IDs, acceptable proposal IDs, leave availability, and -compact stable blocker codes for a bounded set of unavailable targets. Patient -Zero receives a fixed-cap sparse global summary: total eligible pair and -acceptable-proposal counts, at most 12 displayed pairs, eight proposal IDs, -eight leave IDs, stable blocker totals, prioritized examples, and explicit -truncation. It receives no pending decisions or free-form pair matrix and may -recommend only displayed IDs. Eligible pairs use deterministic round-robin -proposer coverage with a tick-based rotation so the fixed display budget does -not permanently favor low-sorting agent IDs. The model copies listed IDs into -the same flat response. Provider -tools are not used: a tool round trip would add another -inference boundary and tokens while duplicating deterministic engine knowledge; -no measured token saving is claimed. - -Formal proposal creation uses the scenario `communicationRangeKm` against -frozen pre-action positions. Same-tick movement cannot make a target newly -eligible. Patient Zero's direct-message endpoint bypass is limited to direct -communication and never bypasses formal diplomacy range. - -Public communication is visible to every agent without a range check. Direct communication authoritatively trims and bounds text, requires a distinct existing recipient, and accepts inclusive pre-action H3 distances 0–3. Moving closer in the same decision cannot change eligibility. Accepted communications enter the bounded world-event stream; rejected attempts remain safe structured turn telemetry with a reason, sender, channel, recipient when applicable, nullable computed distance, timestamp, event ID, and trimmed text. No raw provider response is retained. - -Snapshots keep the newest 120 turn records and 120 world events. Observations expose controller/alliance/effective-color data for current and adjacent cells, up to seven other agents, an eight-entry individual scoreboard, active alliance totals and member contributions, relevant proposals, at most eight chronological alliance events, six control changes, 12 public messages, and six relevant direct messages. These are bounded event-derived views, and all model-authored text remains untrusted subordinate context. +Names, colors, stable IDs, and starting cells remain fixed. + +One tick executes as follows: + +1. **Simulated-player advance.** The configured player profile advances one + deterministic virtual interval over the pre-tick world state, producing an + uncommitted candidate. If Zero is captured or no roster agents remain the + service commits a player-only terminal tick and returns. + +2. **Replan determination.** The service evaluates replan reasons + (`initial`, `periodic-review`, `directive-complete`, `directive-expired`, + `worker-request`, `worker-stalled`, `territory-loss`, `high-pressure`, + `player-disinfection`, `roster-changed`). No reasons means the prior + directives are valid; Zero's action is recompiled from existing candidates + without a provider call (`directive-reuse`). + +3. **Provider-attempt reservation.** When replanning, the tick reserves one + Zero planning attempt plus one Jev attempt per worker. Insufficient capacity + stops the tick before any provider call. + +4. **Zero planning.** The service builds Zero's strategic observation from the + frozen candidate world — including pressure events, completed directives, and + legal Zero action candidates — then calls Agent Zero via the OpenRouter + `swarm-planner-v1` contract. Zero returns a strategy summary, per-worker + directives, and its own action candidate ID. On failure the service falls + back to a deterministic plan; the planner attempt is still recorded. + +5. **Worker reflex dispatch (sequential).** For each worker in seeded order: + compile a local observation with the assigned directive and history; call + TypeSafe Jev; Jev selects one opaque action candidate ID with a probability + distribution and confidence. If the worker lacks an unexpired directive under + a failed planner, the service substitutes deterministic local expansion + without a Jev call. + +6. **World resolution.** The engine applies Zero's action and each worker's + mapped action in the seeded per-tick order. The engine is the sole authority; + it accepts or rejects each action independently. + +7. **Atomic commit.** World state, tick record (plan, directives, Jev + decisions, action results), and virtual time advance together. Provider + attempts survive world rollback. Operator cancellation before this point + commits nothing. ## Experiment telemetry and export @@ -346,31 +261,30 @@ archive never becomes simulation authority. The active experiment has a runtime-validated UUID, start time, versioned authoritative scenario and ordered initial roster, immutable configuration events, initial world, and up to 5,000 complete safe turns. The browser snapshot and world-event list remain capped at 120. Reset creates a new experiment from the current scenario and clears telemetry/cost; no previous experiments survive reset or process restart. -Metrics and filtering are deterministic Game API responsibilities. Schema v10 adds mandatory tick attribution, first-class lost ticks, and per-tick summaries. `modelAttempts` is canonical for provider-call, latency, token, and cost totals so repairs and transient retries are not undercounted. Tick-native and unstarted tick-default experiments export v10; retained sequential experiments remain v9 and cannot mix execution modes. The Game API retains its documented older safe-import support for model configuration. +Metrics and filtering are deterministic Game API responsibilities. All exports +use schema version 12, which carries `swarmArchitectureVersion: "zero-swarm-v1"` +and independent provider-attempt accounting unconditionally. Pre-swarm exports +(schema versions 9, 10, and 11) are rejected outright; there is no migration +path. The provider-attempt ledger is canonical for attempt counts, latency, +token, and cost totals. The agent runtime follows [OpenRouter's usage-accounting contract](https://openrouter.ai/docs/cookbook/administration/usage-accounting) and normalizes optional non-streaming usage fields: prompt, completion, total, reasoning, cached-read, cache-write tokens, and actual `usage.cost` as `costCredits`. It never derives price from a table. Safe usage already returned with a billable response is retained on later decision JSON/schema failure; network and HTTP failures without usage remain unknown. Scripted providers explicitly report zero tokens and zero cost. ## Packages -`packages/shared` owns centralized scenario limits and all public schemas, including model capabilities, behavior assignments, alliances, metrics, schema-v10 tick exports, and genuine legacy schema-v9 exports. Other-agent observations remain deterministically capped at seven for larger rosters. Types are inferred from Zod. +`packages/shared` owns centralized scenario limits and all public schemas, including model capabilities, swarm directives, metrics, and schema-v12 swarm tick exports. Other-agent observations remain deterministically capped at seven for larger rosters. Types are inferred from Zod. -`packages/world-engine` remains deterministic and has no model, HTTP, UI, storage, or credential dependency. It validates world action, communication, and diplomacy independently and is the sole alliance mutation authority. Direct proximity is derived from a separately supplied pre-action state. +`packages/world-engine` remains deterministic and has no model, HTTP, UI, storage, or credential dependency. It validates world actions independently. Direct proximity is derived from a separately supplied pre-action state. -`packages/agent-runtime` contains the OpenRouter adapter and server-only catalog client. The universal contract requires text input/output, chat completions, `max_tokens`, non-streaming operation, and at least 16,384 context tokens. The centralized floor covers the bounded complete observation and fixed prompt while reserving a 4,096-token completion ceiling for the JSON decision. Catalog requests use matching server filters, then locally validate every entry. Inference requests deliberately omit tools, `tool_choice`, `response_format`, and `provider.require_parameters`. Provider-default reasoning omits `reasoning`; Off sends `{ enabled: false, exclude: true }`; an advertised effort sends `{ enabled: true, effort, exclude: true }`. No model-family logic, allowlist, compatibility flag, or model default exists. +`packages/agent-runtime` contains the OpenRouter swarm planner, the TypeSafe Jev reflex adapter, and the server-only catalog client. The planner contract (`swarm-planner-v1`) requires text input/output, chat completions, `max_tokens`, non-streaming operation, and at least 16,384 context tokens. The centralized floor covers the bounded complete observation and fixed prompt while reserving a 4,096-token completion ceiling for the JSON decision. Catalog requests use matching server filters, then locally validate every entry. Inference requests deliberately omit tools, `tool_choice`, `response_format`, and `provider.require_parameters`. Provider-default reasoning omits `reasoning`; Off sends `{ enabled: false, exclude: true }`; an advertised effort sends `{ enabled: true, effort, exclude: true }`. No model-family logic, allowlist, compatibility flag, or model default exists. The catalog has an eight-second timeout and five-minute in-memory TTL. A successful response replaces the cache. A timeout, transport/HTTP failure, or malformed response retains the last successful catalog and marks it stale with a safe error; without a prior success it returns an empty error state. Manual refresh bypasses TTL while coalescing concurrent refreshes. -Every agent resolves an explicit global assignment or per-agent override before execution, including its reasoning profile. The acting agent's resolved slug and profile are passed to its request. Assignments may change while playback is paused and no provider/reset mutation is active. Each change is exported with timestamp, scope, prior/new slug, prior/new reasoning profile, and the first globally unique record ordinal at which it is effective; tick execution applies the configuration to the next committed tick group. No unavailable model/profile or missing model is substituted. +Agent Zero resolves its model from the global assignment before each planning call, including its reasoning profile. Assignments may change while playback is paused and no provider/reset mutation is active. Each change is exported with timestamp, scope, prior/new slug, prior/new reasoning profile, and the first globally unique record ordinal at which it is effective; tick execution applies the configuration to the next committed tick group. No unavailable model/profile or missing model is substituted. -The centralized 75-second provider abort timeout covers the complete response lifecycle, including body reading, response decoding, bounded JSON extraction/repair, normalization, and schema validation, and is cleared after every outcome. The same AbortController supports an explicit non-turn-consuming operator cancellation. Safe records expose only bounded status/code/message/request ID/model/finish-reason/latency/usage fields. Scripted providers are explicit deterministic seams selected only by tests or `HEXZERO_PROVIDER=scripted`; there is no automatic fallback. Manual probes use the exact text/flat-JSON contract and selected reasoning profile, never mutate or advance the world, may incur a small charge, and are cached only for the current server session by model ID, reasoning profile, and contract version. +The centralized 75-second provider abort timeout covers the complete response lifecycle, including body reading, response decoding, bounded JSON extraction/repair, normalization, and schema validation, and is cleared after every outcome. The same AbortController supports an explicit non-tick-consuming operator cancellation. Safe records expose only bounded status/code/message/request ID/model/finish-reason/latency/usage fields. Scripted providers are explicit deterministic seams selected only by tests or `HEXZERO_PROVIDER=scripted`; there is no automatic fallback. Manual probes use the `swarm-planner-v1` contract and selected reasoning profile, never mutate or advance the world, may incur a small charge, and are cached only for the current server session by model ID, reasoning profile, and contract version. -The deadline is shared by both permitted automatic attempts rather than renewed -per call. Tick browser mutations carry bounded client operation IDs and repeated -delivery is coalesced server-side; Turn and Retry retain that behavior only for -legacy sequential API compatibility. When a proxy connection resets or a -response is otherwise lost, World Lab clears its local guard, refetches the -authoritative snapshot, and shows a height-stable reconciling state while polling -an active tick. It never resubmits merely because a response was ambiguous. +The deadline is shared across the planning call and all worker reflex calls in one tick rather than renewed per call. Tick browser mutations carry bounded client operation IDs and repeated delivery is coalesced server-side. When a proxy connection resets or a response is otherwise lost, World Lab clears its local guard, refetches the authoritative snapshot, and shows a height-stable reconciling state while polling an active tick. It never resubmits merely because a response was ambiguous. Attempt aggregation is field-wise: known prompt, completion, total, reasoning, cache-read, and cache-write values remain visible even when another attempt has @@ -382,25 +296,16 @@ when it fits the original deadline, and the active cancellation signal aborts the wait. The rationale and deferrals are recorded in [ADR 0002](adr/0002-first-visible-llm-invasion.md). -Personality ownership and reset semantics are recorded in [ADR 0003](adr/0003-session-personality-configuration.md). Experiment capture and export semantics are recorded in [ADR 0004](adr/0004-server-owned-experiment-telemetry.md). Manual direct SQLite archival of a generated artifact is recorded in [ADR 0021](adr/0021-manual-direct-sqlite-export.md). -Nearby-message authority, observation bounds, and export selection semantics are recorded in [ADR 0005](adr/0005-nearby-agent-messaging.md). -Contested control, capture, territory authority, and schema-v3 selection semantics are recorded in [ADR 0006](adr/0006-contested-hex-control.md). -Decoupled communication and schema-v4 selection semantics are recorded in [ADR 0007](adr/0007-decoupled-world-communication.md). -Selective agent communication and `text-flat-json-v4` attribution are recorded in [ADR 0015](adr/0015-selective-agent-communication.md). -Formal alliances, the expanded experiment, and schema-v5 semantics are recorded in [ADR 0008](adr/0008-formal-alliances-experiment.md). -Fluid alliance capacity, join requests, and authoritative diplomacy affordances supersede its fixed-size/color-capacity rules in [ADR 0016](adr/0016-fluid-alliances-and-diplomacy-affordances.md). -Capability-driven model discovery and experiment assignments are recorded in [ADR 0009](adr/0009-capability-driven-model-catalog.md). -Versioned behavior profiles, seeded assignment, and authoritative diplomacy affordances are recorded in [ADR 0010](adr/0010-versioned-agent-behavior.md). - -Behavior configuration is experiment-owned and includes registry version 1, assignment mode, seed, and one allowlisted personality/strategy pair per agent. Balanced random is the safe default. Reset creates a new experiment and deterministic assignment from its seed; the first completed turn locks behavior. Every retained turn copies its effective assignment, while model and reasoning changes retain their existing between-request semantics. +Contested control, capture, and territory authority are recorded in [ADR 0006](adr/0006-contested-hex-control.md). +Capability-driven model discovery is recorded in [ADR 0009](adr/0009-capability-driven-model-catalog.md). +The zero-swarm architecture, retirement of legacy cognition, and export schema 12 are recorded in [ADR 0033](adr/0033-retire-legacy-multi-agent-architecture.md). -Schema-v8 computed metrics include complete personality, strategy, observed personality/strategy-combination, and agent breakdowns derived from the same filtered retained turns and attempt records as the aggregate. Logical-turn, provider-call, failure, recovery, token, and cost counters therefore remain attributable without storing reasoning. Structural provider failures retain the broad compatibility code plus bounded details such as missing proposal IDs and contradictory diplomacy recipient fields in attempt telemetry and safe exports. Well-formed unavailable IDs remain engine-authoritative rejections and are not retried. +Structural provider failures retain the broad compatibility code plus bounded details in attempt telemetry and safe exports. Well-formed unavailable IDs remain engine-authoritative rejections and are not retried. -# Provider-attempt accounting +## Provider-attempt accounting -Provider work has an independent bounded lifecycle ledger. Schema-v11 exports -and archive-v4 preserve safe attempt records even when no world turn commits; -turn-owned model-attempt arrays remain compatibility detail only. +Provider work has an independent bounded lifecycle ledger. Schema-v12 exports +and archive-v4 preserve safe attempt records even when no world tick commits. diff --git a/docs/EXPERIMENT_ARCHIVE.md b/docs/EXPERIMENT_ARCHIVE.md index a96c053..6f312ac 100644 --- a/docs/EXPERIMENT_ARCHIVE.md +++ b/docs/EXPERIMENT_ARCHIVE.md @@ -1,12 +1,8 @@ # Local experiment archive -> **Note:** this document predates the zero-swarm migration and still describes -> several removed legacy features (per-agent communications, diplomacy, -> alliances, and the schema-v9/v10/v11 compatibility described below). The -> archive now accepts only schema-v12 exports and rejects anything else; see -> ADR 0033. A full rewrite of this document is tracked separately. - The archive accepts only schema-v12 exports and rejects any other schema version outright. +Pre-swarm exports (schema versions 9, 10, and 11) are rejected with no migration path; reading them +requires checking out the Git revision before PR 1 of the zero-swarm migration. Migration 2 adds nullable tick number, deterministic tick position, virtual time, and interval columns. Bounded queries order tick-attributed records by tick and tick position where exposed; the CLI still provides no arbitrary SQL @@ -15,6 +11,15 @@ Migration 3 adds aggregate simulated-player metrics to experiments and the `simulated_player_activity` table. Every metrics-bearing safe export preserves movement/clean/block totals; Full Safe additionally preserves tick-attributed activity without deriving player behavior from agent turns. +Migration 4 adds the independent `provider_attempts` table and per-experiment +attempt-accounting and attempt-retention columns. +Migration 5 adds the `swarm_ticks` table for safe committed zero-swarm plans, +directives, physical action results, and worker choice telemetry. +Migration 6 removes all legacy per-agent-LLM social-system tables: `turns`, +`model_attempts`, `communications`, `communication_recipients`, +`diplomacy_attempts`, and `alliance_events`. The `world_events` table's +`turn_number` column is renamed `tick_number`. Personality and behavior columns +are dropped from `agents` and `experiments`. The experiment archive is a durable, local research surface for completed or partially retained exports. It does not participate in an active simulation: the Game API's in-memory engine remains authoritative, and an archive write cannot change an accepted game outcome. It imports schema-v12 JSON exports only; it is not crash recovery, restartable simulation state, or a scheduler. @@ -73,9 +78,8 @@ Prefer bounded Markdown or JSON over a multi-megabyte export: ```bash pnpm experiment:db summary --format markdown -pnpm experiment:db patient-zero --limit 30 --format markdown pnpm experiment:db failures --limit 20 --format json -pnpm experiment:db notes search "communication hypothesis" --status accepted --limit 10 --format markdown +pnpm experiment:db notes search "directive expiry hypothesis" --status accepted --limit 10 --format markdown ``` Example comparison workflow: @@ -84,7 +88,6 @@ Example comparison workflow: pnpm experiment:db import ./exports/run-a.json pnpm experiment:db import ./exports/run-b.json pnpm experiment:db summary --format markdown -pnpm experiment:db patient-zero --limit 40 --format markdown pnpm experiment:db compare --format markdown ``` @@ -94,7 +97,7 @@ The archive stores only schema-validated safe export fields and curated notes. I MCP and embeddings are deferred because bounded local retrieval solves the immediate need without a network/tool authorization surface or derived semantic store. `ExperimentQueryService` and `ResearchNoteService` are the future extension point for a read-only MCP adapter; write/import authority remains outside that adapter. -# Provider attempts +## Provider attempts Archive schema v4 stores `providerAttempts` independently. Use `pnpm experiment:db provider-attempts ` to inspect committed and diff --git a/docs/GAMEPLAY_FOUNDATION.md b/docs/GAMEPLAY_FOUNDATION.md index 2eb639d..0dbccbc 100644 --- a/docs/GAMEPLAY_FOUNDATION.md +++ b/docs/GAMEPLAY_FOUNDATION.md @@ -1,21 +1,31 @@ # Gameplay Foundation -> **Delivery status (2026-08-23):** the pre-PR5 simultaneous agent tick, -> deterministic virtual clock, shared-deadline dispatcher, phased resolution, -> schema-v10 experiment attribution, and the optional seeded D1 casual cleaner -> are delivered as an operator-driven foundation. Real Player Mode, capture, -> respawn, GPS authority, and background timing remain future work. - -## Current experimental Patient Zero slice - -One scenario roster agent must coordinate global infection strategy through a -bounded authoritative overview, private advisory directives, and ordinary -direct replies. The role changes information and communication only: it has no -extra movement or world-action power, cannot force compliance, cannot see live -player GPS, and does not implement capture succession. It operates under the -simultaneous tick model under the same movement and world-action limits. -Current setup rejects a missing, null, or unknown designation. Historical -exports created when the role was optional remain truthful and readable. +> **Delivery status (2026-08-23, updated for zero-swarm migration):** the +> simultaneous agent tick, deterministic virtual clock, shared-deadline +> dispatcher, phased resolution, schema-v12 experiment attribution, and the +> optional seeded D1 casual cleaner and trail-hunter-v1 simulated-player +> profiles are delivered. `zero-swarm-v1` is the only cognition architecture: +> one generative planner (Agent Zero, contract `swarm-planner-v1`) issues +> structured directives; workers resolve them via TypeSafe Jev reflex cognition. +> Personalities, agent-to-agent communication, formal alliances, per-worker +> goals, and prose memories are removed. Real Player Mode, capture, respawn, +> GPS authority, and background timing remain future work. + +## Current Agent Zero planning slice + +In the zero-swarm architecture one Agent Zero planning call runs per tick +regardless of roster size. Agent Zero issues a strategy summary and +per-worker structured directives (fields: mission, nullable target cell, +priority, risk tolerance, issue tick, expiry tick, optional note up to 160 +characters). Workers resolve their directive via TypeSafe Jev reflex cognition +over enumerated `action_N` candidates with a probability distribution and +confidence score; `deterministic-fallback` is used when the Jev call is +unavailable or its output fails validation. `zero-llm` is Agent Zero's own +planning cognition source, not a worker source. Agent Zero has no +extra movement or world-action power; it is one roster agent like any other. +Current setup rejects a missing or null Agent Zero designation. Pre-swarm +exports (schema versions 9–11) are not readable by current code; schema +version 12 with `swarmArchitectureVersion: 'zero-swarm-v1'` is required. > **Status: accepted product and roadmap direction, not an implementation claim.** > This document records foundational decisions for future World Lab and Player @@ -24,16 +34,17 @@ exports created when the role was optional remain truthful and readable. ## How to read this document -- **Current behavior:** World Lab is an omniscient developer/admin surface; the - development world has full agent visibility and advances one agent at a time. - The current engine supports only `open` and `infected` cells and the small - action set described below. There is no Player Mode, GPS interaction, - autonomous server schedule, simultaneous global tick, or simulated-player - pressure yet. +- **Current behavior:** World Lab is an omniscient developer/admin surface with + full agent visibility. The engine supports only `open` and `infected` cells + and the small action set described below. Agents act on simultaneous global + ticks with a deterministic virtual clock; `casual-cleaner` and + `trail-hunter-v1` simulated-player profiles are available. The only cognition + architecture is `zero-swarm-v1`. There is no Player Mode, GPS interaction, + or autonomous server schedule. - **Accepted foundational direction:** the simple action economy, distinct World Lab and Player Mode visibility, hidden simultaneous agent ticks, continuous player interaction, engine authority, and deterministic testing model are - accepted future rules. + accepted foundational rules — some delivered, the rest guiding future work. - **Tunable through World Lab:** values collected in [Tunable values](#tunable-values-not-settled-mechanics) remain experiment and balancing parameters rather than locked production constants. @@ -45,8 +56,8 @@ exports created when the role was optional remain truthful and readable. Hex Zero should remain mechanically simple. Replayability should emerge from real geography, hidden agent locations, visible infection trails, persistent -24/7 agent activity, model personalities and strategies, alliances and -communication, and human intervention. +24/7 agent activity, swarm planning strategy and directive execution, and +human intervention. The intended player loop is: @@ -101,20 +112,17 @@ The initial action set remains intentionally small: - Infect the current open cell. - Capture eligible abandoned hostile infection. - Wait. -- Optionally send one public or range-limited direct communication and submit one - eligible formal diplomacy intent alongside the world action. The engine remains the sole authority for action availability and consequences. Prompts must not invent mechanics or override validation. The engine-owned objective layer should communicate the following intent: -> You are a persistent autonomous infection agent in a shared geographic world. Expand and retain as much infected territory as possible while preserving your active presence. Human players can see infected territory and disinfect it in real time. They cannot normally see you unless they enter your current hex, but if they discover you, they may capture you immediately. Infecting territory grows your influence but may reveal a trail toward your position. Moving without infecting can conceal your route, but hiding indefinitely does not accomplish your objective. Balance expansion, survival, territorial defense, diplomacy, and deception using only the currently available actions. +> You are a persistent autonomous infection agent in a shared geographic world. Expand and retain as much infected territory as possible while preserving your active presence. Human players can see infected territory and disinfect it in real time. They cannot normally see you unless they enter your current hex, but if they discover you, they may capture you immediately. Infecting territory grows your influence but may reveal a trail toward your position. Moving without infecting can conceal your route, but hiding indefinitely does not accomplish your objective. Balance expansion, survival, territorial defense, and deception using only the currently available actions. The prompt layers have distinct responsibilities: - **Objective** defines durable success and is engine-owned. -- **Personality** controls communication style and temperament. -- **Strategy** biases choices without prescribing a fixed action loop. +- **Directive** carries mission, target cell, priority, and risk tolerance from Agent Zero to each worker. - **Observation** supplies bounded authoritative facts and exact legal actions. The player-threat portion must be capability-gated until player or simulated-player mechanics exist. Agents should never receive fabricated nearby-player evidence merely because the prompt says players exist. @@ -122,9 +130,9 @@ The player-threat portion must be capability-gated until player or simulated-pla ### Why the environment matters more than prompt wording Without player pressure, infecting whenever possible and moving otherwise is the -dominant policy. Better prompting can change destinations, communication, -alliances, and reactions, but prompt wording alone cannot create meaningful -strategy or a reason to sacrifice expansion. +dominant policy. Better prompting can change destinations and reactions, but +prompt wording alone cannot create meaningful strategy or a reason to sacrifice +expansion. Player cleaning, capture, visible trails, territory-loss notifications, and hidden locations create the missing tradeoffs without requiring more agent @@ -134,23 +142,20 @@ actions: - Move silently for multiple ticks to obscure position. - Protect valuable territory by remaining nearby. - Investigate recent losses or flee the likely player location. -- Warn allies, coordinate routes, or create a distraction. Hiding indefinitely is not success; survival preserves the ability to pursue influence. -## Bounded agent knowledge and memory +## Bounded agent knowledge -Agents know that human opposition exists, but receive only engine-produced evidence. Useful structured memory includes: +Agents know that human opposition exists, but receive only engine-produced evidence. +Prose and compact memories across ticks were specific to the legacy per-agent +architecture and are removed. Structured per-tick observations remain and should +include: -- Current strategic intent. -- A bounded history of the agent's own actions and outcomes. +- Current directive from Agent Zero (mission, target cell, priority, risk + tolerance). - Recent cells gained and lost. - Nearby disinfection patterns. -- Current alliance membership and relevant proposals. -- Exact formal-diplomacy affordances derived from frozen pre-action positions. - Proposal creation uses the scenario `communicationRangeKm`; Patient Zero's - direct-message range bypass does not bypass formal diplomacy range. -- Allied warnings and captures. - Last-known player encounters with age and location. - Explicit priority notifications for nearby territory loss. @@ -158,7 +163,7 @@ Examples of legitimate observations include: - `You lost cell X four minutes ago.` - `Three cells southwest of you were disinfected recently.` -- `An allied agent was captured near cell Y.` +- `An agent was captured near cell Y.` - `A player was last observed in your cell one tick ago.` Agents must not receive live player GPS, future player routes, an omniscient @@ -212,7 +217,7 @@ There is no manual travel-state control and no requirement to stop an unrelated ## Capture consequences and population maintenance -Once real or deterministic simulated capture exists, every surviving agent receives a bounded authoritative capture alert regardless of distance. It may identify the captured agent, capture cell, time/tick, alliance, and newly abandoned territory. It must not expose the capturing player's identity, live GPS, route, or continued presence. No capture alerts are generated before capture capability exists. +Once real or deterministic simulated capture exists, every surviving agent receives a bounded authoritative capture alert regardless of distance. It may identify the captured agent, capture cell, time/tick, and newly abandoned territory. It must not expose the capturing player's identity, live GPS, route, or continued presence. No capture alerts are generated before capture capability exists. When an agent is captured: @@ -221,16 +226,27 @@ When an agent is captured: - Its territory remains infected but becomes abandoned. - Its lifetime telemetry is finalized. - A replacement spawns after a configurable cooldown at a valid location sufficiently separated from the capturing player. -- The replacement may receive a new seeded personality and strategy assignment. - The configured active-agent population is restored. This preserves a persistent world without granting agents health or extra lives. ## Alliances -Alliances should initially improve survival through information rather than numerical combat bonuses. +> **Removed (zero-swarm migration).** Formal alliances and agent diplomacy were +> specific to the legacy per-agent decision contract. The swarm architecture has +> one planner (Agent Zero) whose directives already coordinate all workers; +> there is no per-worker negotiation loop that alliances were designed to +> facilitate. Alliance engine code, the diplomacy affordances schema, and all +> related prompt layers were deleted in PRs 1–4 of this migration. Alliances +> are not current behavior. Whether they should return as a future feature for +> a Player Mode social layer is an open product question not settled by this +> migration; no roadmap milestone currently calls for them. The original design +> rationale is preserved below as history. -Potential alliance benefits include: +Original design intent: alliances should initially improve survival through +information rather than numerical combat bonuses. + +Potential alliance benefits included: - Shared last-known player cells and observation age. - Nearby territory-disturbance warnings. @@ -238,7 +254,8 @@ Potential alliance benefits include: - Coordinated expansion directions. - Reduced competition for the same cells. -Allies do not initially receive health, damage, extra lives, shared ownership, or automatic rescue mechanics. +Allies would not initially receive health, damage, extra lives, shared +ownership, or automatic rescue mechanics. ## Deterministic simulated players @@ -262,34 +279,31 @@ territory infected but abandoned. If this removes the last agent, or removes Patient Zero from a zero-swarm experiment, the run records a terminal outcome. Replacement spawning remains a later population-maintenance milestone. -Slice D1.1 adds no cleaner mechanics. The single Patient Zero receives a +Slice D1.1 adds no cleaner mechanics. Agent Zero receives a current-interval-only global feed of authoritative successful disinfections and occupied-cell blocked-clean encounters. Entries identify the affected or -blocking agent and current alliance when available, are deterministically -ordered, and are capped at 128 with explicit totals and truncation; overflow -retains the most recent events in chronological order. Event -cells identify the historical disinfection or blocked-clean location; live -player position, movement, route, target, identity, future timing, regional -coordinators, and extra model calls remain excluded. - -Patient Zero treats blocked cleans as successful historical defenses, not a +blocking agent, are deterministically ordered, and are capped at 128 with +explicit totals and truncation; overflow retains the most recent events in +chronological order. Event cells identify the historical disinfection or +blocked-clean location; live player position, movement, route, target, +identity, future timing, and extra model calls remain excluded. + +Agent Zero treats blocked cleans as successful historical defenses, not a reason to vacate, and successful disinfections as confirmed historical losses, not live cleaner sightings. Because directives arrive on a later tick, Zero -must not issue event-cell chase or evacuation tactics. It communicates only -when pressure materially changes a named recommendation, avoids repeated -unchanged warnings, prefers named alliance reinforcement after sustained member -pressure, and may remember a bounded meaningful pattern rather than every -event. +must not issue event-cell chase or evacuation tactics. Zero should issue a +directive only when pressure materially changes a named recommendation, avoids +repeated unchanged directives, and may retain a bounded meaningful pattern +rather than acting on every event. -D1.2 adds a compact six-tick rollup to each displayed current event so Patient +D1.2 adds a compact six-tick rollup to each displayed current event so Agent Zero can distinguish isolated from repeated subject pressure. It includes -subject event/category totals and consecutive affected ticks plus current-member -alliance totals when the subject is currently allied. The rollup includes the -current event, excludes movement and older events, and does not infer historical -alliance membership. An isolated event normally remains silent, although a -strategically meaningful first loss may justify one directive. Repeated subject -or current-alliance pressure strongly favors one new actionable directive after -checking recent Zero messages for equivalent unchanged advice. +subject event/category totals and consecutive affected ticks. The rollup +includes the current event and excludes movement and older events. An isolated +event normally warrants no directive, although a strategically meaningful first +loss may justify one. Repeated subject pressure strongly favors one new +actionable directive after checking recent Zero plan summaries for equivalent +unchanged strategy. Scenario configuration should include simulated-player count, profile mix, travel characteristics, cleaning aggressiveness, search persistence, and seed. @@ -299,7 +313,7 @@ Simulated players follow the same information and interaction rules intended for - They move and interact during the continuous interval between agent ticks. - They discover agents only through valid co-location. - They obey dwell, speed, range, and atomic validation rules. -- They cannot inspect private messages, pending decisions, or future tick timing. +- They cannot inspect agent directives, pending decisions, or future tick timing. An accelerated World Lab interval should conceptually execute as follows: @@ -311,7 +325,7 @@ An accelerated World Lab interval should conceptually execute as follows: 6. Their decisions are requested concurrently and resolve simultaneously. 7. A new hidden interval begins. -Using identical scenario and player seeds provides comparable pressure across model, personality, and strategy experiments. +Using identical scenario and player seeds provides comparable pressure across model experiments. ## World Lab scenario configuration @@ -324,8 +338,7 @@ The next scenario-building milestone should expose: - Agent count and explicit add/remove controls. - Seeded bulk agent generation. - Spawn seed and minimum separation. -- Global and per-agent model/reasoning assignment. -- Global and per-agent personality/strategy assignment. +- Agent Zero model and reasoning assignment. - Simulated-player configuration when that capability lands. - A preview before replacing the active experiment. @@ -335,22 +348,22 @@ the same physical area, each finer H3 resolution produces approximately seven times as many cells, so World Lab must preview and cap the resulting render and state cost before generation. -Roster and topology changes initially create a new experiment. Mid-experiment removal remains a later explicit operator intervention because it affects territory, alliances, pending work, and telemetry semantics. +Roster and topology changes initially create a new experiment. Mid-experiment removal remains a later explicit operator intervention because it affects territory, pending work, and telemetry semantics. Every experiment export should preserve the complete initial scenario configuration, including topology, resolution, cell count, seeds, roster, behavior assignments, model assignments, enabled capabilities, prompt version, and simulated-player configuration. ## Simultaneous decision dispatch -Simultaneous gameplay semantics must not depend on one inference provider's batch feature. The simulation service should own a provider-neutral decision dispatcher: +Simultaneous gameplay semantics must not depend on one inference provider's batch feature. The simulation service should own a provider-neutral decision dispatcher. In the zero-swarm architecture, a tick involves one planning call (Agent Zero) followed by concurrent Jev reflex calls for each worker: 1. Freeze the authoritative snapshot. -2. Build visibility-filtered observations. -3. Group requests by resolved provider, model, and reasoning profile. -4. Dispatch through the configured transport under bounded concurrency. -5. Preserve one shared tick deadline and per-agent result identity. +2. Build Agent Zero's world observation and each worker's reflex observation. +3. Dispatch Agent Zero's planning call through the configured transport under the shared tick deadline. +4. Distribute the resulting directives to workers; dispatch all worker Jev calls concurrently. +5. Preserve one shared tick deadline and per-worker result identity. 6. Retry only against the saved observation. -7. Convert unfinished decisions to lost turns. -8. Resolve accepted decisions in deterministic engine order. +7. Convert unfinished decisions to lost turns; fall back to `deterministic-fallback` for workers whose Jev call fails. +8. Resolve accepted worker actions in deterministic engine order. Expected transports include: @@ -359,25 +372,30 @@ Expected transports include: - Independent concurrent OpenAI-compatible calls to local vLLM endpoints, allowing each server to schedule its own work. - Deterministic offline providers for tests. -Models assigned to different endpoints or profiles may complete independently; the engine waits only until the shared deadline before resolving the tick. +The engine waits only until the shared deadline before resolving the tick regardless of which calls complete. ## Evaluation telemetry -World Lab should make the new behavior measurable. Useful aggregate and per-agent metrics include: +World Lab should make the new behavior measurable. Swarm-tick records carry +the plan source (`zero-llm`, `directive-reuse`, or `deterministic-fallback`), +replan reasons, per-worker directive and action results, Jev confidence scores, +and provider attempt outcomes. Useful aggregate and derived metrics include: - Territory gained, lost, retained, and abandoned. - Territory per active lifetime. - Time and ticks survived. -- Captures by model, personality, strategy, and simulated-player profile. +- Captures by model and simulated-player profile. - Consecutive silent moves before infection. - Direction changes after infection or nearby loss. -- Responses to disinfection and allied warnings. +- Responses to disinfection events. - Player encounters and escapes. -- Alliance warnings and downstream reactions. +- Directive completion and expiry rates per mission type. +- Replan frequency and reasons. +- Worker Jev confidence distribution. - Simulated-player distance traveled, cells cleaned, and captures. - Decision latency and deadline misses. -- Automatic repair/transport attempts and final lost-tick results. -- Token usage and cost per tick. +- Provider attempt counts and outcomes (success, timeout, failure) per role. +- Token usage and cost per tick (planning call vs. total). Telemetry must continue to exclude raw provider output and private chain-of-thought. @@ -388,11 +406,11 @@ The intended sequence is: 1. Configurable map scale, H3 resolution, and agent roster. **Implemented in the World Lab scenario milestone.** 2. Goal-oriented prompt revision and versioned scenario attribution. **Implemented as `durable-influence-v1` without player-survival language.** -3. Simultaneous agent ticks with a provider-neutral dispatcher and virtual clock. **Implemented as the pre-PR5 experiment foundation without background scheduling or Player Mode timing exposure.** +3. Simultaneous agent ticks with a provider-neutral dispatcher and virtual clock. **Implemented. Zero-swarm migration retired the legacy per-agent architecture; `zero-swarm-v1` with Agent Zero planning and TypeSafe Jev reflex workers is the sole cognition architecture. No background scheduling or Player Mode timing exposure.** 4. Deterministic real-time simulated players and threat observations. **D1 and D1.1 deliver one seeded casual cleaner, bounded local evidence, and the - single Patient Zero current-interval global feed; broader Player Mode - remains future work.** + Agent Zero current-interval global feed; `trail-hunter-v1` is also + delivered. Broader Player Mode remains future work.** 5. Comparative unattended World Lab experiments. 6. Real GPS Player Mode using the already-tested capture and disinfection rules. 7. Optional OpenRouter asynchronous batches and local multi-endpoint optimization where measurements justify them. @@ -410,7 +428,8 @@ Do not initially add: - Real-time agent warnings that a player is approaching. - Omniscient simulated players. - Multiple movement actions per tick solely to compensate for human travel speed. -- Alliance stat bonuses or shared lives. +- Alliances, alliance stat bonuses, or shared lives. (Alliances were built and + removed by the zero-swarm migration; see the Alliances section.) - LLM-controlled simulated players. ## Tunable values, not settled mechanics @@ -423,7 +442,7 @@ World Lab experiments should determine: - Disinfection duration. - Respawn cooldown and minimum player separation. - Agent-to-cell and simulated-player-to-agent density. -- Observation and memory window sizes. +- Observation window sizes. - Provider concurrency and tick decision deadlines. - The balance between expansion score, retained territory, inactivity, and capture penalties. diff --git a/docs/SECURITY.md b/docs/SECURITY.md index dcf8fb6..db78294 100644 --- a/docs/SECURITY.md +++ b/docs/SECURITY.md @@ -10,32 +10,19 @@ agent positions as targets. Capture events and abandoned controllers are authoritative state and are safe to export without exposing player routing internals to agent providers. Patient Zero alone additionally receives a bounded current-interval feed of -successful disinfections and occupied-cell blocks. Its named agent/alliance -attribution is engine-authored; it contains no movement events, player ID, +successful disinfections and occupied-cell blocks. Its named-agent attribution +is engine-authored; it contains no movement events, player ID, live/current cleaner position, route, target, or future interval information. Each event cell intentionally identifies the historical disinfection or occupied-cell blocked-clean location and must not be interpreted as live GPS. - -Public messages are untrusted claims visible to all agents and classified for future player visibility. Direct, alliance, and Zero messages are player-hidden. Only participants receive them in agent observations; the omniscient Private comms feed is restricted to World Lab operator contracts. Only the designated Patient Zero may send a Zero broadcast. Its sender role is authoritative but its strategy remains advisory. Messages never contain raw reasoning, pending decisions, credentials, player GPS, or fabricated threat evidence. - -Patient Zero's global view is bounded to active agent identity/current cells, -allowlisted behavior attribution, territory/alliance totals, proposals, and -recent authoritative events. It never serializes the complete world, future -turn information, provider payloads, credentials, or live player GPS. Direct -range bypass is engine-authoritative and applies only when Patient Zero is one -endpoint; invalid channel/recipient combinations do not mutate state. -The diplomacy portion has roster-independent caps: at most 12 displayed legal -pairs, eight acceptable proposals, eight leave IDs, and eight prioritized -blocker examples, plus aggregate stable blocker counts and explicit truncation. -The cleaner-threat portion contains the most recent 128 current-interval events -in chronological order plus an authoritative total and explicit truncation. -Custom exports that omit recent -control-change evidence clear both local and Patient Zero global threat arrays. -Per-event pressure context is engine-derived from only the current and prior -five ticks. Alliance totals use current membership only. The context contains -counts and tick bounds, not historical event arrays, cleaner movement, live -position, or inferred historical membership; removing feed events also removes -their nested rollups. +The cleaner-threat feed caps at the most recent 128 current-interval events +in chronological order with an authoritative total and explicit truncation. +Custom exports that omit recent control-change evidence clear both local and +Patient Zero global threat arrays. Per-event pressure context is engine-derived +from only the current and prior five ticks. The context contains counts and +tick bounds, not historical event arrays, cleaner movement, live position, or +inferred historical membership; removing feed events also removes their nested +rollups. ## Secrets and deployment @@ -100,7 +87,7 @@ profile, abort signal, and the tick's shared deadline. Agent-authored output cannot mutate the world directly or enter another same-tick observation. Cancellation discards every result from the uncommitted tick. -OpenRouter receives one immutable structured observation and is instructed to return exactly one plain JSON object as text, containing a required world action plus at most one optional communication and one optional diplomacy intent. Its flat required fields use explicit empty-string and `none` sentinels. The runtime performs bounded extraction and conservative repair for wrappers such as code fences, surrounding prose, and trailing commas, then rejects missing text, unusable JSON, unknown fields, contradictory sentinels, or output truncation before the deterministic world engine validates all normalized components independently. +The OpenRouter planner receives one bounded strategic observation per tick and is instructed to return exactly one plain JSON object naming opaque worker and target choices plus a Zero-action selection. TypeSafe Jev receives a compact semantic observation with opaque legal candidate IDs per worker and returns a probability distribution over candidates; a second question in the same request returns an optional bounded replan probability. The runtime performs bounded extraction and conservative repair for wrappers such as code fences, surrounding prose, and trailing commas, then rejects missing text, unusable JSON, unknown fields, or output truncation before the deterministic world engine validates all resolved components independently. The request uses the selected model, messages, `max_tokens`, `stream: false`, and at most one normalized reasoning object selected from sanitized model metadata. Provider default omits the object. Off is offered only for non-mandatory reasoning and sends `{ enabled: false, exclude: true }`; an advertised effort sends `{ enabled: true, effort, exclude: true }`. It deliberately sends no tools, `tool_choice`, `response_format`, `provider.require_parameters`, standalone `reasoning_effort`, or model-specific parameter. Model IDs are never inspected or special-cased. Transport/provider failures, unavailable-model/profile failures, text/JSON contract failures, and later simulation-rule rejection remain distinct safe outcomes. The adapter never silently substitutes a model or scripted behavior. @@ -123,28 +110,20 @@ but never both, and all calls share the original 75-second deadline. A corrective request contains the same authoritative observation plus only allowlisted validation codes; it never contains the raw invalid response, raw Zod issues, stack traces, provider bodies, or copied diagnostic text. -Engine-rejected normalized decisions are not retried. Manual Retry exists only -for legacy sequential/schema-v9 compatibility. Tick recovery is limited to one -bounded in-deadline automatic repair or transient retry; an unresolved decision -becomes a final attributed lost tick. +Engine-rejected normalized decisions are not retried. Tick recovery is limited +to one bounded in-deadline automatic repair or transient retry; an unresolved +decision becomes a final attributed lost tick. The model is explicitly instructed to return only one flat JSON decision with one concise visible summary and no hidden reasoning or chain-of-thought. Optional reasoning configuration always sets `exclude: true`; Provider default sends no reasoning instruction. Only numeric reasoning-token billing metadata is retained if OpenRouter reports it. The application stores no raw prompts, raw provider payloads, reasoning text, or private reasoning. -Agent-authored messages, personalities, summaries, scoreboards, alliance events, proposals, and natural-language alliance claims are bounded untrusted data. They appear only inside the immutable user observation, never the fixed system instruction. Direct eligibility is derived from the pre-action snapshot. Recipient/range, infection, controller-presence, alliance membership, proposal eligibility, system ID/color allocation, and capture validation remain authoritative in the world engine. Models cannot choose alliance IDs, colors, membership lists, or metadata. Only accepted typed diplomacy changes alliance state, and rejected components cannot partially mutate or corrupt one another. World Lab renders model text through React text nodes and never raw HTML. - -Frozen observations expose only runtime-validated exact diplomacy IDs and -bounded stable blocker codes. Patient Zero's sparse global diplomacy summary -uses fixed caps, aggregate counts, deterministic priority, and explicit -truncation; it contains neither pending decisions nor future same-tick actions. -These affordances avoid a provider-controlled tool boundary; submitted -intents still pass authoritative engine validation during deterministic -resolution. - -World Lab personality edits are also untrusted, bounded text. The Game API trims and runtime-validates them before changing the authoritative session, and rejects changes during active model execution. The runtime supplies the active personality only inside the immutable observation as subordinate behavioral context. It is never interpolated into the fixed system instruction and cannot grant actions, weaken engine validation, request secrets, or authorize prompt/reasoning disclosure. React renders active and historical personality text as text rather than HTML. - -Personality mutation errors use typed, generic response bodies. They do not expose raw prompts, provider responses, credentials, diagnostics, stack traces, or internal service details. There is still no authentication or persistence; these endpoints remain limited to the loopback development surface. - -Behavior profile IDs are allowlisted at every boundary and resolve only to application-owned registry fragments. Imports cannot supply profile prompt text. The prompt explicitly separates untrusted chat invitations from engine-authoritative formal proposal IDs, and exact legal diplomacy IDs are derived from current state. Seed values select registry entries only and are never interpreted as prompt text. +Agent Zero's strategy summary and directive notes (at most 160 characters each) +and Jev's structured reflex output are bounded, agent-authored, untrusted data. +They appear only inside the immutable user observation, never the fixed system +instruction. There is no agent chat, diplomacy text, or memory prose. The engine +validates every world action, infection, and capture before committing state; +agent-authored outputs cannot grant engine authority, weaken validation, or +authorize prompt or reasoning disclosure. World Lab renders model text through +React text nodes and never raw HTML. ## Experiment telemetry and exports @@ -153,13 +132,17 @@ timestamps, and the safe frozen observation. A resolved lost tick is final and has no manual retry/skip path. Raw provider responses, reasoning text, credentials, and authorization headers are not retained. -The Game API captures only schema-validated safe observations, requested world actions, optional communication and diplomacy intents, separate result records, visible concise summaries, bounded message text, typed alliance events, sanitized rejected attempts, bounded provider failures, and normalized usage metadata. Malformed identifiers use nullable or absent sanitized representations; raw provider output is never retained. It never records or exports API keys, authorization data, fixed or hidden prompts, raw provider request/response bodies, private chain-of-thought, hidden analysis, secrets, or unbounded diagnostics. Historical records are cloned and immutable. +The Game API captures only schema-validated safe observations, requested world actions, separate result records, visible concise summaries, sanitized rejected attempts, bounded provider failures, and normalized usage metadata. Malformed identifiers use nullable or absent sanitized representations; raw provider output is never retained. It never records or exports API keys, authorization data, fixed or hidden prompts, raw provider request/response bodies, private chain-of-thought, hidden analysis, secrets, or unbounded diagnostics. Historical records are cloned and immutable. -Export requests, agent IDs, levels, ranges, outcome/world-action filters, communication channel/status filters, and Custom dependencies are runtime-validated. Filtering and metrics remain server-owned. Schema v11 preserves schema-v10 tick attribution plus the independent safe provider-attempt ledger; schema-v9/v10 imports remain supported by the Game API. Selected-agent exports use sender/recipient-aware communication filtering and direct multi-agent relevance for proposals and membership changes; unrelated direct messages and rejected diplomacy are excluded. Reset clears communications, alliances, proposals, alliance events, and their metrics while preserving active personality values and unlocking preserved assignments for the new experiment. +Export requests, agent IDs, levels, ranges, and Custom dependencies are +runtime-validated. Filtering and metrics remain server-owned. The export schema +is exclusively version 12; exports carrying schema version 9, 10, or 11 are +rejected outright with no migration path. Reset clears swarm tick history and +metrics while unlocking preserved roster assignments for the new experiment. Actual cost is accepted only from OpenRouter's safe `usage.cost`. Missing cost is unknown, never zero; scripted-test providers explicitly report zero. The active Game API enforces experiment-scoped attempt and conservative credit-admission ceilings, but has no authentication, provider-account balance enforcement, restartable persistence, provider-management endpoint, upload, or sharing link. Credit admission is not an upstream billing guarantee. The loopback-only boundary remains mandatory. -The offline experiment archive adds local persistence only for complete schema-validated safe exports and explicitly curated Markdown notes. Imports scan for prohibited credential/private-reasoning fields and recognizable credential values before a transaction begins; failures roll back. Both the canonical `.hexzero/` and compatible legacy `.agentborne/` database locations are ignored. The CLI exposes bounded typed queries, not arbitrary SQL, and adds no MCP, embedding, vector-store, or network-listener surface. +The offline experiment archive adds local persistence only for complete schema-validated safe exports and explicitly curated Markdown notes. Imports scan for prohibited credential/private-reasoning fields and recognizable credential values before a transaction begins; failures roll back. The canonical `.hexzero/` database location is never exposed to callers. The CLI exposes bounded typed queries, not arbitrary SQL, and adds no MCP, embedding, vector-store, or network-listener surface. World Lab may manually submit only the exact current generated export artifact to a narrow archive endpoint. The browser cannot supply a database path or SQL. @@ -171,15 +154,7 @@ errors without underlying diagnostics. This is a private repository. Report suspected vulnerabilities privately to the repository owners rather than opening a public issue. -## Agent goal text - -Strategic goals and revision reasons are bounded, agent-authored, untrusted data. They are supplied only inside immutable user-observation data, never interpolated into system instructions. The contract requests concise visible summaries and prohibits private chain-of-thought. Goal operations grant no engine authority and cannot bypass world, communication, or diplomacy validation. - -## Compact memory text - -Compact memories are bounded self-authored recollections, not authoritative facts. They remain subordinate observation data and are never interpolated into system instructions. Memory may not retain raw prompts, provider payloads, credentials, or private chain-of-thought. Server-issued IDs and tick attribution are authoritative; memory prose is not. - -# Safe provider-attempt records +## Safe provider-attempt records Attempt records may contain sanitized provider metadata and bounded failures, but never prompts, raw requests/responses, headers, credentials, or private diff --git a/docs/TESTING.md b/docs/TESTING.md index 81192b2..5720075 100644 --- a/docs/TESTING.md +++ b/docs/TESTING.md @@ -1,171 +1,207 @@ # Testing -Zero-swarm tests are offline by default. PR A covers deterministic legal -candidate compilation, a scripted reflex choice through `applyWorldAction`, -malformed and unknown TypeSafe choices, cancellation and bounded transient -retry, and provider attempts retained when a candidate world change is not -committed. `pnpm validate` and `pnpm test:e2e` are the complete local gates. -PR B adds scripted Agent Zero and Jev providers to test plan validation, -planning-before-reflex ordering, real engine resolution, deterministic failure -fallback, cancellation rollback, and independent provider-attempt retention. -The live provider smoke test remains separately opted into. -PR C adds mode-specific World Lab component coverage for Zero strategy, -worker directives and probabilities, provider usage, Zero-only model setup, -and hiding of legacy social/personality views while retaining legacy UI -coverage. Browser smoke still exercises the deterministic legacy baseline. -PR D covers the same-request Jev Choice and Noul response, deterministic -replan signals, periodic and event-triggered Zero calls, directive expiry, -current legal Zero actions on reuse ticks, provider-attempt reduction, -cancellation rollback, and mode-specific World Lab telemetry. -PR E covers seeded trail-hunter routing from visible infection, co-located -capture, abandoned territory, active-roster dispatch after player pressure, -terminal capture outcomes, cancellation rollback, and safe export/UI handling. -The casual-cleaner baseline remains covered by its existing offline tests. - -PR F adds a deterministic comparison harness for `legacy-multi-agent`, -`zero-swarm-v1`, and `deterministic-worker-baseline`. It uses the same seeded -scenario and `trail-hunter-v1` pressure for all variants, retains per-tick and -aggregate metrics, and has no provider, credential, or archive-write path. -Run `pnpm compare:offline` (or bounded `--ticks` and `--seeds` options) to -produce its JSON report. See [Zero-swarm offline comparison](ZERO_SWARM_COMPARISON.md). - -The live comparison command is a separate paid experiment. Its tests inject -scripted providers and verify the acknowledgement gate, input parity, bounded -attempt admission, safe metrics, and a no-network Markdown summary path. -`pnpm validate`, Playwright, and GitHub CI never execute a paid run. See -[Live swarm comparison](LIVE_SWARM_COMPARISON.md). -The read-only `pnpm diagnose:swarm` command summarizes a running local Game API -snapshot without provider calls, keys, prompts, or raw responses. World Lab's -swarm activity summary shows pressure state, physical action counts, and -fallbacks for immediate diagnosis of apparently stationary ticks. -Focused offline progress tests cover a worker advancing after a move, reaching -a directive target, waiting at that target, and the corresponding status seen -by Zero on the next planning tick. -Offline swarm pressure tests cover current-tick disinfection proximity, bounded -event history, capture context, pressure-aware replan thresholds, and the -following tick's worker-request reason. No provider network calls are made. -Directive-lifecycle tests also cover expand completion only after worker control, -relocate and reinforce completion on arrival, with reinforce target validity -checked when issued; evade completion on arrival or -after leaving high cleaning pressure, non-completing hold-at-target behavior, -completed-directive IDs passed to the next Zero observation, and deterministic -fallback for invalid newly issued expand targets. Focused validation tests -reject targets infected by the same worker, another worker, or no controller, -while accepting open targets. These use scripted providers and make no network -calls. - -The pre-live provider audit tests the Jev request's bounded capture-pressure -projection, omission of hidden hunter state and empty capture noise, and the -removal of the inert recent-facts field. Planner tests cover provider-reported -OpenRouter cost and detailed tokens for valid, rejected, and non-success Zero -responses, plus sanitized response IDs/models; missing cost stays unknown. -Planner tests also cover compact opaque worker/target choices, server-issued -directive IDs and lifetimes, Zero reasoning-profile dispatch, and safe -classification of unknown or missing choices. Scripted service tests verify -that a first-plan failure uses legal deterministic local expansion with only -the Zero provider attempt billed. Jev provider tests distinguish unknown -choices from inconsistent probability distributions and retain factual token -usage for rejected decisions; World Lab and the read-only diagnostic show -these safe worker failure reasons. Cost display tests separate provider-reported -cost from admission exposure and show that TypeSafe Jev monetary cost remains -unknown without provider billing data. The browser suite checks that a long -swarm activity log scrolls inside the fixed-height bottom dock. -World Lab component coverage also checks that applying a fresh Trail hunter -scenario after a tick-50 experiment resets the run counter so the next Run to -tick 50 command sends its first Game API tick request. - -Attempt-budget tests use deterministic providers and cover whole-roster tick -admission, retry permits, cancellation finalization, and the distinction -between known zero cost and missing/unknown cost. Provider catalog probes are -outside this accounting boundary. - -Simulated-player coverage uses explicit offline seeds. Focused tests cover -same-seed movement, accepted and occupied-cell-blocked disinfection, -pre-observation ordering, cancellation atomicity, observation privacy, -disabled compatibility, World Setup truthfulness, and export/SQLite round trips. - -Simultaneous-tick coverage is deterministic and offline. Scripted-provider tests -assert frozen observations, bounded concurrent starts and one deadline, -completion-order-independent resolution, seeded order and virtual-interval -reproduction, deterministic phased conflicts, isolated lost ticks, atomic -cancellation, per-agent model/reasoning dispatch, complete-tick retention, -schema-v10 export/archive behavior, schema-v9 compatibility, bounded strategic -goal establishment, continuation, revision, clearing, independent rejection, -frozen-tick commit, and reset behavior, plus compact-memory remember, revise, -forget, capacity, missing-ID, frozen-tick, lost/cancel, reset, and configuration -preservation behavior. World Lab tests -cover Single tick, 5/10/25/50/100 targets, the default target of 25, per-agent -cost warnings, cancellation reconciliation, and lost-tick status. - -Focused deterministic coverage includes physical-distance messaging across H3 -resolutions, the eight-agent observation cap, alliance long-range visibility and -delivery, channel privacy, seeded move-affordance ordering, H3-center-bearing -direction labels across locations and resolutions independent of traversal -order, effective neutral/alliance colors, and operator-only private-feed filters. Provider tests -remain offline and verify the flat `text-flat-json-v8` contract, its -selective-communication, bounded goal and memory, and diplomacy-affordance policy -text, unchanged wire parsing, and legacy v3-v7 attribution compatibility. - -Patient Zero coverage verifies mandatory current-run defaults and rejection of -missing/null/unknown selections while preserving null legacy exports, valid roster -designation, bounded exclusive global awareness, Zero authority and private -fan-out, Patient-Zero-endpoint direct replies, ordinary range enforcement, -immutable retry observations, normal world-action legality, export telemetry, -and restrained World Lab role/filter rendering. Provider tests use -`text-flat-json-v8`; no live provider or geocoder is involved. A worst-case -32-agent test requires the serialized diplomacy summary to remain at or below -4,096 UTF-8 bytes with deterministic ordering, fixed caps, stable blocker -counts, explicit truncation, maximum-cap fixtures, diverse proposer coverage, -and deterministic tick rotation. - -Selective communication is evaluated empirically with a same-model, -same-scenario 10-tick comparison. Fewer than 40 messages across 80 decisions -and near-zero routine action narration are useful diagnostic targets, not -deterministic release gates or claims that a model will comply. Default tests -assert only the prompt policy, contract attribution, parsing, and compatibility. - -Operator-workspace component coverage verifies that Live/Agents switching preserves the mounted execution state, agent selection routes to the semantic inspector, Scoreboard remains directly reachable, and failure/recovery activity stays bounded. Playwright exercises the persistent command bar, workspace navigation, contextual inspector tabs, tabbed activity dock, overflow-routed setup/export actions, and desktop/narrow viewport containment. These tests continue to use only the deterministic provider. - -Behavior Trace coverage verifies the six-record newest-first bound, consecutive -observation-delta derivation, newly retained inbound evidence, legal-action and -chosen-direction presentation, repeated/changed action labeling, explicit -self-reported-not-causal wording, inspector section navigation, and browser-only -cell highlighting. It uses existing turn records and never invokes a provider or -mutates the simulation. -Cleaner evidence coverage verifies local/global labels, Patient Zero-only -visibility, current-interval non-repetition, movement and live/current-position -exclusion while retaining historical event cells, deduplication when Patient -Zero also sees an event locally, the 128-entry cap, -truthful truncation, cell highlighting, prompt guidance, custom-export -redaction, and observation JSON archive compatibility. -Runtime prompt tests also lock blocked-clean hold/reinforcement semantics, -historical-cell and delayed-directive cautions, selective non-repeating -communication, alliance-level sustained-pressure coordination, and bounded -pattern memory. -D1.2 tests cover six-tick exclusion/inclusion, consecutive subject ticks, -current-member alliance aggregation, dishonest schema arithmetic/window/null -pairing, isolated-versus-sustained prompt selection, recent-Zero deduplication, -Behavior Trace count evidence, custom redaction, observation JSON archival, and -independence from unrelated general world-event history churn. - -Configurable-scenario coverage is deterministic and offline: `world-scenario-v1`, temporary roster/world limits, actual H3 count and area, radius presets, seeded identities and separated spawns, default compatibility, infeasibility, pure preview, atomic apply/current-scenario reset, dynamic assignment reconciliation, density warnings, and schema-v9 attribution. Geocoding uses injected fakes; browser coverage retains the default flow and adds a 469-cell/12-agent scenario flow. - -Observation-history tests independently churn more than the 120-event World -Lab display bound and verify chronological limits for per-agent movement and -recently-occupied facts, global actions and public messages, -participant-private direct/alliance/Zero messages, control changes, alliance -lifecycle, and Patient Zero capture history. Service commit paths ingest only -newly committed facts from the complete pre-display-truncation batch; -cancellation, unresolved failure, retry setup, and skip -paths cannot add or duplicate them. Reset and applied World Setup reinitialize -the ledgers. Cleaner locality continues to use its dedicated committed event -ledger plus the current candidate interval. - -Legacy sequential recovery remains covered only as schema-v9 compatibility. Tick tests instead verify that an exhausted per-agent repair or transient retry becomes a final lost-tick record while sibling records commit, and that whole-tick cancellation commits nothing. No live provider call is made. - -Default validation is deterministic and offline except dependency/browser installation and optional basemap requests during browser rendering. No default test or GitHub Actions job contacts OpenRouter. - -The repository owner runs local validation. Coding agents write tests and inspect GitHub CI but do not run local formatting, linting, type checking, tests, builds, Playwright, or real-provider calls unless explicitly asked. +The suite has 26 unit/component test files and one Playwright E2E file. All +default tests are deterministic and offline; no default test or GitHub Actions +job contacts OpenRouter or TypeSafe. Real-provider tests are separately named, +explicitly opted into, and excluded from default CI. Tests are small behavior +tests colocated with the code they cover; large snapshots are avoided. + +## Coverage + +### World engine (`packages/world-engine`) + +`index.test.ts` covers H3 movement (adjacent legal moves, non-adjacent +rejection, deterministic action enumeration), infection (open-cell infection, +repeated-infection rejection, persistence after the agent moves away), capture +(co-located trail-hunter capture, abandoned territory, engine-authority +transfer), simultaneous-tick determinism (shuffled resolution order, inclusive +virtual interval), D1 casual-cleaner behavior (seeded tie-breaking, occupied- +cell block), and trail-hunter routing (infection-evidence selection, hidden- +agent-position exclusion). + +`scenario.test.ts` covers configurable world scenarios: default world +preservation, seeded casual-cleaner reproducibility, stable UUID-compatible +roster generation, spawn seeding, uniqueness enforcement, and infeasibility +rejection. + +### Shared schemas (`packages/shared`) + +`index.test.ts` covers the agent observation schema (bounded state-bearing +observation, control-gain/loss caps), the Patient Zero player-threat feed +(128-event cap with overflow metadata), engine contract identifiers (stability, +eight-agent/127-cell defaults), world snapshot validation (hex-control +invariants, out-of-world simulated player rejection), the Zero strategic +observation schema (bounded semantic worker threat fields, capture caps), +reasoning profiles (metadata-advertised effort ordering, Off exclusion for +mandatory reasoning, legacy-assignment defaults), and snapshot/export contracts +(state-only exports, complete API snapshot, unbounded-history rejection). + +`reflex.test.ts` covers zero-swarm reflex contracts: compact opaque worker +observation acceptance, directive/choice-telemetry mismatch rejection, optional +bounded replan probability. + +`scenario.test.ts` covers scenario contracts: virtual-tick bounds, temporary +limits, attempt and credit-admission bounds, request/preview/applied contract +validation, dynamic roster overflow rejection, Patient Zero requirement, +prompt-attribution exclusion from setup input, and archived-scenario null +preservation. + +### Agent runtime (`packages/agent-runtime`) + +`swarm-planner.test.ts` covers the OpenRouter swarm planner: repeatable +observation-derived plans, bounded worker and target choices mapped to +authoritative directives, completed-directive marking in the compact Zero +request, event-derived worker threat and capture context, unknown-choice +rejection, missing-directive reporting, deterministic-plan bounds checking, +ten-tick lifetime enforcement, invented-candidate and omitted-directive +rejection, overloaded-response retry, complete provider accounting (cost, +tokens, usage retention for invalid or unparseable plans, optional cost +omission), non-OK attempt attribution, cancellation safety, and secret/ +observation-data exclusion from response metadata. + +`typesafe-jev-reflex-provider.test.ts` covers the TypeSafe Jev reflex provider: +current-legal-candidate reuse across calls, pinned model and opaque criteria +dispatch, bounded capture-pressure projection (location and hunter data +excluded), absent-capture omission, malformed-response and out-of-candidates +rejection, missing/malformed Noul rejection, independent HTTP attempt accounting, +deadline enforcement, budget-denial stop, invalid-timeout rejection, cancellation +propagation. Also covers `ScriptedReflexProvider`: deterministic opaque +candidate selection, default replan probability of zero, API-key exclusion from +the request body. + +`model-catalog.test.ts` covers the OpenRouter model catalog: compatible-model +sanitization, pricing parsing, tools/structured-output/reasoning independence, +malformed-entry skipping, cache TTL, stale fallback, and safe failure states. + +### Experiment archive (`packages/experiment-archive`) + +`archive.test.ts` covers schema-v12-only enforcement: swarm-native provenance +archival, idempotent import, query service, credential-like-data rejection before +persistence, unknown-architecture-version rejection, and non-v12 schema +rejection. + +### Game API (`apps/game-api`) + +`app.test.ts` covers the API boundary: repeatable swarm-native scripted +providers, health and swarm-setup contracts, atomic swarm tick through the public +endpoint, and absence of legacy sequential-turn routes. + +`simulation-service.test.ts` covers core tick execution: committing Zero +directives and worker reflex actions in one tick, and reset without retained +ticks. + +`simulation-service.swarm.test.ts` covers full swarm tick scenarios using +scripted providers: conservative and elevated-pressure replan thresholds, +current-tick disinfection escalation into the next Zero replan, terminal +player-only tick on trail-hunter capture of Patient Zero, worker removal before +planning on player capture, unique attempt turn numbers after capture, schema- +valid API response without legacy turn records, frozen-facts ordering and +physical-action engine resolution, first-plan failure with one billed Zero +attempt and deterministic local expansion, directive reuse for four ticks +followed by replanning on the fifth, worker replan request, retained-directive +expiry, at-target and advancing-toward-target Zero reporting, reuse-tick +reservation release on cancellation, simulated-player event export, failed-Jev +wait fallback, cancellation without committed world, relocate completion and +completed-directive identification, and expand completion only after +worker control. + +`reflex-execution.test.ts` covers the reflex execution seam: scripted end-to- +end execution through planner and reflex seams, directive candidate choice and +engine resolution, at-target reporting, four-entry capture-alert cap, immediate +pressure from public disinfection without player-state exposure, completed +provider attempt retention without committed state, malformed-response wait +fallback, fabricated-attribution and partial-probability rejection, and two- +attempt retention after a transient retry. + +`swarm-directives.test.ts` covers directive semantics: expand completion only +after worker-controlled target, relocate and reinforce completion on arrival, +evade completion on arrival or after leaving high pressure, non-completing hold +behavior, infected-target rejection, and missing/already-satisfied/incoherent- +target rejection on issue. + +`swarm-pressure.test.ts` covers pressure classification: one-cell, two-cell, +and distant public-disinfection classification; five-tick history retention; +old-event expiry before pressure derivation; deduplication and cap. + +`attempt-accounting.test.ts` covers credit admission: atomic reservation and +finalization, unused-reservation release, unlimited capacity, decimal input +canonicalization, exact decimal admission with known-cost refund and unknown- +cost exposure retention, atomic rejection with in-flight coverage, overage +fail-closed, unlimited-capacity overage, independent finalized and in-flight +records, and mutation guard on validation failure. + +`swarm-comparison.test.ts` covers the offline comparison harness: +byte-for-byte reproducibility for the same deterministic inputs, and Jev-worker +versus deterministic-worker-baseline comparison. The deterministic-worker +baseline is retained as the ablation control isolating Jev's contribution; it +is not a second production architecture. + +`live-swarm-comparison.test.ts` covers the live comparison admission guard: +confirmation requirement before provider construction, fixed live-experiment +cap enforcement, and matched seeded inputs with Jev calls omitted in the +deterministic control. + +`live-swarm-comparison-cli.test.ts` covers the CLI admission guard: refusal +without cost acknowledgement, model requirement after acknowledgement, saved- +report summary without acknowledgement or providers, unsafe-text rejection in +hand-edited reports, bounded-input defaults and oversized-input rejection, and +separate survival/territory/stall/replan/cost metrics in summaries. + +`swarm-diagnostics-cli.test.ts` covers the diagnostic projection: stationary- +swarm summary showing no player pressure and fallback actions. + +`geographic-direction.test.ts` covers H3 bearing calculations: clockwise sector +boundaries with north wraparound, initial bearings across longitude wraparound, +and same-cell/same-coordinate rejection. + +### World Lab (`apps/world-lab`) + +`swarm-view.test.tsx` covers swarm telemetry panels: inactive pressure/action/ +failure summary, Zero fallback and worker reflex telemetry without social labels, +provider-cost versus admission-exposure separation, completed worker directives +in strategy and activity telemetry, empty-state before first committed tick, +fallback worker actions and failures visible without Jev telemetry, and +reused-directive and structured-replan-request display. + +`world-lab.test.tsx` covers the swarm workspace: fixed swarm architecture and +Agent Zero model readiness, fresh swarm setup without an architecture selector, +tick commit, reset, exact-tick-cap execution without overlapping requests, +cancellation reconciliation, full-safe export preview before export actions, +model console showing one Agent Zero planner row and no per-agent override +controls, and export dialog without agent/turn/level/outcome/action filters. + +`model-options.test.ts` covers shared model options: deduplication and identical +ordering for global and per-agent options, identifier-before-name ordering, and +price-metadata preservation. + +`ui-color.test.ts` covers agent color resolution: own-color resolution and +neutral fallback for unknown agents. + +`world-map-config.test.ts` covers dark basemap configuration: tokenless CARTO +Dark Matter tiles with complete attribution. + +### Playwright E2E (`tests/e2e/world-lab.spec.ts`) + +Two tests: the long swarm-activity log scrolls inside the fixed-height bottom +dock; and a deterministic scripted swarm tick commits and exports safe +telemetry without an OpenRouter request. + +## Scripted and deterministic seams + +`HEXZERO_PROVIDER=scripted` (via `pnpm dev:test-provider`) activates the +scripted path for both applications: the server does not load `.env` and genuine +provider credentials are never read. Unit and integration tests instantiate +`ScriptedSwarmPlannerProvider` (`plannerMode: 'scripted-swarm-test'`) and +`ScriptedReflexProvider` (`reflexMode: 'scripted-reflex-test'`) directly; no +tests use real providers. + +The deterministic-worker baseline (workers that resolve directives without a +model call) is retained alongside Jev as the ablation control. Both +`pnpm compare:offline` (offline, no provider, no archive write) and +`pnpm compare:live` (paid, explicit acknowledgement required) compare only +the Jev and deterministic-worker variants. `pnpm diagnose:swarm` summarizes a +running local Game API snapshot without provider calls, keys, prompts, or raw +responses. ## Owner validation sequence @@ -173,106 +209,37 @@ The repository owner runs local validation. Coding agents write tests and inspec node --version pnpm --version pnpm install --frozen-lockfile -pnpm format:check -pnpm lint -pnpm typecheck -pnpm test -pnpm build +pnpm validate pnpm exec playwright install chromium # only if Chromium is not already installed pnpm test:e2e ``` -`pnpm validate` aggregates formatting, lint, type checking, unit/integration tests, and builds. Playwright remains separate. Its web server starts both applications with the explicit deterministic provider; `HEXZERO_PROVIDER=scripted` is never an implicit OpenRouter fallback. Environment coverage verifies that the canonical provider and archive variables override their deprecated `AGENTBORNE_` aliases. +`pnpm validate` aggregates formatting check, lint, type checking, unit and +integration tests, and builds (`pnpm format:check && pnpm lint && pnpm typecheck +&& pnpm test && pnpm build`). `pnpm test:e2e` runs Playwright separately. Its +web server starts both applications with `HEXZERO_PROVIDER=scripted`; that +variable is never an implicit OpenRouter fallback. -## Coverage - -Deterministic service and component coverage includes engine-derived action -availability, one-slot automatic repair/transport recovery under a shared tick -deadline, lost-tick attribution, attempt-history export, idempotent mutation -delivery, ambiguous-response reconciliation, atomic cancellation, and model and -export modal dismissal. - -World Lab interaction coverage also verifies newest-first public-chat DOM order -and reading-position preservation, browser-local follow-latest selection across -active/next and recovery transitions, non-color acting/next labels, shared -dialog focus/dismissal/overflow structure, and complete collapsed dock headers. -Playwright exercises the map-first layout at 1920×1080, 1440×900, 1024×768, -and approximately 768×900 with deterministic scripted data only. - -Command-navbar coverage verifies one persistent row, always-visible known cost, stable async control slots, accessible icon controls, exact absolute tick targets 5/10/25/50/100, current/past target advancement, hover/focus experiment details, responsive overflow, and removal of the provider badge and inspector export action. Map interaction coverage keeps agent-marker inspection independent from explicit hex selection and verifies that the map-local hex card dismisses on a background click. Export coverage separates preview from generation, includes lost ticks by default, invalidates artifacts after relevant option changes, prevents stale or duplicate copy/download, and checks accessible pending/ready/error states. Shared model-option tests require identical global/per-agent ordering and formatting. Effective-color tests cover current-alliance, retained, base, and neutral fallback precedence. Dark-map tests assert tokenless CARTO URLs and complete attribution without network access. - -Direct archive-write coverage validates the narrow request/response schemas, -compact digest-verified regeneration of the exact generated document, mismatch -rejection, pre-generation and stale-artifact disabling, synchronous -duplicate-activation prevention, bounded notices, injected persistence without -startup file creation, and idempotency through the existing importer. Tests use -injected writers, in-memory SQLite, or temporary paths only. - -Behavior coverage verifies registry uniqueness/versioning, deterministic balanced and fully random assignment, independent profile dimensions, turn-one locking, reset semantics, exact diplomacy affordances, layered prompt trust language, bounded structural detail codes, turn attribution, and export preservation. Agent Controller coverage verifies accessible Overview/Models/Behavior tabs, default readiness, manual pre-turn selection, post-start locking, responsive dialog layout, and compact roster summaries. - -Schema-v8 reconciliation tests require personality and strategy subtotals to match global logical-turn totals and verify that repaired validation attempts retain both `invalid-action-fields` and their stable structural detail code. The conversational-invitation regression expects contradictory diplomacy fields when a model supplies a chat participant as the recipient while omitting the required formal proposal ID. A well-formed but unavailable proposal UUID remains an engine-authoritative, non-retried rejection. - -Attempt-accounting coverage verifies that schema-v7 metrics count every initial, -automatic-repair, automatic-transport-retry, and manual-retry call exactly once, -reconcile logical outcomes independently, -fall back once to top-level provider metadata for legacy records, and preserve -schema-v6 model-configuration import compatibility. - -Partial-accounting fixtures verify independent known token-field sums, -unknown-token attempt disclosure, exact known-cost accumulation, and distinct -unknown-cost attempt versus logical-turn counts. Fake-timer transport tests cover -valid `Retry-After`, the bounded missing/invalid-header fallback, shared-deadline -consumption, cancellation during backoff, and the unchanged two-call ceiling. -Attempt-admission tests also cover exact small-decimal arithmetic, atomic -permit/credit rejection, unstarted reservation release, known-cost refund, -unknown and in-flight exposure, idempotent finalization, reservation overage -fail-closed behavior, and whole-tick rejection before provider dispatch. - -- Centralized development-contract tests prove radius 6 produces exactly 127 unique open/uncontrolled cells, eight unique deterministic starts, stable IDs/default personalities, and an eight-entry scoreboard with up to seven other-agent observations. -- Alliance engine/schema tests cover 10- and 32-agent feasibility, full-roster membership, a maximum-count five-alliance partition without color capacity, free-agent formation, member invitations, unaffiliated join requests to allied recipients, recipient-only acceptance, proposal conflicts, exact two-tick expiry for tick callers, legacy two-roster-round expiry, stale invalidation, one-alliance membership, unilateral leave/switch semantics, deterministic accessible color reuse, and allied-capture rejection. -- Simulation tests cover frozen exact diplomacy affordances and blocker codes, Patient Zero's fixed-cap sparse global diplomacy view, same-tick resolution races, independent world/communication/diplomacy outcomes, isolated lost ticks, bounded authoritative alliance observations, reset/default semantics, multi-agent telemetry relevance, alliance territory sums, and complete eight-record tick groups. - -Prompt tests verify that models copy only exact supplied diplomacy IDs, treat -range/membership/capacity blockers as authoritative, avoid repeating unavailable -plans, and retain the single flat response without tools or another inference. -These are deterministic contract tests, not claims of measured token savings or -model compliance. - -- Runtime mocks cover the explicit per-turn model and reasoning profile, universal text-only request, flat JSON extraction/repair, exact default/off/effort payloads, absent provider-specific controls, malformed or missing output, cancellation, output exhaustion, metadata preservation, and the unchanged one-request boundary without OpenRouter calls. -- Catalog fixtures cover required-capability inclusion/exclusion, text modalities, context floor, pricing parsing, malformed entries, timeout/failure, cache TTL, stale fallback, manual refresh, and credential non-disclosure without network access. -- Schema-v5 export tests cover eight-agent selection, state-only alliance/proposal snapshots, diplomacy/event metrics and preview counts, selected-agent proposal/membership relevance, unrelated direct/rejected exclusion, cost handling, retention, and all four safe tiers. -- React and Playwright fixtures cover 127 MapLibre cells, eight markers, affiliation-derived neutral/alliance colors, tick-native activity attribution with legacy turn fallback, stable explicit agent selection, alliance panels and events, separate component results, safe text rendering, reset, bounded tick targets, and lost-tick inspection without a genuine-provider run. - -- Shared schema tests cover valid/invalid observations and decoupled decisions, required four-way world actions, optional public/direct communication, separate component results, all turn outcomes, response snapshots, history bounds, and model-authored string limits. -- Shared schema tests cover authoritative whitespace trimming and 1/280/281-character boundaries, recipient IDs, typed public/direct events and rejected attempts, 12-entry public and six-entry directional direct observation bounds. -- Shared schema tests cover open/uncontrolled and infected/controlled hex unions, controller validity, alliance-aware capture eligibility, territory scoreboards, gain/loss bounds, independent communication/diplomacy metrics, and export schema version 5. -- Shared schema tests cover trimmed personality updates, empty/oversized/malformed values, update/restore response contracts, and typed mutation errors. -- Shared and service export tests cover optional provider usage and tiny costs, experiment identities/manifests/retention/configuration events, all export levels and filters, Custom dependencies, invalid empty/range/agent selections, previews, generated documents, level-specific omissions, and result-free lost-tick records in Minimal, Standard, Full Safe, and Custom exports. -- World-engine tests cover all existing movement/infection/capture behavior plus public delivery, direct distances zero/one/three, distance-four/self/unknown rejection, message trimming, independent application, pre-action proximity, event ordering, and deterministic construction with unchanged personalities. -- Agent-runtime tests inspect the model-agnostic OpenRouter text request, fixed trust instructions, flat sentinel normalization, fenced/prose-wrapped/trailing-comma JSON recovery, exact metadata-selected reasoning payloads, explicit model overrides, body-inclusive 75-second timeouts, cancellation, bounded diagnostics, secret non-leakage, and provider-name-independent mocked output. -- Agent-runtime tests normalize successful/missing reasoning/cache/token/cost usage, retain known usage through malformed or unsupported decisions, and prove scripted zero cost. -- Simulation-service tests cover valid action plus public/direct messages, rejected action plus accepted public/direct messages, pre-action distance, one call per turn, provider-failure auto-stop semantics, cancellation without world mutation or turn consumption, global/per-agent model and reasoning resolution, exported profile change events, older-export defaults, retention, recovery, and concurrency. -- Export/telemetry tests cover independent world, communication, and diplomacy totals, multi-agent alliance relevance, malformed identifier sanitization, all/one/multi-agent selection, unrelated-direct and unrelated-rejection exclusion, separate preview counts, schema-v5 validation, state-only snapshots, byte estimates, costs, ordering, and immutability. -- Personality service tests cover single-agent updates, unknown/invalid rejection without mutation, next-observation use, preservation of progress and history, reset preservation, eight-profile default restoration, active-turn conflicts, and recovery. -- API integration tests validate snapshot, turn, reset, missing configuration, provider failure, internal-failure propagation and recovery, rejection, and typed conflict responses. -- API integration tests validate personality update/default-restore success, boundary validation, unknown IDs, conflicts, and safe error/response bodies. -- API integration tests validate export preview/generation, unknown/empty/malformed selections, retention disclosure, typed conflicts, and safe-response exclusions. -- React tests cover controls/statuses, playback, reset, selection, existing capture/territory views, a bounded public feed, direct sent/received history with participants and turn/time, visibly separate component results, empty states, hostile-looking text escaping, H3 readiness, and safe errors. -- React tests cover explicit edit/cancel/apply, every preset, Custom matching, character feedback, playback/pending disabling, reset preservation, restore confirmation, and active-versus-historical personality clarity. -- React tests cover experiment/agent usage, export agent selection, levels and Custom switches, filters, preview, copy/download identity and URL cleanup, reset telemetry warnings, and fully infected auto-pause. -- Playwright uses real MapLibre feature inspection and the explicit scripted provider to verify combined decision components, capture/controller transfer, alliance presentation, export/reset behavior, 127 H3 cells, infection counts, and eight markers. -- Playwright previews and runtime-validates a victim-only Minimal capture export with zero matching victim capture turns and one matching control change, verifies zero-cost metrics, then confirms no OpenRouter request occurred. -- The explicit scripted server path does not load `.env`; genuine-provider environment loading remains outside deterministic browser validation. +The repository owner runs local validation. Coding agents write tests and +inspect GitHub CI but do not run local formatting, linting, type checking, +tests, builds, Playwright, or real-provider calls unless explicitly asked. ## Real-provider smoke -The separately opted-in `pnpm smoke:openrouter -- [initial|stateful]` command makes one bounded OpenRouter call and validates the decision. The optional `stateful` scenario supplies an active goal and one populated memory so the goal and memory sentinel contract can be checked explicitly; the default is `initial`. It reads only `OPENROUTER_API_KEY` from `.env`; the model is an explicit argument. It is intentionally absent from default validation, Playwright, and CI and must not be run without deliberate authorization because it incurs third-party cost. - -World Lab also offers an explicit “Test selected model” probe. It uses the production text/flat-JSON contract and selected reasoning profile, does not advance or mutate the world, may incur a small charge, and is cached by model plus profile plus contract version. It is never invoked by deterministic validation or CI. +World Lab offers an explicit "Test Agent Zero planner" probe. It uses the production +planner contract and selected reasoning profile, does not advance or mutate the +world, may incur a small charge, and is cached by model plus profile plus +contract version. It is never invoked by deterministic validation or CI. -Experiment-archive tests generate current schema-v9 exports through the deterministic scripted provider and cover migration/reopen, canonical and legacy path resolution, legacy export filenames, transactional rollback, stable idempotent identifiers, normalized round trips, bounded filters, summary/comparison calculations, canonical metric agreement with preserved source inconsistencies, Patient Zero classifications, retention completeness, FTS notes/supersession, explicit persistence failures, and credential/private-reasoning rejection. They use only in-memory or temporary SQLite databases and make no live provider or geocoding requests. +The live comparison command (`pnpm compare:live`) is a separately paid +experiment requiring an explicit provider-cost acknowledgement and an +operator-selected Zero model before constructing live providers. Each run has +hard attempt and credit-admission caps. Its JSON report contains only +allowlisted scenario, world, decision, and usage metrics; no keys, raw provider +payloads, prompts, or private reasoning. It never launches from default tests, +Playwright, or CI. -# Provider-attempt ledger +## Safe provider-attempt records Offline tests cover attempt success, failure, cancellation, timeout, retry, retention, export filtering, and archive idempotency. Real-provider calls remain