Skip to main content
LifePot
FeedbackDocumentation
← All guidesPlay the game →Download source Markdown ↓

Setup and rule contracts

This page is derived from the canonical developer-reference; its content has one source of truth.

Setup schemas and normalization

Source of truth: src/game/setup.ts, src/game/world.ts.

setupAnswersSchema is a strict object with exactly world, threat, and reward; each is a trimmed, nonempty string of at most 140 characters. Unknown keys fail. canonicalAnswers trims and revalidates. hashSetupRequest hashes the canonical ordered answer tuple and prefixes it with setup_.

LifeConfig is strict at each schema level:

FieldAccepted values / constraint
environment.abundancescarce, balanced, rich
environment.distributionclustered, scattered, seasonal
environment.hazarddrought, toxin, heat, crowding
environment.volatilitystable, pulsing, chaotic
fitnessexactly survive, replicate, cooperate, explore, adapt; each 0–1 and total within 1e-9 of 1
founders.balanceprey_heavy, balanced, predator_heavy
founders.diversityfocused, varied
founders.preyStrategyefficient_grazing, early_brood, armored, swarming, dispersal
founders.predatorStrategyambush, pursuit, pack_hunting, efficient_kill, brood_hunting
rulesoptional WorldRuleGraph; if omitted the default graph is used by the engine

normalizeFitness clamps negative/non-finite inputs to zero and normalizes; an all-zero input becomes equal weights. It is not a substitute for validating external config. defaultConfig() uses balanced/scattered/drought/stable, equal weights, balanced/varied founders, efficient grazing/pursuit, and defaultRuleGraph().

Setup prose maps by fixed keyword rules in deterministicSetup; it does not generate executable logic. The route may request typed setup interpretation from Jev, validates the response, and returns deterministic setup as an explicitly labeled fallback when model access or validation fails.

Fidelity correction and review

Live setup first establishes a model-authored organism-to-slot contract from finite spans of the original world and threat, then selects roles and directed relationships for those named organisms. The initial environment/fitness call no longer independently selects another species count, role set or feeding graph. A duplicate identity can receive one corrective mapping call: valid earlier assignments remain fixed, and the remaining palette excludes already assigned or overlapping earlier mentions. A still-inconsistent correction is rejected. This is mechanical source grounding and bounded model interpretation, not keyword-based semantic acceptance.

The browser shows the named intent, concrete contract conflicts and finite failure-stage/code metadata. A corrected graph must retain the established species, roles and directed links even if a fresh fidelity reviewer says approve. The original answers are preserved, and diagnostics contain no raw provider payload or credentials. Named-intent and failure metadata remain outside the deterministic replay contract. Setup costs six calls directly and at most thirteen with identity/food-web correction and the council protocol correction; all calls are reserved and their successful response usage is accounted for.

Council selection preserves the returned Choice protocol: the selected label must have maximal probability. A reproduced nonmaximal selection with otherwise valid data receives one budgeted corrective request; a second inconsistent response, malformed distribution, invalid metadata or denied reservation remains a failure. The original probability data are never changed or renormalized, and successful correction accounts for both requests. This does not add runtime-council retries or alter simulation/replay validation.

The fidelity request includes the complete interpreted configuration and a readable, engine-derived food web alongside the original answers and encoded graph. Pair directions are decoded using each pair's own endpoints; review checks supported food-web intent, not biological realism or guaranteed success of the player's objective. A reselect or reject fidelity verdict triggers at most one correction; the corrected proposal must independently receive approve, and persistent rejection stays blocked. Roles/count are selected first; the dependent pair request includes the fixed species/roles. The complete corrected graph is validated and reviewed against the unchanged original answers. An approved correction receives a council selected for that graph. Every provider call reserves the existing call budget, and successful response usage is accumulated. A persistent nonapproval gets a finite, model-selected review focus; that focus is not independent proof of a semantic mismatch. Failure inside correction preserves the nonapproval instead of silently returning a seedable fallback. Additional review metadata stays outside deterministic engine/replay contracts.

Run LIFEPOT_LIVE_SETUP_TEST=1 npm test -- src/app/api/judge/setup-live.test.ts with a server-side TYPESAFE_API_KEY already configured to check real Jev acceptance of ordinary inputs. This explicitly opted-in test makes paid inference requests; without both settings it is skipped. Mocked approval tests prove the correction/control flow, not model fidelity. For an approved Cloudflare preview that already holds the server-side key, run PLAYWRIGHT_BASE_URL=http://localhost:9239 LIFEPOT_LIVE_GAMEPLAY_BASE_URL=http://localhost:9239 npm run test:e2e -- e2e/live-jev-gameplay.spec.ts --workers=1 --retries=0. This separate opt-in browser test exercises ordinary setup, adaptive play, reflection, a mobile follow-up and inference-free replay; it is skipped during normal fixture runs. Do not point it at production by default.

Rule graph reference

Source: src/game/rules.ts; tests: src/game/rules.test.ts.

A graph has integer version >= 1, 2–4 species in canonical prefix order (A, B, C, D), one interaction for every canonical species pair exactly once and in order, an environment object, and optional validated council metadata. Species roles: producer, grazer, hunter, scavenger, omnivore. Self-interactions: cooperative, territorial, cannibalistic, neutral. Pair modes: a_consumes_b, b_consumes_a, competition, mutualism, avoidance, neutral.

The graph must have a viable basal-feeding role (producer, grazer, or omnivore). Roles alone do not authorize predation: directional pair edges control inter-species consumption. A strict invalid shape throws Invalid ecosystem rule graph; canonical-order, complete-pair, and basal-path invariant violations throw descriptive errors. Validation returns a cloned graph.

Environment vocabularies are regeneration (steady, pulsed, depletion_feedback), pressure (stability, drought, toxin_wave, heat_wave, fragmentation, nutrient_bloom), volatility (stable, pulsing, chaotic), intensity (low, medium, high), and duration (short, medium, long, persistent). Scheduled activations are immediate, after_6, after_12, after_24, resources_low, population_boom, population_crash, species_emergence, species_extinction, predation_high; transitions are abrupt, ramp, pulse.

A RulePatch is exactly one of: {kind:"pair", pair, mode}, {kind:"self", species, value}, or {kind:"environment", field, value}. It is strict; unknown keys/enum values reject. Pair and species targets must exist. A changed patch increments graph version once; an unchanged patch does not. Scheduled changes bind a generation 0–180, activation, duration, transition, and patch. They only take effect when their trigger is due and the accepted decision's graph-version evidence is valid. Temporary changes revert according to duration; persistent changes do not automatically revert.

Validation example (actual functions)

Run the focused tests above to execute these cases using the repository's installed Vitest. This valid default graph is the actual defaultRuleGraph() contract; the second input is deliberately invalid because it adds an undeclared graph property and strict validation rejects it.

import { defaultRuleGraph, validateRuleGraph } from "./src/game/rules";

const graph = validateRuleGraph(defaultRuleGraph());
console.log(graph.species.length, graph.interactions[0].mode); // 2, "b_consumes_a"
try {
  validateRuleGraph({ ...graph, surprise: true });
} catch (error) {
  console.log((error as Error).message); // "Invalid ecosystem rule graph"
}

This snippet assumes the project TypeScript/Vitest environment and repository-root import path. It is a source-level example, not a standalone JavaScript script.