Aux-lane suppression + PA geometry fixes; probe/verify tooling
CI / quality (push) Failing after 1m9s

MapBuilder.luau
  - Suppress the aux lane across samples 525-550 (AUX_SUPPRESS_FROM/TO),
    honoring the user's hand deletion in Studio so a rebuild no longer
    regenerates it.
  - Smoothstep the width ramp over AUX_BLEND=5 samples on each side. A hard
    cut produced a 26-stud lateral fence jog; the blend removes it.
  - DO NOT remove this suppression. Re-enabling it resurrects geometry the
    user deleted by hand.

rokit.toml
  - rojo 7.5.1 -> 7.7.0 to match the auto-updating Studio plugin.
    Server older than plugin fails the handshake with
    "attempt to index number with 'protocolVersion'".

tools/
  - 34 read-only probe/verify/capture scripts used to measure the datamodel
    instead of reasoning from source.

Verified-good baseline at this commit:
  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 >10st  0
This commit is contained in:
2026-08-06 08:27:47 -04:00
parent c297b20aed
commit 6e50f9718d
36 changed files with 3723 additions and 1 deletions
+104
View File
@@ -0,0 +1,104 @@
-- What do the slip ramps ACTUALLY do? Elevation + lateral profile per segment,
-- and do they intersect the mainline deck?
-- The user says: "on and off ramps go to the bottom and through the highway".
-- Measure that claim directly rather than assuming.
local ws = game:GetService("Workspace")
local RS = game:GetService("ReplicatedStorage")
local Circuit = require(RS:WaitForChild("Shared"):WaitForChild("Circuit"))
local samples = Circuit.samples
local map = ws:FindFirstChild("Map")
if not map then return "NOMAP" end
local out = {}
local function say(s) table.insert(out, s) end
-- Collect ramp deck segments in build order.
local ramps = {}
for _, d in ipairs(map:GetDescendants()) do
if d:IsA("BasePart") then
local name, idx = d.Name:match("^(PA%a+Slip)_Deck_(%d+)$")
if name then
ramps[name] = ramps[name] or {}
table.insert(ramps[name], { i = tonumber(idx), p = d })
end
end
end
-- Nearest mainline sample + signed lateral offset for a world point.
local function nearestSample(p)
local bd, bi = math.huge, -1
for i = 1, #samples do
local s = samples[i]
local dd = (Vector3.new(p.X, 0, p.Z) - Vector3.new(s.pos.X, 0, s.pos.Z)).Magnitude
if dd < bd then bd, bi = dd, i end
end
return bi, bd
end
local function lateralAt(i, p)
local n = #samples
local a = samples[((i - 1) % n) + 1]
local b = samples[(i % n) + 1]
local f = b.pos - a.pos
f = Vector3.new(f.X, 0, f.Z).Unit
local r = Vector3.new(-f.Z, 0, f.X)
local rel = Vector3.new(p.X - a.pos.X, 0, p.Z - a.pos.Z)
return rel:Dot(r), a.pos.Y
end
for _, name in ipairs({ "PAWestSlip", "PAEastSlip" }) do
local segs = ramps[name]
if not segs then
say(name .. ": MISSING")
else
table.sort(segs, function(x, y) return x.i < y.i end)
say(("=== %s (%d segs) ==="):format(name, #segs))
say("seg | rampY | deckY | dY(ramp-deck) | lateral | note")
local under = 0
for k, s in ipairs(segs) do
if k == 1 or k % 6 == 0 or k == #segs then
local si = nearestSample(s.p.Position)
local lat, deckY = lateralAt(si, s.p.Position)
local dy = s.p.Position.Y - deckY
local note = ""
-- |lateral| < 30 means it is horizontally UNDER/INSIDE the deck slab.
if math.abs(lat) < 30 then
note = (math.abs(dy) < 8) and "*** THROUGH DECK ***" or "under/over deck footprint"
end
say(("%3d | %6.1f | %6.1f | %+7.1f | %+7.1f | %s")
:format(s.i, s.p.Position.Y, deckY, dy, lat, note))
end
local si = nearestSample(s.p.Position)
local lat = lateralAt(si, s.p.Position)
if math.abs(lat) < 30 then under += 1 end
end
say(("%s: %d/%d segments sit within the deck footprint (|lateral| < 30)")
:format(name, under, #segs))
end
end
-- Does any ramp part actually overlap a Road part in 3D?
local roads = {}
for _, d in ipairs(map:GetDescendants()) do
if d:IsA("BasePart") and d.Name:match("^Road_%d+$") then
table.insert(roads, d)
end
end
local clashes, tested = {}, 0
for _, name in ipairs({ "PAWestSlip", "PAEastSlip" }) do
for _, s in ipairs(ramps[name] or {}) do
for _, r in ipairs(roads) do
tested += 1
local d = s.p.Position - r.Position
local sx = (s.p.Size.X + r.Size.X) / 2
local sy = (s.p.Size.Y + r.Size.Y) / 2
local sz = (s.p.Size.Z + r.Size.Z) / 2
if math.abs(d.X) < sx and math.abs(d.Y) < sy and math.abs(d.Z) < sz then
table.insert(clashes, ("%s x %s (dY=%.1f)"):format(s.p.Name, r.Name, d.Y))
end
end
end
end
say(("ramp-vs-road AABB tests: %d, overlaps: %d"):format(tested, #clashes))
for k = 1, math.min(#clashes, 12) do say(" " .. clashes[k]) end
if tested == 0 then say("CONTROL FAIL: nothing tested") end
return table.concat(out, "\n")