TiGa-RCE commited on
Commit
46ae7f5
·
verified ·
1 Parent(s): 2a138ca

Add selective input, layer and output freezing

Browse files
.gitattributes CHANGED
@@ -1 +1,2 @@
1
  bin/* 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
BINARY_PROVENANCE.json CHANGED
@@ -1 +1,55 @@
1
- {"artifact_origins":{"bin/altd-sim":{"build_receipt_path":"native/build-receipt.json","build_receipt_sha256":"559a7e4e382f9f7caa1c5ceb566a5a0bbefad2ed3a2e2cf604e31c9c3890c348","bytes":3604272,"origin_type":"local_linux_build","patch_sha256":"42f79de67cb0734cffb2a7582f5479cab42ab82675884b8b42b9f158d46a98e8","sha256":"3aa1d364e0117f553a52404ae336efcfebd827fc0ca347e811196cbe31e32849","source_receipt_sha256":"36feba861501baf8672884476bbeed5e375254cbb4feffb9f4f90aa61a415a93","source_revision":"b90b8af06ffc4ea4e4fd703becd1107a48b8e5e0"},"bin/extract_saved_track":{"build_receipt_path":"IMPORTER_BUILD_RECEIPT.json","build_receipt_sha256":"4ba5c533cc617105478e4d85c83f456a7dfa68b1388049624619871ba9e42e9d","bytes":3247776,"compatibility_receipt_path":"native/build-receipt.json","compatibility_receipt_sha256":"559a7e4e382f9f7caa1c5ceb566a5a0bbefad2ed3a2e2cf604e31c9c3890c348","evidence_path":"IMPORTER_BUILD_RECEIPT.json","evidence_sha256":"4ba5c533cc617105478e4d85c83f456a7dfa68b1388049624619871ba9e42e9d","origin_type":"retained_verified_importer_binary","sha256":"3a7733c45b4301a786fcbfe92660a1c484749272da5f608d62f34878bd4ff31a","source_repository":"https://github.com/Zorro909/driving_sim_rs","source_revision":"d8ab74c25df70b6a86ed101080e33d5fb785ea6f"},"bin/libaltd_gpu.so":{"build_receipt_path":"native/build-receipt.json","build_receipt_sha256":"559a7e4e382f9f7caa1c5ceb566a5a0bbefad2ed3a2e2cf604e31c9c3890c348","bytes":4711704,"origin_type":"retained_cuda_b90","patch_sha256":"42f79de67cb0734cffb2a7582f5479cab42ab82675884b8b42b9f158d46a98e8","sha256":"3b1b88bccc06a21acc33ac4400af016d55a7e3d8727136a0c43b541f3c7887ca","source_receipt_sha256":"36feba861501baf8672884476bbeed5e375254cbb4feffb9f4f90aa61a415a93","source_revision":"b90b8af06ffc4ea4e4fd703becd1107a48b8e5e0"}},"artifacts":{"bin/altd-sim":{"bytes":3604272,"sha256":"3aa1d364e0117f553a52404ae336efcfebd827fc0ca347e811196cbe31e32849"},"bin/extract_saved_track":{"bytes":3247776,"sha256":"3a7733c45b4301a786fcbfe92660a1c484749272da5f608d62f34878bd4ff31a"},"bin/libaltd_gpu.so":{"bytes":4711704,"sha256":"3b1b88bccc06a21acc33ac4400af016d55a7e3d8727136a0c43b541f3c7887ca"}},"build_receipt":"native/build-receipt.json","build_receipt_path":"native/build-receipt.json","build_receipt_sha256":"559a7e4e382f9f7caa1c5ceb566a5a0bbefad2ed3a2e2cf604e31c9c3890c348","importer_source_revision":"d8ab74c25df70b6a86ed101080e33d5fb785ea6f","native_patch_sha256":"42f79de67cb0734cffb2a7582f5479cab42ab82675884b8b42b9f158d46a98e8","note":"The simulator is a fresh Linux build from b90 plus the hashed local analysis patch. The CUDA library is retained b90 and has layout ABI evidence only; this package does not claim local GPU kernel execution. The track importer remains separately identified with bounded compatibility evidence.","source_repository":"https://github.com/Zorro909/driving_sim_rs","source_revision":"b90b8af06ffc4ea4e4fd703becd1107a48b8e5e0"}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ }
FRONTEND_SOURCE.json CHANGED
@@ -1 +1,23 @@
1
- {"base_provenance":{"output_sha256":"a145fbb303a85c728a530d98fbea998677c1c62a2589c46af9b8b287e4ce1f48","scope":"Frontend only; no engine, private data, track assets, API calls or storage copied","source":"Runner r14 single-engine browser UI; selected .track tile renderer added from simulator atlas","source_sha256":"65d1e5f2c4e19b4951b828e82510005ab99a5270cf3dcb9f4eaa0fa1af8c40f8"},"identity_note":"The historical source fields describe the base frontend; local packaged file hashes describe this candidate's derived frontend.","local_customization_id":"v1.2-winners-frozen-evaluation","packaged_frontend_files":{"assets/track-atlas.json":"d97c8900e3e5fb17734b5bd61d1f4f4b196d9be30af9848e2e273ae7e4079ae4","client.js":"96426083c2987332d3393f77bc30438237b186ef0465263f16ba79b304433453","help.html":"ea4b9b0a391f956458e745d2579cdeb89946af0d80bbfbf63cf2e07eb8de2eb3","hf-auth.js":"3f3938bbc0935e4e9230c094029ef46e03beea74be199887c50e053e03dafcfe","index.html":"7c79a0c56e619ae2e86951e805c4e13b76035c618b423278aee69c8e45c51d4d","track-library.js":"351ec4c026b49420ce963f4310cb000d9e987fd28e6dac5ecd0176509340f6e6","track-map.js":"ab5374aa49c7ccec90a787ee8c56cd71beb56b903bf2bbc322783e6f43c009f0"},"packaged_frontend_sha256":"40653451e93118ceb69174e7dee0bee6f4da02669540db7de9f508b981995e2d"}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "base_provenance": {
3
+ "output_sha256": "a145fbb303a85c728a530d98fbea998677c1c62a2589c46af9b8b287e4ce1f48",
4
+ "scope": "Frontend only; no engine, private data, track assets, API calls or storage copied",
5
+ "source": "Runner r14 single-engine browser UI; selected .track tile renderer added from simulator atlas",
6
+ "source_sha256": "65d1e5f2c4e19b4951b828e82510005ab99a5270cf3dcb9f4eaa0fa1af8c40f8"
7
+ },
8
+ "client_sha256": "420c2a22814525083eab0bc9865ad705c48a75bdffe7bdc4f2b85d3837fbe8e4",
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": "v1.2-selective-freezing",
11
+ "output_sha256": "063dcbd45ee0528768b634be6bb2637622a68524dc1077ab4e1599a4776a3111",
12
+ "packaged_frontend_files": {
13
+ "assets/track-atlas.json": "d97c8900e3e5fb17734b5bd61d1f4f4b196d9be30af9848e2e273ae7e4079ae4",
14
+ "client.js": "420c2a22814525083eab0bc9865ad705c48a75bdffe7bdc4f2b85d3837fbe8e4",
15
+ "help.html": "d9b1e3b87641d73d4504b54ee33fa3c7d0917ea9c9c454cc632665fd41ace950",
16
+ "hf-auth.js": "3f3938bbc0935e4e9230c094029ef46e03beea74be199887c50e053e03dafcfe",
17
+ "index.html": "063dcbd45ee0528768b634be6bb2637622a68524dc1077ab4e1599a4776a3111",
18
+ "track-library.js": "351ec4c026b49420ce963f4310cb000d9e987fd28e6dac5ecd0176509340f6e6",
19
+ "track-map.js": "ab5374aa49c7ccec90a787ee8c56cd71beb56b903bf2bbc322783e6f43c009f0"
20
+ },
21
+ "packaged_frontend_sha256": "f32657b54c2633a06a8dd3051a9e8b4cdd10560c9ac5474f7e5c6c3208949706",
22
+ "status": "Local selective-freeze candidate; hosted qualification pending"
23
+ }
RELEASE_MANIFEST.json CHANGED
@@ -1 +1,93 @@
1
- {"backend":"gpu","files":{".gitattributes":"c2ad16718fc51c888d32efc88c8f6e23ebe5fcf6f48e2954f896ba9770f24d72","BETA_TESTING.md":"829dae67ec37dac2a4e7b178ab5ee4fc5f63896af132fbff457a5e35141fe94d","BINARY_PROVENANCE.json":"fa2b6c8962a0ec704ce7db417e7747abfc8af79f9f31effd242c013d8bdeca5f","BUCKET_BUNDLE.md":"cb7a0f023d5a1f93f0288c6a5646b64f8f3e9d36150c0730aea94590e5b80260","CUDA_REFERENCE.md":"f7453c3254d244f8b0de41fde5851cb025159f5cea4a4d1a5d8208a955550c6c","DATA_POLICY.md":"fc5978528abe1c21c14882417ac8a706e04a0831bbd3fdb3de8c64442c1a7b3d","FEEDBACK.md":"f95b8f6afbf4a360976c0edca5d52f5b3a0b668c9a944d4947b840a7c53a122a","FRONTEND_SOURCE.json":"a1e31beb032873eb0f635bfdde4011e1d600d335262c9a33bc9bf1234016c243","GODOT_LICENSE":"fb2b3bb82c60f1e76841ba2122eb902f8e39c151476fe21ce10c9a05d1045304","IMPORTER_BUILD_RECEIPT.json":"4ba5c533cc617105478e4d85c83f456a7dfa68b1388049624619871ba9e42e9d","LICENSE":"53d5851b6440feeae36f72a5f57fcab37858c48b7084765ece4b0c54b9a28ed8","README.md":"c0fb705dff468ea502a0a810f47a450f5d2f42c0c3b0178c3b662b27a327b8a5","STORAGE_BOUNDARY.md":"1d0cab6c82723f1879d7b437bab6b0d21248436bce161f3fbfe6c0e83b9e87a1","TRACK_LIBRARY.md":"be64c91633ef6696233df537afeef4c5175b2d55daac9336758d9eb3d24763c9","UPSTREAM.json":"e71d256ab4fea9a684c211f91086cd8a3eec518686eb54474e79352b20eeed79","WINNERS_AND_EVALUATION.md":"f281cf496763c59c50a79161cfff1a46d3529edfcfaaa14962c9a3f2d4f9446f","analysis_result.py":"0a5d73fe8dbca934b21823b8ffbd50b0baaef8e15a39e32604eefe16f01d1cf2","app.py":"78ddccd56e5c217b89681c5dcbee451b6a5868398c4f75bd2b4db33c235d800f","app_release.py":"7482559c667a665fd3cb6aa8af6c78422a822b515e14589db8306f7fd4860a8b","assets/formula_template.json":"80f745df82bb7be45af52785fd582460bcddc63c5a4e1d8375d85b3122db4c6b","assets/rally_template.json":"7350a3fe28d9b4da7a0965ae6ea7ca3472fb7885303e342310d63a0dce80851c","assets/snowmobile_template.json":"12d30545876011fd6fccdd3e721f9c465938c9c58ac99338205481d5e7ac6742","assets/track-atlas.json":"d97c8900e3e5fb17734b5bd61d1f4f4b196d9be30af9848e2e273ae7e4079ae4","assets/truck_template.json":"a83bffea4d5e818c135ab3aba68a47aa288d6ad0e7b8bd9c95ed0dea9e9df2f7","bin/altd-sim":"3aa1d364e0117f553a52404ae336efcfebd827fc0ca347e811196cbe31e32849","bin/extract_saved_track":"3a7733c45b4301a786fcbfe92660a1c484749272da5f608d62f34878bd4ff31a","bin/libaltd_gpu.so":"3b1b88bccc06a21acc33ac4400af016d55a7e3d8727136a0c43b541f3c7887ca","bucket_storage.py":"73977f5c23c513848a6451fd603609211d829126438db803288ebf4469d1893d","build_info.py":"03efdd1bca81022669a9184667b89d4f1096faba6a83c0514322dd419a938e1f","builtin_tracks.py":"52cb4a285a6079cec7f7610de8af80570f1644a02cf9979e47d2d49736e24cb5","builtin_tracks/catalog.json":"4a7bba4385713e985d1427a0da35dcc32d5ecfd73d93cad7520563deb8685670","builtin_tracks/tracks/Replica A01 Beginner.track":"ca5749537450430794e2eade2e0ac72fa141a4f225e13e2f8ef842abb948ff15","builtin_tracks/tracks/Replica A02 Sharp Turns.track":"097f1ea8edf041112b690d0638075630716ddc03c7d0b1980ddcbeaf5071c8d4","builtin_tracks/tracks/Replica A03 High Speed.track":"88917c63847be1854b989bb28a23af7eeacb964c3e7df9579953aebc9496e6af","builtin_tracks/tracks/Replica A04 Dirt.track":"7f4fe58516227b15898d14bb0abb9a0856126d24fcd793884f051f7a4fae521d","builtin_tracks/tracks/Replica A05 Two Terrains.track":"c4ee2842920d99cdfe3eebdcad59a77e24b626380acef0d02a39ea1e23823e2a","builtin_tracks/tracks/Replica A06 Ice.track":"fccb9a159a06d1b986c6fe7d5bb89c0cabad3a005531f4e0d71f6e37254ada34","builtin_tracks/tracks/Replica A07 Three Terrains.track":"a8fa652ad451e2702a23d5f3429eb0b6a6408bf6a2a76a73d549023e481875c6","builtin_tracks/tracks/Replica A08 Long.track":"3e259bd227776ca847d35baaea88b5e8af57cc920643bf71563176bd6554ad65","builtin_tracks/tracks/Replica A09 Sharpest.track":"5362cea3c564dce8f4f22fcd4b798347931dfaa4e65b84624944952b3e0b0d2a","builtin_tracks/tracks/Replica B01 Oval.track":"0df5755150c145a35edc6c8693f429e5b9ff4b12210ba67cbfcb932c58faf158","builtin_tracks/tracks/Replica B02 Snake.track":"210e699b1fa5f2624a2ff0969b73a20af7bc56bf774f4fd282f6109f80bfdb3c","builtin_tracks/tracks/Replica B03 Slalom.track":"a8bab86f93e3072bf27a81a354220c137207b9fc0b548372c8dab93639a18a24","builtin_tracks/tracks/Replica B04 Rally.track":"9d2fc668a7c86aabb9ca9dbfdbd21dff0d099c5d77029aa2ae96b6c7b9efd3f0","builtin_tracks/tracks/Replica B05 Racetrack.track":"d0804ebc17646d2f7c3be65cfe0f6e94033417e75b101a8c598a69131a170079","builtin_tracks/tracks/Replica B06 Hard.track":"8b1a10fd8485405d7f73abca8890f4845145227177c9ac07ac9a1d79f28908f9","builtin_tracks/tracks/Replica B07 Drift.track":"d6d46216882cb63d55b1e8ce81ffa67f1c95ffd0a86a72806b8fd23973c6ce0a","builtin_tracks/tracks/Replica B08 Arctic Circle.track":"229128e86a87089f781b072a4c677ff729cf8488b1d74ad75cfb43655b9f4a16","builtin_tracks/tracks/Replica B09 Checkered.track":"bec4dbd0edc35e0e4f4d1035c608a0c56bbc99e7301f640f8e2eddba0100b2fe","builtin_tracks/tracks/Replica R01 Blitzring.track":"14b52a7cbbf7de5606c772c74730c0e8776f39ed72955fef5ae1f7c2d8ccef77","builtin_tracks/tracks/Replica R02 Desert Rally.track":"653286b00f2f04450e698d8b8e9d4ecb268064b323b182d2de9db7d017b22238","builtin_tracks/tracks/Replica R03 Glacier.track":"0e1b42ce51ae91a8702e173013a090d00145e518bb47d7a659cb1d1fdff011b5","builtin_tracks/tracks/Replica R04 Truck Maze.track":"d7b89d64e118506e6cec259057886d9267ca4c6fab570e7ba0d6641e8f822f11","builtin_tracks/tracks/Replica R05 Endurance 500.track":"dde36ad5f627bce65d45a96d46a68497f8d446f6011c9df19ee51ce71375cba8","builtin_tracks/tracks/Replica R06 Mix.track":"9de8d912a59001ea13baa7f1b4f92884b8cddf91978f31e19f3237975713f739","builtin_tracks/tracks/Replica R07 Mirage Marina.track":"8c6764f3accb1a8372d910d57f4f681572dd40c590c4a3d03517379bb360fcd7","builtin_tracks/tracks/Replica R08 Demolition Derby.track":"6f11a9ffbcb477c9d19964566b1b612d2a94675605246e93e21f27bbbdb357ef","builtin_tracks/tracks/Replica R09 Eau Noir.track":"3ec0a78478cca1a4f0d2d98ac81f40783928adf271b70f0c32d295a6da2cdaa9","builtin_tracks/tracks/Replica The Champions Trial.track":"a3bfb76422affc774b44c739b0636d08acb901fa7615b9adcb52c069f79834e1","client.js":"96426083c2987332d3393f77bc30438237b186ef0465263f16ba79b304433453","delivery.py":"6bdba2e87c3e19a41440cb16103695af27105f8bafbae38948bbb1b936ed0c1b","gpu_tickets.py":"b81aadb5ed42cec9212d44da7e7bbb7b413c5bd517383cac0b49ec9b4d659c92","help.html":"ea4b9b0a391f956458e745d2579cdeb89946af0d80bbfbf63cf2e07eb8de2eb3","hf-auth.js":"3f3938bbc0935e4e9230c094029ef46e03beea74be199887c50e053e03dafcfe","hf_identity.py":"913fb1e089af21f376e8359a20cbc838d5bcd7971def6989a4382d53c1127b37","index.html":"7c79a0c56e619ae2e86951e805c4e13b76035c618b423278aee69c8e45c51d4d","native/analysis.patch":"42f79de67cb0734cffb2a7582f5479cab42ab82675884b8b42b9f158d46a98e8","native/build-receipt.json":"559a7e4e382f9f7caa1c5ceb566a5a0bbefad2ed3a2e2cf604e31c9c3890c348","native/source-receipt.json":"36feba861501baf8672884476bbeed5e375254cbb4feffb9f4f90aa61a415a93","portable_bundle.py":"aeeb2a81bcdf50bd013f3fa76e20c7c955c8f15344836596cd1043b1b7171026","requirements.txt":"fc7e0703ad2289fd3926a36efbdce8c61f0edc00f7575a87e2b565e46588c5a4","server.py":"1f82c9046324661d7bd4acf1cf37eef3445f985351159d88acdcaf89d1edf859","star_check.py":"61d35bcede5dab75911b2734ff20cb38f7a06bde9fd58c2eff67f5833b260d40","steam_leaderboard.py":"d76397c39cae58f636ddf9a9be1a46ae3d77fefd6b7269feac73d34d97165481","track-library.js":"351ec4c026b49420ce963f4310cb000d9e987fd28e6dac5ecd0176509340f6e6","track-map.js":"ab5374aa49c7ccec90a787ee8c56cd71beb56b903bf2bbc322783e6f43c009f0","training_config.py":"3d7fcaad585b474380e825649e4add3412494bbd68b48b3b14bd1b954e817ad0","vendor/gradio-client/LICENSE":"c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4","vendor/gradio-client/dist/index.min.js":"fdd776db8633354f118fe2908c980592283968737e6b91dc3aa86d648da5c3fd","vendor/gradio-client/package.json":"96c5b9e6d3587fb7bd8e5bb28775ece222de1043045afc4e6389c88db137ad0e","vendor/hf-oauth/LICENSE":"d6e7b19451c1b3d1d66353bb4b1274138953b3bfd9ae60c56e77b1f548796982","vendor/hf-oauth/index.js":"53282844000a171011e547f6472a3846bb4cecb5071adafea079fcac3a2aee7e","vendor/hf-oauth/package.json":"fafd4d8891023a1961546a7d3bc25cd24f64923a2ebfc449fe6d516a2949bda8","worker.py":"9d7d0d8e8730067658bbd6d5cddb20dca194a42cf885d389e193784fe8f15438"},"interface":"single-engine-runner-with-map-winners-analysis-v1","upstream_revision":"b90b8af06ffc4ea4e4fd703becd1107a48b8e5e0"}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "backend": "gpu",
3
+ "files": {
4
+ ".gitattributes": "c2ad16718fc51c888d32efc88c8f6e23ebe5fcf6f48e2954f896ba9770f24d72",
5
+ "BETA_TESTING.md": "829dae67ec37dac2a4e7b178ab5ee4fc5f63896af132fbff457a5e35141fe94d",
6
+ "BINARY_PROVENANCE.json": "e05f4c3a4a2a0da39b213708c532f3e514109c5530250b402347a8d751105052",
7
+ "BUCKET_BUNDLE.md": "cb7a0f023d5a1f93f0288c6a5646b64f8f3e9d36150c0730aea94590e5b80260",
8
+ "CUDA_REFERENCE.md": "f7453c3254d244f8b0de41fde5851cb025159f5cea4a4d1a5d8208a955550c6c",
9
+ "DATA_POLICY.md": "fc5978528abe1c21c14882417ac8a706e04a0831bbd3fdb3de8c64442c1a7b3d",
10
+ "FEEDBACK.md": "f95b8f6afbf4a360976c0edca5d52f5b3a0b668c9a944d4947b840a7c53a122a",
11
+ "FRONTEND_SOURCE.json": "fe24f1251ef7f6c35c121310012b718aaf13f4a409433e67f00e7f3836af7890",
12
+ "GODOT_LICENSE": "fb2b3bb82c60f1e76841ba2122eb902f8e39c151476fe21ce10c9a05d1045304",
13
+ "IMPORTER_BUILD_RECEIPT.json": "4ba5c533cc617105478e4d85c83f456a7dfa68b1388049624619871ba9e42e9d",
14
+ "LICENSE": "53d5851b6440feeae36f72a5f57fcab37858c48b7084765ece4b0c54b9a28ed8",
15
+ "README.md": "c0fb705dff468ea502a0a810f47a450f5d2f42c0c3b0178c3b662b27a327b8a5",
16
+ "STORAGE_BOUNDARY.md": "1d0cab6c82723f1879d7b437bab6b0d21248436bce161f3fbfe6c0e83b9e87a1",
17
+ "TRACK_LIBRARY.md": "be64c91633ef6696233df537afeef4c5175b2d55daac9336758d9eb3d24763c9",
18
+ "UPSTREAM.json": "ad5ff9011f329d9a05b18943118ebee914373501453971f786c1ee037213a83f",
19
+ "WINNERS_AND_EVALUATION.md": "f281cf496763c59c50a79161cfff1a46d3529edfcfaaa14962c9a3f2d4f9446f",
20
+ "analysis_result.py": "0a5d73fe8dbca934b21823b8ffbd50b0baaef8e15a39e32604eefe16f01d1cf2",
21
+ "app.py": "78ddccd56e5c217b89681c5dcbee451b6a5868398c4f75bd2b4db33c235d800f",
22
+ "app_release.py": "7482559c667a665fd3cb6aa8af6c78422a822b515e14589db8306f7fd4860a8b",
23
+ "assets/formula_template.json": "80f745df82bb7be45af52785fd582460bcddc63c5a4e1d8375d85b3122db4c6b",
24
+ "assets/rally_template.json": "7350a3fe28d9b4da7a0965ae6ea7ca3472fb7885303e342310d63a0dce80851c",
25
+ "assets/snowmobile_template.json": "12d30545876011fd6fccdd3e721f9c465938c9c58ac99338205481d5e7ac6742",
26
+ "assets/track-atlas.json": "d97c8900e3e5fb17734b5bd61d1f4f4b196d9be30af9848e2e273ae7e4079ae4",
27
+ "assets/truck_template.json": "a83bffea4d5e818c135ab3aba68a47aa288d6ad0e7b8bd9c95ed0dea9e9df2f7",
28
+ "bin/altd-sim": "ce31f754f6b6f3afaf4dcc44c1e6fda3e6414eb2924fa167b8778523bcaf2070",
29
+ "bin/extract_saved_track": "3a7733c45b4301a786fcbfe92660a1c484749272da5f608d62f34878bd4ff31a",
30
+ "bin/libaltd_gpu.so": "3b1b88bccc06a21acc33ac4400af016d55a7e3d8727136a0c43b541f3c7887ca",
31
+ "bucket_storage.py": "347ad556254aa9f255209141cf37f48c58c01134318c08b7bcd6ed2caa95e7a4",
32
+ "build_info.py": "2a57f73abd9e062cf029b65b09b26b8d12e301bac2f7efec7edb4b85b47671c3",
33
+ "builtin_tracks.py": "52cb4a285a6079cec7f7610de8af80570f1644a02cf9979e47d2d49736e24cb5",
34
+ "builtin_tracks/catalog.json": "4a7bba4385713e985d1427a0da35dcc32d5ecfd73d93cad7520563deb8685670",
35
+ "builtin_tracks/tracks/Replica A01 Beginner.track": "ca5749537450430794e2eade2e0ac72fa141a4f225e13e2f8ef842abb948ff15",
36
+ "builtin_tracks/tracks/Replica A02 Sharp Turns.track": "097f1ea8edf041112b690d0638075630716ddc03c7d0b1980ddcbeaf5071c8d4",
37
+ "builtin_tracks/tracks/Replica A03 High Speed.track": "88917c63847be1854b989bb28a23af7eeacb964c3e7df9579953aebc9496e6af",
38
+ "builtin_tracks/tracks/Replica A04 Dirt.track": "7f4fe58516227b15898d14bb0abb9a0856126d24fcd793884f051f7a4fae521d",
39
+ "builtin_tracks/tracks/Replica A05 Two Terrains.track": "c4ee2842920d99cdfe3eebdcad59a77e24b626380acef0d02a39ea1e23823e2a",
40
+ "builtin_tracks/tracks/Replica A06 Ice.track": "fccb9a159a06d1b986c6fe7d5bb89c0cabad3a005531f4e0d71f6e37254ada34",
41
+ "builtin_tracks/tracks/Replica A07 Three Terrains.track": "a8fa652ad451e2702a23d5f3429eb0b6a6408bf6a2a76a73d549023e481875c6",
42
+ "builtin_tracks/tracks/Replica A08 Long.track": "3e259bd227776ca847d35baaea88b5e8af57cc920643bf71563176bd6554ad65",
43
+ "builtin_tracks/tracks/Replica A09 Sharpest.track": "5362cea3c564dce8f4f22fcd4b798347931dfaa4e65b84624944952b3e0b0d2a",
44
+ "builtin_tracks/tracks/Replica B01 Oval.track": "0df5755150c145a35edc6c8693f429e5b9ff4b12210ba67cbfcb932c58faf158",
45
+ "builtin_tracks/tracks/Replica B02 Snake.track": "210e699b1fa5f2624a2ff0969b73a20af7bc56bf774f4fd282f6109f80bfdb3c",
46
+ "builtin_tracks/tracks/Replica B03 Slalom.track": "a8bab86f93e3072bf27a81a354220c137207b9fc0b548372c8dab93639a18a24",
47
+ "builtin_tracks/tracks/Replica B04 Rally.track": "9d2fc668a7c86aabb9ca9dbfdbd21dff0d099c5d77029aa2ae96b6c7b9efd3f0",
48
+ "builtin_tracks/tracks/Replica B05 Racetrack.track": "d0804ebc17646d2f7c3be65cfe0f6e94033417e75b101a8c598a69131a170079",
49
+ "builtin_tracks/tracks/Replica B06 Hard.track": "8b1a10fd8485405d7f73abca8890f4845145227177c9ac07ac9a1d79f28908f9",
50
+ "builtin_tracks/tracks/Replica B07 Drift.track": "d6d46216882cb63d55b1e8ce81ffa67f1c95ffd0a86a72806b8fd23973c6ce0a",
51
+ "builtin_tracks/tracks/Replica B08 Arctic Circle.track": "229128e86a87089f781b072a4c677ff729cf8488b1d74ad75cfb43655b9f4a16",
52
+ "builtin_tracks/tracks/Replica B09 Checkered.track": "bec4dbd0edc35e0e4f4d1035c608a0c56bbc99e7301f640f8e2eddba0100b2fe",
53
+ "builtin_tracks/tracks/Replica R01 Blitzring.track": "14b52a7cbbf7de5606c772c74730c0e8776f39ed72955fef5ae1f7c2d8ccef77",
54
+ "builtin_tracks/tracks/Replica R02 Desert Rally.track": "653286b00f2f04450e698d8b8e9d4ecb268064b323b182d2de9db7d017b22238",
55
+ "builtin_tracks/tracks/Replica R03 Glacier.track": "0e1b42ce51ae91a8702e173013a090d00145e518bb47d7a659cb1d1fdff011b5",
56
+ "builtin_tracks/tracks/Replica R04 Truck Maze.track": "d7b89d64e118506e6cec259057886d9267ca4c6fab570e7ba0d6641e8f822f11",
57
+ "builtin_tracks/tracks/Replica R05 Endurance 500.track": "dde36ad5f627bce65d45a96d46a68497f8d446f6011c9df19ee51ce71375cba8",
58
+ "builtin_tracks/tracks/Replica R06 Mix.track": "9de8d912a59001ea13baa7f1b4f92884b8cddf91978f31e19f3237975713f739",
59
+ "builtin_tracks/tracks/Replica R07 Mirage Marina.track": "8c6764f3accb1a8372d910d57f4f681572dd40c590c4a3d03517379bb360fcd7",
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": "420c2a22814525083eab0bc9865ad705c48a75bdffe7bdc4f2b85d3837fbe8e4",
64
+ "delivery.py": "6bdba2e87c3e19a41440cb16103695af27105f8bafbae38948bbb1b936ed0c1b",
65
+ "gpu_tickets.py": "b81aadb5ed42cec9212d44da7e7bbb7b413c5bd517383cac0b49ec9b4d659c92",
66
+ "help.html": "d9b1e3b87641d73d4504b54ee33fa3c7d0917ea9c9c454cc632665fd41ace950",
67
+ "hf-auth.js": "3f3938bbc0935e4e9230c094029ef46e03beea74be199887c50e053e03dafcfe",
68
+ "hf_identity.py": "913fb1e089af21f376e8359a20cbc838d5bcd7971def6989a4382d53c1127b37",
69
+ "index.html": "063dcbd45ee0528768b634be6bb2637622a68524dc1077ab4e1599a4776a3111",
70
+ "native/analysis.patch": "42f79de67cb0734cffb2a7582f5479cab42ab82675884b8b42b9f158d46a98e8",
71
+ "native/build-receipt.json": "559a7e4e382f9f7caa1c5ceb566a5a0bbefad2ed3a2e2cf604e31c9c3890c348",
72
+ "native/selective-freeze-build-receipt.json": "ed804b1cd49a9ba34abc6f7cadaf4fb97807e27f3d14af117f8292a2d3f2d172",
73
+ "native/selective-freeze-source.tar.gz": "297d2ce34569994acd2a477e64c5315cb2081699b4333b8abdabb3ff7451d8db",
74
+ "native/source-receipt.json": "36feba861501baf8672884476bbeed5e375254cbb4feffb9f4f90aa61a415a93",
75
+ "portable_bundle.py": "b32ca0b8d79f13230fde6e914769e0af71cd44ef950d798da83499878ab28e15",
76
+ "requirements.txt": "fc7e0703ad2289fd3926a36efbdce8c61f0edc00f7575a87e2b565e46588c5a4",
77
+ "server.py": "1f82c9046324661d7bd4acf1cf37eef3445f985351159d88acdcaf89d1edf859",
78
+ "star_check.py": "61d35bcede5dab75911b2734ff20cb38f7a06bde9fd58c2eff67f5833b260d40",
79
+ "steam_leaderboard.py": "d76397c39cae58f636ddf9a9be1a46ae3d77fefd6b7269feac73d34d97165481",
80
+ "track-library.js": "351ec4c026b49420ce963f4310cb000d9e987fd28e6dac5ecd0176509340f6e6",
81
+ "track-map.js": "ab5374aa49c7ccec90a787ee8c56cd71beb56b903bf2bbc322783e6f43c009f0",
82
+ "training_config.py": "59141f96e47aba5bc91e8a08d0f40384ea8c90ea0b3e5a12ad65abdad3987a8d",
83
+ "vendor/gradio-client/LICENSE": "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4",
84
+ "vendor/gradio-client/dist/index.min.js": "fdd776db8633354f118fe2908c980592283968737e6b91dc3aa86d648da5c3fd",
85
+ "vendor/gradio-client/package.json": "96c5b9e6d3587fb7bd8e5bb28775ece222de1043045afc4e6389c88db137ad0e",
86
+ "vendor/hf-oauth/LICENSE": "d6e7b19451c1b3d1d66353bb4b1274138953b3bfd9ae60c56e77b1f548796982",
87
+ "vendor/hf-oauth/index.js": "53282844000a171011e547f6472a3846bb4cecb5071adafea079fcac3a2aee7e",
88
+ "vendor/hf-oauth/package.json": "fafd4d8891023a1961546a7d3bc25cd24f64923a2ebfc449fe6d516a2949bda8",
89
+ "worker.py": "ebfb82560c721936520bb601e117dc697bb6a046a2fc4ef4207a80250dba917b"
90
+ },
91
+ "interface": "single-engine-runner-with-map-winners-analysis-v1",
92
+ "upstream_revision": "b90b8af06ffc4ea4e4fd703becd1107a48b8e5e0"
93
+ }
UPSTREAM.json CHANGED
@@ -1 +1,21 @@
1
- {"commit":"b90b8af06ffc4ea4e4fd703becd1107a48b8e5e0","importer_source_revision":"d8ab74c25df70b6a86ed101080e33d5fb785ea6f","math_profile":"proton","native_build":{"build_receipt_path":"native/build-receipt.json","build_receipt_sha256":"559a7e4e382f9f7caa1c5ceb566a5a0bbefad2ed3a2e2cf604e31c9c3890c348","cuda_library_origin":"retained b90 CUDA library; layout ABI checked, no local device execution","patch_path":"native/analysis.patch","patch_sha256":"42f79de67cb0734cffb2a7582f5479cab42ab82675884b8b42b9f158d46a98e8","simulator_origin":"locally built Linux executable from b90 plus reviewed local patch","source_receipt_path":"native/source-receipt.json","source_receipt_sha256":"36feba861501baf8672884476bbeed5e375254cbb4feffb9f4f90aa61a415a93","source_revision":"b90b8af06ffc4ea4e4fd703becd1107a48b8e5e0"},"open_prs_not_included":[19,21],"repository":"https://github.com/Zorro909/driving_sim_rs","role":"gpu","ui_refresh_date":"2026-10-12"}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "commit": "b90b8af06ffc4ea4e4fd703becd1107a48b8e5e0",
3
+ "importer_source_revision": "d8ab74c25df70b6a86ed101080e33d5fb785ea6f",
4
+ "math_profile": "proton",
5
+ "native_build": {
6
+ "build_receipt_path": "native/selective-freeze-build-receipt.json",
7
+ "build_receipt_sha256": "ed804b1cd49a9ba34abc6f7cadaf4fb97807e27f3d14af117f8292a2d3f2d172",
8
+ "cuda_library_origin": "retained CUDA library from prior hosted build; device check pending",
9
+ "simulator_origin": "locally cross-compiled Linux executable with selective freezing",
10
+ "source_revision": "b90b8af06ffc4ea4e4fd703becd1107a48b8e5e0",
11
+ "source_snapshot_path": "native/selective-freeze-source.tar.gz",
12
+ "source_snapshot_sha256": "297d2ce34569994acd2a477e64c5315cb2081699b4333b8abdabb3ff7451d8db"
13
+ },
14
+ "open_prs_not_included": [
15
+ 19,
16
+ 21
17
+ ],
18
+ "repository": "https://github.com/Zorro909/driving_sim_rs",
19
+ "role": "gpu",
20
+ "ui_refresh_date": "2026-10-12"
21
+ }
bin/altd-sim CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:3aa1d364e0117f553a52404ae336efcfebd827fc0ca347e811196cbe31e32849
3
- size 3604272
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ce31f754f6b6f3afaf4dcc44c1e6fda3e6414eb2924fa167b8778523bcaf2070
3
+ size 3647808
bucket_storage.py CHANGED
@@ -17,7 +17,7 @@ import uuid
17
 
18
  from portable_bundle import (
19
  BundleError, MAX_BUNDLE, MAX_NETWORK, MAX_ANALYSIS_ARCHIVE,
20
- MAX_ANALYSIS_FILE_BYTES, load_bundle,
21
  )
22
  from worker import network_input
23
 
@@ -124,8 +124,11 @@ def validate_recipe_library(raw: bytes) -> dict:
124
  raise ValueError("Invalid recipe library")
125
  seen.add(slot)
126
  settings = recipe["settings"]
127
- if not isinstance(settings, dict) or set(settings) - set(RECIPE_DEFAULT_SETTINGS):
 
128
  raise ValueError("Invalid recipe library")
 
 
129
  clean = {**RECIPE_DEFAULT_SETTINGS, **settings}
130
  numeric = {
131
  "population": (1, 128, True), "generations": (1, 1000, True),
 
17
 
18
  from portable_bundle import (
19
  BundleError, MAX_BUNDLE, MAX_NETWORK, MAX_ANALYSIS_ARCHIVE,
20
+ MAX_ANALYSIS_FILE_BYTES, load_bundle, validate_freeze,
21
  )
22
  from worker import network_input
23
 
 
124
  raise ValueError("Invalid recipe library")
125
  seen.add(slot)
126
  settings = recipe["settings"]
127
+ if (not isinstance(settings, dict)
128
+ or set(settings) - (set(RECIPE_DEFAULT_SETTINGS) | {"freeze"})):
129
  raise ValueError("Invalid recipe library")
130
+ if "freeze" in settings:
131
+ validate_freeze(settings["freeze"])
132
  clean = {**RECIPE_DEFAULT_SETTINGS, **settings}
133
  numeric = {
134
  "population": (1, 128, True), "generations": (1, 1000, True),
build_info.py CHANGED
@@ -19,6 +19,6 @@ def build_identity():
19
  "package_role": 'gpu',
20
  "binary_sha256": {name: digest for name, digest in manifest["files"].items() if name.startswith("bin/")},
21
  "native_source_revision": native["source_revision"],
22
- "native_patch_sha256": native["patch_sha256"],
23
  "native_build_receipt_sha256": native["build_receipt_sha256"],
24
  }
 
19
  "package_role": 'gpu',
20
  "binary_sha256": {name: digest for name, digest in manifest["files"].items() if name.startswith("bin/")},
21
  "native_source_revision": native["source_revision"],
22
+ "native_source_snapshot_sha256": native["source_snapshot_sha256"],
23
  "native_build_receipt_sha256": native["build_receipt_sha256"],
24
  }
client.js CHANGED
@@ -108,6 +108,7 @@ function syncRunModeUI(unavailable=busy||!!job||bundleRestoring||bucketOperation
108
  for(const id of trainingOnlyControls){const node=$(id);if(node)node.disabled=unavailable||evaluation;}
109
  if($('native_settings'))$('native_settings').hidden=evaluation;
110
  if($('reward_settings'))$('reward_settings').hidden=evaluation;
 
111
  if($('run'))$('run').textContent=evaluation?'Evaluate policy (weights frozen)':'Run training';
112
  if($('run_mode_help'))$('run_mode_help').textContent=evaluation
113
  ?'Frozen evaluation uses the selected policy unchanged in a fresh car. Mutation, decay, crossover, reproduction and winner selection are disabled.'
@@ -433,7 +434,12 @@ async function encoded(file) {
433
  }
434
  const headers = () => ({'X-Job-Key':job.key});
435
  const networkSource=()=>stagedNetwork || $('network').files[0];
436
- $('network').onchange=()=>{stagedNetwork=null;selectedWinner=null;if($('networkChoice'))$('networkChoice').textContent='Uploaded file selected.';buttons();};
 
 
 
 
 
437
  window.TrainingClient={
438
  isBusy:()=>busy||!!job||bundleRestoring,
439
  hasUnsavedState:()=>!!(networkSource()||localResult||$('track').files.length||trackLibrary?.info?.()?.source==='builtin'||$('editor_file')?.files.length||window.hasUnsavedNetworkDraft?.()),
@@ -441,6 +447,7 @@ window.TrainingClient={
441
  if(busy||job)throw Error('Finish or delete the current result before changing the network');
442
  stagedNetwork=file;$('network').value='';
443
  if($('networkChoice'))$('networkChoice').textContent='Browser editor input: '+file.name+'. Not uploaded yet.';
 
444
  buttons();
445
  }
446
  };
@@ -931,7 +938,7 @@ $('run').onclick = async () => {
931
  if($('leaderboard_opt_in')?.checked)void checkSteamLeaderboard(trackInfo,r);
932
  else if($('leaderboard_status'))$('leaderboard_status').textContent='';
933
  if(!comparisonPlan)$('track').value=''; $('network').value='';
934
- stagedNetwork=null;if($('networkChoice'))$('networkChoice').textContent='Network input released after the run.';
935
  say('Result ready ('+job.backend.toUpperCase()+'). Inputs and intermediate worker files have been removed.');
936
  if(autosaveSnapshot){
937
  try{
@@ -1178,6 +1185,12 @@ const bundleMessage=text=>{if($('bundle_status'))$('bundle_status').textContent=
1178
  const bundleExact=(value,keys)=>{
1179
  if(!value||typeof value!=='object'||Array.isArray(value)||Object.keys(value).sort().join()!==[...keys].sort().join())throw Error('Unexpected receipt fields');
1180
  };
 
 
 
 
 
 
1181
  const bundleFinite=value=>typeof value==='number'&&Number.isFinite(value);
1182
  const runHistoryKeys=['generation','mutation','best_score','mean_score','best_lap_seconds','lapped_cars','simulated_ticks'];
1183
  function cleanRunHistory(value){
@@ -1210,7 +1223,7 @@ function cleanRunReceipt(source){
1210
  bundleExact(report.inputs,['track_sha256','network_sha256']);
1211
  if(!/^[a-f0-9]{64}$/.test(report.inputs.track_sha256)||!/^[a-f0-9]{64}$/.test(report.inputs.network_sha256))return null;
1212
  const recipeSettings={...report.settings},sourceMode=recipeSettings.mode,sourceCleanMinLaps=recipeSettings.clean_min_laps;delete recipeSettings.mode;delete recipeSettings.clean_min_laps;
1213
- bundleExact(recipeSettings,Object.keys(window.RecipeLibrary.defaults));
1214
  const analysisSummary=report.analysis_summary?validateAnalysisSummary(report.analysis_summary):null,mode=analysisSummary?.mode??sourceMode;
1215
  const cleanMinLaps=analysisSummary?.conditions.clean_min_laps??sourceCleanMinLaps??2;
1216
  if((sourceMode!==undefined&&!['train','evaluate'].includes(sourceMode))||(analysisSummary&&sourceMode!==undefined&&sourceMode!==analysisSummary.mode)||
@@ -1219,9 +1232,10 @@ function cleanRunReceipt(source){
1219
  let settings;
1220
  if(mode==='evaluate'){
1221
  if(recipeSettings.population!==1||recipeSettings.generations!==1||recipeSettings.mutation!==0||recipeSettings.mutation_end!==0||recipeSettings.schedule!=='fixed'||recipeSettings.selection!=='best'||recipeSettings.parents!==1||recipeSettings.elite!==0||recipeSettings.crossover!=='none'||recipeSettings.decay!==0||recipeSettings.adaptive_mutation!==false)return null;
1222
- const checked=window.RecipeLibrary.settings({...recipeSettings,mutation:0.01,mutation_end:0.01});
1223
  settings={...checked,mutation:0,mutation_end:0};
1224
- }else settings=window.RecipeLibrary.settings(recipeSettings);
 
1225
  const history=cleanRunHistory(report.history);
1226
  settings.mode=mode??'train';settings.clean_min_laps=cleanMinLaps;
1227
  if(report.population!==settings.population||report.generations_requested!==settings.generations||report.requested_ticks!==settings.ticks||(history&&history.length!==report.generations_completed))return null;
@@ -1374,7 +1388,7 @@ async function preparePortableText(text){
1374
  }
1375
  parsed.track.file=await validateBundleTrack(parsed.track);
1376
  }
1377
- if(parsed.recipe){bundleExact(parsed.recipe.settings,Object.keys(window.RecipeLibrary.defaults));parsed.recipe.settings=window.RecipeLibrary.settings(parsed.recipe.settings);}
1378
  if(parsed.receipt){
1379
  if(parsed.analysis){
1380
  const clean=cleanRunReceipt(parsed.receipt);if(!clean)throw Error('Run receipt failed its allowlist or value checks');
 
108
  for(const id of trainingOnlyControls){const node=$(id);if(node)node.disabled=unavailable||evaluation;}
109
  if($('native_settings'))$('native_settings').hidden=evaluation;
110
  if($('reward_settings'))$('reward_settings').hidden=evaluation;
111
+ if($('freeze_settings'))$('freeze_settings').hidden=evaluation;
112
  if($('run'))$('run').textContent=evaluation?'Evaluate policy (weights frozen)':'Run training';
113
  if($('run_mode_help'))$('run_mode_help').textContent=evaluation
114
  ?'Frozen evaluation uses the selected policy unchanged in a fresh car. Mutation, decay, crossover, reproduction and winner selection are disabled.'
 
434
  }
435
  const headers = () => ({'X-Job-Key':job.key});
436
  const networkSource=()=>stagedNetwork || $('network').files[0];
437
+ async function refreshFreezeNetwork(file){
438
+ if(!file){window.setFreezeNetwork?.(null);return;}
439
+ try{const network=await validateNetworkBytes(new Uint8Array(await file.arrayBuffer()));if(networkSource()===file)window.setFreezeNetwork?.(network);}
440
+ catch(error){if(networkSource()===file){window.setFreezeNetwork?.(null);if($('freeze_status'))$('freeze_status').textContent='Network metadata unavailable: '+error.message;}}
441
+ }
442
+ $('network').onchange=()=>{stagedNetwork=null;selectedWinner=null;if($('networkChoice'))$('networkChoice').textContent='Uploaded file selected.';refreshFreezeNetwork(networkSource());buttons();};
443
  window.TrainingClient={
444
  isBusy:()=>busy||!!job||bundleRestoring,
445
  hasUnsavedState:()=>!!(networkSource()||localResult||$('track').files.length||trackLibrary?.info?.()?.source==='builtin'||$('editor_file')?.files.length||window.hasUnsavedNetworkDraft?.()),
 
447
  if(busy||job)throw Error('Finish or delete the current result before changing the network');
448
  stagedNetwork=file;$('network').value='';
449
  if($('networkChoice'))$('networkChoice').textContent='Browser editor input: '+file.name+'. Not uploaded yet.';
450
+ refreshFreezeNetwork(file);
451
  buttons();
452
  }
453
  };
 
938
  if($('leaderboard_opt_in')?.checked)void checkSteamLeaderboard(trackInfo,r);
939
  else if($('leaderboard_status'))$('leaderboard_status').textContent='';
940
  if(!comparisonPlan)$('track').value=''; $('network').value='';
941
+ stagedNetwork=null;window.setFreezeNetwork?.(null);if($('networkChoice'))$('networkChoice').textContent='Network input released after the run.';
942
  say('Result ready ('+job.backend.toUpperCase()+'). Inputs and intermediate worker files have been removed.');
943
  if(autosaveSnapshot){
944
  try{
 
1185
  const bundleExact=(value,keys)=>{
1186
  if(!value||typeof value!=='object'||Array.isArray(value)||Object.keys(value).sort().join()!==[...keys].sort().join())throw Error('Unexpected receipt fields');
1187
  };
1188
+ const bundleSettings=value=>{
1189
+ const currentKeys=Object.keys(window.RecipeLibrary.defaults),legacyKeys=currentKeys.filter(key=>key!=='freeze');
1190
+ const keys=Object.keys(value||{}).sort().join();
1191
+ if(keys!==[...currentKeys].sort().join()&&keys!==legacyKeys.sort().join())throw Error('Unexpected recipe settings fields');
1192
+ return window.RecipeLibrary.settings(value);
1193
+ };
1194
  const bundleFinite=value=>typeof value==='number'&&Number.isFinite(value);
1195
  const runHistoryKeys=['generation','mutation','best_score','mean_score','best_lap_seconds','lapped_cars','simulated_ticks'];
1196
  function cleanRunHistory(value){
 
1223
  bundleExact(report.inputs,['track_sha256','network_sha256']);
1224
  if(!/^[a-f0-9]{64}$/.test(report.inputs.track_sha256)||!/^[a-f0-9]{64}$/.test(report.inputs.network_sha256))return null;
1225
  const recipeSettings={...report.settings},sourceMode=recipeSettings.mode,sourceCleanMinLaps=recipeSettings.clean_min_laps;delete recipeSettings.mode;delete recipeSettings.clean_min_laps;
1226
+ const normalizedSettings=bundleSettings(recipeSettings);
1227
  const analysisSummary=report.analysis_summary?validateAnalysisSummary(report.analysis_summary):null,mode=analysisSummary?.mode??sourceMode;
1228
  const cleanMinLaps=analysisSummary?.conditions.clean_min_laps??sourceCleanMinLaps??2;
1229
  if((sourceMode!==undefined&&!['train','evaluate'].includes(sourceMode))||(analysisSummary&&sourceMode!==undefined&&sourceMode!==analysisSummary.mode)||
 
1232
  let settings;
1233
  if(mode==='evaluate'){
1234
  if(recipeSettings.population!==1||recipeSettings.generations!==1||recipeSettings.mutation!==0||recipeSettings.mutation_end!==0||recipeSettings.schedule!=='fixed'||recipeSettings.selection!=='best'||recipeSettings.parents!==1||recipeSettings.elite!==0||recipeSettings.crossover!=='none'||recipeSettings.decay!==0||recipeSettings.adaptive_mutation!==false)return null;
1235
+ const checked=window.RecipeLibrary.settings({...normalizedSettings,mutation:0.01,mutation_end:0.01});
1236
  settings={...checked,mutation:0,mutation_end:0};
1237
+ }else settings=normalizedSettings;
1238
+ if(mode==='evaluate'&&(settings.freeze.layers.length||settings.freeze.inputs.length||settings.freeze.outputs.length))return null;
1239
  const history=cleanRunHistory(report.history);
1240
  settings.mode=mode??'train';settings.clean_min_laps=cleanMinLaps;
1241
  if(report.population!==settings.population||report.generations_requested!==settings.generations||report.requested_ticks!==settings.ticks||(history&&history.length!==report.generations_completed))return null;
 
1388
  }
1389
  parsed.track.file=await validateBundleTrack(parsed.track);
1390
  }
1391
+ if(parsed.recipe)parsed.recipe.settings=bundleSettings(parsed.recipe.settings);
1392
  if(parsed.receipt){
1393
  if(parsed.analysis){
1394
  const clean=cleanRunReceipt(parsed.receipt);if(!clean)throw Error('Run receipt failed its allowlist or value checks');
help.html CHANGED
@@ -18,7 +18,7 @@
18
  <p class="small">This guide opens in a new tab to keep your current run and unsaved choices in place. Close this tab to return to the lab.</p>
19
  <p class="callout">You can try the built-in replica tracks and browser network editor without installing the original game. This lab does not reproduce the full game, award official stars, or change game progress.</p>
20
  <nav aria-label="Help topics"><ul>
21
- <li><a href="#first-run">Start a run</a></li><li><a href="#concepts">Basic ideas</a></li><li><a href="#continue">Continue a winner</a></li><li><a href="#compare">Compare policies</a></li><li><a href="#storage">Files and storage</a></li><li><a href="#limits">Limits and compute</a></li><li><a href="#feedback">Feedback</a></li>
22
  </ul></nav>
23
  </header>
24
 
@@ -48,6 +48,11 @@
48
  <p>Challenge checks use the selected driving settings, including collision elimination, and the chosen run duration or the track’s longer challenge deadline, capped at 300 simulated seconds. This extra replay may add processing time. A condition that is not met within that replay is not proof that the network could never meet it in a longer run.</p>
49
  </section>
50
 
 
 
 
 
 
51
  <section class="section" id="continue">
52
  <h2>Continue a winner</h2>
53
  <p>After the result has been received, select a role from <strong>Winner to continue or evaluate</strong>:</p>
 
18
  <p class="small">This guide opens in a new tab to keep your current run and unsaved choices in place. Close this tab to return to the lab.</p>
19
  <p class="callout">You can try the built-in replica tracks and browser network editor without installing the original game. This lab does not reproduce the full game, award official stars, or change game progress.</p>
20
  <nav aria-label="Help topics"><ul>
21
+ <li><a href="#first-run">Start a run</a></li><li><a href="#concepts">Basic ideas</a></li><li><a href="#freeze">Selective freezing</a></li><li><a href="#continue">Continue a winner</a></li><li><a href="#compare">Compare policies</a></li><li><a href="#storage">Files and storage</a></li><li><a href="#limits">Limits and compute</a></li><li><a href="#feedback">Feedback</a></li>
22
  </ul></nav>
23
  </header>
24
 
 
48
  <p>Challenge checks use the selected driving settings, including collision elimination, and the chosen run duration or the track’s longer challenge deadline, capped at 300 simulated seconds. This extra replay may add processing time. A condition that is not met within that replay is not proof that the network could never meet it in a longer run.</p>
49
  </section>
50
 
51
+ <section class="section" id="freeze">
52
+ <h2>Selective freezing</h2>
53
+ <p>In Training settings, open <strong>Selective freezing</strong> to keep selected parameters at their values in the starting network. Freezing an input holds its outgoing weights; freezing a hidden layer holds its incoming weights and biases; freezing an output holds its incoming weights and bias. The available choices and names come from the selected network. Freeze selections are part of saved recipes and can be edited later. Frozen evaluation runs the selected policy unchanged.</p>
54
+ </section>
55
+
56
  <section class="section" id="continue">
57
  <h2>Continue a winner</h2>
58
  <p>After the result has been received, select a role from <strong>Winner to continue or evaluate</strong>:</p>
index.html CHANGED
@@ -1,7 +1,7 @@
1
  <!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>AI Learns To Drive</title>
2
  <style>
3
  :root{color-scheme:dark;font:16px system-ui;background:#0c1420;color:#e5edf5}body{max-width:1400px;margin:auto;padding:22px}h1{font-size:32px;margin:0}h2{font-size:21px;margin:0 0 14px}small,.hint{color:#a2b4c8;line-height:1.6}.grid{display:grid;grid-template-columns:minmax(360px,.9fr) minmax(0,1.25fr);gap:24px}.card{background:#152233;border:1px solid #2a3d52;border-radius:16px;padding:22px;margin-top:20px}label{display:block;margin:12px 0 5px}input,select,button{font:inherit;background:#0c1725;color:#e5edf5;border:1px solid #49627c;border-radius:7px;padding:9px}input[type=number],select{width:100%;box-sizing:border-box}input[type=file]{max-width:100%;box-sizing:border-box}button{cursor:pointer}button.primary{background:#62dfb1;color:#102522;font-weight:700}button:disabled{opacity:.4;cursor:default}.row{display:grid;grid-template-columns:1fr 1fr;gap:15px}.reward{display:grid;grid-template-columns:1.7fr 1fr 70px 30px;gap:5px;margin:8px 0}.reward input{width:70px;box-sizing:border-box}a{color:#7ce4c3}canvas{width:100%;background:#09111b;border-radius:10px}#status{white-space:pre-wrap;line-height:1.7}table{width:100%;text-align:left;border-collapse:collapse;font-size:14px}td,th{padding:9px;border-bottom:1px solid #2a3d52}.pill{display:inline-block;background:#284539;border-radius:20px;padding:5px 12px;color:#91efc6;margin:6px 0}#error{color:#ffb5a2;white-space:pre-wrap}.toolbar{display:flex;gap:12px;align-items:center;flex-wrap:wrap;padding-bottom:16px;border-bottom:1px solid #2a3d52;margin-bottom:15px}.run-card{position:sticky;top:20px}details{margin-top:18px;border-top:1px solid #2a3d52;padding-top:14px}summary{cursor:pointer;font-weight:600;color:#c6d9e9}details[open]>summary{margin-bottom:12px}[hidden]{display:none!important}#map_note{font-size:14px}#runs{max-height:380px;overflow:auto}.table-scroll{overflow:auto}@media(max-width:850px){.grid{grid-template-columns:minmax(0,1fr)}.card{min-width:0}.run-card{position:static}body{padding:16px}}
4
- .tabs{display:flex;flex-wrap:wrap;gap:10px;margin:20px 0}.tabs button[aria-selected=true]{background:#62dfb1;color:#102522}.library{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:20px}.library input[type=text]{width:100%;box-sizing:border-box}.queue-row{display:flex;gap:8px;margin:8px 0}.queue-row select{flex:1}.pane{min-width:0}.map{min-height:300px;background:#09111b;border-radius:12px;padding:10px}.map canvas{display:block;width:100%;height:auto;max-height:320px;object-fit:contain}.map-legend{display:flex;gap:18px;flex-wrap:wrap;margin:10px 0;color:#c6d9e9;font-size:14px}pre{white-space:pre-wrap;overflow-wrap:anywhere}input[type=text]{width:100%;box-sizing:border-box}#libraries .row label>input,#libraries .row label>select{display:block;margin-top:6px}#editor_parameters input{max-width:240px} .eyebrow{color:#62dfb1;font-size:12px;letter-spacing:.18em;font-weight:800}.intro{font-size:19px;color:#b9cddd;max-width:820px;margin:10px 0 0}header{padding:12px 0 4px}header h1{font-size:clamp(30px,4vw,45px);letter-spacing:-.03em;margin-top:7px}.about{max-width:850px;font-size:14px;margin-top:15px}.about p{line-height:1.65}.card{box-shadow:0 10px 35px #050a1280}.tabs{position:sticky;top:0;z-index:3;background:#0c1420eF;padding:12px 0;border-bottom:1px solid #2a3d52}.tabs button{border-radius:12px;padding:11px 15px}.map-status{margin:7px 0;color:#dbe9f1;font-size:14px}#run{background:#62dfb1;color:#102522;font-weight:800;width:100%;margin-top:12px;padding:13px}.privacy-note{font-size:13px;line-height:1.5;color:#a2b4c8}.keep-result{display:flex;gap:10px;align-items:flex-start;padding:12px;border:1px solid #3b566b;border-radius:10px;background:#102030;line-height:1.4}.keep-result input{margin:3px 0 0;flex:none} .terrain{display:inline-block;width:11px;height:11px;border-radius:3px;margin-right:4px;background:#607e96}.terrain.dirt{background:#b89561}.terrain.ice{background:#b9d9ed}.terrain.start{background:#66e5aa}.output-options{display:flex;flex-wrap:wrap;gap:5px 14px}.output-options label{display:flex;align-items:center;gap:5px;margin:5px 0}.output-options input{margin:0}#editor_outputs{margin:12px 0;padding:10px 12px;border:1px solid #49627c;border-radius:8px}#editor_outputs legend{padding:0 5px;color:#c6d9e9}@media(max-width:850px){.map{min-height:0}}dialog#appConfirm{box-sizing:border-box;width:min(92vw,440px);border:1px solid #54718d;border-radius:16px;padding:24px;background:#152233;color:#e5edf5;box-shadow:0 24px 80px #000b}dialog#appConfirm::backdrop{background:#02060bcc}#appConfirm h2{margin:0 0 10px}#appConfirm p{line-height:1.55;color:#c4d3e1;white-space:pre-wrap}#appConfirm .actions{display:flex;justify-content:flex-end;gap:10px;flex-wrap:wrap;margin-top:22px}#appConfirm button{min-width:100px}#appConfirm button.danger{background:#8e3b37;color:#fff;border-color:#d7837e}</style>
5
  <dialog id="appConfirm" aria-labelledby="appConfirmTitle" aria-describedby="appConfirmMessage">
6
  <h2 id="appConfirmTitle">Confirm action</h2>
7
  <p id="appConfirmMessage"></p>
@@ -79,6 +79,7 @@
79
  <label for="crossover">Crossover</label><select id="crossover" disabled><option value="none">Off</option><option value="single_point">Single point</option><option value="uniform">Uniform</option></select>
80
  <label for="decay">Weight decay</label><input id="decay" type="number" min="0" max="1" step="0.0001" value="0" disabled><small>Allowed 0–1; suggested 0–0.001. Decay 0.05 shrinks children by 5%.</small>
81
  </details>
 
82
  <details id="reward_settings"><summary>Rewards · presets and up to five metrics</summary>
83
  <label for="reward_preset">Reward preset</label><select id="reward_preset" disabled><option value="custom">Custom</option><option value="distance" selected>First laps · distance only (+100 total score)</option><option value="center">Example mix · center, clearance, collisions</option><option value="clean">Clean driving · distance + collision penalty</option><option value="lap">Lap refinement · best lap only</option></select>
84
  <div id="rewards"></div><button id="add" disabled>+ Add reward</button><small>Weights −100…+100; absolute shares normalize to 100%. Five distinct metrics maximum. The current vehicle runner accepts these metrics; choose them for the behavior you want to train.</small>
@@ -98,7 +99,7 @@
98
  const defaults={population:4,generations:1,ticks:60,mutation:0.01,seed:42,
99
  mutation_end:0.01,schedule:'fixed',selection:'best',parents:1,elite:1,crossover:'none',
100
  decay:0,adaptive_mutation:false,control_hz:30,workers:1,collision:false,idle:false,
101
- rewards:[{metric:'total_score',type:'default',weight:100}]};
102
  const metrics=['total_score','total_speed','total_abs_steering','total_actual_distance',
103
  'total_drifting_amount','total_momentum_change_frequency','total_throttle_change_frequency',
104
  'total_braking_frequency','total_distance_from_wall','total_distance_from_center',
@@ -114,6 +115,8 @@
114
  }
115
  for(const [key,choices] of [['schedule',['fixed','linear','geometric']],['selection',['best','tournament','roulette']],['crossover',['none','single_point','uniform']],['control_hz',[60,30,15]]])if(!choices.includes(clean[key]))throw Error('Invalid '+key);
116
  for(const key of ['adaptive_mutation','collision','idle'])if(typeof clean[key]!=='boolean')throw Error('Invalid '+key);
 
 
117
  if(clean.parents>clean.population||clean.elite>clean.population)throw Error('Parents/elites exceed population');
118
  if(clean.mutation<=0||(clean.schedule!=='fixed'&&clean.mutation_end<=0))throw Error('This training runner requires positive mutation rates, including when continuing an uploaded network');
119
  if(!Array.isArray(clean.rewards)||!clean.rewards.length||clean.rewards.length>5)throw Error('Use one to five rewards');
@@ -282,6 +285,32 @@
282
  const fields=['population','generations','mutation','seed','mutation_end','schedule','selection','parents','elite','crossover','decay','adaptive_mutation','control_hz','workers','collision','idle'];
283
  const booleans=['adaptive_mutation','collision','idle'];
284
  const strings=['schedule','selection','crossover'];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
285
  function rewards(){return [...q('rewards').children].map(row=>({metric:row.children[0].value,type:row.children[1].value,weight:Number(row.children[2].value)}));}
286
  function rewardRow(r){
287
  const row=document.createElement('div');row.className='reward';
@@ -297,13 +326,14 @@
297
  }
298
  function currentSettings(){
299
  const data={};for(const name of fields)data[name]=booleans.includes(name)?q(name).checked:strings.includes(name)?q(name).value:Number(q(name).value);
300
- data.ticks=Number(q('training_ticks').value);data.rewards=rewards();return api.settings(data);
301
  }
302
  function executableSettings(){const data=currentSettings();if(data.population*data.generations*data.ticks>4000000)throw Error('Run exceeds 4,000,000 vehicle-ticks');return data;}
303
  function applySettings(value){
304
  const data=api.settings(value);
305
  for(const name of fields){if(booleans.includes(name))q(name).checked=data[name];else q(name).value=data[name];}
306
  q('training_ticks').value=data.ticks;q('rewards').replaceChildren();data.rewards.forEach(rewardRow);
 
307
  q('recipe_draft').value=JSON.stringify(data,null,2);
308
  }
309
  const editable=[...fields,'training_ticks','add','reward_preset','preset','starter_settings_reset'];
@@ -311,7 +341,7 @@
311
  q('end_rate_group').hidden=false;
312
  const firstRunSettings={...api.defaults,population:32,generations:20,ticks:900,mutation:0.3,mutation_end:0.3,parents:1,elite:1,decay:0,workers:1,collision:false,idle:false,rewards:[{metric:'total_score',type:'default',weight:100}]};
313
  applySettings(firstRunSettings);q('preset').value='starter';q('reward_preset').value='distance';
314
- window.getTrainingSettings=executableSettings;
315
  let stagedPortableRecipe=false;
316
  window.getPortableRecipe=()=>{
317
  if(stagedPortableRecipe)return {slot:q('recipe_slot').value,name:q('recipe_name').value,settings:currentSettings()};
 
1
  <!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>AI Learns To Drive</title>
2
  <style>
3
  :root{color-scheme:dark;font:16px system-ui;background:#0c1420;color:#e5edf5}body{max-width:1400px;margin:auto;padding:22px}h1{font-size:32px;margin:0}h2{font-size:21px;margin:0 0 14px}small,.hint{color:#a2b4c8;line-height:1.6}.grid{display:grid;grid-template-columns:minmax(360px,.9fr) minmax(0,1.25fr);gap:24px}.card{background:#152233;border:1px solid #2a3d52;border-radius:16px;padding:22px;margin-top:20px}label{display:block;margin:12px 0 5px}input,select,button{font:inherit;background:#0c1725;color:#e5edf5;border:1px solid #49627c;border-radius:7px;padding:9px}input[type=number],select{width:100%;box-sizing:border-box}input[type=file]{max-width:100%;box-sizing:border-box}button{cursor:pointer}button.primary{background:#62dfb1;color:#102522;font-weight:700}button:disabled{opacity:.4;cursor:default}.row{display:grid;grid-template-columns:1fr 1fr;gap:15px}.reward{display:grid;grid-template-columns:1.7fr 1fr 70px 30px;gap:5px;margin:8px 0}.reward input{width:70px;box-sizing:border-box}a{color:#7ce4c3}canvas{width:100%;background:#09111b;border-radius:10px}#status{white-space:pre-wrap;line-height:1.7}table{width:100%;text-align:left;border-collapse:collapse;font-size:14px}td,th{padding:9px;border-bottom:1px solid #2a3d52}.pill{display:inline-block;background:#284539;border-radius:20px;padding:5px 12px;color:#91efc6;margin:6px 0}#error{color:#ffb5a2;white-space:pre-wrap}.toolbar{display:flex;gap:12px;align-items:center;flex-wrap:wrap;padding-bottom:16px;border-bottom:1px solid #2a3d52;margin-bottom:15px}.run-card{position:sticky;top:20px}details{margin-top:18px;border-top:1px solid #2a3d52;padding-top:14px}summary{cursor:pointer;font-weight:600;color:#c6d9e9}details[open]>summary{margin-bottom:12px}[hidden]{display:none!important}#map_note{font-size:14px}#runs{max-height:380px;overflow:auto}.table-scroll{overflow:auto}@media(max-width:850px){.grid{grid-template-columns:minmax(0,1fr)}.card{min-width:0}.run-card{position:static}body{padding:16px}}
4
+ .tabs{display:flex;flex-wrap:wrap;gap:10px;margin:20px 0}.tabs button[aria-selected=true]{background:#62dfb1;color:#102522}.library{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:20px}.library input[type=text]{width:100%;box-sizing:border-box}.queue-row{display:flex;gap:8px;margin:8px 0}.queue-row select{flex:1}.pane{min-width:0}.map{min-height:300px;background:#09111b;border-radius:12px;padding:10px}.map canvas{display:block;width:100%;height:auto;max-height:320px;object-fit:contain}.map-legend{display:flex;gap:18px;flex-wrap:wrap;margin:10px 0;color:#c6d9e9;font-size:14px}pre{white-space:pre-wrap;overflow-wrap:anywhere}input[type=text]{width:100%;box-sizing:border-box}#libraries .row label>input,#libraries .row label>select{display:block;margin-top:6px}#editor_parameters input{max-width:240px} .eyebrow{color:#62dfb1;font-size:12px;letter-spacing:.18em;font-weight:800}.intro{font-size:19px;color:#b9cddd;max-width:820px;margin:10px 0 0}header{padding:12px 0 4px}header h1{font-size:clamp(30px,4vw,45px);letter-spacing:-.03em;margin-top:7px}.about{max-width:850px;font-size:14px;margin-top:15px}.about p{line-height:1.65}.card{box-shadow:0 10px 35px #050a1280}.tabs{position:sticky;top:0;z-index:3;background:#0c1420eF;padding:12px 0;border-bottom:1px solid #2a3d52}.tabs button{border-radius:12px;padding:11px 15px}.map-status{margin:7px 0;color:#dbe9f1;font-size:14px}#run{background:#62dfb1;color:#102522;font-weight:800;width:100%;margin-top:12px;padding:13px}.privacy-note{font-size:13px;line-height:1.5;color:#a2b4c8}.keep-result{display:flex;gap:10px;align-items:flex-start;padding:12px;border:1px solid #3b566b;border-radius:10px;background:#102030;line-height:1.4}.keep-result input{margin:3px 0 0;flex:none} .terrain{display:inline-block;width:11px;height:11px;border-radius:3px;margin-right:4px;background:#607e96}.terrain.dirt{background:#b89561}.terrain.ice{background:#b9d9ed}.terrain.start{background:#66e5aa}.output-options{display:flex;flex-wrap:wrap;gap:5px 14px}.output-options label{display:flex;align-items:center;gap:5px;margin:5px 0}.output-options input{margin:0}#editor_outputs{margin:12px 0;padding:10px 12px;border:1px solid #49627c;border-radius:8px}#editor_outputs legend{padding:0 5px;color:#c6d9e9}.freeze-group{min-width:190px;flex:1;margin:8px 0;padding:8px 12px;border:1px solid #49627c;border-radius:8px}.freeze-group summary{padding:0 5px;color:#c6d9e9;cursor:pointer}.freeze-group label{display:block;margin:6px 0}@media(max-width:850px){.map{min-height:0}}dialog#appConfirm{box-sizing:border-box;width:min(92vw,440px);border:1px solid #54718d;border-radius:16px;padding:24px;background:#152233;color:#e5edf5;box-shadow:0 24px 80px #000b}dialog#appConfirm::backdrop{background:#02060bcc}#appConfirm h2{margin:0 0 10px}#appConfirm p{line-height:1.55;color:#c4d3e1;white-space:pre-wrap}#appConfirm .actions{display:flex;justify-content:flex-end;gap:10px;flex-wrap:wrap;margin-top:22px}#appConfirm button{min-width:100px}#appConfirm button.danger{background:#8e3b37;color:#fff;border-color:#d7837e}</style>
5
  <dialog id="appConfirm" aria-labelledby="appConfirmTitle" aria-describedby="appConfirmMessage">
6
  <h2 id="appConfirmTitle">Confirm action</h2>
7
  <p id="appConfirmMessage"></p>
 
79
  <label for="crossover">Crossover</label><select id="crossover" disabled><option value="none">Off</option><option value="single_point">Single point</option><option value="uniform">Uniform</option></select>
80
  <label for="decay">Weight decay</label><input id="decay" type="number" min="0" max="1" step="0.0001" value="0" disabled><small>Allowed 0–1; suggested 0–0.001. Decay 0.05 shrinks children by 5%.</small>
81
  </details>
82
+ <details id="freeze_settings"><summary>Selective freezing · optional</summary><p class="hint">Keep selected sensor inputs, hidden layers, or output controls unchanged while training. Choices follow the selected network and are saved with recipes. Frozen evaluation always uses an empty freeze selection.</p><div id="freeze_status" class="hint" role="status">Select a network to choose components.</div><div id="freeze_controls" class="row"></div></details>
83
  <details id="reward_settings"><summary>Rewards · presets and up to five metrics</summary>
84
  <label for="reward_preset">Reward preset</label><select id="reward_preset" disabled><option value="custom">Custom</option><option value="distance" selected>First laps · distance only (+100 total score)</option><option value="center">Example mix · center, clearance, collisions</option><option value="clean">Clean driving · distance + collision penalty</option><option value="lap">Lap refinement · best lap only</option></select>
85
  <div id="rewards"></div><button id="add" disabled>+ Add reward</button><small>Weights −100…+100; absolute shares normalize to 100%. Five distinct metrics maximum. The current vehicle runner accepts these metrics; choose them for the behavior you want to train.</small>
 
99
  const defaults={population:4,generations:1,ticks:60,mutation:0.01,seed:42,
100
  mutation_end:0.01,schedule:'fixed',selection:'best',parents:1,elite:1,crossover:'none',
101
  decay:0,adaptive_mutation:false,control_hz:30,workers:1,collision:false,idle:false,
102
+ rewards:[{metric:'total_score',type:'default',weight:100}],freeze:{layers:[],inputs:[],outputs:[]}};
103
  const metrics=['total_score','total_speed','total_abs_steering','total_actual_distance',
104
  'total_drifting_amount','total_momentum_change_frequency','total_throttle_change_frequency',
105
  'total_braking_frequency','total_distance_from_wall','total_distance_from_center',
 
115
  }
116
  for(const [key,choices] of [['schedule',['fixed','linear','geometric']],['selection',['best','tournament','roulette']],['crossover',['none','single_point','uniform']],['control_hz',[60,30,15]]])if(!choices.includes(clean[key]))throw Error('Invalid '+key);
117
  for(const key of ['adaptive_mutation','collision','idle'])if(typeof clean[key]!=='boolean')throw Error('Invalid '+key);
118
+ if(!clean.freeze||typeof clean.freeze!=='object'||Array.isArray(clean.freeze)||Object.keys(clean.freeze).sort().join()!=='inputs,layers,outputs')throw Error('Invalid freeze settings');
119
+ for(const [key,max] of [['layers',10],['inputs',19],['outputs',4]]){const values=clean.freeze[key];if(!Array.isArray(values)||values.some(v=>!Number.isInteger(v)||v<(key==='layers'?1:0)||v>max)||new Set(values).size!==values.length)throw Error('Invalid frozen '+key);clean.freeze[key]=[...values].sort((a,b)=>a-b);}
120
  if(clean.parents>clean.population||clean.elite>clean.population)throw Error('Parents/elites exceed population');
121
  if(clean.mutation<=0||(clean.schedule!=='fixed'&&clean.mutation_end<=0))throw Error('This training runner requires positive mutation rates, including when continuing an uploaded network');
122
  if(!Array.isArray(clean.rewards)||!clean.rewards.length||clean.rewards.length>5)throw Error('Use one to five rewards');
 
285
  const fields=['population','generations','mutation','seed','mutation_end','schedule','selection','parents','elite','crossover','decay','adaptive_mutation','control_hz','workers','collision','idle'];
286
  const booleans=['adaptive_mutation','collision','idle'];
287
  const strings=['schedule','selection','crossover'];
288
+ let freezeNetwork=null;
289
+ const freezeLabels={outputs:['Steering','Acceleration','Handbrake','Brake','Boost']};
290
+ function freezeValue(){const f=api.settings({...api.defaults,freeze:{layers:[],inputs:[],outputs:[]}}).freeze;return f;}
291
+ function includeUnavailableFreezeSelections(kind,items,selectedIds){
292
+ const available=new Set(items.map(item=>item.id)),noun=kind==='layers'?'hidden layer':kind==='inputs'?'sensor input':'output';
293
+ const unavailable=selectedIds.filter(id=>!available.has(id)).map(id=>({id,unavailable:true,label:'Unavailable '+noun+' index '+id}));
294
+ return [...items,...unavailable];
295
+ }
296
+ function renderFreeze(){
297
+ const box=q('freeze_controls'),status=q('freeze_status'),openGroups=new Map([...box.querySelectorAll('details.freeze-group')].map(group=>[group.dataset.freezeGroup,group.open]));box.replaceChildren();
298
+ if(!freezeNetwork){status.textContent='Select a network to choose components.';return;}
299
+ const {shape,sensors,outputs}=freezeNetwork;
300
+ const groups=[['layers',Array.from({length:Math.max(0,shape.length-2)},(_,i)=>({id:i+1,label:'Hidden layer '+(i+1)+' · '+shape[i+1]+' nodes'}))],
301
+ ['inputs',sensors.map((sensor,i)=>({id:i,label:'Input '+i+' · '+(sensor.$type==='raycast'?'Raycast '+sensor.Degrees+'°':sensor.$type.replaceAll('_',' '))}))],
302
+ ['outputs',outputs.map((output,i)=>({id:i,label:'Output '+i+' · '+(freezeLabels.outputs[output]||('Control '+output))}))]];
303
+ for(const [kind,availableItems] of groups){const items=includeUnavailableFreezeSelections(kind,availableItems,selectedFreeze[kind]);const field=document.createElement('details');field.className='freeze-group';field.dataset.freezeGroup=kind;field.open=openGroups.get(kind)??false;const summary=document.createElement('summary');summary.textContent=(kind==='layers'?'Hidden layers':kind==='inputs'?'Sensor inputs':'Outputs')+' ('+items.length+')';field.append(summary);
304
+ for(const item of items){const label=document.createElement('label'),input=document.createElement('input');input.type='checkbox';input.dataset.freezeKind=kind;input.value=String(item.id);input.checked=selectedFreeze[kind].includes(item.id);label.append(input,document.createTextNode(' '+item.label));field.append(label);}
305
+ box.append(field);
306
+ }
307
+ const invalid=['layers','inputs','outputs'].flatMap(kind=>selectedFreeze[kind].filter(id=>!itemsFor(kind).includes(id)).map(id=>kind+' '+id));
308
+ status.textContent=invalid.length?'Some saved selections are unavailable. Uncheck their visible “Unavailable” entries before starting training.':'Selected network: '+shape.join(' → ')+' · '+sensors.length+' inputs · '+outputs.length+' outputs.';
309
+ }
310
+ const selectedFreeze=freezeValue();
311
+ function itemsFor(kind){if(!freezeNetwork)return[];if(kind==='layers')return Array.from({length:freezeNetwork.shape.length-2},(_,i)=>i+1);if(kind==='inputs')return freezeNetwork.sensors.map((_,i)=>i);return freezeNetwork.outputs.map((_,i)=>i);}
312
+ window.setFreezeNetwork=network=>{freezeNetwork=network?{shape:[...network.NeuralNetwork.Shape],sensors:network.Sensors.map(x=>({...x})),outputs:[...network.Outputs]}:null;renderFreeze();};
313
+ q('freeze_controls').addEventListener('change',event=>{const input=event.target;if(!input.matches('input[data-freeze-kind]'))return;const kind=input.dataset.freezeKind,id=Number(input.value);selectedFreeze[kind]=input.checked?[...selectedFreeze[kind],id].sort((a,b)=>a-b):selectedFreeze[kind].filter(x=>x!==id);q('preset').value='custom';renderFreeze();});
314
  function rewards(){return [...q('rewards').children].map(row=>({metric:row.children[0].value,type:row.children[1].value,weight:Number(row.children[2].value)}));}
315
  function rewardRow(r){
316
  const row=document.createElement('div');row.className='reward';
 
326
  }
327
  function currentSettings(){
328
  const data={};for(const name of fields)data[name]=booleans.includes(name)?q(name).checked:strings.includes(name)?q(name).value:Number(q(name).value);
329
+ data.ticks=Number(q('training_ticks').value);data.rewards=rewards();data.freeze={layers:[...selectedFreeze.layers],inputs:[...selectedFreeze.inputs],outputs:[...selectedFreeze.outputs]};return api.settings(data);
330
  }
331
  function executableSettings(){const data=currentSettings();if(data.population*data.generations*data.ticks>4000000)throw Error('Run exceeds 4,000,000 vehicle-ticks');return data;}
332
  function applySettings(value){
333
  const data=api.settings(value);
334
  for(const name of fields){if(booleans.includes(name))q(name).checked=data[name];else q(name).value=data[name];}
335
  q('training_ticks').value=data.ticks;q('rewards').replaceChildren();data.rewards.forEach(rewardRow);
336
+ for(const kind of ['layers','inputs','outputs'])selectedFreeze[kind]=[...data.freeze[kind]];renderFreeze();
337
  q('recipe_draft').value=JSON.stringify(data,null,2);
338
  }
339
  const editable=[...fields,'training_ticks','add','reward_preset','preset','starter_settings_reset'];
 
341
  q('end_rate_group').hidden=false;
342
  const firstRunSettings={...api.defaults,population:32,generations:20,ticks:900,mutation:0.3,mutation_end:0.3,parents:1,elite:1,decay:0,workers:1,collision:false,idle:false,rewards:[{metric:'total_score',type:'default',weight:100}]};
343
  applySettings(firstRunSettings);q('preset').value='starter';q('reward_preset').value='distance';
344
+ window.getTrainingSettings=()=>{const data=executableSettings();if(q('run_mode')?.value==='evaluate')data.freeze={layers:[],inputs:[],outputs:[]};else if(freezeNetwork){for(const kind of ['layers','inputs','outputs'])if(data.freeze[kind].some(id=>!itemsFor(kind).includes(id)))throw Error('Remove frozen selections that do not exist on the selected network');}else if(data.freeze.layers.length||data.freeze.inputs.length||data.freeze.outputs.length)throw Error('Select a network before using selective freezing');return data;};
345
  let stagedPortableRecipe=false;
346
  window.getPortableRecipe=()=>{
347
  if(stagedPortableRecipe)return {slot:q('recipe_slot').value,name:q('recipe_name').value,settings:currentSettings()};
native/selective-freeze-build-receipt.json ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "schema": "ald-native-cross-build-attempt-v1",
3
+ "started_utc": "2026-10-14T16:58:09.004157+00:00",
4
+ "command": [
5
+ "/Users/tiga/.cargo/bin/cargo",
6
+ "+1.95.0",
7
+ "build",
8
+ "--target",
9
+ "x86_64-unknown-linux-gnu",
10
+ "--manifest-path",
11
+ "build/source/Cargo.toml",
12
+ "--release",
13
+ "--locked",
14
+ "--offline",
15
+ "--no-default-features",
16
+ "--features",
17
+ "cli",
18
+ "--bin",
19
+ "altd-sim"
20
+ ],
21
+ "environment": {
22
+ "CARGO_TARGET_DIR": "/Volumes/PATRIOT/ALD-TAO-lab/hf-winners-evaluation-v1.2-20261013/build/cross-target",
23
+ "CARGO_PROFILE_RELEASE_LTO": "false",
24
+ "CARGO_PROFILE_RELEASE_CODEGEN_UNITS": "16",
25
+ "CARGO_PROFILE_RELEASE_DEBUG": "0",
26
+ "CARGO_BUILD_JOBS": "4",
27
+ "CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER": "/Volumes/PATRIOT/ALD-TAO-lab/hf-winners-evaluation-v1.2-20261013/build/cross-tools/linux-linker",
28
+ "RUSTFLAGS": "--sysroot /Volumes/PATRIOT/ALD-TAO-lab/hf-winners-evaluation-v1.2-20261013/build/cross-sysroot -C target-cpu=x86-64"
29
+ },
30
+ "status": "compiled",
31
+ "exit_code": 0,
32
+ "artifact": {
33
+ "path": "build/artifacts/altd-sim",
34
+ "bytes": 3647808,
35
+ "sha256": "ce31f754f6b6f3afaf4dcc44c1e6fda3e6414eb2924fa167b8778523bcaf2070"
36
+ },
37
+ "elapsed_seconds": 25.666
38
+ }
native/selective-freeze-source.tar.gz ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:297d2ce34569994acd2a477e64c5315cb2081699b4333b8abdabb3ff7451d8db
3
+ size 491438
portable_bundle.py CHANGED
@@ -35,9 +35,9 @@ RECIPE_KEYS = {
35
  "population", "generations", "ticks", "mutation", "seed", "mutation_end",
36
  "schedule", "selection", "parents", "elite", "crossover", "decay",
37
  "adaptive_mutation", "control_hz", "workers", "collision", "idle", "rewards",
38
- "mode", "clean_min_laps",
39
  }
40
- LEGACY_RECIPE_KEYS = RECIPE_KEYS - {"mode", "clean_min_laps"}
41
  METRICS = {
42
  "total_score", "total_speed", "total_abs_steering", "total_actual_distance",
43
  "total_drifting_amount", "total_momentum_change_frequency", "total_throttle_change_frequency",
@@ -274,7 +274,8 @@ def load_analysis_archive(raw: bytes) -> tuple[dict[str, Any], dict[str, bytes]]
274
  and not (kind == "average" and metric not in AVERAGE_METRICS)]):
275
  raise BundleError("analysis metric or reward channel definitions are invalid")
276
  settings = analysis.get("settings")
277
- if not isinstance(settings, dict) or set(settings) != RECIPE_KEYS:
 
278
  raise BundleError("analysis validated settings are missing")
279
  validate_settings(settings)
280
  if (settings.get("mode") != mode or settings.get("ticks") != conditions["requested_ticks"]
@@ -501,10 +502,26 @@ def _is_number(value: Any, low: float, high: float) -> bool:
501
  return type(value) in (int, float) and math.isfinite(value) and low <= value <= high
502
 
503
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
504
  def validate_settings(value: Any) -> dict[str, Any]:
505
  settings = _strict_keys(value, RECIPE_KEYS, LEGACY_RECIPE_KEYS, "recipe settings")
506
  settings.setdefault("mode", "train")
507
  settings.setdefault("clean_min_laps", 2)
 
 
508
  bounds = {
509
  "population": (1, 128), "generations": (1, 1000), "ticks": (1, 18000),
510
  "seed": (0, 2147483647), "parents": (1, 128), "elite": (0, 128), "workers": (1, 4),
 
35
  "population", "generations", "ticks", "mutation", "seed", "mutation_end",
36
  "schedule", "selection", "parents", "elite", "crossover", "decay",
37
  "adaptive_mutation", "control_hz", "workers", "collision", "idle", "rewards",
38
+ "mode", "clean_min_laps", "freeze",
39
  }
40
+ LEGACY_RECIPE_KEYS = RECIPE_KEYS - {"mode", "clean_min_laps", "freeze"}
41
  METRICS = {
42
  "total_score", "total_speed", "total_abs_steering", "total_actual_distance",
43
  "total_drifting_amount", "total_momentum_change_frequency", "total_throttle_change_frequency",
 
274
  and not (kind == "average" and metric not in AVERAGE_METRICS)]):
275
  raise BundleError("analysis metric or reward channel definitions are invalid")
276
  settings = analysis.get("settings")
277
+ if (not isinstance(settings, dict)
278
+ or set(settings) not in (RECIPE_KEYS, RECIPE_KEYS - {"freeze"})):
279
  raise BundleError("analysis validated settings are missing")
280
  validate_settings(settings)
281
  if (settings.get("mode") != mode or settings.get("ticks") != conditions["requested_ticks"]
 
502
  return type(value) in (int, float) and math.isfinite(value) and low <= value <= high
503
 
504
 
505
+ def validate_freeze(value: Any) -> dict[str, list[int]]:
506
+ """Validate the fixed-index network freeze mask used by hosted recipes and reports."""
507
+ if not isinstance(value, dict) or set(value) != {"layers", "inputs", "outputs"}:
508
+ raise BundleError("recipe freeze mask has unsupported fields")
509
+ bounds = {"layers": (1, 10), "inputs": (0, 19), "outputs": (0, 4)}
510
+ for key, (low, high) in bounds.items():
511
+ indices = value[key]
512
+ if (not isinstance(indices, list)
513
+ or any(type(index) is not int or not low <= index <= high for index in indices)
514
+ or indices != sorted(set(indices))):
515
+ raise BundleError("recipe freeze mask indices are invalid")
516
+ return value
517
+
518
+
519
  def validate_settings(value: Any) -> dict[str, Any]:
520
  settings = _strict_keys(value, RECIPE_KEYS, LEGACY_RECIPE_KEYS, "recipe settings")
521
  settings.setdefault("mode", "train")
522
  settings.setdefault("clean_min_laps", 2)
523
+ if "freeze" in settings:
524
+ validate_freeze(settings["freeze"])
525
  bounds = {
526
  "population": (1, 128), "generations": (1, 1000), "ticks": (1, 18000),
527
  "seed": (0, 2147483647), "parents": (1, 128), "elite": (0, 128), "workers": (1, 4),
training_config.py CHANGED
@@ -5,12 +5,27 @@ import math
5
  DEFAULTS={'mode':'train','clean_min_laps':2,'population':4,'generations':1,'ticks':60,'mutation':.01,'seed':42,
6
  'mutation_end':.01,'schedule':'fixed','selection':'best','parents':1,'elite':1,
7
  'crossover':'none','decay':0,'adaptive_mutation':False,'control_hz':30,'workers':1,
8
- 'collision':False,'idle':False,'rewards':[{'metric':'total_score','type':'default','weight':100}]}
 
9
  METRICS={'total_score','total_speed','total_abs_steering','total_actual_distance',
10
  'total_drifting_amount','total_momentum_change_frequency','total_throttle_change_frequency',
11
  'total_braking_frequency','total_distance_from_wall','total_distance_from_center',
12
  'network_novelty','collision_count','best_lap_performance','total_racing_line_efficiency'}
13
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  def validate_config(value=None):
15
  if value is None:return copy.deepcopy(DEFAULTS)
16
  if not isinstance(value,dict) or set(value)-set(DEFAULTS):raise ValueError('Unexpected training settings')
@@ -26,6 +41,7 @@ def validate_config(value=None):
26
  if c[key] not in choices or (key=='control_hz' and type(c[key]) is not int):raise ValueError('Invalid '+key)
27
  for key in ('adaptive_mutation','collision','idle'):
28
  if type(c[key]) is not bool:raise ValueError('Invalid '+key)
 
29
  if c['mode']=='train' and (c['parents']>c['population'] or c['elite']>c['population']):raise ValueError('Parents/elites exceed population')
30
  if c['mode']=='train' and (c['mutation']<=0 or (c['schedule']!='fixed' and c['mutation_end']<=0)):raise ValueError('This training runner requires positive mutation rates, including when continuing an uploaded network')
31
  # Echo the rate actually passed to the native CLI, not an unused form value.
@@ -40,6 +56,6 @@ def validate_config(value=None):
40
  if not any(r['weight'] for r in clean):raise ValueError('A reward weight must be nonzero')
41
  c['rewards']=clean
42
  if c['mode']=='evaluate':
43
- c.update(population=1,generations=1,mutation=0,mutation_end=0,decay=0,adaptive_mutation=False,parents=1,elite=0,crossover='none',selection='best',schedule='fixed')
44
  if c['population']*c['generations']*c['ticks']>4_000_000:raise ValueError('Run exceeds preview work limit (4,000,000 vehicle-ticks)')
45
  return c
 
5
  DEFAULTS={'mode':'train','clean_min_laps':2,'population':4,'generations':1,'ticks':60,'mutation':.01,'seed':42,
6
  'mutation_end':.01,'schedule':'fixed','selection':'best','parents':1,'elite':1,
7
  'crossover':'none','decay':0,'adaptive_mutation':False,'control_hz':30,'workers':1,
8
+ 'collision':False,'idle':False,'freeze':{'layers':[],'inputs':[],'outputs':[]},
9
+ 'rewards':[{'metric':'total_score','type':'default','weight':100}]}
10
  METRICS={'total_score','total_speed','total_abs_steering','total_actual_distance',
11
  'total_drifting_amount','total_momentum_change_frequency','total_throttle_change_frequency',
12
  'total_braking_frequency','total_distance_from_wall','total_distance_from_center',
13
  'network_novelty','collision_count','best_lap_performance','total_racing_line_efficiency'}
14
 
15
+ def validate_freeze(value):
16
+ """Check the settings envelope; the uploaded network supplies exact bounds."""
17
+ if not isinstance(value,dict) or set(value)!={'layers','inputs','outputs'}:
18
+ raise ValueError('Invalid freeze selection')
19
+ result={}
20
+ for key,low,high in (('layers',1,10),('inputs',0,19),('outputs',0,4)):
21
+ items=value[key]
22
+ if (not isinstance(items,list) or len(items)>high-low+1 or
23
+ any(type(item) is not int or not low<=item<=high for item in items) or
24
+ items!=sorted(set(items))):
25
+ raise ValueError('Invalid frozen '+key)
26
+ result[key]=items[:]
27
+ return result
28
+
29
  def validate_config(value=None):
30
  if value is None:return copy.deepcopy(DEFAULTS)
31
  if not isinstance(value,dict) or set(value)-set(DEFAULTS):raise ValueError('Unexpected training settings')
 
41
  if c[key] not in choices or (key=='control_hz' and type(c[key]) is not int):raise ValueError('Invalid '+key)
42
  for key in ('adaptive_mutation','collision','idle'):
43
  if type(c[key]) is not bool:raise ValueError('Invalid '+key)
44
+ c['freeze']=validate_freeze(c['freeze'])
45
  if c['mode']=='train' and (c['parents']>c['population'] or c['elite']>c['population']):raise ValueError('Parents/elites exceed population')
46
  if c['mode']=='train' and (c['mutation']<=0 or (c['schedule']!='fixed' and c['mutation_end']<=0)):raise ValueError('This training runner requires positive mutation rates, including when continuing an uploaded network')
47
  # Echo the rate actually passed to the native CLI, not an unused form value.
 
56
  if not any(r['weight'] for r in clean):raise ValueError('A reward weight must be nonzero')
57
  c['rewards']=clean
58
  if c['mode']=='evaluate':
59
+ c.update(population=1,generations=1,mutation=0,mutation_end=0,decay=0,adaptive_mutation=False,parents=1,elite=0,crossover='none',selection='best',schedule='fixed',freeze={'layers':[],'inputs':[],'outputs':[]})
60
  if c['population']*c['generations']*c['ticks']>4_000_000:raise ValueError('Run exceeds preview work limit (4,000,000 vehicle-ticks)')
61
  return c
worker.py CHANGED
@@ -111,6 +111,43 @@ def network_input(data):
111
  'NeuronsCount':sum(shape),'TotalParams':sum((a+1)*b for a,b in zip(shape,shape[1:])),
112
  'Weights':weights,'Biases':biases}}
113
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
  def track_input(data):
115
  value=read_json(data)
116
  challenges=value.get('Challenges',[])
@@ -169,6 +206,9 @@ def check_current_network(work, command, env, track, template, config, result, t
169
  if not needs_observations(track,track_sha):
170
  return resolve_check(track,template,config,[],**kwargs)
171
  check_command=list(command)
 
 
 
172
  def option(name,value):
173
  check_command[check_command.index(name)+1]=str(value)
174
  n=template['NeuralNetwork']
@@ -210,6 +250,7 @@ def run_native(track_bytes,network_bytes,*,binary=None,importer=None,scene_templ
210
  started=time.perf_counter()
211
  config=validate_config(config)
212
  track=track_input(track_bytes); template=network_input(network_bytes)
 
213
  # Deployment paths are supplied by trusted application configuration, never uploads.
214
  binary=Path(binary or ROOT/'target/release/altd-sim').resolve()
215
  importer=Path(importer or ROOT/'target/release/examples/extract_saved_track').resolve()
@@ -248,6 +289,8 @@ def run_native(track_bytes,network_bytes,*,binary=None,importer=None,scene_templ
248
  '--checkpoint-every','0','--analysis','--clean-min-laps',str(config['clean_min_laps']),
249
  '--eliminate-on-wall' if config['collision'] else '--no-eliminate-on-wall',
250
  '--idle-eliminate' if config['idle'] else '--no-idle-eliminate']
 
 
251
  if config['mode']=='evaluate':command.append('--evaluate-frozen')
252
  if gpu_library is not None: command.append('--gpu')
253
  subprocess.run(command,cwd=work,env=env,stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL,timeout=25,check=True)
@@ -255,6 +298,7 @@ def run_native(track_bytes,network_bytes,*,binary=None,importer=None,scene_templ
255
  candidate=out/'candidate.json'
256
  if candidate.stat().st_size>1024*1024: raise ValueError('Output too large')
257
  trained=json.loads(candidate.read_text())
 
258
  n['Weights']=trained['weights']; n['Biases']=trained['biases']
259
  result=(network_bytes if config['mode']=='evaluate' else gzip.compress(json.dumps(template,allow_nan=False).encode(),mtime=0))
260
  network_input(result)
 
111
  'NeuronsCount':sum(shape),'TotalParams':sum((a+1)*b for a,b in zip(shape,shape[1:])),
112
  'Weights':weights,'Biases':biases}}
113
 
114
+ def check_freeze_shape(freeze,shape):
115
+ """Resolve selection against this policy, with at least one trainable parameter."""
116
+ if any(layer>=len(shape)-1 for layer in freeze['layers']):
117
+ raise ValueError('Frozen hidden layer exceeds network shape')
118
+ if any(index>=shape[0] for index in freeze['inputs']):
119
+ raise ValueError('Frozen input exceeds sensor count')
120
+ if any(index>=shape[-1] for index in freeze['outputs']):
121
+ raise ValueError('Frozen output exceeds output count')
122
+ layers=set(freeze['layers']);inputs=set(freeze['inputs']);outputs=set(freeze['outputs'])
123
+ trainable=0
124
+ last=len(shape)-2
125
+ for layer,(source_count,dest_count) in enumerate(zip(shape,shape[1:])):
126
+ for source in range(source_count):
127
+ for dest in range(dest_count):
128
+ if not (layer+1 in layers or layer==0 and source in inputs or layer==last and dest in outputs):
129
+ trainable+=1
130
+ for dest in range(dest_count):
131
+ if not (layer+1 in layers or layer==last and dest in outputs):
132
+ trainable+=1
133
+ if not trainable:
134
+ raise ValueError('Freeze selection leaves no trainable parameters; use frozen evaluation')
135
+
136
+ def verify_frozen_parameters(freeze,starting,trained):
137
+ """Never publish a result whose native candidate violates the requested mask."""
138
+ layers=set(freeze['layers']);inputs=set(freeze['inputs']);outputs=set(freeze['outputs'])
139
+ last=len(starting['Shape'])-2
140
+ for layer,matrix in enumerate(starting['Weights']):
141
+ for source,row in enumerate(matrix):
142
+ for dest,value in enumerate(row):
143
+ if (layer+1 in layers or layer==0 and source in inputs or layer==last and dest in outputs):
144
+ if value!=trained['weights'][layer][source][dest]:
145
+ raise ValueError('Native trainer changed a frozen weight')
146
+ for dest,value in enumerate(starting['Biases'][layer]):
147
+ if layer+1 in layers or layer==last and dest in outputs:
148
+ if value!=trained['biases'][layer][dest]:
149
+ raise ValueError('Native trainer changed a frozen bias')
150
+
151
  def track_input(data):
152
  value=read_json(data)
153
  challenges=value.get('Challenges',[])
 
206
  if not needs_observations(track,track_sha):
207
  return resolve_check(track,template,config,[],**kwargs)
208
  check_command=list(command)
209
+ if '--freeze-spec' in check_command:
210
+ index=check_command.index('--freeze-spec')
211
+ del check_command[index:index+2]
212
  def option(name,value):
213
  check_command[check_command.index(name)+1]=str(value)
214
  n=template['NeuralNetwork']
 
250
  started=time.perf_counter()
251
  config=validate_config(config)
252
  track=track_input(track_bytes); template=network_input(network_bytes)
253
+ if config['mode']=='train':check_freeze_shape(config['freeze'],template['NeuralNetwork']['Shape'])
254
  # Deployment paths are supplied by trusted application configuration, never uploads.
255
  binary=Path(binary or ROOT/'target/release/altd-sim').resolve()
256
  importer=Path(importer or ROOT/'target/release/examples/extract_saved_track').resolve()
 
289
  '--checkpoint-every','0','--analysis','--clean-min-laps',str(config['clean_min_laps']),
290
  '--eliminate-on-wall' if config['collision'] else '--no-eliminate-on-wall',
291
  '--idle-eliminate' if config['idle'] else '--no-idle-eliminate']
292
+ if config['mode']=='train' and any(config['freeze'].values()):
293
+ command.extend(('--freeze-spec',save('freeze.json',config['freeze'])))
294
  if config['mode']=='evaluate':command.append('--evaluate-frozen')
295
  if gpu_library is not None: command.append('--gpu')
296
  subprocess.run(command,cwd=work,env=env,stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL,timeout=25,check=True)
 
298
  candidate=out/'candidate.json'
299
  if candidate.stat().st_size>1024*1024: raise ValueError('Output too large')
300
  trained=json.loads(candidate.read_text())
301
+ if any(config['freeze'].values()):verify_frozen_parameters(config['freeze'],n,trained)
302
  n['Weights']=trained['weights']; n['Biases']=trained['biases']
303
  result=(network_bytes if config['mode']=='evaluate' else gzip.compress(json.dumps(template,allow_nan=False).encode(),mtime=0))
304
  network_input(result)