Convert all five scan_files pipelines to process substitution so failed
is set in the parent shell. CI runs gofmt, hygiene, and import-graph
before race tests.
getJwtContext returns nil when missing/wrong type; requireJwtContext
aborts with 500 at every non-optional call site so handlers fail closed
without panic. NewCoalesceOutbound returns (*CoalesceOutbound, error)
instead of panicking on nil writeAsync. Tracks the cleanup design doc.
Pin the enhanced map host to a definite viewport height and invalidate
Leaflet size on layout changes so OSM tiles fill the pane. Remove the
bottom apt/air text backup forms to reclaim console space.
Add config REQUIRE_PILOT_PPL (default false). When enabled, #AP pilot
connections need pilot_rating PPL or higher; ATC is unchanged. Exposed
in admin config editor and /api/v1/config.
I1–I3 may open the Users directory and set network/pilot ratings up to
their own ceilings on any certificate. Create and name/password remain
Supervisor+. Add users.pilot_rating (0–5) via migration.
Replace the three-card user editor with an SSR directory plus create/edit
rail. Filters live in the URL, POST preserves them via dir_* fields, and
users.css provides a dense 16:9 layout. PE tests cover search, sort,
pagination, and rating-ceiling scoping.
Docs point fixtures at pkg/twrfiles/testdata; export DefaultRegistration;
tighten coverage tests; drop dead legacy fixture paths; AGENTS wire checklist.
CI race runs failed intermittently on TestE2E_ATCChatAndITRange and
TestE2E_BeaconAssignAndFPRequest after security/gnet hardening.
- Wait for pilot $FP broadcast before SERVER:FP re-request so the plan is
stored across event loops (empty plan skipped #PC beacon).
- Exchange ATC % positions until peers observe each other before @49999
chat and @94835 IT range fan-out.
Move pure file-shaped types and ParseAPT/ParseAIR into stdlib-only
pkg/twrfiles. sweatbox keeps type aliases and thin wrappers so callers
need minimal renames. Export IsWordName for taxi validation.
Operators can fetch Global Airports apt.dat locally (-download) and convert
to TWRTrainer-style .apt files. openfsd does not ship Laminar data; bulk
outputs and apt.dat caches stay gitignored. See docs/xplane-airport-data.md.
Default DATABASE_SOURCE_NAME to an on-disk WAL file so colocated FSD+web
share one DB; rewrite bare :memory: to a shared in-memory DSN; migrate and
seed config from web as well. Default Gin to release and slog to info.
Rework sweatbox instructor UI with command rail, drafts, and history.
Combine serviceapi DTO extraction and ATC/protocol fixes with FSD
connection, rate, and auth hardening. Prefer server-built leave packets
on client delete over rebroadcasting client-forged #DA/#DP.
Extract pure JSON DTOs into internal/serviceapi so web no longer imports
server. Add $HC wire type, persist assigned beacons, fix ValidATC before
first position, and prevent double leave notifications.
Bump direct modules (gin, jwt, migrate, pq, envconfig, sqlite, x/crypto,
x/net) and Go to 1.26 to clear Dependabot alerts and pick up current
releases. Refresh Dockerfile base image and GitHub Actions majors.
Make Session.FacilityType atomic.Int32 so concurrent handleATCPosition
writes and HTTP online-users reads no longer race under -race. Bump the
Dockerfile build image to golang:1.25 to match go.mod. Add CellIndex/
CellCover unit tests so internal/geo meets the 98% coverage floor.
Replace per-connection reader/writer goroutines with a fixed gnet
event-loop pool and CoalesceOutbound (latest-wins position queue,
immediate reliable flush). Keep classic net path for ForceClassicFSD
and injected Listen. Drop HANDOFF.md after completing the I/O pass.
Replace dual linear/R-tree registry with atomic live slabs, free-list
tombstones, and O(1) UpdatePosition via session VisBox atomics. Drop
tidwall/rtree. Add real-world hub benches. HANDOFF.md tasks the next
agent with gnet fixed-worker I/O plus position write coalescing (delete
after reading).
Expose OnlineUserPilot.Synthetic on service HTTP /online_users so
operators and the dashboard can badge in-process sweatbox aircraft.
Enforce ≥95% hard coverage on internal/sweatbox in check-coverage.sh.
Cover scenario/unpause/multipart/error paths; fail closed on scenario JSON
parse; cap flash msg length; remove dead sticky form fields; tighten XSS
assertions; MaxBytesReader on small form POSTs.
Server-rendered Administrator instructor UI at /sweatbox with CSRF forms,
flash PRG, FSD service HTTP proxy, and disabled/unavailable messaging when
SWEATBOX_ENABLED is off or the control plane is unreachable. No JS required
for the primary path.
Register /sweatbox/* on service HTTP only when SweatboxHost is allocated
(SWEATBOX_ENABLED). Same fsd_service JWT + Administrator middleware as
existing routes. 2 MiB body limit on airport/scenario/command payloads.