- Remove all ignores in tests/ui.rs; harness failure was the broken pin plus no display. CI runs them via xvfb-run (xvfb, libgl1-mesa-dri). - HUD test: HUD is raw draw_text, not widgets; assert view survives Intro->Driving and capture screenshot instead of invisible selectors. - Docs: release gate ticked, blocker 2 closed, 430px HUD clipping noted. Verified: 121 pass / 0 fail / 0 ignored; clippy 0 owned; fmt; diff --check.
13 KiB
nigig-traffic remediation — implementation status (2026-09-26, round 3)
Baseline: EXECUTION_PLAN.md (2026-09-12, audit commit e899a27).
This file records what is DONE in-tree vs what still BLOCKS release.
Nothing here supersedes ADR 001/002; assessment release stays blocked.
Round 3 (2026-09-26) — TRAFFIC-P0-01 closed, first real build/test run
- Upstream fix landed on the fork branch
andodeki/makepad@nigig-traffic-camera-boom-fix(based on the previous pinb580de1, head ofnigig-makepad-test-android; no history rewritten):1561856— game/blocks controller, game/render scene and the gamemaker example pass the filmed body to the 5-argcamera_boom_limit(exactlydocs/UPSTREAM_FIX_camera_boom_limit.patch, plus the third caller the patch missed inexamples/gamemaker).a3d8f52— once the boom error cleared,makepad-game-renderexposed a second drift:EmitterAnchor::EntityLocal(added in game-sim) was not matched ingame/render/particles.rs(E0004). Ported the already- shippedlibs/renderimplementation (pose-awarestep,clear); arcade caller now passes(pos, yaw).
- Workspace re-pinned atomically: every
andodeki/makepadrev inCargo.toml+Cargo.lockmovedb580de1→a3d8f521(same tree plus the two fixes; no other dependency changed;--lockedresolves). - Crate-level compile break the broken pin had hidden:
scenarios.rsbuilt aWalkliteral missing 8 fields added upstream → now..Walk::new(..). - First executed test run ever found 2 real failures in
rule_adversarial: completion copy for roundabout (exit) and speed (compliance) tripped the banned-claim gate. Copy reworded ("route choice and give-way not assessed", "speed-limit behaviour not assessed"); gate NOT weakened. - Clippy ratchet at zero: 11 compiler warnings + 28 clippy findings in
Traffic-owned code fixed (
Vec2now implementsAdd/Sub,matches!transition table, enumerate loop, const assert, auto-fixes). Two intentional flat-scalar builders carry a justifiedallow(clippy::too_many_arguments).
Verification executed (round 3, Linux x86_64, rustc 1.97.1)
| Command | Result |
|---|---|
cargo check --locked -p nigig-traffic --all-targets |
✅ clean, 0 Traffic warnings |
cargo test --locked -p nigig-traffic -- --test-threads=1 |
✅ 117 passed, 0 failed (+4 GUI tests below, which need a display) |
| — lib 84 · asset_validation 3 · coordinate_properties 4 · perf 1 · perf_release 1 · persistence_faults 7 · rule_adversarial 4 · runtime_ui 5 · scenario_replays 4 · ui_basic 4 | |
xvfb-run -a cargo test --locked -p nigig-traffic --test ui |
✅ 4/4 GUI tests pass, 0 ignored |
cargo clippy --locked -p nigig-traffic --all-targets |
✅ exit 0, 0 Traffic-owned diagnostics (CI ratchet baseline 0) |
cargo fmt -p nigig-traffic -- --check |
✅ |
git diff --check |
✅ |
Note: plain cargo clippy ... -- -D warnings still fails on
other workspace members (matrix_client, nigig-core, nigig-uikit
warnings). That is why CI uses the Traffic-owned ratchet; those crates are
out of Traffic scope.
Done (in-tree, gated by CI)
Round-2 closures (all partials advanced to their in-crate maximum):
- TRAFFIC-01 (code-side maximum):
docs/UPSTREAM_FIX_camera_boom_limit.patchcarries the exact upstream fix, verified by reading both call sites:Controller::tickalready has the filmedsubject: u64in scope (its own docs: "subjectis the entity being followed"), andgame/render/scene.rsfilmsworld.cam_thirdexactly like the already-migrated non-game renderer. Application + re-pin + matrix steps are in the patch file. Push + re-pin need a human with fork access (see Blockers). - TRAFFIC-05 (wired):
TrafficWorld::evaluatebuilds one immutableObservationon the course frame and the rule layer consumes only that (+ the live parking footprint passed alongside). No rule reads rawGameWorldstate; observation/heading helpers are the single implementation shared by table and engine. - TRAFFIC-06 (stateful engine, practice scope):
RuleEnginewith ordered criteria, 30-tick speed grace / 30-tick calm re-arm, 60-tick parking dwell, edge-triggered lane/stop mistakes, immediate proximity terminals, reversal-required U-turns, and a bounded (4,096 + drops) evidence trace. Shares predicates + message constants with the one-tick table (which stays as the tested reference). 7 engine unit tests pin grace/dwell/edges/bounds/determinism. - TRAFFIC-07 (frozen): every Driving tick mixes gated input into a
rolling FNV digest; terminal transitions freeze an immutable
AttemptResult(ID + content version + digest) with a recompute-matches invariant, and HUD/score are set from the frozen value by construction. Batch-vs-incremental digest equivalence tested. - TRAFFIC-11 (in-crate maximum): attempts record into an in-memory
session
LearnerProfile(anonymous, compacted at 10k) on every terminal freeze; profile survives scenario switches, resets with the world, is never written to disk here, and settings copy stays session-only (honest). Filesystem persistence + advertised copy remain a later tranche with recovery tests. - TRAFFIC-13 (extended): hostile corpus battery in-tree (nesting,
truncation, bracket-in-string, bad bounds, traversal ids, malformed
UTF-8, empty objects, id-length edges, budget edges).
cargo fuzztarget + release SBOM remain scheduled work.
Round-1 foundations (unchanged, see ADR-002 amendments):
- TRAFFIC-00:
section_paywall/PaywallAction/Upgrade dispatch deleted; Premium/FREE/locked sales copy gone; persistence claim replaced with session-only copy; every scenario labelledPractice preview — finish marker only(settings + scenarios page + drive HUD + lessons intro); unobservable-claim descriptions reworded with practice qualifiers; source-grep gate rejects fictional commerce/persistence copy. - TRAFFIC-01 (half): CI fails CLOSED on Cargo exit status (check gate +
clippy gate both fail on dependency errors; stderr scanned for
^error). Third-party actions pinned to immutable SHAs. Allowed-source- license-presence supply-chain gates added. Upstream pin repair still open (see Blockers).
- TRAFFIC-02:
object_typerecursion fixed + delegation test;Scenariovalidation (IDs, finite coords, positive max_points, course length, speed limits) +validate_catalog+ malformed-fixture tests; content version 0 (LegacyUnvalidated), jurisdictionunreviewed-general, FNV seeds, capability lists; persistence binds ID+version, never index. - TRAFFIC-03: typed
AuthoredPoint2/CoursePoint/Heading/CourseFramewith inverse conversions; lane rule uses course-lateral only;course_lateral/course_alongare the only legal rule inputs; idle false-drift deleted and replaced with a zero-drift regression over all lane scenarios + round-trip/heading property tests. - TRAFFIC-04:
Phase::{Intro,Driving,Paused,Complete,Failed}withdrive_input_allowed/is_terminal+allowed_transitiontable; Intro ticks without simulating; terminal/paused freeze; no-scenario stays Intro; input cleared on focus loss/switch/restart/terminal; determinism + transition-table + pause + head-start + stability tests. - TRAFFIC-05: immutable per-tick
Observationbuilder (course pose, relative heading, speed, lane offset, finish, hazard proximity, tick); oriented-rect containment + documented proximity-only clearance; proximity is NEVER labelled contact. - TRAFFIC-06 (practice scope): U-turn uses course-relative reversal (world-x bug fixed + invariance test); proximity wording fixed; completion strings say PRACTICE and never confirm unobserved behaviour (adversarial suite pins banned strings); finish-only shortcuts complete as labelled practice.
- TRAFFIC-07:
ScorePolicy(validated max, −5/mistake, floor 0, 70% pass) + immutableAttemptResult+ replay digest;max_pointscomes from the catalog (test iterates all 47); Score↔ScorePolicy agreement tested; HUD showsscore/maxfrom the scenario. - TRAFFIC-08 (stage 1): 47-row
CURRICULUM_MATRIX.mdwith real-vs- reserved observations, replay mapping, andunreviewedreviewer column; hazard actors added for child/branch/rain; sign/stop-line/ indicator/handbrake/kerb claims removed or practice-qualified. Qualified expert sign-off still open. - TRAFFIC-09:
InputRouter(keyboard/touch/controller → clampedDriveIntent, brake-beats-throttle, touch brake never reverses); touch halves (left steer / right pedals) + finger cancellation in the view; P pause; equivalent-input cross-source tests. - TRAFFIC-10: 5-tick catch-up cap with drop counter; continuous frames
only in Intro/Driving; Paused/terminal schedule nothing; accumulator
reset on focus return; render-mode changes stay presentational;
MAX_TICKS_PER_FRAME+ touch-curve unit tests. - TRAFFIC-11: versioned atomic
LearnerProfile/AttemptRecord(temp+flush/sync+rename+verify), Absent/Corrupt-preserved/Future-read- only/IoError states, 8 MiB + 10k compaction, traversal/oversize/ malformed rejection, round-trip WITH attempts, fault-injection suite. Round 2 wires session recording into the world (see above); filesystem persistence + advertised copy remain a later tranche. - TRAFFIC-12:
AssetManifest(ID validation, license/hash/bounds, traversal rejection); no-op seam +CARGO_MANIFEST_DIRprobe deleted; explicit primitive fallback with stable log marker; catalog declares no hard visual dependencies (test-pinned). - TRAFFIC-13:
THREAT_MODEL.md(offline scope, supply chain, parser bounds, privacy, unsafe scope, residual risks);SBOM.mdrelease template; CI source/license gates. - TRAFFIC-14: GUI harness documented with owner/expiry ignores (release
stays blocked);
runtime_uiheadless production-path journeys;ui_basiclabelled smoke and extended to all 47 scenarios; replay/adversarial/property suites named per the plan matrix. - TRAFFIC-15:
perf_releaseactive-workload evidence (reported, never asserted) + structural budget asserts;PERF_BASELINE.mdcorrected (median-of-idle-means, diagnostic-only labelling) + release-evidence template with §6 budgets.
Blockers (release stays RED)
Only human/environment gates remain. No further in-crate work is identified for practice-preview scope:
TRAFFIC-P0-01— CLOSED in round 3 (see above). Remaining follow-up: open a PR fromnigig-traffic-camera-boom-fixinto the fork's main line so the pin is not a side branch forever.TRAFFIC-14 harness— CLOSED in round 3. Root cause of "exit 101 before AppStarted" was the broken pin; the remaining startup SIGSEGV was simply running without a display. Underxvfb-run -aall 4tests/ui.rsGUI tests pass, ignores removed, CI step added (withxvfb,libgl1-mesa-dri). The HUD test was rewritten: HUD strings are rawdraw_text(not widgets) so text selectors cannot see them; it now asserts the 3D view survives Intro→Driving and captures a screenshot (manually verified: HUD showsSpeed: 0 km/h Score: 0/100). Follow-up UX note: on a 430 px phone width the HUD header/help lines are clipped at the right edge — wrap or shorten them. Mobile on-device touch journey still needs a real/emulated device.- TRAFFIC-08 sign-off — no qualified instructor/law review; content v0. Assessment release additionally needs per-variant rule supersession with reviewed copy, which is real curriculum work, not code volume.
- TRAFFIC-15 device lab — no release/GPU/latency/soak numbers yet;
run
perf_release+ stats on declared hardware after blocker 1.
Verification actually executed (2026-09-25)
Full-workspace cargo check/test is impossible until blocker 1
clears (dependency crates do not compile). Verified instead:
cargo fmt -p nigig-traffic -- --check: CLEAN (also parses every edited/added file — syntax valid).git diff --check: clean. CI grep gates reproduced locally: nounwrap/expectinsrc/(fixed 5 violations incl. a latentPartialEqgap below), nounsafe, no TODO, no fictional commerce/persistence copy, YAML workflow parses (ruby).- Standalone harnesses in
/tmp(traffic-pure{,2,3}) compiling the BYTE-IDENTICAL real files for every std-only module: 49 tests executed, all pass — pure: geom 3, input 4, observation 3, assets 3, persistence 5 (incl. attempts round-trip + hostile battery); pure2: scoring 5 (incl. incremental-digest equivalence); pure3: geom 3, observation 3, objective 20 (13 table + 7 engine: course-relative U-turn invariance, grace/dwell/edge/bound/determinism pins). The harness caught and fixed one latent bug the broken pin had been hiding:LoadOutcome: PartialEqcould not compile becauseLearnerProfilelackedPartialEq. - Description gate re-checked with an independent script: 20
description:fields, 0 unobservable-claim violations; 2 titles softened ((Handbrake)dropped, three-point renamed). - NOT executed (blocked):
world.rs/scenario.rs/road.rs/game_view.rs/page unit tests, all 8 integration suites, clippy. They were reviewed field-by-field against public APIs instead (see per-item notes in the session); run the §9 matrix on a clean coherent checkout before any release claim.
Practice-preview release may proceed only after (1) lands and the full §9 matrix is green on a clean checkout; assessment release additionally needs (2)–(4) plus per-variant rule supersession with reviewed copy.