TiGa-RCE commited on
Commit
b10f424
·
verified ·
1 Parent(s): 9c2dbdc

Add measured replay black box with native controls and sensor inputs

Browse files

Capture actual cached pre-physics inputs and decision ticks, raw and normalized control commands, and post-physics snapshots from one bounded native CPU drive. Add manual sample/event navigation, side-by-side replay workspace, recording import and strict legacy/v2 handling. Native CPU states and frozen measurements match the retained simulator; CUDA library, importer, physics and policies are unchanged. Hosted acceptance is recorded separately.

.gitattributes CHANGED
@@ -1,3 +1,4 @@
1
  bin/* filter=lfs diff=lfs merge=lfs -text
2
  native/selective-freeze-source.tar.gz filter=lfs diff=lfs merge=lfs -text
3
  native/physics-source.tar.gz filter=lfs diff=lfs merge=lfs -text
 
 
1
  bin/* filter=lfs diff=lfs merge=lfs -text
2
  native/selective-freeze-source.tar.gz filter=lfs diff=lfs merge=lfs -text
3
  native/physics-source.tar.gz filter=lfs diff=lfs merge=lfs -text
4
+ native/blackbox-source.tar.gz filter=lfs diff=lfs merge=lfs -text
BINARY_PROVENANCE.json CHANGED
@@ -1,69 +1,28 @@
1
  {
 
 
 
 
 
 
 
2
  "artifacts": {
3
  "bin/altd-sim": {
4
- "bytes": 3647808,
5
- "sha256": "ce31f754f6b6f3afaf4dcc44c1e6fda3e6414eb2924fa167b8778523bcaf2070"
 
6
  },
7
  "bin/extract_saved_track": {
8
- "bytes": 3247776,
9
- "sha256": "3a7733c45b4301a786fcbfe92660a1c484749272da5f608d62f34878bd4ff31a"
10
- },
11
- "bin/libaltd_gpu.so": {
12
- "bytes": 4711704,
13
- "sha256": "3b1b88bccc06a21acc33ac4400af016d55a7e3d8727136a0c43b541f3c7887ca"
14
- }
15
- },
16
- "build_receipt_path": "native/selective-freeze-build-receipt.json",
17
- "build_receipt_sha256": "ed804b1cd49a9ba34abc6f7cadaf4fb97807e27f3d14af117f8292a2d3f2d172",
18
- "compiler": "rustc 1.95.0 aarch64-apple-darwin -> x86_64-unknown-linux-gnu",
19
- "historical_native_files": [
20
- "native/analysis.patch",
21
- "native/build-receipt.json",
22
- "native/source-receipt.json"
23
- ],
24
- "linux_runtime_status": "hosted execution pending",
25
- "retained_artifact_origins": {
26
- "bin/extract_saved_track": {
27
- "build_receipt_path": "IMPORTER_BUILD_RECEIPT.json",
28
- "build_receipt_sha256": "4ba5c533cc617105478e4d85c83f456a7dfa68b1388049624619871ba9e42e9d",
29
- "bytes": 3247776,
30
- "compatibility_receipt_path": "native/build-receipt.json",
31
- "compatibility_receipt_sha256": "559a7e4e382f9f7caa1c5ceb566a5a0bbefad2ed3a2e2cf604e31c9c3890c348",
32
- "evidence_path": "IMPORTER_BUILD_RECEIPT.json",
33
- "evidence_sha256": "4ba5c533cc617105478e4d85c83f456a7dfa68b1388049624619871ba9e42e9d",
34
- "origin_type": "retained_verified_importer_binary",
35
  "sha256": "3a7733c45b4301a786fcbfe92660a1c484749272da5f608d62f34878bd4ff31a",
36
- "source_repository": "https://github.com/Zorro909/driving_sim_rs",
37
- "source_revision": "d8ab74c25df70b6a86ed101080e33d5fb785ea6f"
38
  },
39
  "bin/libaltd_gpu.so": {
40
- "build_receipt_path": "native/build-receipt.json",
41
- "build_receipt_sha256": "559a7e4e382f9f7caa1c5ceb566a5a0bbefad2ed3a2e2cf604e31c9c3890c348",
42
- "bytes": 4711704,
43
- "origin_type": "retained_cuda_b90",
44
- "patch_sha256": "42f79de67cb0734cffb2a7582f5479cab42ab82675884b8b42b9f158d46a98e8",
45
- "sha256": "3b1b88bccc06a21acc33ac4400af016d55a7e3d8727136a0c43b541f3c7887ca",
46
- "source_receipt_sha256": "36feba861501baf8672884476bbeed5e375254cbb4feffb9f4f90aa61a415a93",
47
- "source_revision": "b90b8af06ffc4ea4e4fd703becd1107a48b8e5e0"
48
  }
49
  },
50
- "schema": "ald-selective-freeze-binary-provenance-v1",
51
- "source_base_revision": "b90b8af06ffc4ea4e4fd703becd1107a48b8e5e0",
52
- "source_repository": "https://github.com/Zorro909/driving_sim_rs",
53
- "source_snapshot_path": "native/selective-freeze-source.tar.gz",
54
- "source_snapshot_sha256": "297d2ce34569994acd2a477e64c5315cb2081699b4333b8abdabb3ff7451d8db",
55
- "physics_update": {
56
- "upstream_version": "1.3.0",
57
- "upstream_revision": "ab3ec67",
58
- "local_additions_preserved": true,
59
- "source_receipt": "native/physics-source-identities.json",
60
- "status": "candidate; requires deployment and hosted app acceptance",
61
- "artifacts": {
62
- "bin/altd-sim": "792139f30bcfecf25f2d78595d2611234d30b0a254b5ece0ec587f1d27a80df2",
63
- "bin/libaltd_gpu.so": "e5e9a61d863bc3b429af69a13cd8d50f63cad8984b3e6a9001ae342fc5981e05"
64
- },
65
- "source_archive": "native/physics-source.tar.gz",
66
- "source_archive_sha256": "6abefb234de18dee58d69758c6cc8900f259993663ac37f90ce39aa114a30718",
67
- "cuda_original_cases_passed": 57
68
- }
69
  }
 
1
  {
2
+ "schema": "ald-native-blackbox-binary-provenance/1",
3
+ "source_repository": "https://github.com/Zorro909/driving_sim_rs",
4
+ "base_hf_revision": "9c2dbdc053f255e4f928ba087ddad3337c287352",
5
+ "source_snapshot_path": "native/blackbox-source.tar.gz",
6
+ "source_snapshot_sha256": "56b43430c68b95bf7ac0d8312975c366c920f99b1653d790fb15b59453728e28",
7
+ "build_receipt_path": "native/blackbox-build-receipt.json",
8
+ "build_receipt_sha256": "de3eea6c45a5ae4897287a97b0e2822fdae552a0655250bf940cef20d9b60d96",
9
  "artifacts": {
10
  "bin/altd-sim": {
11
+ "sha256": "225de9c2b7dd0d9cb11c2578f50fff8a34f4cf6223580035ab0fa64e700beac8",
12
+ "bytes": 3661976,
13
+ "origin": "new telemetry CLI build"
14
  },
15
  "bin/extract_saved_track": {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  "sha256": "3a7733c45b4301a786fcbfe92660a1c484749272da5f608d62f34878bd4ff31a",
17
+ "bytes": 3247776,
18
+ "origin": "retained unchanged from base HF release"
19
  },
20
  "bin/libaltd_gpu.so": {
21
+ "sha256": "e5e9a61d863bc3b429af69a13cd8d50f63cad8984b3e6a9001ae342fc5981e05",
22
+ "bytes": 4707512,
23
+ "origin": "retained unchanged from base HF release"
 
 
 
 
 
24
  }
25
  },
26
+ "historical_provenance_path": "native/pre-blackbox-binary-provenance.json",
27
+ "release_ceiling": "Local CPU and blackbox checks; fresh hosted GPU acceptance recorded separately before final release"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  }
FRONTEND_SOURCE.json CHANGED
@@ -5,20 +5,20 @@
5
  "source": "Runner r14 single-engine browser UI; selected .track tile renderer added from simulator atlas",
6
  "source_sha256": "65d1e5f2c4e19b4951b828e82510005ab99a5270cf3dcb9f4eaa0fa1af8c40f8"
7
  },
8
- "client_sha256": "c27ab8c23669ad69d0d90ecc05f9dff1ef711047f026fe7546ac2b12c21a38fd",
9
  "identity_note": "The historical source fields describe the base frontend; local packaged file hashes describe this candidate's derived frontend.",
10
- "local_customization_id": "frozen-export-fix-20261023",
11
- "output_sha256": "6f926ec7ab0d733adbed3dadf65cd316b3861065d0f3ae6b16c63f33f0d975ae",
12
  "packaged_frontend_files": {
13
  "assets/track-atlas.json": "d97c8900e3e5fb17734b5bd61d1f4f4b196d9be30af9848e2e273ae7e4079ae4",
14
- "client.js": "c27ab8c23669ad69d0d90ecc05f9dff1ef711047f026fe7546ac2b12c21a38fd",
15
  "help.html": "58959e994a8e4bbd3c70b2a6256cb699ac615cde718c6d0288fabeee909098a2",
16
  "hf-auth.js": "3f3938bbc0935e4e9230c094029ef46e03beea74be199887c50e053e03dafcfe",
17
- "index.html": "6f926ec7ab0d733adbed3dadf65cd316b3861065d0f3ae6b16c63f33f0d975ae",
18
  "track-library.js": "351ec4c026b49420ce963f4310cb000d9e987fd28e6dac5ecd0176509340f6e6",
19
- "track-map.js": "dab0d51b4c3d6a9807ce8683cfc5e9a7211908b18556f1464d202d443f7d3368"
20
  },
21
- "packaged_frontend_sha256": "af3bdcc3dd75e783e9282f054dfcae431f527fc4a84bf8ddec09c2b2838e4819",
22
  "packaged_frontend_sha256_format": "SHA-256 of UTF-8 JSON for packaged_frontend_files, sorted keys, compact separators, no trailing newline",
23
- "status": "Isolated candidate: frozen receipt and analysis downloads"
24
  }
 
5
  "source": "Runner r14 single-engine browser UI; selected .track tile renderer added from simulator atlas",
6
  "source_sha256": "65d1e5f2c4e19b4951b828e82510005ab99a5270cf3dcb9f4eaa0fa1af8c40f8"
7
  },
8
+ "client_sha256": "0526336091391457de43dc1fc3d3281a78a5458620fb49fde7a7e3d67ef3ce9e",
9
  "identity_note": "The historical source fields describe the base frontend; local packaged file hashes describe this candidate's derived frontend.",
10
+ "local_customization_id": "native-blackbox-v2-20261023",
11
+ "output_sha256": "c23258d7493ce1d2304fe8d27b220bab1b8f09187c647e4048259cb9dc8e53c7",
12
  "packaged_frontend_files": {
13
  "assets/track-atlas.json": "d97c8900e3e5fb17734b5bd61d1f4f4b196d9be30af9848e2e273ae7e4079ae4",
14
+ "client.js": "0526336091391457de43dc1fc3d3281a78a5458620fb49fde7a7e3d67ef3ce9e",
15
  "help.html": "58959e994a8e4bbd3c70b2a6256cb699ac615cde718c6d0288fabeee909098a2",
16
  "hf-auth.js": "3f3938bbc0935e4e9230c094029ef46e03beea74be199887c50e053e03dafcfe",
17
+ "index.html": "c23258d7493ce1d2304fe8d27b220bab1b8f09187c647e4048259cb9dc8e53c7",
18
  "track-library.js": "351ec4c026b49420ce963f4310cb000d9e987fd28e6dac5ecd0176509340f6e6",
19
+ "track-map.js": "1612b75e95ccbbb2da4a47d8c8bf2ee406e8f40c626475ae2a1c3c19e119a139"
20
  },
21
+ "packaged_frontend_sha256": "077552d65d5a065443907db931a7c09b7d6161357f3517fa2f967f63ea64d42d",
22
  "packaged_frontend_sha256_format": "SHA-256 of UTF-8 JSON for packaged_frontend_files, sorted keys, compact separators, no trailing newline",
23
+ "status": "Manual measured replay with native cached controls and sensor input black box"
24
  }
README.md CHANGED
@@ -39,6 +39,10 @@ Recipes and batches are saved in this browser by default. After connecting an ex
39
 
40
  The packaged worker supports Formula, Rally, Snowmobile, and Truck. Networks can use up to 20 inputs (13 raycasts plus 7 other sensors), 12 total layers, and 16 neurons per hidden layer. Formula, Rally, and Truck support up to five outputs; Snowmobile supports up to four and cannot use Handbrake. Fresh networks for every vehicle require Steering and Acceleration. Formula imports retain previously supported ordered output subsets; Rally, Snowmobile, and Truck imports must include Steering and Acceleration and follow their vehicle-specific output rules. Supported sensors use original-game defaults when optional parameters are omitted. These are the vanilla worker limits, not support for arbitrary modified-game networks. See [TRACK_LIBRARY.md](TRACK_LIBRARY.md) for track scope and provenance, and [WINNERS_AND_EVALUATION.md](WINNERS_AND_EVALUATION.md) for result interpretation.
41
 
 
 
 
 
42
  ## Results and evaluation
43
 
44
  A training result can include the final-generation fitness winner, the fastest completed-lap controller, and a clean-lap controller when one qualifies. A controller may fill more than one role; unavailable roles are labeled. Per-car records cover supported reward channels, but population-relative ranks are not absolute scores across separate runs. Frozen evaluation uses one controller with unchanged weights. See [WINNERS_AND_EVALUATION.md](WINNERS_AND_EVALUATION.md) for the exact rules and comparison limits.
 
39
 
40
  The packaged worker supports Formula, Rally, Snowmobile, and Truck. Networks can use up to 20 inputs (13 raycasts plus 7 other sensors), 12 total layers, and 16 neurons per hidden layer. Formula, Rally, and Truck support up to five outputs; Snowmobile supports up to four and cannot use Handbrake. Fresh networks for every vehicle require Steering and Acceleration. Formula imports retain previously supported ordered output subsets; Rally, Snowmobile, and Truck imports must include Steering and Acceleration and follow their vehicle-specific output rules. Supported sensors use original-game defaults when optional parameters are omitted. These are the vanilla worker limits, not support for arbitrary modified-game networks. See [TRACK_LIBRARY.md](TRACK_LIBRARY.md) for track scope and provenance, and [WINNERS_AND_EVALUATION.md](WINNERS_AND_EVALUATION.md) for result interpretation.
41
 
42
+ ## Visual replay and debugging
43
+
44
+ Record a selected policy for 5 or 15 seconds, then play, pause, scrub, or step through actual native samples. The car black box shows measured motion, contacts, boost, raw/applied controls and the sensor inputs consumed by the policy at its recorded decision tick. Playback starts paused, the camera is manual, and optional pose smoothing does not interpolate telemetry. Recordings can be downloaded and reopened. A GPU-trained policy is replayed in a fresh CPU evaluation; this is separate from its original training generation. See [REPLAY_BLACKBOX.md](REPLAY_BLACKBOX.md) for capture phases and limits.
45
+
46
  ## Results and evaluation
47
 
48
  A training result can include the final-generation fitness winner, the fastest completed-lap controller, and a clean-lap controller when one qualifies. A controller may fill more than one role; unavailable roles are labeled. Per-car records cover supported reward channels, but population-relative ranks are not absolute scores across separate runs. Frozen evaluation uses one controller with unchanged weights. See [WINNERS_AND_EVALUATION.md](WINNERS_AND_EVALUATION.md) for the exact rules and comparison limits.
RELEASE_MANIFEST.json CHANGED
@@ -2,19 +2,20 @@
2
  "backend": "gpu",
3
  "files": {
4
  "BETA_TESTING.md": "829dae67ec37dac2a4e7b178ab5ee4fc5f63896af132fbff457a5e35141fe94d",
5
- "BINARY_PROVENANCE.json": "99c24677a039993b6100ce24551a01753c0187980f6c9c54be865b3dc7a65d00",
6
  "BUCKET_BUNDLE.md": "cb7a0f023d5a1f93f0288c6a5646b64f8f3e9d36150c0730aea94590e5b80260",
7
  "CUDA_REFERENCE.md": "f7453c3254d244f8b0de41fde5851cb025159f5cea4a4d1a5d8208a955550c6c",
8
  "DATA_POLICY.md": "fc5978528abe1c21c14882417ac8a706e04a0831bbd3fdb3de8c64442c1a7b3d",
9
  "FEEDBACK.md": "f95b8f6afbf4a360976c0edca5d52f5b3a0b668c9a944d4947b840a7c53a122a",
10
- "FRONTEND_SOURCE.json": "bd782033822dd5e981b0997ea24d40d2a890eb262cc74e009cf2cb10d939801b",
11
  "GODOT_LICENSE": "fb2b3bb82c60f1e76841ba2122eb902f8e39c151476fe21ce10c9a05d1045304",
12
  "IMPORTER_BUILD_RECEIPT.json": "4ba5c533cc617105478e4d85c83f456a7dfa68b1388049624619871ba9e42e9d",
13
  "LICENSE": "53d5851b6440feeae36f72a5f57fcab37858c48b7084765ece4b0c54b9a28ed8",
14
- "README.md": "c0fb705dff468ea502a0a810f47a450f5d2f42c0c3b0178c3b662b27a327b8a5",
 
15
  "STORAGE_BOUNDARY.md": "1d0cab6c82723f1879d7b437bab6b0d21248436bce161f3fbfe6c0e83b9e87a1",
16
  "TRACK_LIBRARY.md": "be64c91633ef6696233df537afeef4c5175b2d55daac9336758d9eb3d24763c9",
17
- "UPSTREAM.json": "55971b2bbb8c551a4515f6e0d2ce98ec14fab6a67531c5c2815789e7f79259e6",
18
  "WINNERS_AND_EVALUATION.md": "f281cf496763c59c50a79161cfff1a46d3529edfcfaaa14962c9a3f2d4f9446f",
19
  "analysis_result.py": "0a5d73fe8dbca934b21823b8ffbd50b0baaef8e15a39e32604eefe16f01d1cf2",
20
  "app.py": "62dfcda6f47ea8c86d3f7919638d7bc1329507e6ec21377c13fcc33bea9d8f2d",
@@ -24,7 +25,7 @@
24
  "assets/snowmobile_template.json": "8232f4d54829445c44de9292e12557bfe66b3d43e0363e07d2ae0b4118721c08",
25
  "assets/track-atlas.json": "d97c8900e3e5fb17734b5bd61d1f4f4b196d9be30af9848e2e273ae7e4079ae4",
26
  "assets/truck_template.json": "a83bffea4d5e818c135ab3aba68a47aa288d6ad0e7b8bd9c95ed0dea9e9df2f7",
27
- "bin/altd-sim": "792139f30bcfecf25f2d78595d2611234d30b0a254b5ece0ec587f1d27a80df2",
28
  "bin/extract_saved_track": "3a7733c45b4301a786fcbfe92660a1c484749272da5f608d62f34878bd4ff31a",
29
  "bin/libaltd_gpu.so": "e5e9a61d863bc3b429af69a13cd8d50f63cad8984b3e6a9001ae342fc5981e05",
30
  "bucket_storage.py": "f3044964724de322c1372adc23fa31f83f33ff0096f2b8509eb137953d983ddb",
@@ -59,32 +60,35 @@
59
  "builtin_tracks/tracks/Replica R08 Demolition Derby.track": "6f11a9ffbcb477c9d19964566b1b612d2a94675605246e93e21f27bbbdb357ef",
60
  "builtin_tracks/tracks/Replica R09 Eau Noir.track": "3ec0a78478cca1a4f0d2d98ac81f40783928adf271b70f0c32d295a6da2cdaa9",
61
  "builtin_tracks/tracks/Replica The Champions Trial.track": "a3bfb76422affc774b44c739b0636d08acb901fa7615b9adcb52c069f79834e1",
62
- "client.js": "c27ab8c23669ad69d0d90ecc05f9dff1ef711047f026fe7546ac2b12c21a38fd",
63
  "delivery.py": "6bdba2e87c3e19a41440cb16103695af27105f8bafbae38948bbb1b936ed0c1b",
64
  "gpu_tickets.py": "20928fcf1ca24648809ad8712c929377bdcc8b5e6b4387bfff3503ec5711928b",
65
  "help.html": "58959e994a8e4bbd3c70b2a6256cb699ac615cde718c6d0288fabeee909098a2",
66
  "hf-auth.js": "3f3938bbc0935e4e9230c094029ef46e03beea74be199887c50e053e03dafcfe",
67
  "hf_identity.py": "913fb1e089af21f376e8359a20cbc838d5bcd7971def6989a4382d53c1127b37",
68
- "index.html": "6f926ec7ab0d733adbed3dadf65cd316b3861065d0f3ae6b16c63f33f0d975ae",
69
  "native/analysis.patch": "42f79de67cb0734cffb2a7582f5479cab42ab82675884b8b42b9f158d46a98e8",
 
 
70
  "native/build-receipt.json": "559a7e4e382f9f7caa1c5ceb566a5a0bbefad2ed3a2e2cf604e31c9c3890c348",
71
  "native/physics-build-receipt.json": "63561c108554a09884cc68a1bfadfb8a3f530a800de0700ff671d99e558609fe",
72
  "native/physics-parity.json": "006cc6b455e8f49af395ed60f3c5c88dbb2865ee6cad51d8cfdae040293d9f9e",
73
  "native/physics-source-identities.json": "e3414e24144d517f4a0309e1f9d0dbab8309b4c0b70bd61ccb2c0f40b8f14998",
74
  "native/physics-source.tar.gz": "6abefb234de18dee58d69758c6cc8900f259993663ac37f90ce39aa114a30718",
75
  "native/physics.patch": "bae8eeb9342cad1e52ad77dc8026b8bd2ff510a1b836165fc753c043a04859b3",
 
76
  "native/selective-freeze-build-receipt.json": "ed804b1cd49a9ba34abc6f7cadaf4fb97807e27f3d14af117f8292a2d3f2d172",
77
  "native/selective-freeze-source.tar.gz": "297d2ce34569994acd2a477e64c5315cb2081699b4333b8abdabb3ff7451d8db",
78
  "native/source-receipt.json": "36feba861501baf8672884476bbeed5e375254cbb4feffb9f4f90aa61a415a93",
79
  "native/upstream-v1.3.patch": "a9810c9abd40ddcbac5fcf6914320d5fc04fcde23849df9437ec293c83be15ed",
80
  "portable_bundle.py": "58df5b87956745ea909c41c4b12a23cf9ab8c40a7df47d1529f47ae4de9bf51f",
81
- "replay.py": "cce5dadc682dafadaa558b49fe1dac735e225fc26881566f59f6e59447b9ab4f",
82
  "requirements.txt": "fc7e0703ad2289fd3926a36efbdce8c61f0edc00f7575a87e2b565e46588c5a4",
83
- "server.py": "5656f969f09d171a0eb257b004191bb84f2a365ed2552dacbe3ec77b4ab77294",
84
  "star_check.py": "5c17080957b81ffccf0de8314635b471562e55c92c97a1207d9034a99279b2c3",
85
  "steam_leaderboard.py": "d76397c39cae58f636ddf9a9be1a46ae3d77fefd6b7269feac73d34d97165481",
86
  "track-library.js": "351ec4c026b49420ce963f4310cb000d9e987fd28e6dac5ecd0176509340f6e6",
87
- "track-map.js": "dab0d51b4c3d6a9807ce8683cfc5e9a7211908b18556f1464d202d443f7d3368",
88
  "training_config.py": "6eb7282bbee3b3a6273bddc29c949d9904067414c26e501d815012f033173a1c",
89
  "vendor/gradio-client/LICENSE": "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4",
90
  "vendor/gradio-client/dist/index.min.js": "fdd776db8633354f118fe2908c980592283968737e6b91dc3aa86d648da5c3fd",
@@ -94,7 +98,7 @@
94
  "vendor/hf-oauth/package.json": "fafd4d8891023a1961546a7d3bc25cd24f64923a2ebfc449fe6d516a2949bda8",
95
  "worker.py": "d18053363baf8147425808e9fd939f44f00af23781662d353196ade974144974"
96
  },
97
- "interface": "single-engine-runner-with-map-winners-analysis-v1",
98
  "physics_revision": "20261017-v1.3-candidate",
99
  "upstream_revision": "b90b8af06ffc4ea4e4fd703becd1107a48b8e5e0"
100
  }
 
2
  "backend": "gpu",
3
  "files": {
4
  "BETA_TESTING.md": "829dae67ec37dac2a4e7b178ab5ee4fc5f63896af132fbff457a5e35141fe94d",
5
+ "BINARY_PROVENANCE.json": "4c8fbc45f4766fecbc04cc23bfd953e7fd8f4d96532150524ef75c76fbe569ce",
6
  "BUCKET_BUNDLE.md": "cb7a0f023d5a1f93f0288c6a5646b64f8f3e9d36150c0730aea94590e5b80260",
7
  "CUDA_REFERENCE.md": "f7453c3254d244f8b0de41fde5851cb025159f5cea4a4d1a5d8208a955550c6c",
8
  "DATA_POLICY.md": "fc5978528abe1c21c14882417ac8a706e04a0831bbd3fdb3de8c64442c1a7b3d",
9
  "FEEDBACK.md": "f95b8f6afbf4a360976c0edca5d52f5b3a0b668c9a944d4947b840a7c53a122a",
10
+ "FRONTEND_SOURCE.json": "927344c920ee813ab9cfcec43a1adebdb7a8e8ec3de7892596ec570e97f92fb2",
11
  "GODOT_LICENSE": "fb2b3bb82c60f1e76841ba2122eb902f8e39c151476fe21ce10c9a05d1045304",
12
  "IMPORTER_BUILD_RECEIPT.json": "4ba5c533cc617105478e4d85c83f456a7dfa68b1388049624619871ba9e42e9d",
13
  "LICENSE": "53d5851b6440feeae36f72a5f57fcab37858c48b7084765ece4b0c54b9a28ed8",
14
+ "README.md": "d40518e2b817bc95e28253352d75752a410a85d4ad662e6cbb5398b921769d87",
15
+ "REPLAY_BLACKBOX.md": "08cbb1fca44e54ac127d049fbad4d34f7e2048c3609f362277bd86dfe524931f",
16
  "STORAGE_BOUNDARY.md": "1d0cab6c82723f1879d7b437bab6b0d21248436bce161f3fbfe6c0e83b9e87a1",
17
  "TRACK_LIBRARY.md": "be64c91633ef6696233df537afeef4c5175b2d55daac9336758d9eb3d24763c9",
18
+ "UPSTREAM.json": "78472cb79a40839face9ccf81f5b87f3f20a5f1d663101287070222f54ee4608",
19
  "WINNERS_AND_EVALUATION.md": "f281cf496763c59c50a79161cfff1a46d3529edfcfaaa14962c9a3f2d4f9446f",
20
  "analysis_result.py": "0a5d73fe8dbca934b21823b8ffbd50b0baaef8e15a39e32604eefe16f01d1cf2",
21
  "app.py": "62dfcda6f47ea8c86d3f7919638d7bc1329507e6ec21377c13fcc33bea9d8f2d",
 
25
  "assets/snowmobile_template.json": "8232f4d54829445c44de9292e12557bfe66b3d43e0363e07d2ae0b4118721c08",
26
  "assets/track-atlas.json": "d97c8900e3e5fb17734b5bd61d1f4f4b196d9be30af9848e2e273ae7e4079ae4",
27
  "assets/truck_template.json": "a83bffea4d5e818c135ab3aba68a47aa288d6ad0e7b8bd9c95ed0dea9e9df2f7",
28
+ "bin/altd-sim": "225de9c2b7dd0d9cb11c2578f50fff8a34f4cf6223580035ab0fa64e700beac8",
29
  "bin/extract_saved_track": "3a7733c45b4301a786fcbfe92660a1c484749272da5f608d62f34878bd4ff31a",
30
  "bin/libaltd_gpu.so": "e5e9a61d863bc3b429af69a13cd8d50f63cad8984b3e6a9001ae342fc5981e05",
31
  "bucket_storage.py": "f3044964724de322c1372adc23fa31f83f33ff0096f2b8509eb137953d983ddb",
 
60
  "builtin_tracks/tracks/Replica R08 Demolition Derby.track": "6f11a9ffbcb477c9d19964566b1b612d2a94675605246e93e21f27bbbdb357ef",
61
  "builtin_tracks/tracks/Replica R09 Eau Noir.track": "3ec0a78478cca1a4f0d2d98ac81f40783928adf271b70f0c32d295a6da2cdaa9",
62
  "builtin_tracks/tracks/Replica The Champions Trial.track": "a3bfb76422affc774b44c739b0636d08acb901fa7615b9adcb52c069f79834e1",
63
+ "client.js": "0526336091391457de43dc1fc3d3281a78a5458620fb49fde7a7e3d67ef3ce9e",
64
  "delivery.py": "6bdba2e87c3e19a41440cb16103695af27105f8bafbae38948bbb1b936ed0c1b",
65
  "gpu_tickets.py": "20928fcf1ca24648809ad8712c929377bdcc8b5e6b4387bfff3503ec5711928b",
66
  "help.html": "58959e994a8e4bbd3c70b2a6256cb699ac615cde718c6d0288fabeee909098a2",
67
  "hf-auth.js": "3f3938bbc0935e4e9230c094029ef46e03beea74be199887c50e053e03dafcfe",
68
  "hf_identity.py": "913fb1e089af21f376e8359a20cbc838d5bcd7971def6989a4382d53c1127b37",
69
+ "index.html": "c23258d7493ce1d2304fe8d27b220bab1b8f09187c647e4048259cb9dc8e53c7",
70
  "native/analysis.patch": "42f79de67cb0734cffb2a7582f5479cab42ab82675884b8b42b9f158d46a98e8",
71
+ "native/blackbox-build-receipt.json": "de3eea6c45a5ae4897287a97b0e2822fdae552a0655250bf940cef20d9b60d96",
72
+ "native/blackbox-source.tar.gz": "56b43430c68b95bf7ac0d8312975c366c920f99b1653d790fb15b59453728e28",
73
  "native/build-receipt.json": "559a7e4e382f9f7caa1c5ceb566a5a0bbefad2ed3a2e2cf604e31c9c3890c348",
74
  "native/physics-build-receipt.json": "63561c108554a09884cc68a1bfadfb8a3f530a800de0700ff671d99e558609fe",
75
  "native/physics-parity.json": "006cc6b455e8f49af395ed60f3c5c88dbb2865ee6cad51d8cfdae040293d9f9e",
76
  "native/physics-source-identities.json": "e3414e24144d517f4a0309e1f9d0dbab8309b4c0b70bd61ccb2c0f40b8f14998",
77
  "native/physics-source.tar.gz": "6abefb234de18dee58d69758c6cc8900f259993663ac37f90ce39aa114a30718",
78
  "native/physics.patch": "bae8eeb9342cad1e52ad77dc8026b8bd2ff510a1b836165fc753c043a04859b3",
79
+ "native/pre-blackbox-binary-provenance.json": "99c24677a039993b6100ce24551a01753c0187980f6c9c54be865b3dc7a65d00",
80
  "native/selective-freeze-build-receipt.json": "ed804b1cd49a9ba34abc6f7cadaf4fb97807e27f3d14af117f8292a2d3f2d172",
81
  "native/selective-freeze-source.tar.gz": "297d2ce34569994acd2a477e64c5315cb2081699b4333b8abdabb3ff7451d8db",
82
  "native/source-receipt.json": "36feba861501baf8672884476bbeed5e375254cbb4feffb9f4f90aa61a415a93",
83
  "native/upstream-v1.3.patch": "a9810c9abd40ddcbac5fcf6914320d5fc04fcde23849df9437ec293c83be15ed",
84
  "portable_bundle.py": "58df5b87956745ea909c41c4b12a23cf9ab8c40a7df47d1529f47ae4de9bf51f",
85
+ "replay.py": "5c2167adb2557c9fc798f2ad308805e4b5fcead344ba9b7de3cf9948bd568d76",
86
  "requirements.txt": "fc7e0703ad2289fd3926a36efbdce8c61f0edc00f7575a87e2b565e46588c5a4",
87
+ "server.py": "35747ac597969b2ec8625669bb5e6eb528f3905379f650092b2b7ed8308333af",
88
  "star_check.py": "5c17080957b81ffccf0de8314635b471562e55c92c97a1207d9034a99279b2c3",
89
  "steam_leaderboard.py": "d76397c39cae58f636ddf9a9be1a46ae3d77fefd6b7269feac73d34d97165481",
90
  "track-library.js": "351ec4c026b49420ce963f4310cb000d9e987fd28e6dac5ecd0176509340f6e6",
91
+ "track-map.js": "1612b75e95ccbbb2da4a47d8c8bf2ee406e8f40c626475ae2a1c3c19e119a139",
92
  "training_config.py": "6eb7282bbee3b3a6273bddc29c949d9904067414c26e501d815012f033173a1c",
93
  "vendor/gradio-client/LICENSE": "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4",
94
  "vendor/gradio-client/dist/index.min.js": "fdd776db8633354f118fe2908c980592283968737e6b91dc3aa86d648da5c3fd",
 
98
  "vendor/hf-oauth/package.json": "fafd4d8891023a1961546a7d3bc25cd24f64923a2ebfc449fe6d516a2949bda8",
99
  "worker.py": "d18053363baf8147425808e9fd939f44f00af23781662d353196ade974144974"
100
  },
101
+ "interface": "single-engine-manual-replay-native-blackbox-v2",
102
  "physics_revision": "20261017-v1.3-candidate",
103
  "upstream_revision": "b90b8af06ffc4ea4e4fd703becd1107a48b8e5e0"
104
  }
REPLAY_BLACKBOX.md ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Measured replay and car black box
2
+
3
+ Recording runs the selected unchanged policy in one fresh native CPU drive, including when the policy was trained on GPU. It is not a recording of an earlier training population. Physics and decisions run at 60 Hz with batch_count=1; snapshots are saved at tick 1, every sixth tick and the requested endpoint (5 or 15 seconds). The new single-pass recorder replaces repeated prefix runs. No commands or sensor values are reconstructed in the browser.
4
+
5
+ Playback starts paused. Full-circuit and follow cameras are manual. Previous/next sample selects actual measurements. Measured poses are the default; optional pose smoothing interpolates position/heading only. The inspector always displays the preceding actual native sample, not an interpolated control or sensor value.
6
+
7
+ The car black box shows post-physics position, velocity, heading, angular velocity, boost energy, active status, physical contact counter and statistics update count. Native control commands appear beside their normalized values applied by physics. The ordered sensor vector is copied from the inference cache that actually drove the controls, with its pre-physics decision tick. Held decisions retain their original tick; reset clears the cache. Missing output slots are native defaults, not claimed neural outputs. Hidden-layer activations and ray-hit positions are not recorded.
8
+
9
+ Contact and active-state events mark sampled intervals. A contact increase in (tick A, tick B] does not identify an exact impact tick, and the engine contact counter is not a count of unique crashes. Reward metrics are cumulative native statistics, not instantaneous reward contributions.
10
+
11
+ Version 2 JSON contains explicit capture provenance and phases, the ordered sensor descriptors/output slots, each frame's raw/applied commands, and its cached decision tick/input vector. The browser rejects mismatched selected track/policy hashes, missing samples, nonfinite values, invalid sensor layouts, normalization mismatches, future or backward decision clocks and decreasing contact counters. Legacy version 1 recordings remain viewable with controls/sensors explicitly unavailable. Open recording and Download recording support repeatable inspection without starting another simulation. Imported recordings are data, not authenticated provenance claims.
12
+
13
+ The native extension does not change CUDA kernels, GPU ABI, physics or evolutionary policy rules. An actual Linux CPU comparison checks old versus new physical samples exactly. Native cache tests check pre-physics inputs and last decision/reset semantics. GPU execution of the new candidate is a separate quota-checked release gate; CPU replay cannot establish general CPU/GPU or original-game parity.
UPSTREAM.json CHANGED
@@ -3,13 +3,13 @@
3
  "importer_source_revision": "d8ab74c25df70b6a86ed101080e33d5fb785ea6f",
4
  "math_profile": "proton",
5
  "native_build": {
6
- "build_receipt_path": "native/physics-build-receipt.json",
7
- "build_receipt_sha256": "63561c108554a09884cc68a1bfadfb8a3f530a800de0700ff671d99e558609fe",
8
  "cuda_library_origin": "newly compiled library; 57 original-engine cases passed on HF ZeroGPU",
9
- "simulator_origin": "HF feature branch with original-engine-verified contact and snowmobile fixes",
10
  "source_revision": "b90b8af06ffc4ea4e4fd703becd1107a48b8e5e0",
11
- "source_snapshot_path": "native/physics-source.tar.gz",
12
- "source_snapshot_sha256": "6abefb234de18dee58d69758c6cc8900f259993663ac37f90ce39aa114a30718"
13
  },
14
  "open_prs_not_included": [
15
  19,
@@ -19,5 +19,6 @@
19
  "role": "gpu",
20
  "ui_refresh_date": "2026-10-12",
21
  "physics_revision": "ald-parity-20261017",
22
- "applied_upstream_delta": "65810f5..ab3ec67 (release/build delta; HF feature branch retained)"
 
23
  }
 
3
  "importer_source_revision": "d8ab74c25df70b6a86ed101080e33d5fb785ea6f",
4
  "math_profile": "proton",
5
  "native_build": {
6
+ "build_receipt_path": "native/blackbox-build-receipt.json",
7
+ "build_receipt_sha256": "de3eea6c45a5ae4897287a97b0e2822fdae552a0655250bf940cef20d9b60d96",
8
  "cuda_library_origin": "newly compiled library; 57 original-engine cases passed on HF ZeroGPU",
9
+ "simulator_origin": "Retained physics branch plus read-only cached decision telemetry and bounded single-pass recorder",
10
  "source_revision": "b90b8af06ffc4ea4e4fd703becd1107a48b8e5e0",
11
+ "source_snapshot_path": "native/blackbox-source.tar.gz",
12
+ "source_snapshot_sha256": "56b43430c68b95bf7ac0d8312975c366c920f99b1653d790fb15b59453728e28"
13
  },
14
  "open_prs_not_included": [
15
  19,
 
19
  "role": "gpu",
20
  "ui_refresh_date": "2026-10-12",
21
  "physics_revision": "ald-parity-20261017",
22
+ "applied_upstream_delta": "65810f5..ab3ec67 (release/build delta; HF feature branch retained)",
23
+ "replay_revision": "native-blackbox-v2-20261023"
24
  }
bin/altd-sim CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:792139f30bcfecf25f2d78595d2611234d30b0a254b5ece0ec587f1d27a80df2
3
- size 3646480
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:225de9c2b7dd0d9cb11c2578f50fff8a34f4cf6223580035ab0fa64e700beac8
3
+ size 3661976
client.js CHANGED
@@ -90,6 +90,7 @@ function buttons() {
90
  $('forgetLocal').disabled = busy || !localResult;
91
  $('track').disabled=unavailable;
92
  $('network').disabled=unavailable;
 
93
  if($('replay_record'))$('replay_record').disabled=unavailable||batchActive||!capabilitiesReady||!replayNetworkSource();
94
  if($('replay_duration'))$('replay_duration').disabled=settingsUnavailable;
95
  if($('replay_download'))$('replay_download').disabled=replayBusy||!localReplay;
@@ -515,6 +516,21 @@ if($('replay_record'))$('replay_record').onclick=async()=>{
515
  clearTimeout(timeout);replayBusy=false;busy=false;buttons();
516
  }
517
  };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
518
  if($('replay_download'))$('replay_download').onclick=()=>{
519
  if(localReplay)downloadTextFile(JSON.stringify(localReplay),'ald-recorded-drive.json','application/json');
520
  };
 
90
  $('forgetLocal').disabled = busy || !localResult;
91
  $('track').disabled=unavailable;
92
  $('network').disabled=unavailable;
93
+ if($('replay_import'))$('replay_import').disabled=unavailable||batchActive||!replayNetworkSource();
94
  if($('replay_record'))$('replay_record').disabled=unavailable||batchActive||!capabilitiesReady||!replayNetworkSource();
95
  if($('replay_duration'))$('replay_duration').disabled=settingsUnavailable;
96
  if($('replay_download'))$('replay_download').disabled=replayBusy||!localReplay;
 
516
  clearTimeout(timeout);replayBusy=false;busy=false;buttons();
517
  }
518
  };
519
+ if($('replay_focus'))$('replay_focus').onclick=()=>{const focused=$('drive').classList.toggle('replay-focused');$('replay_focus').textContent=focused?'Return to run setup':'Expand replay workspace';$('replay_focus').setAttribute('aria-pressed',String(focused));};
520
+ if($('replay_import'))$('replay_import').onchange=async()=>{
521
+ const file=$('replay_import').files[0];$('replay_import').value='';
522
+ if(!file||busy||job||batchActive||bucketOperation||bundleRestoring)return;
523
+ busy=true;replayBusy=true;invalidateReplay('Opening recorded drive…');const attempt=replayRequestId;buttons();
524
+ try{
525
+ if(file.size<1||file.size>2*1024*1024)throw Error('Choose a recording under 2 MiB.');
526
+ const track=await trackSource(),network=replayNetworkSource();if(!track||!network)throw Error('Select the matching track and policy first.');
527
+ const [trackSha,networkSha]=await Promise.all([track.arrayBuffer().then(sha),network.arrayBuffer().then(sha)]);
528
+ const recording=JSON.parse(await file.text());
529
+ if(attempt!==replayRequestId)throw Error('Selection changed while opening recording.');
530
+ window.TrackReplay.setRecording(recording,trackSha,networkSha);localReplay=recording;
531
+ }catch(error){if(attempt===replayRequestId)window.TrackReplay?.clearRecording?.('Recording unavailable: '+error.message);}
532
+ finally{busy=false;replayBusy=false;buttons();}
533
+ };
534
  if($('replay_download'))$('replay_download').onclick=()=>{
535
  if(localReplay)downloadTextFile(JSON.stringify(localReplay),'ald-recorded-drive.json','application/json');
536
  };
index.html CHANGED
@@ -6,6 +6,8 @@
6
  *{box-sizing:border-box}button,select,summary{min-height:44px}button,a,summary,input,select,textarea{scroll-margin-top:90px}:focus-visible{outline:3px solid #ffd073;outline-offset:3px}.lab-header{display:flex;align-items:center;justify-content:space-between;gap:16px;flex-wrap:wrap;padding:6px 0}.lab-header h1{font-size:clamp(26px,3vw,34px);margin-top:4px}.lab-header .intro{font-size:16px;margin-top:5px}.header-actions{display:flex;align-items:center;gap:10px;flex-wrap:wrap}.help-link{display:inline-flex;align-items:center;min-height:44px;border:1px solid #49627c;border-radius:8px;padding:9px 13px;text-decoration:none;font-weight:650}.about{max-width:none;margin:4px 0 0;padding:0;border:0}.about>summary{display:flex;align-items:center;font-size:14px;width:fit-content;gap:8px}.about>summary::before{content:'▸'}.about[open]>summary::before{content:'▾'}.about[open]{border:1px solid #2a3d52;border-radius:10px;padding:0 16px 12px}.quick-start{border:1px solid #385568;background:#102232;border-radius:12px;margin-top:8px;padding:0 16px}.quick-start>summary{padding:12px 0;line-height:1.4}.quick-start>summary .hint{font-size:14px;font-weight:400;margin-left:12px}.quick-start[open]>summary{margin-bottom:0}.quick-steps{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:18px;list-style:none;padding:12px 0;margin:0;counter-reset:quick}.quick-steps li{counter-increment:quick;min-width:0}.quick-steps strong{display:block;margin-bottom:8px}.quick-steps strong::before{content:counter(quick) '. ';color:#62dfb1}.quick-steps p{font-size:14px;line-height:1.55;color:#b9cddd;margin:0 0 10px}.quick-footer{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;padding:12px 0;border-top:1px solid #2a3d52}.tabs{margin:12px 0 0;gap:8px}.tabs button{border-radius:9px}.pane>.card{margin-top:16px}.section-heading{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}.section-heading h2,.section-heading h3{margin:0}.section-heading a{font-size:14px}.section-intro{max-width:85ch;margin:10px 0 18px;color:#b9cddd;line-height:1.55}.recipe-panel{border:1px solid #385568;border-radius:12px;background:#102030;padding:16px;margin:16px 0 24px}.recipe-panel .row label{margin-top:0}.recipe-actions,.batch-actions{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-top:14px}.form-state{font-size:14px;font-weight:650;color:#ffd073;margin:10px 0 0;line-height:1.55}.form-state[data-state="saved"]{color:#82e6bb}.form-state[data-state="invalid"]{color:#ffb5a2}.settings-summary{font-size:14px;color:#b9cddd;line-height:1.55;margin:8px 0 0;overflow-wrap:anywhere}.recipe-panel details{margin-top:12px;padding-top:10px}.recipe-panel textarea{box-sizing:border-box;width:100%;background:#0c1725;color:#e5edf5;border:1px solid #49627c;border-radius:8px;padding:10px}.recipe-panel .manage-actions{display:flex;align-items:start;gap:12px;flex-wrap:wrap}.destructive-action{margin-top:14px;color:#ffb5a2}.batch-layout{display:grid;grid-template-columns:minmax(0,1.7fr) minmax(280px,1fr);gap:24px;align-items:start}.batch-setup{background:#102030;border:1px solid #385568;border-radius:12px;padding:18px;position:sticky;top:92px}.batch-setup h3{margin:0 0 10px}.batch-context{margin:12px 0}.batch-context div{padding:9px 0;border-bottom:1px solid #2a3d52}.batch-context dt{font-size:13px;color:#a2b4c8}.batch-context dd{margin:3px 0 0;overflow-wrap:anywhere;font-weight:600}.sequence-heading{display:flex;justify-content:space-between;align-items:center;gap:12px;margin-top:22px}.sequence-heading h3{margin:0}.step-count{font-size:14px;color:#b9cddd;white-space:nowrap}.batch-steps{list-style:none;counter-reset:steps;padding:0;margin:12px 0}.batch-step{border:1px solid #3b5268;border-radius:10px;padding:14px;margin-bottom:10px;background:#101d2c}.batch-step[data-invalid="true"]{border-color:#d78970}.step-header{display:grid;grid-template-columns:30px minmax(0,1fr);align-items:center;gap:10px}.step-number{color:#82e6bb;font-size:14px;font-weight:800;text-align:center}.step-summary{font-size:14px;line-height:1.5;color:#b9cddd;margin:10px 0 8px;padding-left:40px}.step-actions{display:flex;gap:8px;flex-wrap:wrap;padding-left:40px}.step-actions button{font-size:14px;padding:8px 10px}.batch-empty{border:1px dashed #49627c;border-radius:10px;padding:18px;margin:12px 0;color:#b9cddd;line-height:1.55}.batch-empty p{margin:0 0 12px}.add-step{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:10px;align-items:end}.add-step label{margin:0}.add-step select{margin-top:6px}.batch-mode{margin:18px 0 6px;display:flex;align-items:flex-start;gap:10px;line-height:1.5}.batch-mode input{margin-top:5px;flex:none}.batch-progress{border-top:1px solid #2a3d52;margin-top:24px;padding-top:20px}.batch-progress h3{margin:0 0 12px}.batch-progress #batch_status{line-height:1.6}.batch-setup #batch_start{flex:1;min-width:140px}.batch-setup #batch_ready{line-height:1.55}.batch-actions button{min-height:46px}#recipe_feedback:empty,#batches_feedback:empty{display:none}.muted-note{font-size:14px;line-height:1.6;color:#b9cddd}.training-track{margin-top:18px}.training-track label{margin-top:0}
7
  @media(max-width:1000px){.batch-layout{grid-template-columns:minmax(0,1fr)}.batch-setup{position:static}.quick-steps{grid-template-columns:repeat(2,minmax(0,1fr))}}@media(max-width:600px){body{padding:12px}.card{padding:16px}.row{grid-template-columns:minmax(0,1fr)}.quick-steps{grid-template-columns:minmax(0,1fr)}.header-actions{width:100%}.header-actions>*{flex:1;justify-content:center;text-align:center}.lab-header .intro{font-size:15px}.quick-start>summary .hint{display:block;margin-left:18px}.tabs{display:grid;grid-template-columns:1fr 1fr;gap:6px}.tabs button{font-size:14px;padding:9px 7px}.step-actions,.step-summary{padding-left:0}.add-step{grid-template-columns:minmax(0,1fr)}.batch-setup{padding:14px}.recipe-actions>*{flex:1}.reward{grid-template-columns:minmax(0,1fr) minmax(85px,.7fr) 65px 44px}.reward input{width:65px}.recipe-panel{padding:12px}}
8
  .replay-bar{background:#101d2c;border:1px solid #2a3d52;border-radius:11px;padding:10px 12px;margin:10px 0}.replay-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.replay-row button{min-height:36px;padding:6px 11px;font-size:13px;font-weight:650}.replay-row select{width:auto;min-height:36px;padding:5px 9px;font-size:13px}.replay-row input[type=range]{flex:1;min-width:120px;accent-color:#62dfb1;padding:0}.replay-time{font:600 12px ui-monospace,SFMono-Regular,monospace;color:#91efc6;white-space:nowrap}.replay-layers{display:flex;gap:6px 12px;flex-wrap:wrap;margin-top:8px;padding-top:8px;border-top:1px solid #223447;font-size:12.5px;color:#b9cddd}.replay-layers label{display:inline-flex;align-items:center;gap:5px;margin:0;cursor:pointer}.replay-layers input{margin:0}.kpi-strip{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px;margin:12px 0}.kpi-tile{background:#101d2c;border:1px solid #2a3d52;border-radius:10px;padding:10px 12px}.kpi-tile .kpi-label{font-size:11.5px;text-transform:uppercase;letter-spacing:.06em;color:#a2b4c8}.kpi-tile .kpi-val{font:800 19px ui-monospace,SFMono-Regular,monospace;color:#62dfb1;margin-top:3px}.kpi-tile .kpi-sub{font-size:11.5px;color:#8fa6bc;margin-top:2px}.chart-box{background:#09111b;border:1px solid #2a3d52;border-radius:10px;padding:10px;margin:10px 0}.chart-box canvas{max-height:190px;display:block}.subtab-bar{display:flex;gap:8px;flex-wrap:wrap;margin:14px 0}.subtab-bar button{min-height:36px;padding:6px 12px;font-size:13px;border-radius:18px}.subtab-bar button[aria-pressed=true]{background:#62dfb1;color:#102522;font-weight:700}.editor-visual-grid{display:grid;grid-template-columns:minmax(260px,.85fr) minmax(0,1.35fr);gap:16px;align-items:start;margin:14px 0}@media(max-width:850px){.kpi-strip{grid-template-columns:1fr 1fr}.editor-visual-grid{grid-template-columns:minmax(0,1fr)}}
 
 
9
  </style>
10
  <dialog id="appConfirm" aria-labelledby="appConfirmTitle" aria-describedby="appConfirmMessage">
11
  <h2 id="appConfirmTitle">Confirm action</h2>
@@ -48,16 +50,23 @@
48
  <p><label>Track (.track) <input id="track" type="file" accept=".track"></label></p>
49
  <p><label>Vehicle network (.evolution) <input id="network" type="file" accept=".evolution"></label></p>
50
  <p id="networkChoice" role="status">Choose an uploaded file or use a network from the browser editor.</p><p class="privacy-note">Uploads are processed for this run. By default, the server copy is deleted after the browser verifies the download.</p><details><summary>Optional repeat download</summary><label class="keep-result"><input id="keepServer" type="checkbox"> Keep this result on the server for up to five minutes so I can download it again</label><p class="privacy-note">This is optional and resets after each run. When bucket auto-save is on, verified receipt must delete the server copy first, so repeat download is disabled. All results expire after five minutes. <a href="/policy" target="_blank" rel="noopener">Data policy</a></p>
51
- </details></section><section class="card"><h2>Selected track &amp; terrain</h2><p id="mapStatus" class="map-status" role="status">Loading selected track…</p><div class="map"><canvas id="trackMap" width="1000" height="500" role="img" aria-label="Selected track tile layout and terrain"></canvas></div><div class="replay-bar" id="replayControls" aria-label="Recorded drive controls">
52
- <div class="replay-row"><button type="button" id="replay_record" disabled>Record selected policy</button><label for="replay_duration" style="margin:0">Length</label><select id="replay_duration"><option value="300" selected>5 seconds</option><option value="900">15 seconds</option></select><button type="button" id="replay_download" disabled>Download recording</button></div>
 
 
 
 
 
53
  <p id="replay_policy" class="hint">Choose or create a network to record a drive.</p>
54
  <p class="hint">Fresh CPU drive · unchanged weights · 60 Hz physics and decisions · wall-hit and idle elimination off. Recording takes a few seconds; playback runs in your browser.</p>
55
  <p id="replay_status" role="status">No replay recorded. The map shows the selected track and its saved starting point.</p>
56
- <div class="replay-row"><button type="button" id="replay_play" disabled>Play</button><button type="button" id="replay_reset" disabled>Restart</button><input type="range" id="replay_scrub" min="1" max="300" value="1" disabled aria-label="Replay tick scrubber"><span id="replay_time_label" class="replay-time">No recording</span></div>
57
  <div class="replay-row" style="margin-top:8px"><label for="replay_camera" style="margin:0">Camera</label><select id="replay_camera" aria-label="Replay camera mode" disabled><option value="full" selected>Full circuit</option><option value="follow">Follow car</option></select><label for="replay_speed" style="margin:0">Speed</label><select id="replay_speed" aria-label="Replay playback speed" disabled><option value="0.25">0.25×</option><option value="0.5">0.5×</option><option value="1" selected>1×</option><option value="2">2×</option></select></div>
58
  <div class="replay-layers"><label><input type="checkbox" id="replay_layer_outline" checked disabled> Car outline</label><label><input type="checkbox" id="replay_layer_line" checked disabled> Recorded path</label><label><input type="checkbox" id="replay_layer_hud" checked disabled> Recorded telemetry</label></div>
 
 
59
  <p id="replay_readout" style="font-size:16px;font-variant-numeric:tabular-nums" aria-live="off"></p>
60
- <details><summary>What does this recording show?</summary><p>Vehicle positions and velocities are sampled every 0.1 seconds from the native CPU simulator. Playback interpolates between those samples; it does not simulate the car. Speed is calculated from recorded velocity. Controls, sensor rays, skid marks and neural activations are not recorded. This fresh drive does not replace the measurements from your training run.</p><p>The recording remains in this page until replaced, cleared by a changed selection, or the page is closed. Use Download recording to keep its measured samples.</p></details>
61
  </div><div class="map-legend"><span><i class="terrain asphalt"></i> Asphalt</span><span><i class="terrain dirt"></i> Dirt</span><span><i class="terrain ice"></i> Ice</span><span><i class="terrain start"></i> Start</span></div><p id="mapLegend" class="hint"></p><h2>Run &amp; results</h2><button id="download" disabled>Download result</button> <button id="erase" disabled>Delete server-side job data now</button>
62
  <p><button id="saveLocal" disabled>Download received result (browser only)</button> <button id="forgetLocal" disabled>Discard browser result</button></p>
63
  <p>The browser keeps the received result in memory until discarded, replaced by a new run, or this page is closed. It is not saved to browser storage.</p>
 
6
  *{box-sizing:border-box}button,select,summary{min-height:44px}button,a,summary,input,select,textarea{scroll-margin-top:90px}:focus-visible{outline:3px solid #ffd073;outline-offset:3px}.lab-header{display:flex;align-items:center;justify-content:space-between;gap:16px;flex-wrap:wrap;padding:6px 0}.lab-header h1{font-size:clamp(26px,3vw,34px);margin-top:4px}.lab-header .intro{font-size:16px;margin-top:5px}.header-actions{display:flex;align-items:center;gap:10px;flex-wrap:wrap}.help-link{display:inline-flex;align-items:center;min-height:44px;border:1px solid #49627c;border-radius:8px;padding:9px 13px;text-decoration:none;font-weight:650}.about{max-width:none;margin:4px 0 0;padding:0;border:0}.about>summary{display:flex;align-items:center;font-size:14px;width:fit-content;gap:8px}.about>summary::before{content:'▸'}.about[open]>summary::before{content:'▾'}.about[open]{border:1px solid #2a3d52;border-radius:10px;padding:0 16px 12px}.quick-start{border:1px solid #385568;background:#102232;border-radius:12px;margin-top:8px;padding:0 16px}.quick-start>summary{padding:12px 0;line-height:1.4}.quick-start>summary .hint{font-size:14px;font-weight:400;margin-left:12px}.quick-start[open]>summary{margin-bottom:0}.quick-steps{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:18px;list-style:none;padding:12px 0;margin:0;counter-reset:quick}.quick-steps li{counter-increment:quick;min-width:0}.quick-steps strong{display:block;margin-bottom:8px}.quick-steps strong::before{content:counter(quick) '. ';color:#62dfb1}.quick-steps p{font-size:14px;line-height:1.55;color:#b9cddd;margin:0 0 10px}.quick-footer{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;padding:12px 0;border-top:1px solid #2a3d52}.tabs{margin:12px 0 0;gap:8px}.tabs button{border-radius:9px}.pane>.card{margin-top:16px}.section-heading{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}.section-heading h2,.section-heading h3{margin:0}.section-heading a{font-size:14px}.section-intro{max-width:85ch;margin:10px 0 18px;color:#b9cddd;line-height:1.55}.recipe-panel{border:1px solid #385568;border-radius:12px;background:#102030;padding:16px;margin:16px 0 24px}.recipe-panel .row label{margin-top:0}.recipe-actions,.batch-actions{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-top:14px}.form-state{font-size:14px;font-weight:650;color:#ffd073;margin:10px 0 0;line-height:1.55}.form-state[data-state="saved"]{color:#82e6bb}.form-state[data-state="invalid"]{color:#ffb5a2}.settings-summary{font-size:14px;color:#b9cddd;line-height:1.55;margin:8px 0 0;overflow-wrap:anywhere}.recipe-panel details{margin-top:12px;padding-top:10px}.recipe-panel textarea{box-sizing:border-box;width:100%;background:#0c1725;color:#e5edf5;border:1px solid #49627c;border-radius:8px;padding:10px}.recipe-panel .manage-actions{display:flex;align-items:start;gap:12px;flex-wrap:wrap}.destructive-action{margin-top:14px;color:#ffb5a2}.batch-layout{display:grid;grid-template-columns:minmax(0,1.7fr) minmax(280px,1fr);gap:24px;align-items:start}.batch-setup{background:#102030;border:1px solid #385568;border-radius:12px;padding:18px;position:sticky;top:92px}.batch-setup h3{margin:0 0 10px}.batch-context{margin:12px 0}.batch-context div{padding:9px 0;border-bottom:1px solid #2a3d52}.batch-context dt{font-size:13px;color:#a2b4c8}.batch-context dd{margin:3px 0 0;overflow-wrap:anywhere;font-weight:600}.sequence-heading{display:flex;justify-content:space-between;align-items:center;gap:12px;margin-top:22px}.sequence-heading h3{margin:0}.step-count{font-size:14px;color:#b9cddd;white-space:nowrap}.batch-steps{list-style:none;counter-reset:steps;padding:0;margin:12px 0}.batch-step{border:1px solid #3b5268;border-radius:10px;padding:14px;margin-bottom:10px;background:#101d2c}.batch-step[data-invalid="true"]{border-color:#d78970}.step-header{display:grid;grid-template-columns:30px minmax(0,1fr);align-items:center;gap:10px}.step-number{color:#82e6bb;font-size:14px;font-weight:800;text-align:center}.step-summary{font-size:14px;line-height:1.5;color:#b9cddd;margin:10px 0 8px;padding-left:40px}.step-actions{display:flex;gap:8px;flex-wrap:wrap;padding-left:40px}.step-actions button{font-size:14px;padding:8px 10px}.batch-empty{border:1px dashed #49627c;border-radius:10px;padding:18px;margin:12px 0;color:#b9cddd;line-height:1.55}.batch-empty p{margin:0 0 12px}.add-step{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:10px;align-items:end}.add-step label{margin:0}.add-step select{margin-top:6px}.batch-mode{margin:18px 0 6px;display:flex;align-items:flex-start;gap:10px;line-height:1.5}.batch-mode input{margin-top:5px;flex:none}.batch-progress{border-top:1px solid #2a3d52;margin-top:24px;padding-top:20px}.batch-progress h3{margin:0 0 12px}.batch-progress #batch_status{line-height:1.6}.batch-setup #batch_start{flex:1;min-width:140px}.batch-setup #batch_ready{line-height:1.55}.batch-actions button{min-height:46px}#recipe_feedback:empty,#batches_feedback:empty{display:none}.muted-note{font-size:14px;line-height:1.6;color:#b9cddd}.training-track{margin-top:18px}.training-track label{margin-top:0}
7
  @media(max-width:1000px){.batch-layout{grid-template-columns:minmax(0,1fr)}.batch-setup{position:static}.quick-steps{grid-template-columns:repeat(2,minmax(0,1fr))}}@media(max-width:600px){body{padding:12px}.card{padding:16px}.row{grid-template-columns:minmax(0,1fr)}.quick-steps{grid-template-columns:minmax(0,1fr)}.header-actions{width:100%}.header-actions>*{flex:1;justify-content:center;text-align:center}.lab-header .intro{font-size:15px}.quick-start>summary .hint{display:block;margin-left:18px}.tabs{display:grid;grid-template-columns:1fr 1fr;gap:6px}.tabs button{font-size:14px;padding:9px 7px}.step-actions,.step-summary{padding-left:0}.add-step{grid-template-columns:minmax(0,1fr)}.batch-setup{padding:14px}.recipe-actions>*{flex:1}.reward{grid-template-columns:minmax(0,1fr) minmax(85px,.7fr) 65px 44px}.reward input{width:65px}.recipe-panel{padding:12px}}
8
  .replay-bar{background:#101d2c;border:1px solid #2a3d52;border-radius:11px;padding:10px 12px;margin:10px 0}.replay-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.replay-row button{min-height:36px;padding:6px 11px;font-size:13px;font-weight:650}.replay-row select{width:auto;min-height:36px;padding:5px 9px;font-size:13px}.replay-row input[type=range]{flex:1;min-width:120px;accent-color:#62dfb1;padding:0}.replay-time{font:600 12px ui-monospace,SFMono-Regular,monospace;color:#91efc6;white-space:nowrap}.replay-layers{display:flex;gap:6px 12px;flex-wrap:wrap;margin-top:8px;padding-top:8px;border-top:1px solid #223447;font-size:12.5px;color:#b9cddd}.replay-layers label{display:inline-flex;align-items:center;gap:5px;margin:0;cursor:pointer}.replay-layers input{margin:0}.kpi-strip{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px;margin:12px 0}.kpi-tile{background:#101d2c;border:1px solid #2a3d52;border-radius:10px;padding:10px 12px}.kpi-tile .kpi-label{font-size:11.5px;text-transform:uppercase;letter-spacing:.06em;color:#a2b4c8}.kpi-tile .kpi-val{font:800 19px ui-monospace,SFMono-Regular,monospace;color:#62dfb1;margin-top:3px}.kpi-tile .kpi-sub{font-size:11.5px;color:#8fa6bc;margin-top:2px}.chart-box{background:#09111b;border:1px solid #2a3d52;border-radius:10px;padding:10px;margin:10px 0}.chart-box canvas{max-height:190px;display:block}.subtab-bar{display:flex;gap:8px;flex-wrap:wrap;margin:14px 0}.subtab-bar button{min-height:36px;padding:6px 12px;font-size:13px;border-radius:18px}.subtab-bar button[aria-pressed=true]{background:#62dfb1;color:#102522;font-weight:700}.editor-visual-grid{display:grid;grid-template-columns:minmax(260px,.85fr) minmax(0,1.35fr);gap:16px;align-items:start;margin:14px 0}@media(max-width:850px){.kpi-strip{grid-template-columns:1fr 1fr}.editor-visual-grid{grid-template-columns:minmax(0,1fr)}}
9
+
10
+ .replay-workbench{display:grid;gap:14px;align-items:start}#replay_blackbox{max-height:520px;overflow:auto;padding:12px;border:1px solid #2a3d52;border-radius:10px;min-width:0}#replay_blackbox h3{margin-top:0}#replay_blackbox td,#replay_blackbox th{padding:6px;font-size:12px}#drive.replay-focused>.grid{grid-template-columns:minmax(0,1fr)}#drive.replay-focused>.grid>section:first-child{display:none}#drive.replay-focused .replay-workbench{grid-template-columns:minmax(0,1.35fr) minmax(320px,1fr)}#drive.replay-focused .map{position:sticky;top:70px}#drive.replay-focused .map canvas{max-height:500px}@media(max-width:850px){#drive.replay-focused .replay-workbench{grid-template-columns:minmax(0,1fr)}#drive.replay-focused .map{position:static}#replay_blackbox{max-height:400px}}
11
  </style>
12
  <dialog id="appConfirm" aria-labelledby="appConfirmTitle" aria-describedby="appConfirmMessage">
13
  <h2 id="appConfirmTitle">Confirm action</h2>
 
50
  <p><label>Track (.track) <input id="track" type="file" accept=".track"></label></p>
51
  <p><label>Vehicle network (.evolution) <input id="network" type="file" accept=".evolution"></label></p>
52
  <p id="networkChoice" role="status">Choose an uploaded file or use a network from the browser editor.</p><p class="privacy-note">Uploads are processed for this run. By default, the server copy is deleted after the browser verifies the download.</p><details><summary>Optional repeat download</summary><label class="keep-result"><input id="keepServer" type="checkbox"> Keep this result on the server for up to five minutes so I can download it again</label><p class="privacy-note">This is optional and resets after each run. When bucket auto-save is on, verified receipt must delete the server copy first, so repeat download is disabled. All results expire after five minutes. <a href="/policy" target="_blank" rel="noopener">Data policy</a></p>
53
+ </details></section><section class="card"><h2>Visual replay &amp; car black box</h2><p id="mapStatus" class="map-status" role="status">Loading selected track…</p><button type="button" id="replay_focus" aria-pressed="false">Expand replay workspace</button><div class="replay-workbench"><div class="map"><canvas id="trackMap" width="1000" height="500" role="img" aria-label="Selected track tile layout and terrain"></canvas></div><section id="replay_blackbox" hidden aria-label="Recorded car black box"><h3>Car black box</h3><p id="blackbox_phase" class="hint"></p>
54
+ <p class="hint">All values below belong to the selected native sample. Sensor inputs were consumed before physics at the decision tick; vehicle state is captured after physics. Samples are 0.1 seconds apart. Contact events identify intervals, not exact impact ticks; the counter does not count unique crashes.</p>
55
+ <details><summary>Recorded vehicle state</summary><div class="table-scroll"><table><thead><tr><th>Vehicle state</th><th>Recorded value</th></tr></thead><tbody id="blackbox_state"></tbody></table></div></details>
56
+ <h4>Native control commands</h4><div class="table-scroll"><table><thead><tr><th>Control</th><th>Raw command</th><th>Applied after normalization</th><th>Source</th></tr></thead><tbody id="blackbox_controls"></tbody></table></div>
57
+ <details><summary>Inputs consumed by the native network</summary><div class="table-scroll"><table><thead><tr><th>Input index</th><th>Sensor</th><th>Parameters</th><th>Native input value</th></tr></thead><tbody id="blackbox_inputs"></tbody></table></div><p class="hint">These are the input values the policy consumed. Ray inputs are not ray-hit positions. Hidden-layer activations are not recorded.</p></details>
58
+ <details><summary>Recorded cumulative reward metrics</summary><p class="hint">Metrics accumulate at native statistics callbacks; they are not instantaneous forces or per-reward contributions.</p><div class="table-scroll"><table><thead><tr><th>Metric</th><th>Recorded cumulative value</th></tr></thead><tbody id="blackbox_metrics"></tbody></table></div></details></section></div><div class="replay-bar" id="replayControls" aria-label="Recorded drive controls">
59
+ <div class="replay-row"><button type="button" id="replay_record" disabled>Record selected policy</button><label for="replay_duration" style="margin:0">Length</label><select id="replay_duration"><option value="300" selected>5 seconds</option><option value="900">15 seconds</option></select><button type="button" id="replay_download" disabled>Download recording</button><label for="replay_import">Open recording<input type="file" id="replay_import" accept=".json,application/json" disabled></label></div>
60
  <p id="replay_policy" class="hint">Choose or create a network to record a drive.</p>
61
  <p class="hint">Fresh CPU drive · unchanged weights · 60 Hz physics and decisions · wall-hit and idle elimination off. Recording takes a few seconds; playback runs in your browser.</p>
62
  <p id="replay_status" role="status">No replay recorded. The map shows the selected track and its saved starting point.</p>
63
+ <div class="replay-row"><button type="button" id="replay_play" disabled>Play</button><button type="button" id="replay_reset" disabled>Restart</button><button type="button" id="replay_prev" disabled>Previous sample</button><button type="button" id="replay_next" disabled>Next sample</button><input type="range" id="replay_scrub" min="1" max="300" value="1" disabled aria-label="Replay tick scrubber"><span id="replay_time_label" class="replay-time">No recording</span></div>
64
  <div class="replay-row" style="margin-top:8px"><label for="replay_camera" style="margin:0">Camera</label><select id="replay_camera" aria-label="Replay camera mode" disabled><option value="full" selected>Full circuit</option><option value="follow">Follow car</option></select><label for="replay_speed" style="margin:0">Speed</label><select id="replay_speed" aria-label="Replay playback speed" disabled><option value="0.25">0.25×</option><option value="0.5">0.5×</option><option value="1" selected>1×</option><option value="2">2×</option></select></div>
65
  <div class="replay-layers"><label><input type="checkbox" id="replay_layer_outline" checked disabled> Car outline</label><label><input type="checkbox" id="replay_layer_line" checked disabled> Recorded path</label><label><input type="checkbox" id="replay_layer_hud" checked disabled> Recorded telemetry</label></div>
66
+ <div class="replay-row"><label><input type="checkbox" id="replay_interpolate" disabled> Smooth pose between measured samples</label><label for="replay_event">Contact / active-state interval</label><select id="replay_event" aria-label="Recorded event interval" disabled><option value="">No recording</option></select></div>
67
+
68
  <p id="replay_readout" style="font-size:16px;font-variant-numeric:tabular-nums" aria-live="off"></p>
69
+ <details><summary>What does this recording show?</summary><p>A single fresh CPU drive records native state, raw and normalized control commands, and the exact cached sensor inputs every 0.1 seconds. Physics and policy decisions run at 60 Hz. Playback starts paused and shows measured poses by default; optional pose smoothing only interpolates between adjacent measured samples. It does not simulate the car. Black-box values always remain at an actual recorded sample. Ray-hit positions, skid marks and hidden-layer activations are not recorded. This is a selected-policy CPU replay, including for GPU-trained policies; it is not a recording of the original training population.</p><p>The recording remains in this page until replaced, cleared by a changed selection, or the page is closed. Use Download recording to keep its measured samples.</p></details>
70
  </div><div class="map-legend"><span><i class="terrain asphalt"></i> Asphalt</span><span><i class="terrain dirt"></i> Dirt</span><span><i class="terrain ice"></i> Ice</span><span><i class="terrain start"></i> Start</span></div><p id="mapLegend" class="hint"></p><h2>Run &amp; results</h2><button id="download" disabled>Download result</button> <button id="erase" disabled>Delete server-side job data now</button>
71
  <p><button id="saveLocal" disabled>Download received result (browser only)</button> <button id="forgetLocal" disabled>Discard browser result</button></p>
72
  <p>The browser keeps the received result in memory until discarded, replaced by a new run, or this page is closed. It is not saved to browser storage.</p>
native/blackbox-build-receipt.json ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "schema": "ald-native-blackbox-build/1",
3
+ "source_archive_sha256": "56b43430c68b95bf7ac0d8312975c366c920f99b1653d790fb15b59453728e28",
4
+ "base_source_archive_sha256": "6abefb234de18dee58d69758c6cc8900f259993663ac37f90ce39aa114a30718",
5
+ "build": {
6
+ "command": [
7
+ "/Users/tiga/.cargo/bin/cargo",
8
+ "+1.95.0",
9
+ "build",
10
+ "--manifest-path",
11
+ "/Volumes/PATRIOT/Codex/2026-10-17/c/work/hf-ald-release-20261023/native-source/Cargo.toml",
12
+ "--target",
13
+ "x86_64-unknown-linux-gnu",
14
+ "--release",
15
+ "--locked",
16
+ "--offline",
17
+ "--no-default-features",
18
+ "--features",
19
+ "cli",
20
+ "--bin",
21
+ "altd-sim"
22
+ ],
23
+ "environment": {
24
+ "CARGO_TARGET_DIR": "/Volumes/PATRIOT/Codex/2026-10-17/c/work/hf-ald-release-20261023/linux-target",
25
+ "CARGO_BUILD_JOBS": "2",
26
+ "CARGO_PROFILE_RELEASE_LTO": "false",
27
+ "CARGO_PROFILE_RELEASE_CODEGEN_UNITS": "16",
28
+ "CARGO_PROFILE_RELEASE_DEBUG": "0",
29
+ "CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER": "/Volumes/PATRIOT/ALD-TAO-lab/hf-winners-evaluation-v1.2-20261013/build/cross-tools/linux-linker",
30
+ "RUSTFLAGS": "--sysroot /Volumes/PATRIOT/ALD-TAO-lab/hf-winners-evaluation-v1.2-20261013/build/cross-sysroot -C target-cpu=x86-64"
31
+ },
32
+ "exit_code": 0,
33
+ "seconds": 8.920037874951959,
34
+ "scope": "Isolated cross-target; existing official Rust target and linker/sysroot read only",
35
+ "sha256": "225de9c2b7dd0d9cb11c2578f50fff8a34f4cf6223580035ab0fa64e700beac8",
36
+ "bytes": 3661976
37
+ },
38
+ "binary_sha256": "225de9c2b7dd0d9cb11c2578f50fff8a34f4cf6223580035ab0fa64e700beac8",
39
+ "native_library_tests": {
40
+ "passed": 88,
41
+ "ignored": 2
42
+ },
43
+ "cpu_recording_validation": {
44
+ "status": "pass",
45
+ "cases": [
46
+ {
47
+ "ticks": 300,
48
+ "samples": 51,
49
+ "seconds": 0.7552870421204716,
50
+ "old_physical_fields_exact": true,
51
+ "inference_ticks_current": true
52
+ },
53
+ {
54
+ "ticks": 900,
55
+ "samples": 151,
56
+ "seconds": 2.2923885830678046,
57
+ "old_physical_fields_exact": true,
58
+ "inference_ticks_current": true
59
+ }
60
+ ],
61
+ "five_second_prefix_exact": true,
62
+ "constant_commands_verified": true,
63
+ "constant_contacts": 743,
64
+ "scope": "Actual Linux x86_64 native binary in network-isolated Docker; exact comparison against previously downloaded hosted native states"
65
+ },
66
+ "cuda_library_changed": false,
67
+ "gpu_abi_changed": false,
68
+ "hosted_gpu_execution": "Not run for this candidate; requires separate quota-checked acceptance",
69
+ "scope": "Actual cached CPU inference telemetry and bounded single-pass CLI recording. Physics and evolution algorithms unchanged."
70
+ }
native/blackbox-source.tar.gz ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:56b43430c68b95bf7ac0d8312975c366c920f99b1653d790fb15b59453728e28
3
+ size 922923
native/pre-blackbox-binary-provenance.json ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "artifacts": {
3
+ "bin/altd-sim": {
4
+ "bytes": 3647808,
5
+ "sha256": "ce31f754f6b6f3afaf4dcc44c1e6fda3e6414eb2924fa167b8778523bcaf2070"
6
+ },
7
+ "bin/extract_saved_track": {
8
+ "bytes": 3247776,
9
+ "sha256": "3a7733c45b4301a786fcbfe92660a1c484749272da5f608d62f34878bd4ff31a"
10
+ },
11
+ "bin/libaltd_gpu.so": {
12
+ "bytes": 4711704,
13
+ "sha256": "3b1b88bccc06a21acc33ac4400af016d55a7e3d8727136a0c43b541f3c7887ca"
14
+ }
15
+ },
16
+ "build_receipt_path": "native/selective-freeze-build-receipt.json",
17
+ "build_receipt_sha256": "ed804b1cd49a9ba34abc6f7cadaf4fb97807e27f3d14af117f8292a2d3f2d172",
18
+ "compiler": "rustc 1.95.0 aarch64-apple-darwin -> x86_64-unknown-linux-gnu",
19
+ "historical_native_files": [
20
+ "native/analysis.patch",
21
+ "native/build-receipt.json",
22
+ "native/source-receipt.json"
23
+ ],
24
+ "linux_runtime_status": "hosted execution pending",
25
+ "retained_artifact_origins": {
26
+ "bin/extract_saved_track": {
27
+ "build_receipt_path": "IMPORTER_BUILD_RECEIPT.json",
28
+ "build_receipt_sha256": "4ba5c533cc617105478e4d85c83f456a7dfa68b1388049624619871ba9e42e9d",
29
+ "bytes": 3247776,
30
+ "compatibility_receipt_path": "native/build-receipt.json",
31
+ "compatibility_receipt_sha256": "559a7e4e382f9f7caa1c5ceb566a5a0bbefad2ed3a2e2cf604e31c9c3890c348",
32
+ "evidence_path": "IMPORTER_BUILD_RECEIPT.json",
33
+ "evidence_sha256": "4ba5c533cc617105478e4d85c83f456a7dfa68b1388049624619871ba9e42e9d",
34
+ "origin_type": "retained_verified_importer_binary",
35
+ "sha256": "3a7733c45b4301a786fcbfe92660a1c484749272da5f608d62f34878bd4ff31a",
36
+ "source_repository": "https://github.com/Zorro909/driving_sim_rs",
37
+ "source_revision": "d8ab74c25df70b6a86ed101080e33d5fb785ea6f"
38
+ },
39
+ "bin/libaltd_gpu.so": {
40
+ "build_receipt_path": "native/build-receipt.json",
41
+ "build_receipt_sha256": "559a7e4e382f9f7caa1c5ceb566a5a0bbefad2ed3a2e2cf604e31c9c3890c348",
42
+ "bytes": 4711704,
43
+ "origin_type": "retained_cuda_b90",
44
+ "patch_sha256": "42f79de67cb0734cffb2a7582f5479cab42ab82675884b8b42b9f158d46a98e8",
45
+ "sha256": "3b1b88bccc06a21acc33ac4400af016d55a7e3d8727136a0c43b541f3c7887ca",
46
+ "source_receipt_sha256": "36feba861501baf8672884476bbeed5e375254cbb4feffb9f4f90aa61a415a93",
47
+ "source_revision": "b90b8af06ffc4ea4e4fd703becd1107a48b8e5e0"
48
+ }
49
+ },
50
+ "schema": "ald-selective-freeze-binary-provenance-v1",
51
+ "source_base_revision": "b90b8af06ffc4ea4e4fd703becd1107a48b8e5e0",
52
+ "source_repository": "https://github.com/Zorro909/driving_sim_rs",
53
+ "source_snapshot_path": "native/selective-freeze-source.tar.gz",
54
+ "source_snapshot_sha256": "297d2ce34569994acd2a477e64c5315cb2081699b4333b8abdabb3ff7451d8db",
55
+ "physics_update": {
56
+ "upstream_version": "1.3.0",
57
+ "upstream_revision": "ab3ec67",
58
+ "local_additions_preserved": true,
59
+ "source_receipt": "native/physics-source-identities.json",
60
+ "status": "candidate; requires deployment and hosted app acceptance",
61
+ "artifacts": {
62
+ "bin/altd-sim": "792139f30bcfecf25f2d78595d2611234d30b0a254b5ece0ec587f1d27a80df2",
63
+ "bin/libaltd_gpu.so": "e5e9a61d863bc3b429af69a13cd8d50f63cad8984b3e6a9001ae342fc5981e05"
64
+ },
65
+ "source_archive": "native/physics-source.tar.gz",
66
+ "source_archive_sha256": "6abefb234de18dee58d69758c6cc8900f259993663ac37f90ce39aa114a30718",
67
+ "cuda_original_cases_passed": 57
68
+ }
69
+ }
replay.py CHANGED
@@ -1,11 +1,8 @@
1
- """Bounded, measured playback using the installed native benchmark command.
2
-
3
- Each sample is a deterministic fresh CPU evaluation of the same policy up to
4
- that tick. This is not a recording of a previous training generation. Native
5
- bench captures car state before turnover, accepts only positive tick counts,
6
- and disables wall/idle elimination. With population one its preserved parent
7
- is the supplied policy; every dump is checked against that exact parameter
8
- vector before any recording is returned.
9
  """
10
 
11
  import hashlib
@@ -132,7 +129,17 @@ def _parameter_bytes(values):
132
  return b''.join(struct.pack('!d', _number(value, 'policy parameter')) for value in values)
133
 
134
 
135
- def _frame(dump, tick, expected_parameters):
 
 
 
 
 
 
 
 
 
 
136
  agents = dump.get('agents')
137
  networks = dump.get('next_networks')
138
  if (not isinstance(agents, list) or len(agents) != 1 or not isinstance(agents[0], dict)
@@ -157,6 +164,23 @@ def _frame(dump, tick, expected_parameters):
157
  'vy': velocity[1],
158
  'active': agent['active'],
159
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
160
  for field in ('angular_velocity', 'boost_energy'):
161
  if field in agent:
162
  frame[field] = _number(agent[field], field)
@@ -236,21 +260,22 @@ def record_replay(track_bytes, network_bytes, *, binary, importer, scene_templat
236
  '--spawn-trace', spawn_path, '--population', '1', '--warmup-ticks', '0',
237
  '--seed', '0', '--spawn-index', '0', '--batch-count', '1', '--dump-state', str(dump_path),
238
  ]
239
- frames = []
240
- for tick in sample_ticks:
241
- # A successful command without a new dump must not reuse a prior
242
- # sample. A single file also bounds temporary storage independently
243
- # of the recording length.
244
- dump_path.unlink(missing_ok=True)
245
- _run(command + ['--ticks', str(tick)], work=work, env=environment,
246
- deadline=deadline, stage='evaluation')
247
- dump = _read_json(dump_path, MAX_DUMP_BYTES, 'car state')
248
- frames.append(_frame(dump, tick, expected_parameters))
249
- _remaining(deadline)
 
250
 
251
  result = {
252
  'schema': 'ald.recorded-replay',
253
- 'version': 1,
254
  'kind': 'fresh_cpu_evaluation',
255
  'physics_hz': 60,
256
  'sample_interval_ticks': SAMPLE_INTERVAL_TICKS,
@@ -268,7 +293,15 @@ def record_replay(track_bytes, network_bytes, *, binary, importer, scene_templat
268
  'population': 1,
269
  'warmup_ticks': 0,
270
  'policy_weights_verified': True,
271
- 'sampling_method': 'deterministic_cumulative_native_bench',
 
 
 
 
 
 
 
 
272
  'position_units': 'game_world_units',
273
  'velocity_units': 'game_world_units_per_second',
274
  'rotation_units': 'radians',
 
1
+ """Bounded native CPU replay with actual control and inference-cache telemetry.
2
+
3
+ One unchanged policy runs once. The native bench exports post-physics state
4
+ and its actual cached pre-physics inference inputs at each requested sample.
5
+ No sensor readings, commands or poses are reconstructed by this module.
 
 
 
6
  """
7
 
8
  import hashlib
 
129
  return b''.join(struct.pack('!d', _number(value, 'policy parameter')) for value in values)
130
 
131
 
132
+ def _controls(value, label):
133
+ fields = {'steering', 'acceleration', 'brake', 'handbrake', 'boost'}
134
+ if not isinstance(value, dict) or set(value) != fields:
135
+ raise ReplayError('Native replay returned invalid ' + label)
136
+ result = {key: _number(value[key], label) for key in sorted(fields)}
137
+ if any(abs(v) > 1 for v in result.values()):
138
+ raise ReplayError('Native replay returned out-of-range ' + label)
139
+ return result
140
+
141
+
142
+ def _frame(dump, tick, expected_parameters, *, sensor_count):
143
  agents = dump.get('agents')
144
  networks = dump.get('next_networks')
145
  if (not isinstance(agents, list) or len(agents) != 1 or not isinstance(agents[0], dict)
 
164
  'vy': velocity[1],
165
  'active': agent['active'],
166
  }
167
+ commands = _controls(agent.get('controls'), 'control commands')
168
+ applied = _controls(agent.get('applied_controls'), 'applied controls')
169
+ expected_applied = {key: max(0.0, value) if key in {'handbrake', 'boost'} else value
170
+ for key, value in commands.items()}
171
+ if applied != expected_applied:
172
+ raise ReplayError('Native replay control normalization does not match')
173
+ if 'decision' not in agent:
174
+ raise ReplayError('Native replay omitted its inference snapshot')
175
+ decision = agent['decision']
176
+ if decision is not None:
177
+ if (not isinstance(decision, dict) or set(decision) != {'tick', 'inputs'}
178
+ or type(decision['tick']) is not int or not 1 <= decision['tick'] <= tick
179
+ or not isinstance(decision['inputs'], list) or len(decision['inputs']) != sensor_count):
180
+ raise ReplayError('Native replay returned an invalid inference snapshot')
181
+ decision = {'tick': decision['tick'],
182
+ 'inputs': [_number(value, 'sensor input') for value in decision['inputs']]}
183
+ frame.update(controls=commands, applied_controls=applied, decision=decision)
184
  for field in ('angular_velocity', 'boost_energy'):
185
  if field in agent:
186
  frame[field] = _number(agent[field], field)
 
260
  '--spawn-trace', spawn_path, '--population', '1', '--warmup-ticks', '0',
261
  '--seed', '0', '--spawn-index', '0', '--batch-count', '1', '--dump-state', str(dump_path),
262
  ]
263
+ _run(command + ['--ticks', str(ticks), '--record-interval', str(SAMPLE_INTERVAL_TICKS)],
264
+ work=work, env=environment, deadline=deadline, stage='recording')
265
+ dump = _read_json(dump_path, MAX_DUMP_BYTES, 'car state')
266
+ samples = dump.get('replay_frames')
267
+ if (not isinstance(samples, list) or len(samples) != len(sample_ticks)
268
+ or any(not isinstance(sample, dict) or sample.get('tick') != tick
269
+ for sample, tick in zip(samples, sample_ticks))):
270
+ raise ReplayError('Native replay omitted its expected trace samples')
271
+ frames = [_frame({'agents': sample.get('agents'), 'next_networks': dump.get('next_networks')},
272
+ tick, expected_parameters, sensor_count=network['Shape'][0])
273
+ for sample, tick in zip(samples, sample_ticks)]
274
+ _remaining(deadline)
275
 
276
  result = {
277
  'schema': 'ald.recorded-replay',
278
+ 'version': 2,
279
  'kind': 'fresh_cpu_evaluation',
280
  'physics_hz': 60,
281
  'sample_interval_ticks': SAMPLE_INTERVAL_TICKS,
 
293
  'population': 1,
294
  'warmup_ticks': 0,
295
  'policy_weights_verified': True,
296
+ 'sampling_method': 'single_native_bench_trace',
297
+ 'telemetry': {
298
+ 'source': 'native_cached_inference',
299
+ 'state_phase': 'post_physics',
300
+ 'decision_phase': 'pre_physics_at_decision_tick',
301
+ 'sensors': template['Sensors'],
302
+ 'output_ids': template['Outputs'],
303
+ 'controls': 'raw_network_commands_and_native_normalized_controls',
304
+ },
305
  'position_units': 'game_world_units',
306
  'velocity_units': 'game_world_units_per_second',
307
  'rotation_units': 'radians',
server.py CHANGED
@@ -25,12 +25,16 @@ from portable_bundle import (BundleError, load_bundle, MAX_BUNDLE, MAX_NETWORK,
25
  ROOT=Path(__file__).resolve().parent
26
  EVOLUTION_SIDECAR=re.compile(r'^[a-z0-9][a-z0-9-]{0,63}-(formula|rally|snowmobile|truck)-[0-9]{8}T[0-9]{6}Z-[0-9a-f]{8}(?:-(fitness-winner|fastest-lap-winner|clean-laps-winner))?\.evolution$')
27
 
28
- def create_app(worker=run_reported,store=None,gpu_worker=None,track_library=None,require_analysis=False):
29
  app=create_api(store)
30
  admission=threading.BoundedSemaphore(1)
31
  leaderboard_admission=threading.BoundedSemaphore(1)
32
  bucket_admission=threading.BoundedSemaphore(1)
33
  library=track_library if track_library is not None else TrackLibrary(ROOT/'builtin_tracks')
 
 
 
 
34
 
35
  @app.middleware('http')
36
  async def bucket_no_store(request:Request, call_next):
@@ -392,8 +396,7 @@ def create_app(worker=run_reported,store=None,gpu_worker=None,track_library=None
392
  from replay import record_replay, ReplayError
393
  try:
394
  recording=await run_in_threadpool(record_replay,track,network,
395
- binary=ROOT/'bin/altd-sim',importer=ROOT/'bin/extract_saved_track',
396
- scene_template=ROOT/'assets/formula_template.json',ticks=body['ticks'])
397
  recording['build']=build_identity()
398
  return JSONResponse(recording,headers={'Cache-Control':'no-store','X-Content-Type-Options':'nosniff'})
399
  except (TimeoutError,subprocess.TimeoutExpired):
 
25
  ROOT=Path(__file__).resolve().parent
26
  EVOLUTION_SIDECAR=re.compile(r'^[a-z0-9][a-z0-9-]{0,63}-(formula|rally|snowmobile|truck)-[0-9]{8}T[0-9]{6}Z-[0-9a-f]{8}(?:-(fitness-winner|fastest-lap-winner|clean-laps-winner))?\.evolution$')
27
 
28
+ def create_app(worker=run_reported,store=None,gpu_worker=None,track_library=None,require_analysis=False,replay_tools=None):
29
  app=create_api(store)
30
  admission=threading.BoundedSemaphore(1)
31
  leaderboard_admission=threading.BoundedSemaphore(1)
32
  bucket_admission=threading.BoundedSemaphore(1)
33
  library=track_library if track_library is not None else TrackLibrary(ROOT/'builtin_tracks')
34
+ # Trusted application configuration only; request bodies never select tools.
35
+ replay_tools = dict(replay_tools) if replay_tools is not None else dict(
36
+ binary=ROOT/'bin/altd-sim', importer=ROOT/'bin/extract_saved_track',
37
+ scene_template=ROOT/'assets/formula_template.json')
38
 
39
  @app.middleware('http')
40
  async def bucket_no_store(request:Request, call_next):
 
396
  from replay import record_replay, ReplayError
397
  try:
398
  recording=await run_in_threadpool(record_replay,track,network,
399
+ **replay_tools,ticks=body['ticks'])
 
400
  recording['build']=build_identity()
401
  return JSONResponse(recording,headers={'Cache-Control':'no-store','X-Content-Type-Options':'nosniff'})
402
  except (TimeoutError,subprocess.TimeoutExpired):
track-map.js CHANGED
@@ -212,8 +212,56 @@
212
  if(typeof value!=='string'||!/^[a-f0-9]{64}$/i.test(value))throw Error(label+' must be a SHA-256 hash');
213
  return value.toLowerCase();
214
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
215
  function validateRecording(payload,expectedTrackSha,expectedNetworkSha){
216
- if(!payload||payload.schema!=='ald.recorded-replay'||payload.version!==1||payload.kind!=='fresh_cpu_evaluation')
217
  throw Error('This file is not a supported recorded CPU evaluation');
218
  if(payload.physics_hz!==60||payload.control_hz!==60||payload.sample_interval_ticks!==6||payload.first_sample_tick!==1||
219
  payload.execution_backend!=='cpu'||payload.math_profile!=='proton'||payload.collision_elimination!==false||payload.idle_elimination!==false)
@@ -229,6 +277,7 @@
229
  if(expectedTicks[expectedTicks.length-1]!==ticks)expectedTicks.push(ticks);
230
  if(!Array.isArray(payload.frames)||payload.frames.length!==expectedTicks.length)
231
  throw Error('Recording is missing its expected native samples');
 
232
  const frames=payload.frames.map((frame,index)=>{
233
  if(!frame||frame.tick!==expectedTicks[index]||typeof frame.active!=='boolean')throw Error('Recorded frame ticks or active state are invalid');
234
  const copy={tick:frame.tick,active:frame.active};
@@ -242,9 +291,27 @@
242
  if((key==='collision_count'||key==='update_count')&&(!Number.isInteger(frame[key])||frame[key]<0))throw Error('Recorded '+key+' is invalid');
243
  copy[key]=frame[key];
244
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
245
  return copy;
246
  });
247
- return {schema:payload.schema,version:1,kind:payload.kind,physics_hz:60,control_hz:60,sample_interval_ticks:6,
 
 
 
 
248
  first_sample_tick:1,track_sha256:trackSha,network_sha256:networkSha,vehicle_type:payload.vehicle_type,
249
  requested_ticks:ticks,execution_backend:'cpu',math_profile:'proton',collision_elimination:false,idle_elimination:false,frames};
250
  }
@@ -276,6 +343,7 @@
276
  let playSpeed=Math.max(0.25,Math.min(4,Number(element('replay_speed')?.value)||1));
277
  let cameraMode=element('replay_camera')?.value==='follow'?'follow':'full';
278
  const layers={outline:true,line:true,hud:true};
 
279
  const noRecording='No replay recorded. The map shows the selected track and its saved starting point.';
280
  const summaryOnly='No replay recorded. This run contains summary measurements, not vehicle positions or control samples.';
281
  function setText(id,text){const node=element(id);if(node&&node.textContent!==text)node.textContent=text;}
@@ -283,20 +351,48 @@
283
  const last=recording?.frames[recording.frames.length-1].tick;
284
  const play=element('replay_play');
285
  if(play){play.disabled=!recording||cursor>=last;play.textContent=playing?'Pause':'Play';}
286
- for(const id of ['replay_reset','replay_scrub','replay_speed','replay_camera','replay_layer_outline','replay_layer_line','replay_layer_hud']){
287
  const node=element(id);if(node)node.disabled=!recording;
288
  }
 
 
 
 
289
  const scrub=element('replay_scrub');
290
  if(scrub){scrub.min='1';scrub.max=String(last??1);scrub.step='1';scrub.value=String(Math.round(cursor));}
291
  if(!recording){
292
  setText('replay_status',reason||(hasRunSummary?summaryOnly:noRecording));
293
  setText('replay_time_label','No recorded samples');
294
- setText('replay_readout','Record a drive to inspect position and speed. Controls and sensors are not recorded.');
295
  }else{
296
  const state=cursor>=last?'Finished. Use Restart to view it again.':playing?'Playing.':'Paused.';
297
- setText('replay_status',`Fresh recorded CPU evaluation · ${recording.frames.length} samples · 60 Hz physics and controls · 10 Hz recording. ${state}`);
298
  }
299
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
300
  function stopPlayback(){
301
  if(animId!==null&&typeof root?.cancelAnimationFrame==='function')root.cancelAnimationFrame(animId);
302
  animId=null;playing=false;lastFrameTime=null;
@@ -305,7 +401,8 @@
305
  function draw(){
306
  if(!currentTrack){renderEmpty();return;}
307
  const ctx=canvas.getContext('2d'),view=viewport(canvas,currentTrack);
308
- const state=recording?sampleRecording(recording,cursor):null;
 
309
  const position=state?worldPoint(view,state.x,state.y):null;
310
  ctx.clearRect(0,0,canvas.width,canvas.height);ctx.fillStyle='#0c1926';ctx.fillRect(0,0,canvas.width,canvas.height);
311
  ctx.save();
@@ -324,20 +421,20 @@
324
  }
325
  ctx.restore();
326
  if(state){
327
- const frame=state.frame,speed=Math.hypot(frame.vx,frame.vy)/15*3.6;
328
  const contacts=frame.collision_count===undefined?'unavailable':String(frame.collision_count);
329
  setText('replay_time_label',`${(cursor/60).toFixed(2)}s / ${(recording.requested_ticks/60).toFixed(2)}s · Tick ${Math.round(cursor)} · Recorded sample ${frame.tick}`);
330
- setText('replay_readout',`Recorded sample tick ${frame.tick} (${(frame.tick/60).toFixed(2)}s). Speed ${speed.toFixed(1)} km/h, derived from recorded velocity. Position (${frame.x.toFixed(2)}, ${frame.y.toFixed(2)}). Contacts ${contacts}. ${frame.active?'Active':'Inactive'} at this sample. Controls and sensors unavailable.`);
331
  if(layers.hud){
332
  ctx.save();ctx.fillStyle='rgba(9,17,27,0.88)';ctx.beginPath();ctx.roundRect(12,12,310,80,8);ctx.fill();
333
  ctx.fillStyle='#62dfb1';ctx.font='700 12px system-ui,sans-serif';ctx.fillText('RECORDED CPU EVALUATION',24,33);
334
  ctx.fillStyle='#e5edf5';ctx.font='600 12px ui-monospace,monospace';ctx.fillText(`Sample ${frame.tick} · ${speed.toFixed(1)} km/h from velocity`,24,55);
335
- ctx.fillStyle='#b4c5d5';ctx.font='12px system-ui,sans-serif';ctx.fillText('Controls and sensors unavailable',24,77);ctx.restore();
336
  }
337
  }
338
  }
339
  function clearRecording(reason){
340
- const hadRecording=recording!==null;stopPlayback();recording=null;cursor=1;
341
  if(hadRecording)draw();syncControls(reason);
342
  }
343
  function step(now){
@@ -364,6 +461,9 @@
364
  if(!recording)return;const value=Number(element('replay_scrub').value);if(!Number.isFinite(value))return;
365
  stopPlayback();cursor=Math.max(recording.frames[0].tick,Math.min(recording.frames[recording.frames.length-1].tick,value));draw();syncControls();
366
  });
 
 
 
367
  on('replay_speed','change',()=>{playSpeed=Math.max(0.25,Math.min(4,Number(element('replay_speed').value)||1));});
368
  on('replay_camera','change',()=>{cameraMode=element('replay_camera').value==='follow'?'follow':'full';draw();});
369
  for(const key of ['outline','line','hud']){
@@ -413,7 +513,7 @@
413
  const next=validateRecording(payload,expectedTrackSha,expectedNetworkSha);
414
  if(!currentTrack||!currentTrackSha)throw Error('The selected track must finish loading and hash verification before replay');
415
  if(next.track_sha256!==currentTrackSha)throw Error('The recording belongs to a different selected track');
416
- recording=next;cursor=next.frames[0].tick;draw();syncControls();
417
  return {frames:next.frames.length,first_tick:cursor,last_tick:next.frames[next.frames.length-1].tick};
418
  }catch(error){clearRecording('Replay unavailable: '+error.message);throw error;}
419
  },
@@ -422,5 +522,5 @@
422
  bind();syncControls();document.addEventListener('track-library-change',refresh);refresh();
423
  return controller;
424
  }
425
- return {mount,model,decode,render,validateRecording,sampleRecording};
426
  });
 
212
  if(typeof value!=='string'||!/^[a-f0-9]{64}$/i.test(value))throw Error(label+' must be a SHA-256 hash');
213
  return value.toLowerCase();
214
  }
215
+ const CONTROL_KEYS=['steering','acceleration','handbrake','brake','boost'];
216
+ const SCALAR_SENSORS=['speed','velocityFront','velocitySide','angularVelocity','wheelAngle','boostCapacity','correctDirection'];
217
+ function exactKeys(value,keys,label){
218
+ if(!value||typeof value!=='object'||Array.isArray(value)||Object.keys(value).sort().join()!==[...keys].sort().join())throw Error('Invalid '+label);
219
+ }
220
+ function finiteValue(value,label,limit=1e12){if(typeof value!=='number'||!Number.isFinite(value)||Math.abs(value)>limit)throw Error('Invalid '+label);return value;}
221
+ function sensorDescriptor(sensor){
222
+ const kind=sensor?.$type,keys=SCALAR_SENSORS.includes(kind)?[]:({raycast:['Degrees','Length'],accelerationFront:['MaxAcceleration'],accelerationSide:['MaxAcceleration'],distanceFromWall:['MaxDistance'],trackCurvature:['MinLookaheadDistance','MaxLookaheadDistance'],grip:['PositionOffset']})[kind];
223
+ if(!keys)throw Error('Unsupported recorded sensor');exactKeys(sensor,['$type',...keys],'sensor descriptor');
224
+ const clean={$type:kind};
225
+ for(const key of keys){
226
+ if(key==='PositionOffset'){exactKeys(sensor[key],['X','Y'],'grip offset');clean[key]={X:finiteValue(sensor[key].X,'grip X',1e6),Y:finiteValue(sensor[key].Y,'grip Y',1e6)};}
227
+ else clean[key]=finiteValue(sensor[key],'sensor '+key,1e6);
228
+ }
229
+ if(kind==='raycast'&&(Math.abs(clean.Degrees)>360||clean.Length<1||clean.Length>10000))throw Error('Invalid ray parameters');
230
+ if(keys.includes('MaxAcceleration')&&clean.MaxAcceleration<=0||kind==='distanceFromWall'&&clean.MaxDistance<=0)throw Error('Invalid sensor normalization');
231
+ return clean;
232
+ }
233
+ function recordingTelemetry(payload){
234
+ if(payload.version===1)return null;
235
+ if(payload.policy_weights_verified!==true||payload.sampling_method!=='single_native_bench_trace'||payload.population!==1||payload.warmup_ticks!==0||payload.seed!==0)throw Error('Unsupported native recording conditions');
236
+ const value=payload.telemetry;exactKeys(value,['source','state_phase','decision_phase','sensors','output_ids','controls'],'telemetry');
237
+ if(value.source!=='native_cached_inference'||value.state_phase!=='post_physics'||value.decision_phase!=='pre_physics_at_decision_tick'||value.controls!=='raw_network_commands_and_native_normalized_controls')throw Error('Unsupported telemetry phases');
238
+ if(!Array.isArray(value.sensors)||!value.sensors.length||value.sensors.length>20)throw Error('Invalid recorded sensor count');
239
+ const sensors=value.sensors.map(sensorDescriptor),ids=value.output_ids;
240
+ if(sensors.filter(x=>x.$type==='raycast').length>13||sensors.filter(x=>x.$type!=='raycast').length>7)throw Error('Invalid sensor layout');
241
+ if(!Array.isArray(ids)||!ids.length||ids.length>5||new Set(ids).size!==ids.length||ids.some(x=>!Number.isInteger(x)||x<0||x>4)||!ids.includes(0)||!ids.includes(1)||payload.vehicle_type===2&&ids.includes(2))throw Error('Invalid recorded output slots');
242
+ return {...value,sensors,output_ids:[...ids]};
243
+ }
244
+ function recordedControls(value,label){
245
+ exactKeys(value,CONTROL_KEYS,label);return Object.fromEntries(CONTROL_KEYS.map(key=>[key,finiteValue(value[key],label,1)]));
246
+ }
247
+ function recordingEvents(recording){
248
+ const result=[];
249
+ recording.frames.forEach((frame,index)=>{
250
+ const previous=recording.frames[index-1],from=previous?.tick??frame.tick;
251
+ if(frame.collision_count!==undefined){
252
+ const count=previous?.collision_count===undefined?frame.collision_count:frame.collision_count-previous.collision_count;
253
+ if(count>0)result.push({from_tick:from,to_tick:frame.tick,kind:'contacts',count,label:previous?`${count} contact(s) recorded in (${from}, ${frame.tick}]`:`${count} contact(s) at first sample ${frame.tick}`});
254
+ }
255
+ if(previous&&previous.active!==frame.active)result.push({from_tick:from,to_tick:frame.tick,kind:'active',label:`${frame.active?'Active':'Inactive'} by sample ${frame.tick}; changed in (${from}, ${frame.tick}]`});
256
+ });return result;
257
+ }
258
+ function adjacentSampleTick(recording,tick,direction){
259
+ if(direction!==-1&&direction!==1||!Number.isFinite(tick))throw Error('Invalid sample step');
260
+ const frames=recording.frames;
261
+ return direction>0?(frames.find(frame=>frame.tick>tick)?.tick??frames[frames.length-1].tick):([...frames].reverse().find(frame=>frame.tick<tick)?.tick??frames[0].tick);
262
+ }
263
  function validateRecording(payload,expectedTrackSha,expectedNetworkSha){
264
+ if(!payload||payload.schema!=='ald.recorded-replay'||![1,2].includes(payload.version)||payload.kind!=='fresh_cpu_evaluation')
265
  throw Error('This file is not a supported recorded CPU evaluation');
266
  if(payload.physics_hz!==60||payload.control_hz!==60||payload.sample_interval_ticks!==6||payload.first_sample_tick!==1||
267
  payload.execution_backend!=='cpu'||payload.math_profile!=='proton'||payload.collision_elimination!==false||payload.idle_elimination!==false)
 
277
  if(expectedTicks[expectedTicks.length-1]!==ticks)expectedTicks.push(ticks);
278
  if(!Array.isArray(payload.frames)||payload.frames.length!==expectedTicks.length)
279
  throw Error('Recording is missing its expected native samples');
280
+ const telemetry=recordingTelemetry(payload);
281
  const frames=payload.frames.map((frame,index)=>{
282
  if(!frame||frame.tick!==expectedTicks[index]||typeof frame.active!=='boolean')throw Error('Recorded frame ticks or active state are invalid');
283
  const copy={tick:frame.tick,active:frame.active};
 
291
  if((key==='collision_count'||key==='update_count')&&(!Number.isInteger(frame[key])||frame[key]<0))throw Error('Recorded '+key+' is invalid');
292
  copy[key]=frame[key];
293
  }
294
+ if(frame.metrics!==undefined){
295
+ if(!frame.metrics||typeof frame.metrics!=='object'||Array.isArray(frame.metrics)||Object.keys(frame.metrics).length>64)throw Error('Invalid recorded metrics');
296
+ copy.metrics=Object.fromEntries(Object.entries(frame.metrics).map(([key,value])=>{if(!key.length||key.length>96)throw Error('Invalid metric name');return [key,value===null?null:finiteValue(value,'metric')];}));
297
+ }
298
+ if(telemetry){
299
+ copy.controls=recordedControls(frame.controls,'control commands');copy.applied_controls=recordedControls(frame.applied_controls,'applied controls');
300
+ for(const key of CONTROL_KEYS){const expected=['boost','handbrake'].includes(key)?Math.max(0,copy.controls[key]):copy.controls[key];if(copy.applied_controls[key]!==expected)throw Error('Control normalization differs');}
301
+ if(frame.decision===null)copy.decision=null;
302
+ else{
303
+ exactKeys(frame.decision,['tick','inputs'],'recorded decision');
304
+ if(!Number.isInteger(frame.decision.tick)||frame.decision.tick<1||frame.decision.tick>frame.tick||!Array.isArray(frame.decision.inputs)||frame.decision.inputs.length!==telemetry.sensors.length)throw Error('Invalid decision tick or sensor vector');
305
+ copy.decision={tick:frame.decision.tick,inputs:frame.decision.inputs.map(value=>finiteValue(value,'sensor input'))};
306
+ }
307
+ }
308
  return copy;
309
  });
310
+ for(let i=1;i<frames.length;i++){
311
+ if(frames[i].collision_count!==undefined&&frames[i-1].collision_count!==undefined&&frames[i].collision_count<frames[i-1].collision_count)throw Error('Contact counter moved backwards');
312
+ if(telemetry&&frames[i-1].decision&&(frames[i].decision===null||frames[i].decision.tick<frames[i-1].decision.tick))throw Error('Decision clock moved backwards');
313
+ }
314
+ return {schema:payload.schema,version:payload.version,telemetry,kind:payload.kind,physics_hz:60,control_hz:60,sample_interval_ticks:6,
315
  first_sample_tick:1,track_sha256:trackSha,network_sha256:networkSha,vehicle_type:payload.vehicle_type,
316
  requested_ticks:ticks,execution_backend:'cpu',math_profile:'proton',collision_elimination:false,idle_elimination:false,frames};
317
  }
 
343
  let playSpeed=Math.max(0.25,Math.min(4,Number(element('replay_speed')?.value)||1));
344
  let cameraMode=element('replay_camera')?.value==='follow'?'follow':'full';
345
  const layers={outline:true,line:true,hud:true};
346
+ let smoothPose=false,blackboxTick=null;
347
  const noRecording='No replay recorded. The map shows the selected track and its saved starting point.';
348
  const summaryOnly='No replay recorded. This run contains summary measurements, not vehicle positions or control samples.';
349
  function setText(id,text){const node=element(id);if(node&&node.textContent!==text)node.textContent=text;}
 
351
  const last=recording?.frames[recording.frames.length-1].tick;
352
  const play=element('replay_play');
353
  if(play){play.disabled=!recording||cursor>=last;play.textContent=playing?'Pause':'Play';}
354
+ for(const id of ['replay_reset','replay_scrub','replay_speed','replay_camera','replay_layer_outline','replay_layer_line','replay_layer_hud','replay_interpolate','replay_prev','replay_next','replay_event']){
355
  const node=element(id);if(node)node.disabled=!recording;
356
  }
357
+ if(element('replay_prev'))element('replay_prev').disabled=!recording||cursor<=recording.frames[0].tick;
358
+ if(element('replay_next'))element('replay_next').disabled=!recording||cursor>=last;
359
+ if(element('replay_event'))element('replay_event').disabled=!recording||!recordingEvents(recording).length;
360
+ if(element('replay_blackbox'))element('replay_blackbox').hidden=!recording;
361
  const scrub=element('replay_scrub');
362
  if(scrub){scrub.min='1';scrub.max=String(last??1);scrub.step='1';scrub.value=String(Math.round(cursor));}
363
  if(!recording){
364
  setText('replay_status',reason||(hasRunSummary?summaryOnly:noRecording));
365
  setText('replay_time_label','No recorded samples');
366
+ setText('replay_readout','Record a drive to inspect position and speed. Native controls and sensor inputs appear after a version 2 recording is loaded.');
367
  }else{
368
  const state=cursor>=last?'Finished. Use Restart to view it again.':playing?'Playing.':'Paused.';
369
+ setText('replay_status',`Fresh recorded CPU evaluation · ${recording.frames.length} samples · 60 Hz physics and controls · 10 Hz recording. ${smoothPose?'Pose interpolation on.':'Measured sample poses.'} ${state}`);
370
  }
371
  }
372
+ function rows(id,entries){
373
+ const body=element(id);if(!body)return;
374
+ const nodes=entries.map(cells=>{const row=document.createElement('tr');cells.forEach((value,index)=>{const cell=document.createElement(index===0?'th':'td');cell.textContent=String(value);row.append(cell);});return row;});body.replaceChildren(...nodes);
375
+ }
376
+ function blackbox(frame){
377
+ if(blackboxTick===frame.tick)return;blackboxTick=frame.tick;
378
+ const number=value=>value===undefined||value===null?'Unavailable':typeof value==='number'?Number(value.toPrecision(8)).toString():String(value);
379
+ const decision=frame.decision;
380
+ setText('blackbox_phase',`Post-physics snapshot: tick ${frame.tick}. ${decision?`Native decision: tick ${decision.tick}, pre-physics${decision.tick<frame.tick?' (held from an earlier tick)':''}.`:recording.telemetry?'No inference captured before this snapshot.':'Legacy recording: controls and sensors unavailable.'}`);
381
+ rows('blackbox_state',[
382
+ ['Snapshot time',(frame.tick/60).toFixed(3)+' s'],['Position X / Y',number(frame.x)+' / '+number(frame.y)+' game units'],
383
+ ['Velocity X / Y',number(frame.vx)+' / '+number(frame.vy)+' game units/s'],['Speed',number(Math.hypot(frame.vx,frame.vy))+' game units/s'],
384
+ ['Heading',number(frame.rotation)+' rad'],['Angular velocity',number(frame.angular_velocity)+' rad/s'],['Boost energy',number(frame.boost_energy)],
385
+ ['Physical contacts',number(frame.collision_count)],['Active',frame.active?'Yes':'No'],['Statistics updates',number(frame.update_count)]
386
+ ]);
387
+ rows('blackbox_controls',recording.telemetry?CONTROL_KEYS.map((key,index)=>[key,number(frame.controls[key]),number(frame.applied_controls[key]),recording.telemetry.output_ids.includes(index)?'Policy output':'Native default (no output slot)']):[['Unavailable','Not captured in this recording','Unavailable','Unavailable']]);
388
+ rows('blackbox_inputs',recording.telemetry?recording.telemetry.sensors.map((sensor,index)=>[index,sensor.$type,JSON.stringify(Object.fromEntries(Object.entries(sensor).filter(([key])=>key!=='$type'))),decision?number(decision.inputs[index]):'Not captured yet']):[['Unavailable','Legacy recording','No input capture','Unavailable']]);
389
+ rows('blackbox_metrics',Object.entries(frame.metrics??{}).map(([key,value])=>[key,number(value)]));
390
+ }
391
+ function eventOptions(){
392
+ const select=element('replay_event');if(!select)return;select.replaceChildren();
393
+ const empty=document.createElement('option');empty.value='';empty.textContent=recording?'Choose contact / active-state interval':'No recording';select.append(empty);
394
+ if(recording)recordingEvents(recording).forEach(event=>{const option=document.createElement('option');option.value=String(event.to_tick);option.textContent=event.label;select.append(option);});
395
+ }
396
  function stopPlayback(){
397
  if(animId!==null&&typeof root?.cancelAnimationFrame==='function')root.cancelAnimationFrame(animId);
398
  animId=null;playing=false;lastFrameTime=null;
 
401
  function draw(){
402
  if(!currentTrack){renderEmpty();return;}
403
  const ctx=canvas.getContext('2d'),view=viewport(canvas,currentTrack);
404
+ let state=recording?sampleRecording(recording,cursor):null;
405
+ if(state&&!smoothPose)state={...state,x:state.frame.x,y:state.frame.y,rotation:state.frame.rotation};
406
  const position=state?worldPoint(view,state.x,state.y):null;
407
  ctx.clearRect(0,0,canvas.width,canvas.height);ctx.fillStyle='#0c1926';ctx.fillRect(0,0,canvas.width,canvas.height);
408
  ctx.save();
 
421
  }
422
  ctx.restore();
423
  if(state){
424
+ const frame=state.frame;blackbox(frame);const speed=Math.hypot(frame.vx,frame.vy)/15*3.6;
425
  const contacts=frame.collision_count===undefined?'unavailable':String(frame.collision_count);
426
  setText('replay_time_label',`${(cursor/60).toFixed(2)}s / ${(recording.requested_ticks/60).toFixed(2)}s · Tick ${Math.round(cursor)} · Recorded sample ${frame.tick}`);
427
+ setText('replay_readout',`Recorded sample tick ${frame.tick} (${(frame.tick/60).toFixed(2)}s). Speed ${speed.toFixed(1)} km/h, derived from recorded velocity. Position (${frame.x.toFixed(2)}, ${frame.y.toFixed(2)}). Contacts ${contacts}. ${frame.active?'Active':'Inactive'} at this sample. ${frame.decision?'Native controls and inputs captured at tick '+frame.decision.tick+'.':'No captured decision at this sample.'}`);
428
  if(layers.hud){
429
  ctx.save();ctx.fillStyle='rgba(9,17,27,0.88)';ctx.beginPath();ctx.roundRect(12,12,310,80,8);ctx.fill();
430
  ctx.fillStyle='#62dfb1';ctx.font='700 12px system-ui,sans-serif';ctx.fillText('RECORDED CPU EVALUATION',24,33);
431
  ctx.fillStyle='#e5edf5';ctx.font='600 12px ui-monospace,monospace';ctx.fillText(`Sample ${frame.tick} · ${speed.toFixed(1)} km/h from velocity`,24,55);
432
+ ctx.fillStyle='#b4c5d5';ctx.font='12px system-ui,sans-serif';ctx.fillText(frame.decision?'Decision tick '+frame.decision.tick+' · native controls + inputs':'No captured decision at this sample',24,77);ctx.restore();
433
  }
434
  }
435
  }
436
  function clearRecording(reason){
437
+ const hadRecording=recording!==null;stopPlayback();recording=null;cursor=1;blackboxTick=null;eventOptions();
438
  if(hadRecording)draw();syncControls(reason);
439
  }
440
  function step(now){
 
461
  if(!recording)return;const value=Number(element('replay_scrub').value);if(!Number.isFinite(value))return;
462
  stopPlayback();cursor=Math.max(recording.frames[0].tick,Math.min(recording.frames[recording.frames.length-1].tick,value));draw();syncControls();
463
  });
464
+ for(const [id,direction]of [['replay_prev',-1],['replay_next',1]])on(id,'click',()=>{if(!recording)return;stopPlayback();cursor=adjacentSampleTick(recording,cursor,direction);draw();syncControls();});
465
+ on('replay_event','change',()=>{if(!recording||!element('replay_event').value)return;stopPlayback();cursor=Number(element('replay_event').value);draw();syncControls();});
466
+ on('replay_interpolate','change',()=>{smoothPose=element('replay_interpolate').checked;draw();syncControls();});
467
  on('replay_speed','change',()=>{playSpeed=Math.max(0.25,Math.min(4,Number(element('replay_speed').value)||1));});
468
  on('replay_camera','change',()=>{cameraMode=element('replay_camera').value==='follow'?'follow':'full';draw();});
469
  for(const key of ['outline','line','hud']){
 
513
  const next=validateRecording(payload,expectedTrackSha,expectedNetworkSha);
514
  if(!currentTrack||!currentTrackSha)throw Error('The selected track must finish loading and hash verification before replay');
515
  if(next.track_sha256!==currentTrackSha)throw Error('The recording belongs to a different selected track');
516
+ recording=next;blackboxTick=null;cursor=next.frames[0].tick;eventOptions();draw();syncControls();
517
  return {frames:next.frames.length,first_tick:cursor,last_tick:next.frames[next.frames.length-1].tick};
518
  }catch(error){clearRecording('Replay unavailable: '+error.message);throw error;}
519
  },
 
522
  bind();syncControls();document.addEventListener('track-library-change',refresh);refresh();
523
  return controller;
524
  }
525
+ return {mount,model,decode,render,validateRecording,sampleRecording,recordingEvents,adjacentSampleTick};
526
  });