world_visibility and asset_type were each declared twice: once explicitly
via `.create(checkfirst=True)`, and again implicitly by SQLAlchemy when
create_table() compiled the inline postgresql.ENUM() column type (which
defaults create_type=True). On a genuinely empty database this raises
asyncpg.DuplicateObjectError mid-transaction and the migration never
completes -- verified this was true 100% of the time from a fresh
container, meaning the backend has never successfully bootstrapped from
scratch. Fixed by passing create_type=False on the inline column
declarations, since the type is already created explicitly above.
Also parameterized both services' host ports (POSTGRES_HOST_PORT /
REDIS_HOST_PORT, defaulting to the original 5432/6379) so concurrent
agent workspaces sharing this same docker-compose.yml can run isolated
databases without colliding on the host port.
- avatar_slot_registry.gd: _slot_data/_slot_definitions made static (every
caller uses AvatarSlotRegistry.method() on the class, never an instance,
so the old instance _init() populating them was never invoked); moved
registry build to static func _static_init()
- avatar_catalog.gd: compute_loadout_hash() return type uint32 -> int
(GDScript has no fixed-width uint type)
- avatar_loader.gd: GLTFDocument.parse() (doesn't exist) -> the real
append_from_buffer()+generate_scene() API; Error.parse_error() (doesn't
exist) -> error_string(); Mesh.ARRAY_JOINTS (doesn't exist) ->
Mesh.ARRAY_BONES; removed a dead 'mesh is MultiMesh' check that can
never be true (MeshInstance3D.mesh is always Mesh, never MultiMesh);
fixed _merge_node_into_avatar to recurse into a Skeleton3D's children
(skinned meshes are commonly children of the skeleton in a GLB export,
the old code returned before ever reaching them)
- avatar_customization_ui.gd: added the missing _on_slot_button_pressed
handler (referenced by a button connect, never defined -- just calls
the existing _select_slot())
Verified: godot --headless --import + --quit is fully clean, and the
avatar_customization.tscn scene now instantiates successfully.
Remaining, scoped separately: avatar_visualizer.gd calls a
AvatarLoader.load_slot() static async API and SlotItem/SlotResult types
that don't exist -- AvatarLoader's real API (matching the project's own
avatar.md spec: one canonical skeleton, attachments retargeted onto it)
is instance-based load_base_body()/load_attachment(). AvatarVisualizer
needs rewriting to use that real API; it's the one out of step with spec,
not AvatarLoader.
- scenes/avatar_customization.tscn: script_extense -> script (typo meant
the customization UI script was never actually attached to the scene)
- scripts/avatar/avatar_loadout.gd: add missing class_name AvatarLoadout
(avatar_system.gd references the type everywhere; only this file among
the avatar scripts lacked its class_name)
- scripts/main_menu.gd: _ready() referenced _customize_button/_settings_button/
_quit_button but the @onready vars are named without the leading
underscore