Files
tokyo-wangan-racing/CLAUDE.md
T
jesse dc0df9122e
CI / quality (push) Failing after 46s
docs: project CLAUDE.md for native-Windows Claude Code handoff
Pure ASCII (PS 5.1 reads non-ASCII as ANSI and desyncs the parser).
Records the aux-lane suppression invariant, the verified 6e50f97 baseline,
the read/write channel split, and the probe scripts that check each metric.
2026-08-06 08:45:27 -04:00

140 lines
5.6 KiB
Markdown

# CLAUDE.md -- Tokyo Wangan Racing
Guidance for Claude Code running **natively on `windows-gpu`**, the same machine
as Roblox Studio. Pure ASCII on purpose (PowerShell 5.1 reads non-ASCII as ANSI
and desyncs the parser).
---
## 1. Read this before touching MapBuilder
`src/server/MapBuilder.luau` generates the map procedurally. The user also edits
geometry **by hand in Studio**. Those two facts collide, and that collision is
the single most important thing about this repo:
> **A rebuild regenerates anything the source still describes.**
> If the user deleted geometry by hand and you rebuild without teaching the
> source about that deletion, you silently put it back.
The user WILL notice, immediately, and will say so ("you just added back the X
that I deleted"). When that happens: **stop editing, run a read-only probe,
report exact numbers.** Do not "fix" it with another rebuild.
### The live invariant: aux-lane suppression
```lua
local AUX_SUPPRESS_FROM = 525 -- samples 525..550 have NO aux lane
local AUX_SUPPRESS_TO = 550 -- because the user deleted that run by hand
local AUX_BLEND = 5 -- smoothstep width ramp, do not hard-cut
```
- **Do not remove or widen this range.** Re-enabling it resurrects deleted geometry.
- `AUX_BLEND = 5` is not cosmetic. A hard cut produced a **26-stud lateral fence
jog**. The smoothstep removes it.
- The parapet is force-closed across the same range (~line 1031). Normally the
parapet OPENS along a speed-change lane because the aux lane re-fences the
outer edge -- with no aux lane there is nothing to re-fence with, leaving the
deck edge bare. That was the measured barrier gap at samples 527..548.
Any change touching aux lanes, parapets, or barriers must re-run
`tools/probe_regression.luau` and match the baseline below.
---
## 2. Verified baseline (commit 6e50f97)
Measured in the live datamodel, not inferred from source:
| Metric | Value |
|---|---|
| total parts | 16788 |
| PAWestSlip | 60 segs, 34.4 deg total bend, worst 1.4, 0 kinks >5 |
| PAEastSlip | 60 segs, 30.7 deg total bend, worst 1.3, 0 kinks >5 |
| AuxLane parts | 30 (samples 525-550 deliberately absent) |
| barrier coverage | 823 samples, 0 unguarded |
| fence jogs >10 studs | 0 |
`AuxLane = 30` is the **user's hand-edited count**, not the source's original 52.
If a probe reports 52, a rebuild has undone the suppression -- that is a
regression, not progress.
---
## 3. Two channels, different jobs
```
[A] MCP bridge (roblox_studio) -> READ run Luau in Studio, measure, screenshot
[B] Rojo -> WRITE push .luau source into Studio (~1 s)
```
**Use [A] to verify what [B] did. Never assume a sync landed.**
Rojo syncs **scripts, not built geometry**. Editing MapBuilder replaces the
ModuleScript instantly, but `workspace.Map` still holds parts from a PREVIOUS
`build()` run. The map looks stale until you re-run the build. Do not tell the
user "you'll see it live" about map geometry.
**Rojo version must match the Studio plugin.** The plugin auto-updates from the
Marketplace without asking. Server older than plugin fails the handshake with a
cryptic `attempt to index number with 'protocolVersion'`. Both are pinned at
**7.7.0** (`rokit.toml`). If the user reports a connect error, check this first.
---
## 4. Workflow
```bash
make check # stylua --check + selene + rojo build
make build # rojo build --output build.rbxl
make serve # rojo serve (Studio: Rojo -> Connect)
make fmt # stylua src/
```
Probe scripts in `tools/` are **read-only** -- they measure the live datamodel
and never build. Run them through the MCP bridge.
| Script | Answers |
|---|---|
| `probe_regression.luau` | full baseline check vs the table above |
| `verify_auxlane.luau` | is the 525-550 suppression intact? |
| `verify_slips.luau` | slip-road bend angles / kink count |
| `probe_barriergap.luau` | any unguarded deck edge? |
| `probe_jog.luau` | lateral fence jogs |
---
## 5. Hard-won rules
- **Measure, then fix.** Do not infer a bug from symptoms. One inverted
convention can produce three unrelated-looking symptoms; fixing each symptom
leaves the root cause intact.
- **A metric derived from a constant cannot fail.** Ask: would this number
differ between the broken and fixed build? If not, it is not a test.
- **An empty result set must FAIL, never pass.** Count what you actually
exercised; `if tested == 0 then return "NOTHING TESTED -- FAILURE" end`.
- **Verification in Play mode proves nothing.** Play is a disposable sandbox
discarded on stop. Verify in Edit mode.
- **require() caches stale bytecode after a Rojo edit.** The cache still holds
old bytecode even though `.Source` is new -- no error, no warning. Clone the
module and require the clone.
- **Enumerate part names, don't just count.** A raw total hides partial removals
(deleted the tall barrier, missed the kerb). Tally what should be gone vs
what should remain, and report both.
- **AutoRecovery places are silently stale.** After a crash Studio reopens
`*_AutoRecovery_1.rbxl` holding pre-crash state. Check the title bar.
- **Creator Store assets: 50+ scripts or 1M+ tris is zero-tolerance.** Get exact
counts before inserting anything.
---
## 6. Shell
Git Bash (`C:\Program Files\Git\bin\bash.exe`) is present -- prefer it.
PowerShell over a non-interactive pipe mangles quoting. `&` is not a statement
separator in PowerShell. When PowerShell is unavoidable non-interactively, use
`-EncodedCommand` with UTF-16LE base64.
`StudioMCP.exe` lives inside the versioned Studio install and **moves on every
update**. Never hardcode it; `~/claude-tools/studio-mcp.bat` resolves it
dynamically.