The live adapter used to parse free-form @dig/@open/@create response
text with a plain "#NNN" regex (extract_dbref) to recover the newly
created object's dbref. That broke whenever the server output format
shifted — the tracker's open item flagged this as
version-fragile. Thing creation also silently dropped its dbref
entirely, leaving state entries unindexed for later reconciler runs.
Replace the parsing path with a sentinel-wrapped `think` round-trip:
think WB1[<expr>]WB2
`think` emits its evaluated argument verbatim on the executor's
output stream, so the response buffer contains the literal bytes
`WB1<value>WB2`. `parse_think_response()` takes the *last* match so
we land on the evaluated output rather than the command echo, which
also carries the sentinel bytes in its un-evaluated form. On top of
that helper, `query_last_created(conn, kind)` wraps
`lastcreate(me, R|E|T|P)` to deterministically pull the just-created
object's dbref without any parsing assumptions.
executor.py's three create paths (rooms, exits, things) now use
query_last_created instead of extract_dbref(resp). Thing creation
also captures its dbref + objid into state, which was missing.
extract_dbref() is removed as dead code. The live_adapter module
docstring documents the one remaining server-format dependency
(`%L`, a MUX core invariant).
test_worldbuilder.py (72), test_diff_v3.py, and test_reconciler.py
(36) still pass. Top-level ISSUES.md index updated to move
WorldBuilder into the fully-closed trackers list.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Deduplicate mux_escape/mux_unescape into live_adapter.py (single source)
- Executor now consumes Operation objects from the planner instead of
walking spec directly; phased execution (rooms/exits/things/destroys)
- Add query_live_object() and query_live_snapshot() to live_adapter for
producing reconciler-compatible normalized snapshots from a running game
- Add normalize_imported_room/exit helpers; importer generate_state() now
produces reconciler-compatible output with proper flag lists and exits
- Add test_reconciler.py (36 tests covering all 7 reconciliation states)
- Add ISSUES.md tracking the integration gaps and their resolution
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace Virtual ID / &WB_ID design with objid() for identity tracking.
State file bumped to v4 with objid stored alongside dbref. Executor,
importer, and verify all capture and validate objid to detect dbref
recycling.
Add Known Defects section (D1-D8) documenting architectural gaps in v2
code that must be resolved before v3 features: attribute escaping
ambiguity, Things not tracked, teleport/here fragility, lossy exit
identity, silent command failures, missing zone creation, inconsistent
description escaping, and dry-run state pollution.
Document deferred @destroy semantics — GOING flag, @undestroy race,
pending_destroy state tracking, re-creation race conditions.
Restructure implementation order into three phases: fix foundations,
complete object model, then build v3 features.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Upgrade StateFile to v3: stores description, flags, and attributes.
- Enhance diff_spec to compare specific fields with old/new values.
- Refactor compile_incremental to emit surgical MUX commands.
- Implement room destruction in incremental compiler.
- Update importer to generate v3 state files.
Issue fixes:
1. mux_escape() — proper %r/%t/%% escaping, replaces naive \n→%r
2. Full exit model — lock, desc, succ/osucc/fail/ofail/drop/odrop, flags
3. Reliable dbref capture — think %L primary, @dig parse fallback
4. Content hashing in state — sha256 of name+desc+attrs+flags
5. Auto _instance_id param — components can use ${_instance_id}
@decomp integration:
Importer tries @decomp/tf first (one command, all attrs)
Falls back to lattr+get if @decomp unavailable
Parses &ATTR #dbref=value format
Output formats (--format flag):
default — comments + commands (human-readable)
upload — unformat-compatible .mux format (TF /quote)
raw — commands only (pipe to telnet)
Exit property compilation:
@lock, @desc, @succ, @osucc, @fail, @ofail, @drop, @odrop, @set
emitted after @open when exit spec has those fields
All 4 valid test specs pass DRC.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Procedural generation:
Grid generator creates WxH rooms with cardinal exits
Seeded-random description selection (deterministic)
Density parameter controls connectivity (0.0-1.0)
Edge ports for wiring grid to external rooms
forest_area.yaml — 7 description variants
street_grid.yaml — 5 description variants
Verify command (executor.py verify):
Connects to live game, checks rooms match spec
Validates names, descriptions, attributes against state
Reports discrepancies
Rollback command (executor.py rollback):
Destroys objects in reverse order (exits first, then rooms)
Clears state file after destruction
Dry-run mode supported
Thing support:
Thing model (name, location, description, flags, attrs, parent)
Parsed from spec YAML and component definitions
Compiled to @create + @desc + &attr + @parent commands
Shown in plan output
Component things expand with parameter substitution
New components:
tavern.yaml — 3 rooms + barkeeper NPC thing
street_grid.yaml — procedural city block grid
Test specs:
town.yaml — combines tavern + street_grid + manual rooms/things
forest.yaml — 4x4 procedural forest with edge connection
Zone support:
@chzone emitted in compiler for all rooms
@parent emitted when room has parent field
All 4 test specs pass DRC.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
executor.py — connects to a MUX and applies compiled specs:
MuxConnection class:
Synchronous telnet with IAC stripping
SSL/TLS support, login with character/password
Send commands, read responses with quiet-timeout
Execution engine:
Phase 1: create rooms via @dig/teleport, capture dbrefs from output
Phase 2: create exits via @open with resolved dbrefs
Sets descriptions, flags, attributes per room
Handles existing rooms (teleport + update instead of recreate)
State file (.worldbuilder/<zone>.state.yaml):
Tracks spec_id → dbref mapping across runs
Enables incremental updates and dbref resolution
YAML format for human readability
Safety:
DRC validation before any commands sent
Dry-run mode (--dry-run) logs commands without executing
Optional log file (--log) for full audit trail
Sequential execution with response capture
CLI: worldbuilder executor.py <spec> --host --port --character --password
[--ssl] [--dry-run] [--log] [--state]
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>