Review 2026-04-21 caught that the hybrid soft-lock refresh path is unreachable during normal WASD locomotion. `main.gd` was wiring `TargetSelectionClient` to `PositionAuthorityClient.authoritative_position_received`, which only fires on boot sync and move-rejection resync — successful `move-stream` 200s are intentionally silent to avoid RTT rubber-banding. So walking out of an alpha/beta radius never triggered the throttled `GET /target` the HUD depends on, and validity stayed stuck at `ok`. Add a separate `authoritative_ack(world)` signal on `PositionAuthorityClient` emitted from both `BOOT_GET` 200 and successful `move-stream` 200, and switch `TargetSelectionClient` (+ `main.gd`) to it. The snap signal keeps its current semantics so rubber-band suppression is untouched; the ack signal is a pure heartbeat that cooldown-throttled consumers can hook. Also adds an integration test that wires both real clients together (per the review's suggestion 1) so renames or mis-wires between the two scripts fail loudly rather than silently skipping the end-to-end path. - `client/scripts/position_authority_client.gd`: new `authoritative_ack` signal; extracted `_parse_world_from_response` helper to share JSON parse across `BOOT_GET` and `STREAM_POST`; emit ack from both. - `client/scripts/target_selection_client.gd`: rename `on_authoritative_position_snap` to `on_authoritative_ack`; drop `apply_as_snap` gate (no longer meaningful). - `client/scripts/main.gd`: connect the new signal. - `client/test/position_authority_client_test.gd`: assert ack on boot 200 and stream 200. - `client/test/target_selection_client_test.gd`: rename tests for new handler. - `client/test/target_refresh_on_locomotion_test.gd`: new integration suite wiring real authority + target clients. - Plan Decision 3 + Tests row + Files-to-modify row updated. - `docs/reviews/2026-04-21-NEO-24.md`: committed with blocking issue + suggestions struck through with `Done.` notes per planning-implementation-docs rule. - `docs/decomposition/modules/documentation_and_implementation_alignment.md`: E1.M3 row now reflects NEO-24 landed. - `client/README.md` + `docs/manual-qa/NEO-24.md`: refreshed signal names so the soft-lock refresh description matches the wiring. Tests: 88/88 GdUnit headless passed locally. |
||
|---|---|---|
| .cursor | ||
| .github/workflows | ||
| .vscode | ||
| bruno/neon-sprawl-server | ||
| client | ||
| content | ||
| docs | ||
| scripts | ||
| server | ||
| .gitignore | ||
| AGENTS.md | ||
| NeonSprawl.sln | ||
| README.md | ||
| docker-compose.yml | ||
| gdlintrc | ||
| neon_sprawl_vision.plan.md | ||
README.md
Neon Sprawl
Neon Sprawl is the working title for a crafting-focused sci-fi / cyberpunk MMORPG with gigs (combat roles) and open non-combat skills (solo-dev scope). Product intent and phase gates: neon_sprawl_vision.plan.md. Design axioms: it must be fun, and it must stay distinctly cyberpunk in theme (see Design axioms in the vision plan).
Tech stack (locked)
| Area | Choice |
|---|---|
| Client | Godot 4.x (GDScript) |
| Game server | C# / .NET 10 (ASP.NET Core), PostgreSQL, Protobuf (JSON OK for earliest spike) |
| Content | JSON/YAML + JSON Schema in CI |
Full rationale and constraints: docs/architecture/tech_stack.md.
Decomposition
Epic-level breakdown: docs/decomposition/README.md.
Git workflow
- Documentation (Markdown under
docs/, README files,neon_sprawl_vision.plan.md): work and commit directly onmain. - Code and implementation (server/client source, Godot project,
content/data, Docker/build/CI config): use a branch, then merge tomainwhen ready. Mixed doc + code changes follow the branch rule.
Repository layout (prototype scaffold)
| Path | Purpose |
|---|---|
NeonSprawl.sln |
.NET solution |
server/NeonSprawl.Server/ |
ASP.NET Core game server |
client/ |
Godot 4.x project (import project.godot) |
content/ |
JSON data + JSON Schema (skills/, schemas/) |
docker-compose.yml |
Local PostgreSQL (docker compose up -d) |
Run the server
cd server/NeonSprawl.Server && dotnet run
Then open http://localhost:5253/health (port from launchSettings.json).
Run Postgres locally
docker compose up -d
Connection (dev): host localhost, port 5432, database neon_sprawl, user neon_sprawl, password neon_sprawl_dev.
Run the client
Open the client/ folder in Godot 4.6 and run the main scene (see client/README.md).