Validate provision.sh on a live box first; packer -on-error=ask; batch fixes;
check size/forge prereqs before building; code via dist:sync (image rebuild only
for toolchain/accelerator changes).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
rust-source-of-truth.md: add the "two-path divergence" rule to the canonical
content store section. Content reaches the sim two ways — in-game (GDScript
DataLoader reads JSON at runtime, projection.rs:41) and headless (Rust falls back
to a compile-time include_str!/hardcode copy, dispatch.rs:410). A balance constant
hardcoded in a crate is both a Rail-2 violation and a silent second copy that
drifts from the JSON — and headless is where the AI trains. Rule: grep
public/resources + public/games/**/data for a JSON home before adding a numeric
balance const; if it exists, LOAD it (OnceLock+include_str!, never std::fs in
shared sim code). References the p3-28 ContentRegistry endgame.
p3-28: add the matching "Rail-2 verify gate (enforcement)" acceptance bullet —
tools/check-no-rust-hardcoded-content.py + a verify step to catch the next
hardcode, best landed alongside the ContentRegistry.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds a narration convention so the user SEES the orchestration (and can verify parallelism at a
glance): whoever orchestrates emits a "▶ Dispatching [parallel|sequential] (N): agent(task)…" start
line and a "✓/✗ agent — outcome · proof" finish line per specialist. "parallel" must match behavior
(one message, multiple Agent calls). Milestone/decision/blocker also go out-of-band via TTS(ravdess02)
/ PushNotification; per-dispatch stays text-only (TTS every spawn = noise). Wired into the playbook
(agents-task-map.md), the team-lead agent, and the finish-game-1 skill's reporting section.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The hook left no trace, so 'did the bootloader fire this session?' was unverifiable. Now every fire
(a) stamps the orientation header with 'bootloader fired <UTC>' (visible in-context) and (b) appends
a line to .local/last-session-orient (gitignored breadcrumb) — so verification is one command:
cat .local/last-session-orient. Answers the 'how do I know it bootloaded?' question deterministically.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replaces the ad-hoc "/loop finish game 1" with a durable skill that captures both the mission and the
method. Encodes: the 3-part definition of done (scope complete + headless sim complete + Rail-1
getState unification), the per-iteration loop (orient → load rails → pick → classify → implement →
verify-by-type → commit → continue), the stop-and-ask conditions (balance/scope/architecture/render-
host = owner's call), and the guardrails this session paid for (verify premises, Rust drives, eliminate
don't fix the orchestrator, no stubs, don't gold-plate). Chains the tooling built this session
(session-orient → specialist-preamble → code-layering → orchestration).
First project skill; creates tooling/claude/dot-claude/skills/. Available next session (skills load at
session start).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Final agent-tooling pass folding in this session's hardest-won lessons (previously only in my memory):
code-layering.md:
- anti-pattern #4 "fixing the orchestrator instead of eliminating it" (the swap→extract→FFI drift;
the fix is usually DELETE the GDScript path, let Rust compute + UI render getState()).
- anti-pattern #5 "UI holding state / calling logic instead of reading getState()".
- principles rewritten: (1) Rust drives everything — divergence is a bug to DELETE, never reconcile;
(2) the UI is a pure view of getState() (render/act/end_turn, GdPlayerApi is the reference);
(3) single-source LOGIC not necessarily STATE — but never two state copies in ONE running game.
specialist-preamble.md (always-loaded core):
- verify rule gains "verify architectural PREMISES before committing to a plan" (the 3-turn drift,
collapsed by one grep of view.rs).
- layering rule gains the Rust-drives / UI-is-a-view-of-getState one-liner.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
No project bootloader existed: a new session/agent booted with only the static CLAUDE.md router and
had to manually dig for current state. Adds a SessionStart hook (session-orient.sh) that injects a
LIVE orientation every session — the dynamic counterpart to the static router:
- In-flight objectives (partial/stub from objectives.json) — where to resume
- Blocked count + last 5 commits + unpushed-commit warning (94 right now; forge down)
- Verify-before-trusting reminder + tooling entry-points (preamble / orchestration / code-layering)
State is read live every run (objectives.json + git) — never embedded, so it can't go stale
(the same anti-drift principle the agent tooling enforces). Read-only, <2s, never breaks the
session (any error → exits 0). Dual-mode: hook JSON by default, `--human` prints markdown for
manual mid-session re-orientation (`bash .claude/hooks/session-orient.sh --human`).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Specialist agents had ZERO shared instruction layer — each inlined its own knowledge, none
referenced the rails/layering/verification rules, so the same mistakes recurred. Restructured
into a DRY shape grounded in the bugs this session surfaced:
NEW specialist-preamble.md — the shared core every specialist loads first. Six commandments,
each earned by a real violation: (1) verify-don't-infer incl. docs/memory drift (the rust-source
false claims), (2) code-layering (formula vs orchestration vs presentation vs content vs type),
(3) prove-it by output type (cargo test / headless loop / golden-repin / render-proof), (4) stay
in scope (Game 1, no gold-plating disabled systems), (5) objective state = pointer+protocol not
embedded, (6) safety/workflow (build-output, atomic commits, worktree-fork→file-extraction).
agents-task-map.md rewritten as the orchestration PLAYBOOK (not just a lookup): dispatch-vs-inline,
parallel-by-default, the mandatory verify gate per output type, the worktree-fork integration rule,
"specialists return data not prose". Fixed the phantom mc-magic row (Game 2/3, no crate).
All 13 agents converted to thin shared-core pointer + domain delta (fault line + domain docs +
how-to-verify), each fault line drawn from a real drift risk for that specialist. Router + README +
CLAUDE.md agents section updated.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Better-guide-agents pass, grounded in this session's architecture review (GDScript turn-logic
divergence, rules leaked into mc-core). Two-pronged:
NEW `code-layering.md` — the decision PROCEDURE that was missing (the Rails state the rule; agents
still drifted because there was no "where does this code go?" procedure). Classifies every change as
formula/orchestration/presentation/content/shared-type, gives each one home, mandates grep-before-
reimplement, uses biomes as the template, records the real anti-patterns hit. Wired into the
always-loaded router + README index.
FIX `rust-source-of-truth.md` drift (it was actively misleading agents):
- "AI exception (one of one)" CONTRADICTED Rail-1 → recast as tech-debt; GdAiController DOES exist
(api-gdext/src/ai.rs:333), dispatch via mc_player_api::controllers.
- crate table listed phantom `mc-magic` + claimed BiomeRegistry in mc-core (false) → accurate
pure-logic-vs-orchestrator table; mc-core = shared TYPES, no rules.
game-systems + godot-engine agents point at code-layering at the fault lines they own.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
project_resources hardcoded happiness_pool: 0 (a stub from before the happiness phase
existed). Now that process_happiness_phase computes player.happiness each turn, surface it
in the PlayerView so the headless view exposes it end-to-end (compute → projection → view).
mc-player-api 135/0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Three geological natural-event categories (parallel agent port, extracted file-only onto
current main — the agent worktree forked from a stale base, so a branch merge was unsafe;
events.rs is a clean superset verified to compile + test against current HEAD):
- seismic — shifts tile elevation over a radius (with falloff).
- impact (asteroid) — T1-4 crater (biome/elevation/moisture/quality + local heat + aerosol);
T5 extinction (global aerosol injection). Magic/anchor/resource-spawn deferred (Game-3).
- tsunami — floods coastal land (moisture/quality/reef_health), skips open water.
Each: apply_X + dispatch_X + match arm in process_events + tests. Configs already present
(seismic/impact/tsunami.json) + auto-loaded via the headless harness, so they dispatch in
process_climate_phase with no extra wiring. mc-climate 61/0; mc-turn builds.
6/12 categories live (wildfire/drought/volcanic/seismic/impact/tsunami).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Exposed by a new hotseat full-game driver (drives both player seats over the
multi-slot wire, no AI dependency) — a 31-turn 2-player game surfaced these.
- mc-player-api: the AI→PlayerAction converter (apply_ai_action + the suggest
sibling) emitted the bare tactical city index ("0") for QueueProduction, but
find_city_indices needs the projector wire id "{player}_{c_idx}" — so every
AI/suggested queue_production failed UnknownCity. This silently broke the
in-box AI's production-steering, not just the wire. Emit the wire id at all
three sites; thread slot into the suggest converter; add a regression test.
Result in the playthrough: roundtrip failures 58→1, city_building_completed 0→18.
- api-gdext: advance_round_phase/end_player_round_phase did not compile at HEAD —
godot-rust 0.2.4 Array::push needs &Dictionary (AsArg); Pcg64 builds via ::seed
not ::seed_from_u64; dropped a dead rng binding. The gdext crate could not be
rebuilt from source until this.
- mc-worldsim: pub use GamePhase/RoundPhase (api-gdext references them through
mc_worldsim; they were a private re-export → E0603).
- tooling: add hotseat_playthrough.py — applies each seat's suggested actions
and flags any offered action that fails to apply, with severity triage.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Stale May 31–Jun 8 agent worktrees, all behind main with no unique work
(every change landed or superseded). Removed checkouts, branches, and the
accidentally-committed gitlink entries.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The first in-session magic_civ_screenshot timed out: windowed Godot spawned by
the MCP (a throttled background GUI process under Claude Code) inits far slower
than a terminal launch, exceeding the 45s connect timeout — though the driver
DID bind the port (verified 8787 open). Fixes:
- connect-first: if a rendered driver is already listening (e.g. a foreground
`MC_MCP_RENDER=1 ./run play`), connect to it directly and skip the slow,
throttled background spawn entirely.
- start timeout 45s -> 150s for the spawn fallback.
- a failed start now clears its cached promise + reaps the child so the next
tool call respawns instead of replaying the rejection until an MCP restart.
Re-verified end-to-end through the built RenderClient (spawn path): ping {ok},
screenshot -> a real 3420x1923 PNG of the live world map.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- render_client.ts: TCP client that spawns the rendered game via
render-driver-server.sh, then sends screenshot / open_screen / ping correlated
by id (distinct from the headless stdin HarnessClient).
- scripts/render-driver-server.sh: boots the REAL game (MC_AUTO_START +
MC_MCP_RENDER, gl_compatibility, not --headless) so the driver captures real
frames; client connects on MC_MCP_PORT.
- index.ts: magic_civ_screenshot + magic_civ_open_screen tools, render-client
holder + cleanup.
Verified end-to-end through the BUILT TypeScript (no Claude restart needed):
RenderClient -> game -> TCP ping {ok}, screenshot -> a real 3420x1923 PNG of the
live world map. dist/ is gitignored (built locally per .mcp.json); the tools
surface in a Claude session after the next restart.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Full integration of worktree-bridge-cse_01Nnt (54 commits) into main.
Conflicts (17) resolved: adopt branch's p2-65 GameState->mc-state crate move
across mc-ai/mc-core/mc-player-api/mc-turn; keep main's design-token theme
system (build-ui-theme.py, tile_info_panel.gd) and main's newer p0-26b evidence.
Workspace: 2624 tests pass; 5 pre-existing/environmental failures inherited from
main (constructor_smoke capping test, five_players_overflow, 3x gpu_rollout_parity)
— zero regressions introduced by the merge. api-gdext (GDExtension) compiles.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>