-- READ-ONLY REGRESSION CHECK. Does NOT build. Inspects whatever is currently -- in Studio and compares against every property we had verified as good, so we -- can tell whether the last edits preserved the good version or damaged it. -- -- Known-good baseline (measured earlier this session): -- ramp PAEastSlip total bend 30.7deg, worst 1.3, over5=0, level run 20 -- ramp PAWestSlip total bend 34.4deg, worst 1.4, over5=0, level run 20 -- AuxLane parts = 30 (user's hand-edited count, NOT the source's 52) -- unguarded deck edges = 0 across all 823 samples -- parts ~= 16788 local out = {} local function say(s) table.insert(out, s) end local map = workspace:FindFirstChild("Map") if not map then return "Map MISSING -- nothing built" end local UP = Vector3.new(0, 1, 0) local function flat(v) return Vector3.new(v.X, 0, v.Z) end local parts = 0 local deck, aux, bars, slipParts = {}, {}, {}, {} for _, d in ipairs(map:GetDescendants()) do if d:IsA("BasePart") then parts += 1 local k = d.Name:match("^Road_(%d+)$") or d.Name:match("^Deck_(%d+)$") if k then deck[tonumber(k)] = d end local a = d.Name:match("^AuxLane_(%d+)$") if a then aux[tonumber(a)] = d end if d.Name == "Barrier" or d.Name == "EdgeRail" then table.insert(bars, d) end if d.Name:match("Slip") then table.insert(slipParts, d) end end end say(("parts = %d (baseline ~16788)"):format(parts)) -- 1. RAMP SMOOTHNESS -- the thing the user cares most about right now local rampOK = true for _, s in ipairs({ "PAWestSlip", "PAEastSlip" }) do local segs = {} for _, d in ipairs(map:GetDescendants()) do if d:IsA("BasePart") then local k = d.Name:match("^" .. s .. "_Deck_(%d+)$") if k then table.insert(segs, { i = tonumber(k), p = d.Position, cf = d.CFrame }) end end end table.sort(segs, function(a, b) return a.i < b.i end) if #segs == 0 then say(s .. ": ABSENT <<< RAMP GONE") rampOK = false else local total, worst, worstAt, over = 0, 0, -1, 0 for j = 2, #segs do local a, b = segs[j - 1].cf.LookVector, segs[j].cf.LookVector local dth = math.deg(math.acos(math.clamp(a:Dot(b), -1, 1))) total += dth if dth > worst then worst = dth; worstAt = segs[j].i end if dth > 5 then over += 1 end end local topY, level = segs[1].p.Y, 0 for _, sg in ipairs(segs) do if math.abs(sg.p.Y - topY) < 0.5 then level += 1 else break end end if over > 0 then rampOK = false end say(("%s: segs=%d total=%.1fdeg worst=%.1f@%d over5=%d level=%d %s"):format( s, #segs, total, worst, worstAt, over, level, over == 0 and "OK" or "<<< KINKED")) end end say(rampOK and ">> RAMPS STILL SMOOTH" or ">> RAMP REGRESSION") -- 2. USER'S DELETED LANE -- must stay deleted local auxN, inRange = 0, 0 for i in pairs(aux) do auxN += 1 if i >= 525 and i <= 550 then inRange += 1 end end say(("AuxLane = %d (baseline 30) | inside deleted run 525..550 = %d (want 0) %s"):format( auxN, inRange, (auxN == 30 and inRange == 0) and "OK" or "<<< REGRESSION")) -- 3. BARRIER COVERAGE -- full loop local holes = {} local swept = 0 for i, d in pairs(deck) do swept += 1 local right = d.CFrame.LookVector:Cross(UP).Unit for _, sgn in ipairs({ -1, 1 }) do local edge = d.Position + right * sgn * (d.Size.X / 2 + 2) local bd = math.huge for _, b in ipairs(bars) do if math.abs(b.Position.Y - edge.Y) < 14 then local dd = (flat(b.Position) - flat(edge)).Magnitude if dd < bd then bd = dd end end end if bd >= 12 then local okb = false local a = aux[i] if a then local outer = a.Position + right * sgn * (a.Size.X / 2 + 2) local bd2 = math.huge for _, b in ipairs(bars) do if math.abs(b.Position.Y - outer.Y) < 14 then local dd = (flat(b.Position) - flat(outer)).Magnitude if dd < bd2 then bd2 = dd end end end if bd2 < 14 then okb = true end end if not okb then local sd = math.huge for _, p in ipairs(slipParts) do local dd = (flat(p.Position) - flat(edge)).Magnitude if dd < sd then sd = dd end end if sd > 30 then table.insert(holes, i .. (sgn < 0 and "L" or "R")) end end end end end say(("barrier sweep: %d samples, unguarded=%d %s"):format(swept, #holes, #holes == 0 and "OK" or ("<<< " .. table.concat(holes, ",")))) -- 4. FENCE JOG at the suppression boundary local prevLat, jogs = nil, {} for i = 505, 570 do local d = deck[i] if d then local right = d.CFrame.LookVector:Cross(UP).Unit local best, bestLat = math.huge, nil for _, b in ipairs(bars) do if b.Name == "Barrier" and math.abs(b.Position.Y - d.Position.Y) < 14 then local rel = b.Position - d.Position local along = math.abs(rel:Dot(d.CFrame.LookVector)) local lat = rel:Dot(right) if along < 22 and lat < 0 and along < best then best = along; bestLat = lat end end end if bestLat then if prevLat then local step = math.abs(math.abs(bestLat) - math.abs(prevLat)) if step > 10 then table.insert(jogs, ("%d(%.1f)"):format(i, step)) end end prevLat = bestLat else prevLat = nil end end end say(("fence jogs >10 studs: %d %s"):format(#jogs, #jogs == 0 and "OK" or ("<<< " .. table.concat(jogs, " ")))) return table.concat(out, "\n")