Census locomotive tail blockers across local saves
This commit is contained in:
parent
61472bf72d
commit
cbfe0a8df9
16 changed files with 2022 additions and 319 deletions
|
|
@ -2696,7 +2696,7 @@
|
|||
},
|
||||
{
|
||||
"descriptor_id": 299,
|
||||
"label": "GP 35 Availability",
|
||||
"label": "Lower-Band Locomotive Availability Slot 59",
|
||||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
|
|
@ -2705,7 +2705,7 @@
|
|||
},
|
||||
{
|
||||
"descriptor_id": 300,
|
||||
"label": "U1 Availability",
|
||||
"label": "Lower-Band Locomotive Availability Slot 60",
|
||||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
|
|
@ -2714,7 +2714,7 @@
|
|||
},
|
||||
{
|
||||
"descriptor_id": 301,
|
||||
"label": "Zephyr Availability",
|
||||
"label": "Lower-Band Locomotive Availability Slot 61",
|
||||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
|
|
@ -2727,8 +2727,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 303,
|
||||
|
|
@ -2736,8 +2736,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 304,
|
||||
|
|
@ -2745,8 +2745,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 305,
|
||||
|
|
@ -2754,8 +2754,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 306,
|
||||
|
|
@ -2763,8 +2763,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 307,
|
||||
|
|
@ -2772,8 +2772,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 308,
|
||||
|
|
@ -2781,8 +2781,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 309,
|
||||
|
|
@ -2790,8 +2790,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 310,
|
||||
|
|
@ -2799,8 +2799,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 311,
|
||||
|
|
@ -2808,8 +2808,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 312,
|
||||
|
|
@ -2817,8 +2817,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 313,
|
||||
|
|
@ -2826,8 +2826,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 314,
|
||||
|
|
@ -2835,8 +2835,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 315,
|
||||
|
|
@ -2844,8 +2844,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 316,
|
||||
|
|
@ -2853,8 +2853,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 317,
|
||||
|
|
@ -2862,8 +2862,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 318,
|
||||
|
|
@ -2871,8 +2871,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 319,
|
||||
|
|
@ -2880,8 +2880,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 320,
|
||||
|
|
@ -2889,8 +2889,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 321,
|
||||
|
|
@ -2898,8 +2898,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 322,
|
||||
|
|
@ -2907,8 +2907,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 323,
|
||||
|
|
@ -2916,8 +2916,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 324,
|
||||
|
|
@ -2925,8 +2925,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 325,
|
||||
|
|
@ -2934,8 +2934,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 326,
|
||||
|
|
@ -2943,8 +2943,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 327,
|
||||
|
|
@ -2952,8 +2952,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 328,
|
||||
|
|
@ -2961,8 +2961,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 329,
|
||||
|
|
@ -2970,8 +2970,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 330,
|
||||
|
|
@ -2979,8 +2979,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 331,
|
||||
|
|
@ -2988,8 +2988,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 332,
|
||||
|
|
@ -2997,8 +2997,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 333,
|
||||
|
|
@ -3006,8 +3006,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 334,
|
||||
|
|
@ -3015,8 +3015,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 335,
|
||||
|
|
@ -3024,8 +3024,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 336,
|
||||
|
|
@ -3033,8 +3033,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 337,
|
||||
|
|
@ -3042,8 +3042,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 338,
|
||||
|
|
@ -3051,8 +3051,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 339,
|
||||
|
|
@ -3060,8 +3060,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 340,
|
||||
|
|
@ -3069,8 +3069,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 341,
|
||||
|
|
@ -3078,8 +3078,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 342,
|
||||
|
|
@ -3087,8 +3087,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 343,
|
||||
|
|
@ -3096,8 +3096,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 344,
|
||||
|
|
@ -3105,8 +3105,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 345,
|
||||
|
|
@ -3114,8 +3114,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 346,
|
||||
|
|
@ -3123,8 +3123,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 347,
|
||||
|
|
@ -3132,8 +3132,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 348,
|
||||
|
|
@ -3141,8 +3141,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 349,
|
||||
|
|
@ -3150,8 +3150,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 350,
|
||||
|
|
@ -3159,8 +3159,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 351,
|
||||
|
|
@ -3168,8 +3168,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 352,
|
||||
|
|
@ -3695,7 +3695,7 @@
|
|||
},
|
||||
{
|
||||
"descriptor_id": 410,
|
||||
"label": "GP 35 Cost",
|
||||
"label": "Lower-Band Locomotive Cost Slot 59",
|
||||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_cost_scalar",
|
||||
"runtime_key": null,
|
||||
|
|
@ -3704,7 +3704,7 @@
|
|||
},
|
||||
{
|
||||
"descriptor_id": 411,
|
||||
"label": "U1 Cost",
|
||||
"label": "Lower-Band Locomotive Cost Slot 60",
|
||||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_cost_scalar",
|
||||
"runtime_key": null,
|
||||
|
|
@ -3713,7 +3713,7 @@
|
|||
},
|
||||
{
|
||||
"descriptor_id": 412,
|
||||
"label": "Zephyr Cost",
|
||||
"label": "Lower-Band Locomotive Cost Slot 61",
|
||||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_cost_scalar",
|
||||
"runtime_key": null,
|
||||
|
|
@ -3726,8 +3726,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_cost_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 414,
|
||||
|
|
@ -3735,8 +3735,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_cost_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 415,
|
||||
|
|
@ -3744,8 +3744,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_cost_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 416,
|
||||
|
|
@ -3753,8 +3753,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_cost_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 417,
|
||||
|
|
@ -3762,8 +3762,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_cost_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 418,
|
||||
|
|
@ -3771,8 +3771,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_cost_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 419,
|
||||
|
|
@ -3780,8 +3780,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_cost_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 420,
|
||||
|
|
@ -3789,8 +3789,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_cost_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 421,
|
||||
|
|
@ -3798,8 +3798,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_cost_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 422,
|
||||
|
|
@ -3807,8 +3807,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_cost_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 423,
|
||||
|
|
@ -3816,8 +3816,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_cost_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 424,
|
||||
|
|
@ -3825,8 +3825,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_cost_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 425,
|
||||
|
|
@ -3834,8 +3834,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_cost_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 426,
|
||||
|
|
@ -3843,8 +3843,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_cost_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 427,
|
||||
|
|
@ -3852,8 +3852,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_cost_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 428,
|
||||
|
|
@ -3861,8 +3861,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_cost_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 429,
|
||||
|
|
@ -3870,8 +3870,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_cost_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 430,
|
||||
|
|
@ -3879,8 +3879,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_cost_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 431,
|
||||
|
|
@ -3888,8 +3888,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_cost_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 432,
|
||||
|
|
@ -3897,8 +3897,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_cost_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 433,
|
||||
|
|
@ -3906,8 +3906,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_cost_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 434,
|
||||
|
|
@ -3915,8 +3915,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_cost_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 435,
|
||||
|
|
@ -3924,8 +3924,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_cost_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 436,
|
||||
|
|
@ -3933,8 +3933,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_cost_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 437,
|
||||
|
|
@ -3942,8 +3942,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_cost_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 438,
|
||||
|
|
@ -3951,8 +3951,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_cost_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 439,
|
||||
|
|
@ -3960,8 +3960,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_cost_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 440,
|
||||
|
|
@ -3969,8 +3969,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_cost_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 441,
|
||||
|
|
@ -3978,8 +3978,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_cost_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 442,
|
||||
|
|
@ -3987,8 +3987,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_cost_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 443,
|
||||
|
|
@ -3996,8 +3996,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_cost_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 444,
|
||||
|
|
@ -4005,8 +4005,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_cost_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 445,
|
||||
|
|
@ -4014,8 +4014,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_cost_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 446,
|
||||
|
|
@ -4023,8 +4023,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_cost_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 447,
|
||||
|
|
@ -4032,8 +4032,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_cost_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 448,
|
||||
|
|
@ -4041,8 +4041,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_cost_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 449,
|
||||
|
|
@ -4050,8 +4050,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_cost_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 450,
|
||||
|
|
@ -4059,8 +4059,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_cost_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 451,
|
||||
|
|
@ -4068,8 +4068,8 @@
|
|||
"target_mask_bits": 11,
|
||||
"parameter_family": "locomotive_cost_scalar",
|
||||
"runtime_key": null,
|
||||
"runtime_status": "evidence_blocked",
|
||||
"executable_in_runtime": false
|
||||
"runtime_status": "executable",
|
||||
"executable_in_runtime": true
|
||||
},
|
||||
{
|
||||
"descriptor_id": 452,
|
||||
|
|
|
|||
477
artifacts/exports/rt3-1.06/locomotive-catalog-tail-census.json
Normal file
477
artifacts/exports/rt3-1.06/locomotive-catalog-tail-census.json
Normal file
|
|
@ -0,0 +1,477 @@
|
|||
{
|
||||
"root_path": "rt3_wineprefix/drive_c",
|
||||
"file_count": 29,
|
||||
"files_with_named_locomotive_table_count": 5,
|
||||
"files_with_locomotive_catalog_count": 5,
|
||||
"files_with_packed_event_collection_count": 26,
|
||||
"stable_prefix_length": 58,
|
||||
"stable_prefix_last_name": "VL80T",
|
||||
"tail_cluster_count": 2,
|
||||
"tail_clusters": [
|
||||
{
|
||||
"entry_count": 63,
|
||||
"tail_entries": [
|
||||
{
|
||||
"locomotive_id": 59,
|
||||
"name": "242 A1"
|
||||
},
|
||||
{
|
||||
"locomotive_id": 60,
|
||||
"name": "Class 460"
|
||||
},
|
||||
{
|
||||
"locomotive_id": 61,
|
||||
"name": "Class A1"
|
||||
},
|
||||
{
|
||||
"locomotive_id": 62,
|
||||
"name": "Class P8"
|
||||
},
|
||||
{
|
||||
"locomotive_id": 63,
|
||||
"name": "U1"
|
||||
}
|
||||
],
|
||||
"file_count": 1,
|
||||
"sample_paths": [
|
||||
"rt3_wineprefix/drive_c/rt3_105/Saved Games/g.gms"
|
||||
],
|
||||
"map_paths": [
|
||||
"Spanish Mainline.gmp"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entry_count": 61,
|
||||
"tail_entries": [
|
||||
{
|
||||
"locomotive_id": 59,
|
||||
"name": "GP 35"
|
||||
},
|
||||
{
|
||||
"locomotive_id": 60,
|
||||
"name": "U1"
|
||||
},
|
||||
{
|
||||
"locomotive_id": 61,
|
||||
"name": "Zephyr"
|
||||
}
|
||||
],
|
||||
"file_count": 4,
|
||||
"sample_paths": [
|
||||
"rt3_wineprefix/drive_c/rt3_105/Saved Games/Autosave.gms",
|
||||
"rt3_wineprefix/drive_c/rt3_105/Saved Games/nom.gms",
|
||||
"rt3_wineprefix/drive_c/rt3_105/Saved Games/p.gms",
|
||||
"rt3_wineprefix/drive_c/rt3_105/Saved Games/q.gms"
|
||||
],
|
||||
"map_paths": [
|
||||
"Alternate USA.gmp",
|
||||
"Southern Pacific.gmp"
|
||||
]
|
||||
}
|
||||
],
|
||||
"extra_shipped_name_coverage": [
|
||||
{
|
||||
"name": "242 A1",
|
||||
"observed_in_catalog_file_count": 1,
|
||||
"observed_ordinals": [
|
||||
59
|
||||
],
|
||||
"sample_paths": [
|
||||
"rt3_wineprefix/drive_c/rt3_105/Saved Games/g.gms"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Class 460",
|
||||
"observed_in_catalog_file_count": 1,
|
||||
"observed_ordinals": [
|
||||
60
|
||||
],
|
||||
"sample_paths": [
|
||||
"rt3_wineprefix/drive_c/rt3_105/Saved Games/g.gms"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Class A1",
|
||||
"observed_in_catalog_file_count": 1,
|
||||
"observed_ordinals": [
|
||||
61
|
||||
],
|
||||
"sample_paths": [
|
||||
"rt3_wineprefix/drive_c/rt3_105/Saved Games/g.gms"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Class P8",
|
||||
"observed_in_catalog_file_count": 1,
|
||||
"observed_ordinals": [
|
||||
62
|
||||
],
|
||||
"sample_paths": [
|
||||
"rt3_wineprefix/drive_c/rt3_105/Saved Games/g.gms"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Class QJ",
|
||||
"observed_in_catalog_file_count": 0,
|
||||
"observed_ordinals": [],
|
||||
"sample_paths": []
|
||||
}
|
||||
],
|
||||
"descriptor_452_hits": {
|
||||
"row_count": 0,
|
||||
"file_count": 0,
|
||||
"descriptor_ids_present": [],
|
||||
"descriptor_labels_present": [],
|
||||
"carrier_paths": []
|
||||
},
|
||||
"upper_availability_band_hits": {
|
||||
"row_count": 0,
|
||||
"file_count": 0,
|
||||
"descriptor_ids_present": [],
|
||||
"descriptor_labels_present": [],
|
||||
"carrier_paths": []
|
||||
},
|
||||
"upper_cost_band_hits": {
|
||||
"row_count": 0,
|
||||
"file_count": 0,
|
||||
"descriptor_ids_present": [],
|
||||
"descriptor_labels_present": [],
|
||||
"carrier_paths": []
|
||||
},
|
||||
"skipped_file_count": 3,
|
||||
"samples": [
|
||||
{
|
||||
"path": "rt3_wineprefix/drive_c/rt3/Saved Games/Autosave.gms",
|
||||
"container_profile_family": "rt3-classic-save-container-v1",
|
||||
"mechanism_family": "classic-save-rehydrate-v1",
|
||||
"map_path": "British Isles.gmp",
|
||||
"display_name": "British Isles",
|
||||
"named_locomotive_table_entry_count": null,
|
||||
"locomotive_catalog_entry_count": 0,
|
||||
"tail_entries": []
|
||||
},
|
||||
{
|
||||
"path": "rt3_wineprefix/drive_c/rt3/Saved Games/hh.gms",
|
||||
"container_profile_family": "rt3-classic-save-container-v1",
|
||||
"mechanism_family": "classic-save-rehydrate-v1",
|
||||
"map_path": "British Isles.gmp",
|
||||
"display_name": "British Isles",
|
||||
"named_locomotive_table_entry_count": null,
|
||||
"locomotive_catalog_entry_count": 0,
|
||||
"tail_entries": []
|
||||
},
|
||||
{
|
||||
"path": "rt3_wineprefix/drive_c/rt3/Saved Games/kk.gms",
|
||||
"container_profile_family": "rt3-classic-save-container-v1",
|
||||
"mechanism_family": "classic-save-rehydrate-v1",
|
||||
"map_path": "British Isles.gmp",
|
||||
"display_name": "British Isles",
|
||||
"named_locomotive_table_entry_count": null,
|
||||
"locomotive_catalog_entry_count": 0,
|
||||
"tail_entries": []
|
||||
},
|
||||
{
|
||||
"path": "rt3_wineprefix/drive_c/rt3_105/Saved Games/111.gmx",
|
||||
"container_profile_family": "rt3-105-sandbox-container-v1",
|
||||
"mechanism_family": "rt3-105-candidate-catalog-source-v1",
|
||||
"map_path": null,
|
||||
"display_name": null,
|
||||
"named_locomotive_table_entry_count": null,
|
||||
"locomotive_catalog_entry_count": 0,
|
||||
"tail_entries": []
|
||||
},
|
||||
{
|
||||
"path": "rt3_wineprefix/drive_c/rt3_105/Saved Games/Autosave.gms",
|
||||
"container_profile_family": "rt3-105-save-container-v1",
|
||||
"mechanism_family": "rt3-105-save-post-span-bridge-v1",
|
||||
"map_path": "Alternate USA.gmp",
|
||||
"display_name": "Alternate USA",
|
||||
"named_locomotive_table_entry_count": 61,
|
||||
"locomotive_catalog_entry_count": 61,
|
||||
"tail_entries": [
|
||||
{
|
||||
"locomotive_id": 59,
|
||||
"name": "GP 35"
|
||||
},
|
||||
{
|
||||
"locomotive_id": 60,
|
||||
"name": "U1"
|
||||
},
|
||||
{
|
||||
"locomotive_id": 61,
|
||||
"name": "Zephyr"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "rt3_wineprefix/drive_c/rt3_105/Saved Games/Autosave.gmx",
|
||||
"container_profile_family": "rt3-105-sandbox-container-v1",
|
||||
"mechanism_family": "rt3-105-candidate-catalog-source-v1",
|
||||
"map_path": null,
|
||||
"display_name": null,
|
||||
"named_locomotive_table_entry_count": null,
|
||||
"locomotive_catalog_entry_count": 0,
|
||||
"tail_entries": []
|
||||
},
|
||||
{
|
||||
"path": "rt3_wineprefix/drive_c/rt3_105/Saved Games/g.gms",
|
||||
"container_profile_family": "rt3-105-alt-save-container-v1",
|
||||
"mechanism_family": "rt3-105-alt-save-post-span-bridge-v1",
|
||||
"map_path": "Spanish Mainline.gmp",
|
||||
"display_name": "Spanish Mainline",
|
||||
"named_locomotive_table_entry_count": 63,
|
||||
"locomotive_catalog_entry_count": 63,
|
||||
"tail_entries": [
|
||||
{
|
||||
"locomotive_id": 59,
|
||||
"name": "242 A1"
|
||||
},
|
||||
{
|
||||
"locomotive_id": 60,
|
||||
"name": "Class 460"
|
||||
},
|
||||
{
|
||||
"locomotive_id": 61,
|
||||
"name": "Class A1"
|
||||
},
|
||||
{
|
||||
"locomotive_id": 62,
|
||||
"name": "Class P8"
|
||||
},
|
||||
{
|
||||
"locomotive_id": 63,
|
||||
"name": "U1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "rt3_wineprefix/drive_c/rt3_105/Saved Games/ggg.gmx",
|
||||
"container_profile_family": "unknown",
|
||||
"mechanism_family": "rt3-105-candidate-catalog-source-v1",
|
||||
"map_path": null,
|
||||
"display_name": null,
|
||||
"named_locomotive_table_entry_count": null,
|
||||
"locomotive_catalog_entry_count": 0,
|
||||
"tail_entries": []
|
||||
},
|
||||
{
|
||||
"path": "rt3_wineprefix/drive_c/rt3_105/Saved Games/kai0.gmx",
|
||||
"container_profile_family": "rt3-105-sandbox-container-v1",
|
||||
"mechanism_family": "rt3-105-candidate-catalog-source-v1",
|
||||
"map_path": null,
|
||||
"display_name": null,
|
||||
"named_locomotive_table_entry_count": null,
|
||||
"locomotive_catalog_entry_count": 0,
|
||||
"tail_entries": []
|
||||
},
|
||||
{
|
||||
"path": "rt3_wineprefix/drive_c/rt3_105/Saved Games/kai1.gmx",
|
||||
"container_profile_family": "rt3-105-sandbox-container-v1",
|
||||
"mechanism_family": "rt3-105-candidate-catalog-source-v1",
|
||||
"map_path": null,
|
||||
"display_name": null,
|
||||
"named_locomotive_table_entry_count": null,
|
||||
"locomotive_catalog_entry_count": 0,
|
||||
"tail_entries": []
|
||||
},
|
||||
{
|
||||
"path": "rt3_wineprefix/drive_c/rt3_105/Saved Games/kai2.gmx",
|
||||
"container_profile_family": "rt3-105-sandbox-container-v1",
|
||||
"mechanism_family": "rt3-105-candidate-catalog-source-v1",
|
||||
"map_path": null,
|
||||
"display_name": null,
|
||||
"named_locomotive_table_entry_count": null,
|
||||
"locomotive_catalog_entry_count": 0,
|
||||
"tail_entries": []
|
||||
},
|
||||
{
|
||||
"path": "rt3_wineprefix/drive_c/rt3_105/Saved Games/kai3.gmx",
|
||||
"container_profile_family": "rt3-105-sandbox-container-v1",
|
||||
"mechanism_family": "rt3-105-candidate-catalog-source-v1",
|
||||
"map_path": null,
|
||||
"display_name": null,
|
||||
"named_locomotive_table_entry_count": null,
|
||||
"locomotive_catalog_entry_count": 0,
|
||||
"tail_entries": []
|
||||
},
|
||||
{
|
||||
"path": "rt3_wineprefix/drive_c/rt3_105/Saved Games/kai4.gmx",
|
||||
"container_profile_family": "rt3-105-sandbox-container-v1",
|
||||
"mechanism_family": "rt3-105-candidate-catalog-source-v1",
|
||||
"map_path": null,
|
||||
"display_name": null,
|
||||
"named_locomotive_table_entry_count": null,
|
||||
"locomotive_catalog_entry_count": 0,
|
||||
"tail_entries": []
|
||||
},
|
||||
{
|
||||
"path": "rt3_wineprefix/drive_c/rt3_105/Saved Games/kai5.gmx",
|
||||
"container_profile_family": "rt3-105-sandbox-container-v1",
|
||||
"mechanism_family": "rt3-105-candidate-catalog-source-v1",
|
||||
"map_path": null,
|
||||
"display_name": null,
|
||||
"named_locomotive_table_entry_count": null,
|
||||
"locomotive_catalog_entry_count": 0,
|
||||
"tail_entries": []
|
||||
},
|
||||
{
|
||||
"path": "rt3_wineprefix/drive_c/rt3_105/Saved Games/kai6.gmx",
|
||||
"container_profile_family": "rt3-105-sandbox-container-v1",
|
||||
"mechanism_family": "rt3-105-candidate-catalog-source-v1",
|
||||
"map_path": null,
|
||||
"display_name": null,
|
||||
"named_locomotive_table_entry_count": null,
|
||||
"locomotive_catalog_entry_count": 0,
|
||||
"tail_entries": []
|
||||
},
|
||||
{
|
||||
"path": "rt3_wineprefix/drive_c/rt3_105/Saved Games/kai7.gmx",
|
||||
"container_profile_family": "rt3-105-sandbox-container-v1",
|
||||
"mechanism_family": "rt3-105-candidate-catalog-source-v1",
|
||||
"map_path": null,
|
||||
"display_name": null,
|
||||
"named_locomotive_table_entry_count": null,
|
||||
"locomotive_catalog_entry_count": 0,
|
||||
"tail_entries": []
|
||||
},
|
||||
{
|
||||
"path": "rt3_wineprefix/drive_c/rt3_105/Saved Games/kai8.gmx",
|
||||
"container_profile_family": "rt3-105-sandbox-container-v1",
|
||||
"mechanism_family": "rt3-105-candidate-catalog-source-v1",
|
||||
"map_path": null,
|
||||
"display_name": null,
|
||||
"named_locomotive_table_entry_count": null,
|
||||
"locomotive_catalog_entry_count": 0,
|
||||
"tail_entries": []
|
||||
},
|
||||
{
|
||||
"path": "rt3_wineprefix/drive_c/rt3_105/Saved Games/kai9.gmx",
|
||||
"container_profile_family": "rt3-105-sandbox-container-v1",
|
||||
"mechanism_family": "rt3-105-candidate-catalog-source-v1",
|
||||
"map_path": null,
|
||||
"display_name": null,
|
||||
"named_locomotive_table_entry_count": null,
|
||||
"locomotive_catalog_entry_count": 0,
|
||||
"tail_entries": []
|
||||
},
|
||||
{
|
||||
"path": "rt3_wineprefix/drive_c/rt3_105/Saved Games/kaimama.gmx",
|
||||
"container_profile_family": "rt3-105-sandbox-container-v1",
|
||||
"mechanism_family": "rt3-105-candidate-catalog-source-v1",
|
||||
"map_path": null,
|
||||
"display_name": null,
|
||||
"named_locomotive_table_entry_count": null,
|
||||
"locomotive_catalog_entry_count": 0,
|
||||
"tail_entries": []
|
||||
},
|
||||
{
|
||||
"path": "rt3_wineprefix/drive_c/rt3_105/Saved Games/lll.gmx",
|
||||
"container_profile_family": "unknown",
|
||||
"mechanism_family": "rt3-105-candidate-catalog-source-v1",
|
||||
"map_path": null,
|
||||
"display_name": null,
|
||||
"named_locomotive_table_entry_count": null,
|
||||
"locomotive_catalog_entry_count": 0,
|
||||
"tail_entries": []
|
||||
},
|
||||
{
|
||||
"path": "rt3_wineprefix/drive_c/rt3_105/Saved Games/n.gmx",
|
||||
"container_profile_family": "rt3-105-sandbox-container-v1",
|
||||
"mechanism_family": "rt3-105-candidate-catalog-source-v1",
|
||||
"map_path": null,
|
||||
"display_name": null,
|
||||
"named_locomotive_table_entry_count": null,
|
||||
"locomotive_catalog_entry_count": 0,
|
||||
"tail_entries": []
|
||||
},
|
||||
{
|
||||
"path": "rt3_wineprefix/drive_c/rt3_105/Saved Games/nom.gms",
|
||||
"container_profile_family": "rt3-105-save-container-v1",
|
||||
"mechanism_family": "rt3-105-save-post-span-bridge-v1",
|
||||
"map_path": "Alternate USA.gmp",
|
||||
"display_name": "Alternate USA",
|
||||
"named_locomotive_table_entry_count": 61,
|
||||
"locomotive_catalog_entry_count": 61,
|
||||
"tail_entries": [
|
||||
{
|
||||
"locomotive_id": 59,
|
||||
"name": "GP 35"
|
||||
},
|
||||
{
|
||||
"locomotive_id": 60,
|
||||
"name": "U1"
|
||||
},
|
||||
{
|
||||
"locomotive_id": 61,
|
||||
"name": "Zephyr"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "rt3_wineprefix/drive_c/rt3_105/Saved Games/ooo.gmx",
|
||||
"container_profile_family": "unknown",
|
||||
"mechanism_family": "rt3-105-candidate-catalog-source-v1",
|
||||
"map_path": null,
|
||||
"display_name": null,
|
||||
"named_locomotive_table_entry_count": null,
|
||||
"locomotive_catalog_entry_count": 0,
|
||||
"tail_entries": []
|
||||
},
|
||||
{
|
||||
"path": "rt3_wineprefix/drive_c/rt3_105/Saved Games/p.gms",
|
||||
"container_profile_family": "rt3-105-scenario-save-container-v1",
|
||||
"mechanism_family": "rt3-105-scenario-post-span-bridge-v1",
|
||||
"map_path": "Southern Pacific.gmp",
|
||||
"display_name": "Southern Pacific",
|
||||
"named_locomotive_table_entry_count": 61,
|
||||
"locomotive_catalog_entry_count": 61,
|
||||
"tail_entries": [
|
||||
{
|
||||
"locomotive_id": 59,
|
||||
"name": "GP 35"
|
||||
},
|
||||
{
|
||||
"locomotive_id": 60,
|
||||
"name": "U1"
|
||||
},
|
||||
{
|
||||
"locomotive_id": 61,
|
||||
"name": "Zephyr"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "rt3_wineprefix/drive_c/rt3_105/Saved Games/ppp.gmx",
|
||||
"container_profile_family": "rt3-105-sandbox-container-v1",
|
||||
"mechanism_family": "rt3-105-candidate-catalog-source-v1",
|
||||
"map_path": null,
|
||||
"display_name": null,
|
||||
"named_locomotive_table_entry_count": null,
|
||||
"locomotive_catalog_entry_count": 0,
|
||||
"tail_entries": []
|
||||
},
|
||||
{
|
||||
"path": "rt3_wineprefix/drive_c/rt3_105/Saved Games/q.gms",
|
||||
"container_profile_family": "rt3-105-scenario-save-container-v1",
|
||||
"mechanism_family": "rt3-105-scenario-post-span-bridge-v1",
|
||||
"map_path": "Southern Pacific.gmp",
|
||||
"display_name": "Southern Pacific",
|
||||
"named_locomotive_table_entry_count": 61,
|
||||
"locomotive_catalog_entry_count": 61,
|
||||
"tail_entries": [
|
||||
{
|
||||
"locomotive_id": 59,
|
||||
"name": "GP 35"
|
||||
},
|
||||
{
|
||||
"locomotive_id": 60,
|
||||
"name": "U1"
|
||||
},
|
||||
{
|
||||
"locomotive_id": 61,
|
||||
"name": "Zephyr"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -14,6 +14,11 @@ pub(super) fn parse_scan_command(
|
|||
root_path: root_path.into(),
|
||||
})
|
||||
}
|
||||
[subcommand, root_path] if subcommand == "scan-locomotive-catalog-tail" => {
|
||||
Ok(ScanCommand::ScanLocomotiveCatalogTail {
|
||||
root_path: root_path.into(),
|
||||
})
|
||||
}
|
||||
[subcommand, root_path] if subcommand == "scan-special-conditions" => {
|
||||
Ok(ScanCommand::ScanSpecialConditions {
|
||||
root_path: root_path.into(),
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
use crate::app::command::ScanCommand;
|
||||
use crate::app::runtime_scan::{
|
||||
scan_aligned_runtime_rule_band, scan_candidate_table_headers, scan_candidate_table_named_runs,
|
||||
scan_post_special_conditions_scalars, scan_post_special_conditions_tail,
|
||||
scan_recipe_book_lines, scan_special_conditions,
|
||||
scan_locomotive_catalog_tail, scan_post_special_conditions_scalars,
|
||||
scan_post_special_conditions_tail, scan_recipe_book_lines, scan_special_conditions,
|
||||
};
|
||||
|
||||
pub(super) fn dispatch_scan(command: ScanCommand) -> Result<(), Box<dyn std::error::Error>> {
|
||||
|
|
@ -13,6 +13,9 @@ pub(super) fn dispatch_scan(command: ScanCommand) -> Result<(), Box<dyn std::err
|
|||
ScanCommand::ScanCandidateTableNamedRuns { root_path } => {
|
||||
scan_candidate_table_named_runs(&root_path)
|
||||
}
|
||||
ScanCommand::ScanLocomotiveCatalogTail { root_path } => {
|
||||
scan_locomotive_catalog_tail(&root_path)
|
||||
}
|
||||
ScanCommand::ScanSpecialConditions { root_path } => scan_special_conditions(&root_path),
|
||||
ScanCommand::ScanAlignedRuntimeRuleBand { root_path } => {
|
||||
scan_aligned_runtime_rule_band(&root_path)
|
||||
|
|
|
|||
|
|
@ -447,7 +447,8 @@ fn build_named_run_aggregates(
|
|||
find_named_run_by_names(&sample.port_runs, "Port00", "Port00", 1),
|
||||
find_named_run_by_names(&sample.warehouse_runs, "Warehouse00", "Warehouse00", 1),
|
||||
) {
|
||||
let row_pair_key = format!("{}/{}", port00_run.start_index, warehouse00_run.start_index);
|
||||
let row_pair_key =
|
||||
format!("{}/{}", port00_run.start_index, warehouse00_run.start_index);
|
||||
*aggregates
|
||||
.port00_warehouse00_row_pair_map_counts
|
||||
.entry(row_pair_key.clone())
|
||||
|
|
|
|||
569
crates/rrt-cli/src/app/runtime_scan/locomotive_tail.rs
Normal file
569
crates/rrt-cli/src/app/runtime_scan/locomotive_tail.rs
Normal file
|
|
@ -0,0 +1,569 @@
|
|||
use std::collections::{BTreeMap, BTreeSet};
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use serde::Serialize;
|
||||
|
||||
use rrt_runtime::inspect::smp::save_load::{
|
||||
SmpLoadedLocomotiveCatalogEntry, SmpLoadedSaveSlice, load_save_slice_file,
|
||||
};
|
||||
|
||||
const EXTRA_SHIPPED_ENGINE_TYPE_NAMES: [&str; 5] =
|
||||
["242 A1", "Class 460", "Class A1", "Class P8", "Class QJ"];
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct RuntimeLocomotiveCatalogTailScanSample {
|
||||
path: String,
|
||||
container_profile_family: Option<String>,
|
||||
mechanism_family: String,
|
||||
map_path: Option<String>,
|
||||
display_name: Option<String>,
|
||||
named_locomotive_table_entry_count: Option<usize>,
|
||||
locomotive_catalog_entries: Vec<SmpLoadedLocomotiveCatalogEntry>,
|
||||
descriptor_rows: Vec<RuntimeLocomotiveDescriptorRowHit>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
struct RuntimeLocomotiveDescriptorRowHit {
|
||||
descriptor_id: u32,
|
||||
descriptor_label: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize)]
|
||||
pub(crate) struct RuntimeObservedLocomotiveCatalogEntry {
|
||||
pub(crate) locomotive_id: u32,
|
||||
pub(crate) name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
|
||||
pub(crate) struct RuntimeLocomotiveCatalogTailScanSampleReport {
|
||||
pub(crate) path: String,
|
||||
pub(crate) container_profile_family: Option<String>,
|
||||
pub(crate) mechanism_family: String,
|
||||
pub(crate) map_path: Option<String>,
|
||||
pub(crate) display_name: Option<String>,
|
||||
pub(crate) named_locomotive_table_entry_count: Option<usize>,
|
||||
pub(crate) locomotive_catalog_entry_count: usize,
|
||||
pub(crate) tail_entries: Vec<RuntimeObservedLocomotiveCatalogEntry>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
|
||||
pub(crate) struct RuntimeLocomotiveCatalogTailCluster {
|
||||
pub(crate) entry_count: usize,
|
||||
pub(crate) tail_entries: Vec<RuntimeObservedLocomotiveCatalogEntry>,
|
||||
pub(crate) file_count: usize,
|
||||
pub(crate) sample_paths: Vec<String>,
|
||||
pub(crate) map_paths: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
|
||||
pub(crate) struct RuntimeLocomotiveExtraNameCoverageSummary {
|
||||
pub(crate) name: String,
|
||||
pub(crate) observed_in_catalog_file_count: usize,
|
||||
pub(crate) observed_ordinals: Vec<u32>,
|
||||
pub(crate) sample_paths: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
|
||||
pub(crate) struct RuntimeLocomotiveDescriptorBandHitSummary {
|
||||
pub(crate) row_count: usize,
|
||||
pub(crate) file_count: usize,
|
||||
pub(crate) descriptor_ids_present: Vec<u32>,
|
||||
pub(crate) descriptor_labels_present: Vec<String>,
|
||||
pub(crate) carrier_paths: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
|
||||
pub(crate) struct RuntimeLocomotiveCatalogTailCensusReport {
|
||||
pub(crate) root_path: String,
|
||||
pub(crate) file_count: usize,
|
||||
pub(crate) files_with_named_locomotive_table_count: usize,
|
||||
pub(crate) files_with_locomotive_catalog_count: usize,
|
||||
pub(crate) files_with_packed_event_collection_count: usize,
|
||||
pub(crate) stable_prefix_length: usize,
|
||||
pub(crate) stable_prefix_last_name: Option<String>,
|
||||
pub(crate) tail_cluster_count: usize,
|
||||
pub(crate) tail_clusters: Vec<RuntimeLocomotiveCatalogTailCluster>,
|
||||
pub(crate) extra_shipped_name_coverage: Vec<RuntimeLocomotiveExtraNameCoverageSummary>,
|
||||
pub(crate) descriptor_452_hits: RuntimeLocomotiveDescriptorBandHitSummary,
|
||||
pub(crate) upper_availability_band_hits: RuntimeLocomotiveDescriptorBandHitSummary,
|
||||
pub(crate) upper_cost_band_hits: RuntimeLocomotiveDescriptorBandHitSummary,
|
||||
pub(crate) skipped_file_count: usize,
|
||||
pub(crate) samples: Vec<RuntimeLocomotiveCatalogTailScanSampleReport>,
|
||||
}
|
||||
|
||||
pub(crate) fn scan_locomotive_catalog_tail(
|
||||
root_path: &Path,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut candidate_paths = Vec::new();
|
||||
collect_locomotive_tail_input_paths(root_path, &mut candidate_paths)?;
|
||||
|
||||
let file_count = candidate_paths.len();
|
||||
let mut samples = Vec::new();
|
||||
let mut skipped_file_count = 0usize;
|
||||
for path in candidate_paths {
|
||||
match load_locomotive_catalog_tail_scan_sample(&path) {
|
||||
Ok(sample) => samples.push(sample),
|
||||
Err(_) => skipped_file_count += 1,
|
||||
}
|
||||
}
|
||||
|
||||
let files_with_named_locomotive_table_count = samples
|
||||
.iter()
|
||||
.filter(|sample| sample.named_locomotive_table_entry_count.is_some())
|
||||
.count();
|
||||
let files_with_locomotive_catalog_count = samples
|
||||
.iter()
|
||||
.filter(|sample| !sample.locomotive_catalog_entries.is_empty())
|
||||
.count();
|
||||
let files_with_packed_event_collection_count = samples
|
||||
.iter()
|
||||
.filter(|sample| !sample.descriptor_rows.is_empty())
|
||||
.count();
|
||||
let stable_prefix_length = stable_catalog_prefix_length(&samples);
|
||||
let stable_prefix_last_name = stable_prefix_last_name(&samples, stable_prefix_length);
|
||||
let tail_clusters = build_tail_clusters(&samples, stable_prefix_length);
|
||||
let extra_shipped_name_coverage = build_extra_shipped_name_coverage(&samples);
|
||||
let descriptor_452_hits = build_descriptor_band_hit_summary(&samples, 452..=452);
|
||||
let upper_availability_band_hits = build_descriptor_band_hit_summary(&samples, 457..=474);
|
||||
let upper_cost_band_hits = build_descriptor_band_hit_summary(&samples, 475..=502);
|
||||
let sample_reports = build_sample_reports(&samples, stable_prefix_length);
|
||||
|
||||
let report = RuntimeLocomotiveCatalogTailCensusReport {
|
||||
root_path: root_path.display().to_string(),
|
||||
file_count,
|
||||
files_with_named_locomotive_table_count,
|
||||
files_with_locomotive_catalog_count,
|
||||
files_with_packed_event_collection_count,
|
||||
stable_prefix_length,
|
||||
stable_prefix_last_name,
|
||||
tail_cluster_count: tail_clusters.len(),
|
||||
tail_clusters,
|
||||
extra_shipped_name_coverage,
|
||||
descriptor_452_hits,
|
||||
upper_availability_band_hits,
|
||||
upper_cost_band_hits,
|
||||
skipped_file_count,
|
||||
samples: sample_reports,
|
||||
};
|
||||
println!("{}", serde_json::to_string_pretty(&report)?);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn build_sample_reports(
|
||||
samples: &[RuntimeLocomotiveCatalogTailScanSample],
|
||||
stable_prefix_length: usize,
|
||||
) -> Vec<RuntimeLocomotiveCatalogTailScanSampleReport> {
|
||||
let mut reports = samples
|
||||
.iter()
|
||||
.map(|sample| RuntimeLocomotiveCatalogTailScanSampleReport {
|
||||
path: sample.path.clone(),
|
||||
container_profile_family: sample.container_profile_family.clone(),
|
||||
mechanism_family: sample.mechanism_family.clone(),
|
||||
map_path: sample.map_path.clone(),
|
||||
display_name: sample.display_name.clone(),
|
||||
named_locomotive_table_entry_count: sample.named_locomotive_table_entry_count,
|
||||
locomotive_catalog_entry_count: sample.locomotive_catalog_entries.len(),
|
||||
tail_entries: tail_entries(sample, stable_prefix_length),
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
reports.sort_by(|left, right| left.path.cmp(&right.path));
|
||||
reports
|
||||
}
|
||||
|
||||
fn stable_prefix_last_name(
|
||||
samples: &[RuntimeLocomotiveCatalogTailScanSample],
|
||||
stable_prefix_length: usize,
|
||||
) -> Option<String> {
|
||||
(stable_prefix_length != 0).then(|| {
|
||||
samples
|
||||
.iter()
|
||||
.find_map(|sample| {
|
||||
sample
|
||||
.locomotive_catalog_entries
|
||||
.get(stable_prefix_length - 1)
|
||||
})
|
||||
.map(|entry| entry.name.clone())
|
||||
.expect("stable prefix entry should exist")
|
||||
})
|
||||
}
|
||||
|
||||
fn stable_catalog_prefix_length(samples: &[RuntimeLocomotiveCatalogTailScanSample]) -> usize {
|
||||
let catalog_samples = samples
|
||||
.iter()
|
||||
.filter(|sample| !sample.locomotive_catalog_entries.is_empty())
|
||||
.collect::<Vec<_>>();
|
||||
if catalog_samples.is_empty() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let min_count = catalog_samples
|
||||
.iter()
|
||||
.map(|sample| sample.locomotive_catalog_entries.len())
|
||||
.min()
|
||||
.unwrap_or(0);
|
||||
|
||||
let mut stable_prefix_length = 0usize;
|
||||
for index in 0..min_count {
|
||||
let first_name = &catalog_samples[0].locomotive_catalog_entries[index].name;
|
||||
if catalog_samples
|
||||
.iter()
|
||||
.all(|sample| sample.locomotive_catalog_entries[index].name == *first_name)
|
||||
{
|
||||
stable_prefix_length += 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
stable_prefix_length
|
||||
}
|
||||
|
||||
fn build_tail_clusters(
|
||||
samples: &[RuntimeLocomotiveCatalogTailScanSample],
|
||||
stable_prefix_length: usize,
|
||||
) -> Vec<RuntimeLocomotiveCatalogTailCluster> {
|
||||
let mut grouped = BTreeMap::<
|
||||
Vec<RuntimeObservedLocomotiveCatalogEntry>,
|
||||
Vec<&RuntimeLocomotiveCatalogTailScanSample>,
|
||||
>::new();
|
||||
for sample in samples
|
||||
.iter()
|
||||
.filter(|sample| !sample.locomotive_catalog_entries.is_empty())
|
||||
{
|
||||
grouped
|
||||
.entry(tail_entries(sample, stable_prefix_length))
|
||||
.or_default()
|
||||
.push(sample);
|
||||
}
|
||||
|
||||
let mut clusters = grouped
|
||||
.into_iter()
|
||||
.map(|(tail_entries, samples)| {
|
||||
let mut sample_paths = samples
|
||||
.iter()
|
||||
.map(|sample| sample.path.clone())
|
||||
.collect::<Vec<_>>();
|
||||
let mut map_paths = samples
|
||||
.iter()
|
||||
.filter_map(|sample| sample.map_path.clone())
|
||||
.collect::<BTreeSet<_>>()
|
||||
.into_iter()
|
||||
.collect::<Vec<_>>();
|
||||
sample_paths.sort();
|
||||
map_paths.sort();
|
||||
RuntimeLocomotiveCatalogTailCluster {
|
||||
entry_count: stable_prefix_length + tail_entries.len(),
|
||||
tail_entries,
|
||||
file_count: samples.len(),
|
||||
sample_paths,
|
||||
map_paths,
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
clusters.sort_by(|left, right| {
|
||||
left.tail_entries
|
||||
.cmp(&right.tail_entries)
|
||||
.then(left.entry_count.cmp(&right.entry_count))
|
||||
});
|
||||
clusters
|
||||
}
|
||||
|
||||
fn tail_entries(
|
||||
sample: &RuntimeLocomotiveCatalogTailScanSample,
|
||||
stable_prefix_length: usize,
|
||||
) -> Vec<RuntimeObservedLocomotiveCatalogEntry> {
|
||||
sample
|
||||
.locomotive_catalog_entries
|
||||
.iter()
|
||||
.skip(stable_prefix_length)
|
||||
.map(|entry| RuntimeObservedLocomotiveCatalogEntry {
|
||||
locomotive_id: entry.locomotive_id,
|
||||
name: entry.name.clone(),
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn build_extra_shipped_name_coverage(
|
||||
samples: &[RuntimeLocomotiveCatalogTailScanSample],
|
||||
) -> Vec<RuntimeLocomotiveExtraNameCoverageSummary> {
|
||||
EXTRA_SHIPPED_ENGINE_TYPE_NAMES
|
||||
.into_iter()
|
||||
.map(|name| {
|
||||
let mut observed_ordinals = BTreeSet::new();
|
||||
let mut sample_paths = Vec::new();
|
||||
for sample in samples {
|
||||
let matching_ordinals = sample
|
||||
.locomotive_catalog_entries
|
||||
.iter()
|
||||
.filter(|entry| entry.name == name)
|
||||
.map(|entry| entry.locomotive_id)
|
||||
.collect::<Vec<_>>();
|
||||
if matching_ordinals.is_empty() {
|
||||
continue;
|
||||
}
|
||||
observed_ordinals.extend(matching_ordinals);
|
||||
sample_paths.push(sample.path.clone());
|
||||
}
|
||||
sample_paths.sort();
|
||||
RuntimeLocomotiveExtraNameCoverageSummary {
|
||||
name: name.to_string(),
|
||||
observed_in_catalog_file_count: sample_paths.len(),
|
||||
observed_ordinals: observed_ordinals.into_iter().collect(),
|
||||
sample_paths,
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn build_descriptor_band_hit_summary(
|
||||
samples: &[RuntimeLocomotiveCatalogTailScanSample],
|
||||
descriptor_ids: std::ops::RangeInclusive<u32>,
|
||||
) -> RuntimeLocomotiveDescriptorBandHitSummary {
|
||||
let mut row_count = 0usize;
|
||||
let mut carrier_paths = Vec::new();
|
||||
let mut descriptor_ids_present = BTreeSet::new();
|
||||
let mut descriptor_labels_present = BTreeSet::new();
|
||||
|
||||
for sample in samples {
|
||||
let matching_rows = sample
|
||||
.descriptor_rows
|
||||
.iter()
|
||||
.filter(|row| descriptor_ids.contains(&row.descriptor_id))
|
||||
.collect::<Vec<_>>();
|
||||
if matching_rows.is_empty() {
|
||||
continue;
|
||||
}
|
||||
row_count += matching_rows.len();
|
||||
carrier_paths.push(sample.path.clone());
|
||||
for row in matching_rows {
|
||||
descriptor_ids_present.insert(row.descriptor_id);
|
||||
if let Some(label) = &row.descriptor_label {
|
||||
descriptor_labels_present.insert(label.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
carrier_paths.sort();
|
||||
RuntimeLocomotiveDescriptorBandHitSummary {
|
||||
row_count,
|
||||
file_count: carrier_paths.len(),
|
||||
descriptor_ids_present: descriptor_ids_present.into_iter().collect(),
|
||||
descriptor_labels_present: descriptor_labels_present.into_iter().collect(),
|
||||
carrier_paths,
|
||||
}
|
||||
}
|
||||
|
||||
fn load_locomotive_catalog_tail_scan_sample(
|
||||
smp_path: &Path,
|
||||
) -> Result<RuntimeLocomotiveCatalogTailScanSample, Box<dyn std::error::Error>> {
|
||||
let save_slice = load_save_slice_file(smp_path)?;
|
||||
Ok(build_locomotive_catalog_tail_scan_sample(
|
||||
smp_path,
|
||||
&save_slice,
|
||||
))
|
||||
}
|
||||
|
||||
fn build_locomotive_catalog_tail_scan_sample(
|
||||
smp_path: &Path,
|
||||
save_slice: &SmpLoadedSaveSlice,
|
||||
) -> RuntimeLocomotiveCatalogTailScanSample {
|
||||
RuntimeLocomotiveCatalogTailScanSample {
|
||||
path: smp_path.display().to_string(),
|
||||
container_profile_family: save_slice.container_profile_family.clone(),
|
||||
mechanism_family: save_slice.mechanism_family.clone(),
|
||||
map_path: save_slice
|
||||
.profile
|
||||
.as_ref()
|
||||
.and_then(|profile| profile.map_path.clone()),
|
||||
display_name: save_slice
|
||||
.profile
|
||||
.as_ref()
|
||||
.and_then(|profile| profile.display_name.clone()),
|
||||
named_locomotive_table_entry_count: save_slice
|
||||
.named_locomotive_availability_table
|
||||
.as_ref()
|
||||
.map(|table| table.observed_entry_count),
|
||||
locomotive_catalog_entries: save_slice
|
||||
.locomotive_catalog
|
||||
.as_ref()
|
||||
.map(|catalog| catalog.entries.clone())
|
||||
.unwrap_or_default(),
|
||||
descriptor_rows: save_slice
|
||||
.event_runtime_collection
|
||||
.as_ref()
|
||||
.map(|summary| {
|
||||
summary
|
||||
.records
|
||||
.iter()
|
||||
.flat_map(|record| {
|
||||
record.grouped_effect_rows.iter().map(|row| {
|
||||
RuntimeLocomotiveDescriptorRowHit {
|
||||
descriptor_id: row.descriptor_id,
|
||||
descriptor_label: row.descriptor_label.clone(),
|
||||
}
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
})
|
||||
.unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_locomotive_tail_input_paths(
|
||||
root_path: &Path,
|
||||
out: &mut Vec<PathBuf>,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let metadata = match fs::symlink_metadata(root_path) {
|
||||
Ok(metadata) => metadata,
|
||||
Err(err) if err.kind() == std::io::ErrorKind::PermissionDenied => return Ok(()),
|
||||
Err(err) => return Err(err.into()),
|
||||
};
|
||||
if metadata.file_type().is_symlink() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if root_path.is_file() {
|
||||
if path_is_locomotive_tail_input(root_path) {
|
||||
out.push(root_path.to_path_buf());
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let entries = match fs::read_dir(root_path) {
|
||||
Ok(entries) => entries,
|
||||
Err(err) if err.kind() == std::io::ErrorKind::PermissionDenied => return Ok(()),
|
||||
Err(err) => return Err(err.into()),
|
||||
};
|
||||
|
||||
for entry in entries {
|
||||
let entry = entry?;
|
||||
let path = entry.path();
|
||||
if path.is_dir() {
|
||||
collect_locomotive_tail_input_paths(&path, out)?;
|
||||
continue;
|
||||
}
|
||||
if path_is_locomotive_tail_input(&path) {
|
||||
out.push(path);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn path_is_locomotive_tail_input(path: &Path) -> bool {
|
||||
path.extension()
|
||||
.and_then(|ext| ext.to_str())
|
||||
.is_some_and(|ext| matches!(ext.to_ascii_lowercase().as_str(), "gms" | "gmx" | "smp"))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn sample(
|
||||
path: &str,
|
||||
names: &[&str],
|
||||
descriptor_ids: &[u32],
|
||||
) -> RuntimeLocomotiveCatalogTailScanSample {
|
||||
RuntimeLocomotiveCatalogTailScanSample {
|
||||
path: path.to_string(),
|
||||
container_profile_family: Some("rt3-classic-save-container-v1".to_string()),
|
||||
mechanism_family: "classic-save-rehydrate-v1".to_string(),
|
||||
map_path: Some(format!("{path}.gmp")),
|
||||
display_name: Some(path.to_string()),
|
||||
named_locomotive_table_entry_count: Some(names.len()),
|
||||
locomotive_catalog_entries: names
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, name)| SmpLoadedLocomotiveCatalogEntry {
|
||||
locomotive_id: (index + 1) as u32,
|
||||
name: (*name).to_string(),
|
||||
})
|
||||
.collect(),
|
||||
descriptor_rows: descriptor_ids
|
||||
.iter()
|
||||
.map(|descriptor_id| RuntimeLocomotiveDescriptorRowHit {
|
||||
descriptor_id: *descriptor_id,
|
||||
descriptor_label: Some(format!("Descriptor {descriptor_id}")),
|
||||
})
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn computes_stable_prefix_length_across_catalog_samples() {
|
||||
let samples = vec![
|
||||
sample("a", &["Big Boy", "VL80T", "242 A1"], &[]),
|
||||
sample("b", &["Big Boy", "VL80T", "GP 35"], &[]),
|
||||
];
|
||||
|
||||
assert_eq!(stable_catalog_prefix_length(&samples), 2);
|
||||
assert_eq!(
|
||||
stable_prefix_last_name(&samples, 2),
|
||||
Some("VL80T".to_string())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn groups_tail_clusters_by_exact_tail_sequence() {
|
||||
let samples = vec![
|
||||
sample("a", &["Big Boy", "VL80T", "242 A1", "Class 460"], &[]),
|
||||
sample("b", &["Big Boy", "VL80T", "242 A1", "Class 460"], &[]),
|
||||
sample("c", &["Big Boy", "VL80T", "GP 35", "U1"], &[]),
|
||||
];
|
||||
|
||||
let clusters = build_tail_clusters(&samples, 2);
|
||||
|
||||
assert_eq!(clusters.len(), 2);
|
||||
let counts = clusters
|
||||
.iter()
|
||||
.map(|cluster| cluster.file_count)
|
||||
.collect::<Vec<_>>();
|
||||
assert_eq!(counts, vec![2, 1]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn summarizes_extra_shipped_name_coverage() {
|
||||
let samples = vec![
|
||||
sample("a", &["Big Boy", "242 A1", "Class 460"], &[]),
|
||||
sample("b", &["Big Boy", "Class QJ"], &[]),
|
||||
];
|
||||
|
||||
let coverage = build_extra_shipped_name_coverage(&samples);
|
||||
|
||||
assert_eq!(coverage[0].name, "242 A1");
|
||||
assert_eq!(coverage[0].observed_in_catalog_file_count, 1);
|
||||
assert_eq!(coverage[0].observed_ordinals, vec![2]);
|
||||
assert_eq!(coverage[4].name, "Class QJ");
|
||||
assert_eq!(coverage[4].observed_in_catalog_file_count, 1);
|
||||
assert_eq!(coverage[4].observed_ordinals, vec![2]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn summarizes_descriptor_band_hits() {
|
||||
let samples = vec![
|
||||
sample("a", &["Big Boy"], &[452, 457, 475]),
|
||||
sample("b", &["Big Boy"], &[457, 458]),
|
||||
];
|
||||
|
||||
let descriptor_452_hits = build_descriptor_band_hit_summary(&samples, 452..=452);
|
||||
let upper_availability_hits = build_descriptor_band_hit_summary(&samples, 457..=474);
|
||||
|
||||
assert_eq!(descriptor_452_hits.row_count, 1);
|
||||
assert_eq!(descriptor_452_hits.file_count, 1);
|
||||
assert_eq!(upper_availability_hits.row_count, 3);
|
||||
assert_eq!(upper_availability_hits.file_count, 2);
|
||||
assert_eq!(
|
||||
upper_availability_hits.descriptor_ids_present,
|
||||
vec![457, 458]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn accepts_gmx_inputs_in_locomotive_tail_scan() {
|
||||
assert!(path_is_locomotive_tail_input(Path::new("save.gms")));
|
||||
assert!(path_is_locomotive_tail_input(Path::new("sandbox.gmx")));
|
||||
assert!(path_is_locomotive_tail_input(Path::new("fixture.smp")));
|
||||
assert!(!path_is_locomotive_tail_input(Path::new("map.gmp")));
|
||||
}
|
||||
}
|
||||
|
|
@ -3,11 +3,13 @@ pub(crate) mod post_special;
|
|||
|
||||
mod aligned_band;
|
||||
mod candidate_table;
|
||||
mod locomotive_tail;
|
||||
mod recipe_book;
|
||||
mod special_conditions;
|
||||
|
||||
pub(super) use aligned_band::scan_aligned_runtime_rule_band;
|
||||
pub(super) use candidate_table::{scan_candidate_table_headers, scan_candidate_table_named_runs};
|
||||
pub(super) use locomotive_tail::scan_locomotive_catalog_tail;
|
||||
pub(super) use post_special::{
|
||||
scan_post_special_conditions_scalars, scan_post_special_conditions_tail,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1571,8 +1571,10 @@ fn blocks_scalar_locomotive_availability_rows_without_catalog_context() {
|
|||
grouped_effect_rows: vec![SmpLoadedPackedEventGroupedEffectRowSummary {
|
||||
group_index: 0,
|
||||
row_index: 0,
|
||||
descriptor_id: 250,
|
||||
descriptor_label: Some("Big Boy 4-8-8-4 Availability".to_string()),
|
||||
descriptor_id: 302,
|
||||
descriptor_label: Some(
|
||||
"Lower-Band Locomotive Availability Slot 62".to_string(),
|
||||
),
|
||||
target_mask_bits: Some(0x08),
|
||||
parameter_family: Some("locomotive_availability_scalar".to_string()),
|
||||
grouped_target_subject: None,
|
||||
|
|
@ -1587,11 +1589,13 @@ fn blocks_scalar_locomotive_availability_rows_without_catalog_context() {
|
|||
value_word_0x16: 0,
|
||||
row_shape: "scalar_assignment".to_string(),
|
||||
semantic_family: Some("scalar_assignment".to_string()),
|
||||
semantic_preview: Some("Set Big Boy 4-8-8-4 Availability to 42".to_string()),
|
||||
semantic_preview: Some(
|
||||
"Set Lower-Band Locomotive Availability Slot 62 to 42".to_string(),
|
||||
),
|
||||
recovered_cargo_slot: None,
|
||||
recovered_cargo_class: None,
|
||||
recovered_cargo_label: None,
|
||||
recovered_locomotive_id: Some(10),
|
||||
recovered_locomotive_id: Some(62),
|
||||
locomotive_name: None,
|
||||
notes: vec![],
|
||||
}],
|
||||
|
|
@ -1599,8 +1603,9 @@ fn blocks_scalar_locomotive_availability_rows_without_catalog_context() {
|
|||
decoded_actions: vec![],
|
||||
executable_import_ready: false,
|
||||
notes: vec![
|
||||
"decoded from grounded real 0x4e9a row framing".to_string(),
|
||||
"scalar locomotive availability rows still need catalog context".to_string(),
|
||||
"decoded from lower-tail real 0x4e9a row framing".to_string(),
|
||||
"scalar lower-tail locomotive availability row still needs catalog context"
|
||||
.to_string(),
|
||||
],
|
||||
}],
|
||||
}),
|
||||
|
|
@ -1609,7 +1614,7 @@ fn blocks_scalar_locomotive_availability_rows_without_catalog_context() {
|
|||
|
||||
let input = build_runtime_state_input_from_save_slice(
|
||||
&save_slice,
|
||||
"packed-events-recovered-locomotive-availability-frontier",
|
||||
"packed-events-recovered-locomotive-availability-lower-tail-frontier",
|
||||
None,
|
||||
)
|
||||
.expect("save slice should project");
|
||||
|
|
@ -1737,7 +1742,7 @@ fn imports_scalar_locomotive_availability_rows_with_save_derived_catalog_context
|
|||
bridge_family: None,
|
||||
profile: None,
|
||||
candidate_availability_table: None,
|
||||
named_locomotive_availability_table: Some(save_named_locomotive_table(61)),
|
||||
named_locomotive_availability_table: Some(save_named_locomotive_table(62)),
|
||||
locomotive_catalog: None,
|
||||
cargo_catalog: None,
|
||||
world_issue_37_state: None,
|
||||
|
|
@ -1799,7 +1804,7 @@ fn imports_scalar_locomotive_availability_rows_with_save_derived_catalog_context
|
|||
grouped_effect_row_counts: vec![2, 0, 0, 0],
|
||||
grouped_effect_rows: vec![
|
||||
real_locomotive_availability_row(250, 42),
|
||||
real_locomotive_availability_row(301, 7),
|
||||
real_locomotive_availability_row(302, 7),
|
||||
],
|
||||
decoded_conditions: Vec::new(),
|
||||
decoded_actions: vec![],
|
||||
|
|
@ -1820,7 +1825,7 @@ fn imports_scalar_locomotive_availability_rows_with_save_derived_catalog_context
|
|||
)
|
||||
.expect("save slice should project");
|
||||
|
||||
assert_eq!(input.state.locomotive_catalog.len(), 61);
|
||||
assert_eq!(input.state.locomotive_catalog.len(), 62);
|
||||
assert_eq!(input.state.event_runtime_records.len(), 1);
|
||||
assert_eq!(
|
||||
input
|
||||
|
|
@ -1845,11 +1850,228 @@ fn imports_scalar_locomotive_availability_rows_with_save_derived_catalog_context
|
|||
Some(&42)
|
||||
);
|
||||
assert_eq!(
|
||||
input.state.named_locomotive_availability.get("Zephyr"),
|
||||
input
|
||||
.state
|
||||
.named_locomotive_availability
|
||||
.get("Locomotive 62"),
|
||||
Some(&7)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn imports_scalar_locomotive_availability_rows_with_dynamic_tail_catalog_context() {
|
||||
let mut names = (0..58)
|
||||
.map(default_save_named_locomotive_name)
|
||||
.collect::<Vec<_>>();
|
||||
names.extend([
|
||||
"242 A1".to_string(),
|
||||
"Class 460".to_string(),
|
||||
"Class A1".to_string(),
|
||||
"Class P8".to_string(),
|
||||
"U1".to_string(),
|
||||
]);
|
||||
let save_slice = SmpLoadedSaveSlice {
|
||||
file_extension_hint: Some("gms".to_string()),
|
||||
container_profile_family: Some("rt3-classic-save-container-v1".to_string()),
|
||||
mechanism_family: "classic-save-rehydrate-v1".to_string(),
|
||||
mechanism_confidence: "grounded".to_string(),
|
||||
trailer_family: None,
|
||||
bridge_family: None,
|
||||
profile: None,
|
||||
candidate_availability_table: None,
|
||||
named_locomotive_availability_table: Some(save_named_locomotive_table_with_names(&names)),
|
||||
locomotive_catalog: None,
|
||||
cargo_catalog: None,
|
||||
world_issue_37_state: None,
|
||||
world_economic_tuning_state: None,
|
||||
world_finance_neighborhood_state: None,
|
||||
world_locomotive_policy_state: None,
|
||||
company_roster: None,
|
||||
chairman_profile_table: None,
|
||||
region_collection: None,
|
||||
region_fixed_row_run_summary: None,
|
||||
placed_structure_collection: None,
|
||||
placed_structure_dynamic_side_buffer_summary: None,
|
||||
special_conditions_table: None,
|
||||
event_runtime_collection: Some(SmpLoadedEventRuntimeCollectionSummary {
|
||||
source_kind: "packed-event-runtime-collection".to_string(),
|
||||
mechanism_family: "classic-save-rehydrate-v1".to_string(),
|
||||
mechanism_confidence: "grounded".to_string(),
|
||||
container_profile_family: Some("rt3-classic-save-container-v1".to_string()),
|
||||
metadata_tag_offset: 0x7100,
|
||||
records_tag_offset: 0x7200,
|
||||
close_tag_offset: 0x7600,
|
||||
packed_state_version: 0x3e9,
|
||||
packed_state_version_hex: "0x000003e9".to_string(),
|
||||
live_id_bound: 34,
|
||||
live_record_count: 1,
|
||||
live_entry_ids: vec![34],
|
||||
decoded_record_count: 1,
|
||||
imported_runtime_record_count: 0,
|
||||
records_with_trigger_kind: 0,
|
||||
records_missing_trigger_kind: 0,
|
||||
nondirect_compact_record_count: 0,
|
||||
nondirect_compact_records_missing_trigger_kind: 0,
|
||||
trigger_kinds_present: vec![],
|
||||
control_lane_notes: vec![],
|
||||
add_building_dispatch_strip_record_indexes: vec![],
|
||||
add_building_dispatch_strip_descriptor_labels: vec![],
|
||||
add_building_dispatch_strip_records_with_trigger_kind: 0,
|
||||
add_building_dispatch_strip_records_missing_trigger_kind: 0,
|
||||
add_building_dispatch_strip_row_shape_families: vec![],
|
||||
add_building_dispatch_strip_signature_families: vec![],
|
||||
add_building_dispatch_strip_condition_tuple_families: vec![],
|
||||
add_building_dispatch_strip_signature_condition_clusters: vec![],
|
||||
records: vec![SmpLoadedPackedEventRecordSummary {
|
||||
record_index: 0,
|
||||
live_entry_id: 34,
|
||||
payload_offset: Some(0x7202),
|
||||
payload_len: Some(96),
|
||||
decode_status: "parity_only".to_string(),
|
||||
payload_family: "real_packed_v1".to_string(),
|
||||
trigger_kind: Some(7),
|
||||
active: None,
|
||||
marks_collection_dirty: None,
|
||||
one_shot: Some(false),
|
||||
compact_control: Some(real_compact_control()),
|
||||
text_bands: vec![],
|
||||
standalone_condition_row_count: 0,
|
||||
standalone_condition_rows: vec![],
|
||||
negative_sentinel_scope: None,
|
||||
grouped_effect_row_counts: vec![1, 0, 0, 0],
|
||||
grouped_effect_rows: vec![real_locomotive_availability_row(299, 7)],
|
||||
decoded_conditions: Vec::new(),
|
||||
decoded_actions: vec![],
|
||||
executable_import_ready: false,
|
||||
notes: vec![
|
||||
"save-derived locomotive availability row uses scenario-dependent tail names"
|
||||
.to_string(),
|
||||
],
|
||||
}],
|
||||
}),
|
||||
notes: vec![],
|
||||
};
|
||||
|
||||
let mut input = build_runtime_state_input_from_save_slice(
|
||||
&save_slice,
|
||||
"save-derived-dynamic-tail-locomotive-availability",
|
||||
None,
|
||||
)
|
||||
.expect("save slice should project");
|
||||
|
||||
execute_step_command(
|
||||
&mut input.state,
|
||||
&StepCommand::ServiceTriggerKind { trigger_kind: 7 },
|
||||
)
|
||||
.expect("save-derived dynamic-tail locomotive availability record should run");
|
||||
|
||||
assert_eq!(
|
||||
input.state.named_locomotive_availability.get("242 A1"),
|
||||
Some(&7)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keeps_upper_band_locomotive_availability_rows_on_descriptor_parity() {
|
||||
let save_slice = SmpLoadedSaveSlice {
|
||||
file_extension_hint: Some("gms".to_string()),
|
||||
container_profile_family: Some("rt3-classic-save-container-v1".to_string()),
|
||||
mechanism_family: "classic-save-rehydrate-v1".to_string(),
|
||||
mechanism_confidence: "grounded".to_string(),
|
||||
trailer_family: None,
|
||||
bridge_family: None,
|
||||
profile: None,
|
||||
candidate_availability_table: None,
|
||||
named_locomotive_availability_table: Some(save_named_locomotive_table(140)),
|
||||
locomotive_catalog: None,
|
||||
cargo_catalog: None,
|
||||
world_issue_37_state: None,
|
||||
world_economic_tuning_state: None,
|
||||
world_finance_neighborhood_state: None,
|
||||
world_locomotive_policy_state: None,
|
||||
company_roster: None,
|
||||
chairman_profile_table: None,
|
||||
region_collection: None,
|
||||
region_fixed_row_run_summary: None,
|
||||
placed_structure_collection: None,
|
||||
placed_structure_dynamic_side_buffer_summary: None,
|
||||
special_conditions_table: None,
|
||||
event_runtime_collection: Some(SmpLoadedEventRuntimeCollectionSummary {
|
||||
source_kind: "packed-event-runtime-collection".to_string(),
|
||||
mechanism_family: "classic-save-rehydrate-v1".to_string(),
|
||||
mechanism_confidence: "grounded".to_string(),
|
||||
container_profile_family: Some("rt3-classic-save-container-v1".to_string()),
|
||||
metadata_tag_offset: 0x7100,
|
||||
records_tag_offset: 0x7200,
|
||||
close_tag_offset: 0x7600,
|
||||
packed_state_version: 0x3e9,
|
||||
packed_state_version_hex: "0x000003e9".to_string(),
|
||||
live_id_bound: 34,
|
||||
live_record_count: 1,
|
||||
live_entry_ids: vec![34],
|
||||
decoded_record_count: 1,
|
||||
imported_runtime_record_count: 0,
|
||||
records_with_trigger_kind: 0,
|
||||
records_missing_trigger_kind: 0,
|
||||
nondirect_compact_record_count: 0,
|
||||
nondirect_compact_records_missing_trigger_kind: 0,
|
||||
trigger_kinds_present: vec![],
|
||||
control_lane_notes: vec![],
|
||||
add_building_dispatch_strip_record_indexes: vec![],
|
||||
add_building_dispatch_strip_descriptor_labels: vec![],
|
||||
add_building_dispatch_strip_records_with_trigger_kind: 0,
|
||||
add_building_dispatch_strip_records_missing_trigger_kind: 0,
|
||||
add_building_dispatch_strip_row_shape_families: vec![],
|
||||
add_building_dispatch_strip_signature_families: vec![],
|
||||
add_building_dispatch_strip_condition_tuple_families: vec![],
|
||||
add_building_dispatch_strip_signature_condition_clusters: vec![],
|
||||
records: vec![SmpLoadedPackedEventRecordSummary {
|
||||
record_index: 0,
|
||||
live_entry_id: 34,
|
||||
payload_offset: Some(0x7202),
|
||||
payload_len: Some(96),
|
||||
decode_status: "parity_only".to_string(),
|
||||
payload_family: "real_packed_v1".to_string(),
|
||||
trigger_kind: Some(7),
|
||||
active: None,
|
||||
marks_collection_dirty: None,
|
||||
one_shot: Some(false),
|
||||
compact_control: Some(real_compact_control()),
|
||||
text_bands: vec![],
|
||||
standalone_condition_row_count: 0,
|
||||
standalone_condition_rows: vec![],
|
||||
negative_sentinel_scope: None,
|
||||
grouped_effect_row_counts: vec![1, 0, 0, 0],
|
||||
grouped_effect_rows: vec![real_locomotive_availability_row(457, 1)],
|
||||
decoded_conditions: Vec::new(),
|
||||
decoded_actions: vec![],
|
||||
executable_import_ready: false,
|
||||
notes: vec![
|
||||
"upper-band locomotive availability row remains descriptor parity".to_string(),
|
||||
],
|
||||
}],
|
||||
}),
|
||||
notes: vec![],
|
||||
};
|
||||
|
||||
let input = build_runtime_state_input_from_save_slice(
|
||||
&save_slice,
|
||||
"packed-events-upper-band-locomotive-availability",
|
||||
None,
|
||||
)
|
||||
.expect("save slice should project");
|
||||
|
||||
assert!(input.state.event_runtime_records.is_empty());
|
||||
assert_eq!(
|
||||
input
|
||||
.state
|
||||
.packed_event_collection
|
||||
.as_ref()
|
||||
.and_then(|summary| summary.records[0].import_outcome.as_deref()),
|
||||
Some("blocked_evidence_blocked_descriptor")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn overlays_scalar_locomotive_availability_rows_into_named_availability_effects() {
|
||||
let base_state = RuntimeState {
|
||||
|
|
@ -2099,11 +2321,13 @@ fn blocks_recovered_locomotive_cost_rows_without_catalog_context_lower_band() {
|
|||
standalone_condition_rows: vec![],
|
||||
negative_sentinel_scope: None,
|
||||
grouped_effect_row_counts: vec![1, 0, 0, 0],
|
||||
grouped_effect_rows: vec![real_locomotive_cost_row(352, 250000)],
|
||||
grouped_effect_rows: vec![real_locomotive_cost_row(413, 250000)],
|
||||
decoded_conditions: Vec::new(),
|
||||
decoded_actions: vec![],
|
||||
executable_import_ready: false,
|
||||
notes: vec!["scalar locomotive cost row still needs catalog context".to_string()],
|
||||
notes: vec![
|
||||
"scalar lower-tail locomotive cost row still needs catalog context".to_string(),
|
||||
],
|
||||
}],
|
||||
}),
|
||||
notes: vec![],
|
||||
|
|
@ -2237,7 +2461,7 @@ fn imports_scalar_locomotive_cost_rows_with_save_derived_catalog_context() {
|
|||
bridge_family: None,
|
||||
profile: None,
|
||||
candidate_availability_table: None,
|
||||
named_locomotive_availability_table: Some(save_named_locomotive_table(61)),
|
||||
named_locomotive_availability_table: Some(save_named_locomotive_table(62)),
|
||||
locomotive_catalog: None,
|
||||
cargo_catalog: None,
|
||||
world_issue_37_state: None,
|
||||
|
|
@ -2299,7 +2523,7 @@ fn imports_scalar_locomotive_cost_rows_with_save_derived_catalog_context() {
|
|||
grouped_effect_row_counts: vec![2, 0, 0, 0],
|
||||
grouped_effect_rows: vec![
|
||||
real_locomotive_cost_row(352, 250000),
|
||||
real_locomotive_cost_row(412, 325000),
|
||||
real_locomotive_cost_row(413, 325000),
|
||||
],
|
||||
decoded_conditions: Vec::new(),
|
||||
decoded_actions: vec![],
|
||||
|
|
@ -2319,7 +2543,7 @@ fn imports_scalar_locomotive_cost_rows_with_save_derived_catalog_context() {
|
|||
)
|
||||
.expect("save slice should project");
|
||||
|
||||
assert_eq!(input.state.locomotive_catalog.len(), 61);
|
||||
assert_eq!(input.state.locomotive_catalog.len(), 62);
|
||||
assert_eq!(input.state.event_runtime_records.len(), 1);
|
||||
assert_eq!(
|
||||
input
|
||||
|
|
@ -2341,11 +2565,110 @@ fn imports_scalar_locomotive_cost_rows_with_save_derived_catalog_context() {
|
|||
Some(&250000)
|
||||
);
|
||||
assert_eq!(
|
||||
input.state.named_locomotive_cost.get("Zephyr"),
|
||||
input.state.named_locomotive_cost.get("Locomotive 62"),
|
||||
Some(&325000)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keeps_upper_band_locomotive_cost_rows_on_descriptor_parity() {
|
||||
let save_slice = SmpLoadedSaveSlice {
|
||||
file_extension_hint: Some("gms".to_string()),
|
||||
container_profile_family: Some("rt3-classic-save-container-v1".to_string()),
|
||||
mechanism_family: "classic-save-rehydrate-v1".to_string(),
|
||||
mechanism_confidence: "grounded".to_string(),
|
||||
trailer_family: None,
|
||||
bridge_family: None,
|
||||
profile: None,
|
||||
candidate_availability_table: None,
|
||||
named_locomotive_availability_table: Some(save_named_locomotive_table(140)),
|
||||
locomotive_catalog: None,
|
||||
cargo_catalog: None,
|
||||
world_issue_37_state: None,
|
||||
world_economic_tuning_state: None,
|
||||
world_finance_neighborhood_state: None,
|
||||
world_locomotive_policy_state: None,
|
||||
company_roster: None,
|
||||
chairman_profile_table: None,
|
||||
region_collection: None,
|
||||
region_fixed_row_run_summary: None,
|
||||
placed_structure_collection: None,
|
||||
placed_structure_dynamic_side_buffer_summary: None,
|
||||
special_conditions_table: None,
|
||||
event_runtime_collection: Some(SmpLoadedEventRuntimeCollectionSummary {
|
||||
source_kind: "packed-event-runtime-collection".to_string(),
|
||||
mechanism_family: "classic-save-rehydrate-v1".to_string(),
|
||||
mechanism_confidence: "grounded".to_string(),
|
||||
container_profile_family: Some("rt3-classic-save-container-v1".to_string()),
|
||||
metadata_tag_offset: 0x7100,
|
||||
records_tag_offset: 0x7200,
|
||||
close_tag_offset: 0x7600,
|
||||
packed_state_version: 0x3e9,
|
||||
packed_state_version_hex: "0x000003e9".to_string(),
|
||||
live_id_bound: 42,
|
||||
live_record_count: 1,
|
||||
live_entry_ids: vec![42],
|
||||
decoded_record_count: 1,
|
||||
imported_runtime_record_count: 0,
|
||||
records_with_trigger_kind: 0,
|
||||
records_missing_trigger_kind: 0,
|
||||
nondirect_compact_record_count: 0,
|
||||
nondirect_compact_records_missing_trigger_kind: 0,
|
||||
trigger_kinds_present: vec![],
|
||||
control_lane_notes: vec![],
|
||||
add_building_dispatch_strip_record_indexes: vec![],
|
||||
add_building_dispatch_strip_descriptor_labels: vec![],
|
||||
add_building_dispatch_strip_records_with_trigger_kind: 0,
|
||||
add_building_dispatch_strip_records_missing_trigger_kind: 0,
|
||||
add_building_dispatch_strip_row_shape_families: vec![],
|
||||
add_building_dispatch_strip_signature_families: vec![],
|
||||
add_building_dispatch_strip_condition_tuple_families: vec![],
|
||||
add_building_dispatch_strip_signature_condition_clusters: vec![],
|
||||
records: vec![SmpLoadedPackedEventRecordSummary {
|
||||
record_index: 0,
|
||||
live_entry_id: 42,
|
||||
payload_offset: Some(0x7202),
|
||||
payload_len: Some(96),
|
||||
decode_status: "parity_only".to_string(),
|
||||
payload_family: "real_packed_v1".to_string(),
|
||||
trigger_kind: Some(7),
|
||||
active: None,
|
||||
marks_collection_dirty: None,
|
||||
one_shot: Some(false),
|
||||
compact_control: Some(real_compact_control()),
|
||||
text_bands: vec![],
|
||||
standalone_condition_row_count: 0,
|
||||
standalone_condition_rows: vec![],
|
||||
negative_sentinel_scope: None,
|
||||
grouped_effect_row_counts: vec![1, 0, 0, 0],
|
||||
grouped_effect_rows: vec![real_locomotive_cost_row(475, 250000)],
|
||||
decoded_conditions: Vec::new(),
|
||||
decoded_actions: vec![],
|
||||
executable_import_ready: false,
|
||||
notes: vec!["upper-band locomotive cost row remains descriptor parity".to_string()],
|
||||
}],
|
||||
}),
|
||||
notes: vec![],
|
||||
};
|
||||
|
||||
let input = build_runtime_state_input_from_save_slice(
|
||||
&save_slice,
|
||||
"packed-events-upper-band-locomotive-cost",
|
||||
None,
|
||||
)
|
||||
.expect("save slice should project");
|
||||
|
||||
assert!(input.state.event_runtime_records.is_empty());
|
||||
assert_eq!(
|
||||
input
|
||||
.state
|
||||
.packed_event_collection
|
||||
.as_ref()
|
||||
.and_then(|summary| summary.records[0].import_outcome.as_deref()),
|
||||
Some("blocked_evidence_blocked_descriptor")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn overlays_scalar_locomotive_cost_rows_into_named_cost_effects() {
|
||||
let base_state = RuntimeState {
|
||||
|
|
@ -2519,6 +2842,119 @@ fn overlays_scalar_locomotive_cost_rows_into_named_cost_effects() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn imports_scalar_locomotive_cost_rows_with_dynamic_tail_catalog_context() {
|
||||
let mut names = (0..58)
|
||||
.map(default_save_named_locomotive_name)
|
||||
.collect::<Vec<_>>();
|
||||
names.extend([
|
||||
"242 A1".to_string(),
|
||||
"Class 460".to_string(),
|
||||
"Class A1".to_string(),
|
||||
"Class P8".to_string(),
|
||||
"U1".to_string(),
|
||||
]);
|
||||
let save_slice = SmpLoadedSaveSlice {
|
||||
file_extension_hint: Some("gms".to_string()),
|
||||
container_profile_family: Some("rt3-classic-save-container-v1".to_string()),
|
||||
mechanism_family: "classic-save-rehydrate-v1".to_string(),
|
||||
mechanism_confidence: "grounded".to_string(),
|
||||
trailer_family: None,
|
||||
bridge_family: None,
|
||||
profile: None,
|
||||
candidate_availability_table: None,
|
||||
named_locomotive_availability_table: Some(save_named_locomotive_table_with_names(&names)),
|
||||
locomotive_catalog: None,
|
||||
cargo_catalog: None,
|
||||
world_issue_37_state: None,
|
||||
world_economic_tuning_state: None,
|
||||
world_finance_neighborhood_state: None,
|
||||
world_locomotive_policy_state: None,
|
||||
company_roster: None,
|
||||
chairman_profile_table: None,
|
||||
region_collection: None,
|
||||
region_fixed_row_run_summary: None,
|
||||
placed_structure_collection: None,
|
||||
placed_structure_dynamic_side_buffer_summary: None,
|
||||
special_conditions_table: None,
|
||||
event_runtime_collection: Some(SmpLoadedEventRuntimeCollectionSummary {
|
||||
source_kind: "packed-event-runtime-collection".to_string(),
|
||||
mechanism_family: "classic-save-rehydrate-v1".to_string(),
|
||||
mechanism_confidence: "grounded".to_string(),
|
||||
container_profile_family: Some("rt3-classic-save-container-v1".to_string()),
|
||||
metadata_tag_offset: 0x7100,
|
||||
records_tag_offset: 0x7200,
|
||||
close_tag_offset: 0x7600,
|
||||
packed_state_version: 0x3e9,
|
||||
packed_state_version_hex: "0x000003e9".to_string(),
|
||||
live_id_bound: 37,
|
||||
live_record_count: 1,
|
||||
live_entry_ids: vec![37],
|
||||
decoded_record_count: 1,
|
||||
imported_runtime_record_count: 0,
|
||||
records_with_trigger_kind: 0,
|
||||
records_missing_trigger_kind: 0,
|
||||
nondirect_compact_record_count: 0,
|
||||
nondirect_compact_records_missing_trigger_kind: 0,
|
||||
trigger_kinds_present: vec![],
|
||||
control_lane_notes: vec![],
|
||||
add_building_dispatch_strip_record_indexes: vec![],
|
||||
add_building_dispatch_strip_descriptor_labels: vec![],
|
||||
add_building_dispatch_strip_records_with_trigger_kind: 0,
|
||||
add_building_dispatch_strip_records_missing_trigger_kind: 0,
|
||||
add_building_dispatch_strip_row_shape_families: vec![],
|
||||
add_building_dispatch_strip_signature_families: vec![],
|
||||
add_building_dispatch_strip_condition_tuple_families: vec![],
|
||||
add_building_dispatch_strip_signature_condition_clusters: vec![],
|
||||
records: vec![SmpLoadedPackedEventRecordSummary {
|
||||
record_index: 0,
|
||||
live_entry_id: 37,
|
||||
payload_offset: Some(0x7202),
|
||||
payload_len: Some(96),
|
||||
decode_status: "parity_only".to_string(),
|
||||
payload_family: "real_packed_v1".to_string(),
|
||||
trigger_kind: Some(7),
|
||||
active: None,
|
||||
marks_collection_dirty: None,
|
||||
one_shot: Some(false),
|
||||
compact_control: Some(real_compact_control()),
|
||||
text_bands: vec![],
|
||||
standalone_condition_row_count: 0,
|
||||
standalone_condition_rows: vec![],
|
||||
negative_sentinel_scope: None,
|
||||
grouped_effect_row_counts: vec![1, 0, 0, 0],
|
||||
grouped_effect_rows: vec![real_locomotive_cost_row(410, 325000)],
|
||||
decoded_conditions: Vec::new(),
|
||||
decoded_actions: vec![],
|
||||
executable_import_ready: false,
|
||||
notes: vec![
|
||||
"save-derived locomotive cost row uses scenario-dependent tail names"
|
||||
.to_string(),
|
||||
],
|
||||
}],
|
||||
}),
|
||||
notes: vec![],
|
||||
};
|
||||
|
||||
let mut input = build_runtime_state_input_from_save_slice(
|
||||
&save_slice,
|
||||
"save-derived-dynamic-tail-locomotive-cost",
|
||||
None,
|
||||
)
|
||||
.expect("save slice should project");
|
||||
|
||||
execute_step_command(
|
||||
&mut input.state,
|
||||
&StepCommand::ServiceTriggerKind { trigger_kind: 7 },
|
||||
)
|
||||
.expect("save-derived dynamic-tail locomotive cost record should run");
|
||||
|
||||
assert_eq!(
|
||||
input.state.named_locomotive_cost.get("242 A1"),
|
||||
Some(&325000)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keeps_negative_locomotive_cost_rows_parity_only() {
|
||||
let save_slice = SmpLoadedSaveSlice {
|
||||
|
|
|
|||
|
|
@ -590,9 +590,6 @@ pub(super) fn real_locomotive_availability_row(
|
|||
56 => Some("Trans-Euro"),
|
||||
57 => Some("V200"),
|
||||
58 => Some("VL80T"),
|
||||
59 => Some("GP 35"),
|
||||
60 => Some("U1"),
|
||||
61 => Some("Zephyr"),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
@ -709,9 +706,6 @@ pub(super) fn real_locomotive_cost_row(
|
|||
56 => Some("Trans-Euro"),
|
||||
57 => Some("V200"),
|
||||
58 => Some("VL80T"),
|
||||
59 => Some("GP 35"),
|
||||
60 => Some("U1"),
|
||||
61 => Some("Zephyr"),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
@ -759,10 +753,7 @@ pub(super) fn real_locomotive_cost_row(
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) fn save_named_locomotive_table(
|
||||
count: usize,
|
||||
) -> SmpLoadedNamedLocomotiveAvailabilityTable {
|
||||
fn grounded_locomotive_name(index: usize) -> String {
|
||||
pub(super) fn default_save_named_locomotive_name(index: usize) -> String {
|
||||
match index {
|
||||
0 => "2-D-2",
|
||||
1 => "E-88",
|
||||
|
|
@ -830,6 +821,10 @@ pub(super) fn save_named_locomotive_table(
|
|||
.to_string()
|
||||
}
|
||||
|
||||
pub(super) fn save_named_locomotive_table_with_names(
|
||||
names: &[String],
|
||||
) -> SmpLoadedNamedLocomotiveAvailabilityTable {
|
||||
let count = names.len();
|
||||
SmpLoadedNamedLocomotiveAvailabilityTable {
|
||||
source_kind: "runtime-save-direct-serializer".to_string(),
|
||||
semantic_family: "scenario-named-locomotive-availability-table".to_string(),
|
||||
|
|
@ -839,11 +834,13 @@ pub(super) fn save_named_locomotive_table(
|
|||
observed_entry_count: count,
|
||||
zero_availability_count: 0,
|
||||
zero_availability_names: vec![],
|
||||
entries: (0..count)
|
||||
.map(|index| SmpRt3105SaveNameTableEntry {
|
||||
entries: names
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, name)| SmpRt3105SaveNameTableEntry {
|
||||
index,
|
||||
offset: 0x7c78 + index * 0x41,
|
||||
text: grounded_locomotive_name(index),
|
||||
text: name.clone(),
|
||||
availability_dword: 1,
|
||||
availability_dword_hex: "0x00000001".to_string(),
|
||||
trailer_word: 1,
|
||||
|
|
@ -853,6 +850,16 @@ pub(super) fn save_named_locomotive_table(
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) fn save_named_locomotive_table(
|
||||
count: usize,
|
||||
) -> SmpLoadedNamedLocomotiveAvailabilityTable {
|
||||
let names = (0..count)
|
||||
.map(default_save_named_locomotive_name)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
save_named_locomotive_table_with_names(&names)
|
||||
}
|
||||
|
||||
pub(super) fn save_cargo_catalog(
|
||||
entries: &[(u32, crate::event::targets::RuntimeCargoClass)],
|
||||
) -> SmpLoadedCargoCatalog {
|
||||
|
|
|
|||
|
|
@ -2,24 +2,21 @@ use super::super::super::*;
|
|||
use std::collections::BTreeMap;
|
||||
use std::sync::OnceLock;
|
||||
|
||||
const STATIC_GROUNDED_LOCOMOTIVE_NAME_MAX_ID: u32 = 58;
|
||||
|
||||
pub(in crate::inspect::smp) fn recovered_locomotive_availability_descriptor_metadata(
|
||||
descriptor_id: u32,
|
||||
) -> Option<RealGroupedEffectDescriptorMetadata> {
|
||||
if let Some(loco_id) = recovered_locomotive_availability_loco_id(descriptor_id) {
|
||||
let label = recovered_locomotive_availability_label(loco_id);
|
||||
let executable_in_runtime = (loco_id as usize) <= GROUNDED_LOCOMOTIVE_PREFIX.len();
|
||||
return Some(RealGroupedEffectDescriptorMetadata {
|
||||
descriptor_id,
|
||||
label,
|
||||
target_mask_bits: 0x08,
|
||||
parameter_family: "locomotive_availability_scalar",
|
||||
runtime_key: None,
|
||||
runtime_status: if executable_in_runtime {
|
||||
RealGroupedEffectRuntimeStatus::Executable
|
||||
} else {
|
||||
RealGroupedEffectRuntimeStatus::EvidenceBlocked
|
||||
},
|
||||
executable_in_runtime,
|
||||
runtime_status: RealGroupedEffectRuntimeStatus::Executable,
|
||||
executable_in_runtime: true,
|
||||
});
|
||||
}
|
||||
(457..=474)
|
||||
|
|
@ -45,6 +42,9 @@ pub(in crate::inspect::smp) fn recovered_locomotive_availability_loco_id(
|
|||
}
|
||||
|
||||
pub(in crate::inspect::smp) fn grounded_locomotive_name(loco_id: u32) -> Option<&'static str> {
|
||||
if loco_id > STATIC_GROUNDED_LOCOMOTIVE_NAME_MAX_ID {
|
||||
return None;
|
||||
}
|
||||
let index = loco_id.checked_sub(1)? as usize;
|
||||
GROUNDED_LOCOMOTIVE_PREFIX.get(index).copied()
|
||||
}
|
||||
|
|
@ -153,8 +153,7 @@ pub(in crate::inspect::smp) fn recovered_locomotive_cost_descriptor_metadata(
|
|||
descriptor_id: u32,
|
||||
) -> Option<RealGroupedEffectDescriptorMetadata> {
|
||||
recovered_locomotive_cost_label(descriptor_id).map(|label| {
|
||||
let executable_in_runtime = recovered_locomotive_cost_loco_id(descriptor_id)
|
||||
.is_some_and(|loco_id| (loco_id as usize) <= GROUNDED_LOCOMOTIVE_PREFIX.len());
|
||||
let executable_in_runtime = recovered_locomotive_cost_loco_id(descriptor_id).is_some();
|
||||
RealGroupedEffectDescriptorMetadata {
|
||||
descriptor_id,
|
||||
label,
|
||||
|
|
|
|||
|
|
@ -223,11 +223,33 @@ fn looks_up_upper_band_recovered_locomotive_availability_descriptor_metadata() {
|
|||
#[test]
|
||||
fn looks_up_extended_lower_band_locomotive_availability_descriptor_metadata() {
|
||||
let metadata =
|
||||
real_grouped_effect_descriptor_metadata(301).expect("descriptor metadata should exist");
|
||||
real_grouped_effect_descriptor_metadata(298).expect("descriptor metadata should exist");
|
||||
|
||||
assert_eq!(metadata.label, "Zephyr Availability");
|
||||
assert_eq!(metadata.label, "VL80T Availability");
|
||||
assert_eq!(metadata.parameter_family, "locomotive_availability_scalar");
|
||||
assert_eq!(recovered_locomotive_availability_loco_id(301), Some(61));
|
||||
assert_eq!(recovered_locomotive_availability_loco_id(298), Some(58));
|
||||
assert!(metadata.executable_in_runtime);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn looks_up_first_unstable_lower_band_locomotive_availability_descriptor_metadata() {
|
||||
let metadata =
|
||||
real_grouped_effect_descriptor_metadata(299).expect("descriptor metadata should exist");
|
||||
|
||||
assert_eq!(metadata.label, "Lower-Band Locomotive Availability Slot 59");
|
||||
assert_eq!(metadata.parameter_family, "locomotive_availability_scalar");
|
||||
assert_eq!(recovered_locomotive_availability_loco_id(299), Some(59));
|
||||
assert!(metadata.executable_in_runtime);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn looks_up_lower_tail_locomotive_availability_descriptor_metadata() {
|
||||
let metadata =
|
||||
real_grouped_effect_descriptor_metadata(302).expect("descriptor metadata should exist");
|
||||
|
||||
assert_eq!(metadata.label, "Lower-Band Locomotive Availability Slot 62");
|
||||
assert_eq!(metadata.parameter_family, "locomotive_availability_scalar");
|
||||
assert_eq!(recovered_locomotive_availability_loco_id(302), Some(62));
|
||||
assert!(metadata.executable_in_runtime);
|
||||
}
|
||||
|
||||
|
|
@ -359,11 +381,33 @@ fn looks_up_recovered_upper_band_locomotive_cost_descriptor_metadata() {
|
|||
#[test]
|
||||
fn looks_up_extended_lower_band_locomotive_cost_descriptor_metadata() {
|
||||
let metadata =
|
||||
real_grouped_effect_descriptor_metadata(412).expect("descriptor metadata should exist");
|
||||
real_grouped_effect_descriptor_metadata(409).expect("descriptor metadata should exist");
|
||||
|
||||
assert_eq!(metadata.label, "Zephyr Cost");
|
||||
assert_eq!(metadata.label, "VL80T Cost");
|
||||
assert_eq!(metadata.parameter_family, "locomotive_cost_scalar");
|
||||
assert_eq!(recovered_locomotive_cost_loco_id(412), Some(61));
|
||||
assert_eq!(recovered_locomotive_cost_loco_id(409), Some(58));
|
||||
assert!(metadata.executable_in_runtime);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn looks_up_first_unstable_lower_band_locomotive_cost_descriptor_metadata() {
|
||||
let metadata =
|
||||
real_grouped_effect_descriptor_metadata(410).expect("descriptor metadata should exist");
|
||||
|
||||
assert_eq!(metadata.label, "Lower-Band Locomotive Cost Slot 59");
|
||||
assert_eq!(metadata.parameter_family, "locomotive_cost_scalar");
|
||||
assert_eq!(recovered_locomotive_cost_loco_id(410), Some(59));
|
||||
assert!(metadata.executable_in_runtime);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn looks_up_lower_tail_locomotive_cost_descriptor_metadata() {
|
||||
let metadata =
|
||||
real_grouped_effect_descriptor_metadata(413).expect("descriptor metadata should exist");
|
||||
|
||||
assert_eq!(metadata.label, "Lower-Band Locomotive Cost Slot 62");
|
||||
assert_eq!(metadata.parameter_family, "locomotive_cost_scalar");
|
||||
assert_eq!(recovered_locomotive_cost_loco_id(413), Some(62));
|
||||
assert!(metadata.executable_in_runtime);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -313,8 +313,12 @@ The highest-value next passes are now:
|
|||
- recovered scalar locomotive availability and locomotive-cost descriptors now import through that
|
||||
save-native or embedded `RuntimeState.locomotive_catalog` context into the ordinary
|
||||
`named_locomotive_availability` and `named_locomotive_cost` runtime maps
|
||||
- the grounded executable lower locomotive prefix now extends through save-backed locomotive id
|
||||
`61` (`Zephyr`); the unresolved lower tail and upper locomotive bands stay on explicit parity
|
||||
- the full lower locomotive bands now execute through that save-native ordinal catalog too:
|
||||
availability `241..351` and cost `352..451`; the checked `29`-save `.gms + .gmx`
|
||||
`locomotive-catalog-tail-census.json` export now fixes the last save-stable static descriptor
|
||||
boundary at ordinal `58` (`VL80T`) and leaves descriptor `452` plus the upper bands
|
||||
`457..474` / `475..502` as external-corpus or dynamic blockers rather than active repo-local
|
||||
static work
|
||||
- cargo-production `230..240` and territory-access-cost `453` now execute too through minimal
|
||||
world-side scalar landing surfaces: slot-indexed `cargo_production_overrides` and
|
||||
`world_restore.territory_access_cost`
|
||||
|
|
@ -331,8 +335,10 @@ The highest-value next passes are now:
|
|||
- the company/chairman frontier has moved too: checked-in save-slice documents can now carry that
|
||||
context natively, so the next work on that axis is broader recovery and eventual raw save
|
||||
reconstruction rather than overlay-only ownership
|
||||
- keep in mind that the current local `.gms` corpus still exports with no packed event collection,
|
||||
so real descriptor mapping needs to stay plumbing-first until better captures exist
|
||||
- keep in mind that the current local `.gms + .gmx` corpus does carry packed-event collections,
|
||||
but the checked `29`-save locomotive census still finds no descriptor carriers in `452` or
|
||||
`457..502`, so further locomotives-page closure now needs either broader save evidence or
|
||||
dynamic captures
|
||||
- use `rrt-hook` primarily as optional capture or integration tooling, not as the first execution
|
||||
environment
|
||||
- keep `docs/runtime-rehost-plan.md` current as the runtime baseline and next implementation slice
|
||||
|
|
|
|||
|
|
@ -10,18 +10,23 @@ This file is the short active queue for the current runtime and reverse-engineer
|
|||
|
||||
## Current Active Items
|
||||
|
||||
- Keep the periodic-company trace as the main shellless simulation frontier, with the next concrete control-lane pass focused on the ordinary loaded runtime-effect strip `0x00444d92 -> 0x00432f40(kind 8) -> 0x004323a0 -> 0x00431b20`.
|
||||
The checked `rt3_105/maps` compact-dispatch corpus is now exported directly and partially mirrored into the periodic-company trace: `41` maps scanned, `38` with dispatch-strip rows, `318` nondirect rows total, the add-building subset is only `10` grouped occurrences across `7` descriptor keys, and the strongest broader nondirect families are now bounded too at `36` grouped occurrences across `18` maps for `nondirect-ge1e-h0001-0360-0004-0100-0200-p0000-0000-0000-ffff :: [864:4]` plus `27` across `14` maps for the mixed `[-1:4]` cluster. All of those checked rows still lack recovered trigger kind. The packed-state bridge is narrower than that queue head used to allow too: `0x0042db20/0x00430d70` rebuild and serialize only the fixed text bands plus the standalone and grouped row lists, while the metadata band `+0x7ee..+0x80e` is only mirrored by deep-copy helper `0x0042e050`. The active open question is therefore which ordinary loaded rows acquire or bypass the missing trigger-kind control lane before they can reach placed-structure mutation opcodes.
|
||||
The dispatcher-side caller census is wider in a way that makes the remaining blocker sharper: `0x00432f40` is already driven shelllessly for kinds `1/0/3/2` and then `5/4` from the recurring simulation-maintenance strip `0x0040a220..0x0040a9ac`, for kind `7` from the grounded company-startup family, and for kind `6` from the placed-structure post-create, startup-refresh, and route-entry post-change tails, while `LoadScreen.win` still owns kind `9`. So the missing piece is no longer “find another shellless dispatcher entrypoint.” It is why ordinary loaded rows still fail to present a matching nonzero `[event+0x7ef]` when the later world-entry one-shot at `0x00444d92` requests kind `8`.
|
||||
The largest direct writer table is ruled out now too: `0x004d8ea0` is the shell-side `EventConditions.win` commit helper, where controls `0x4e98..0x4ea2` write `[event+0x7ef] = 0..10` on the currently selected live event, so that seed family does not explain shellless post-load bringup.
|
||||
The broad scenario-name fixup owner is narrower in the same direction: `0x00442c30` really does mutate live event rows after reload, but its grounded trigger-kind writes still only retag `1 -> 5` and `0 -> 2`, while the surrounding event-side branches only patch modifier bytes or nested payload dwords under already-existing kinds. No grounded branch there seeds kind `8`.
|
||||
The metadata-copy helper is ruled out in the same way: `0x0042e050` really does clone `[event+0x7ef]`, but the current whole-binary caller search still finds only the shell-side selected-event clone path `0x004db8b0`, not any shellless post-load or periodic caller.
|
||||
The direct write census is tighter in the same direction: the only grounded explicit write of value `8` into `[event+0x7ef]` is `0x004d91b3` inside that same shell helper, while the runtime-side grounded writers still only cover zero-init, copy, `2/3` follow-on seeds, and the later `5` / `2` retags.
|
||||
Static progress on this head now appears genuinely blocked: the whole-binary `[...+0x7ef]` reference census still collapses to that same grounded writer set plus the already-known compare and copy helpers, so the next honest step likely requires hook-side or runtime tracing between reload `0x00433130` and the world-entry kind-`8` sweep at `0x00444d92`.
|
||||
- No active repo-local non-dynamic items remain.
|
||||
The last local static head was the locomotives-page tail, and the checked [locomotive catalog tail census](../artifacts/exports/rt3-1.06/locomotive-catalog-tail-census.json) now exhausts the full local `.gms + .gmx` corpus under `rt3_wineprefix/drive_c`: `29` candidate saves found, `26` parsed samples, `5` catalog-bearing saves, one save-stable ordinal prefix through `58` (`VL80T`), two observed `59+` tail clusters (`g.gms` with `242 A1 / Class 460 / Class A1 / Class P8 / U1`, and the four classic 1.05 saves with `GP 35 / U1 / Zephyr`), zero observed `Class QJ`, and zero packed-event carriers for descriptor `452` or the upper bands `457..474` / `475..502`.
|
||||
The added `18` `.gmx` sandbox saves widen the local corpus and packed-event coverage, but they still contribute no named locomotive table and no derived `locomotive_catalog`, so they do not move the save-native tail evidence beyond the same five catalog-bearing `.gms` saves.
|
||||
That means the remaining locomotive questions are no longer repo-local static work. They now require either a broader save corpus or dynamic tracing.
|
||||
Preserved checked locomotive blocker detail now lives in [Locomotive descriptor tails](rehost-queue/locomotive-descriptor-tails-2026-04-21.md).
|
||||
Preserved checked format inventory detail now lives in [RT3 format inventory](rehost-queue/format-inventory-2026-04-21.md).
|
||||
|
||||
## Preserved External And Dynamic Blockers
|
||||
|
||||
- The locomotives-page tail remains preserved as an external-corpus blocker.
|
||||
Static repo-local work on this head is now exhausted: the local `29`-save `.gms + .gmx` census proves the stable prefix through `58`, proves the same two scenario-dependent `59+` tail families, and still finds no `Class QJ` placement plus no descriptor carriers in `452` or `457..502`. The next honest non-hook step requires a broader save corpus; the next non-static step requires dynamic tracing.
|
||||
Preserved checked blocker detail now lives in [Locomotive descriptor tails](rehost-queue/locomotive-descriptor-tails-2026-04-21.md).
|
||||
- The periodic-company control-lane head remains preserved as a dynamic blocker around the ordinary loaded runtime-effect strip `0x00444d92 -> 0x00432f40(kind 8) -> 0x004323a0 -> 0x00431b20`.
|
||||
Static progress on this head now appears genuinely blocked: the whole-binary `[...+0x7ef]` reference census still collapses to the grounded writer set plus the already-known compare and copy helpers, so the next honest step likely requires hook-side or runtime tracing between reload `0x00433130` and the world-entry kind-`8` sweep at `0x00444d92`.
|
||||
Preserved checked control-lane detail now lives in [Periodic company control lane](rehost-queue/periodic-company-control-lane-2026-04-21.md).
|
||||
- Keep the next static Tier-2 building pass focused on the earlier seed/projection seam into `0x00412d70`, not another broad `BuildingTypes` sweep.
|
||||
The grounded owner strip is `0x004196c0 -> 0x00414490 -> 0x00416ce0 -> 0x00419230`, and the checked candidate-table exports now keep the concrete scenario-side families explicit too: among the `37` probe-bearing maps, `Port00/Warehouse00` stay at `35/43` on `30` maps and shift earlier to `10/18` on `7`, while `Port01..11` / `Warehouse01..11` stay fixed at `45..55` / `56..66` and the numbered trailer family splits independently at `0x00000001 -> 28 maps` versus `0x00000000 -> 9 maps`. The new crossover matrix stays mixed rather than collapsing to one side too: `35/43 :: 0x00000001 -> 25 maps`, `35/43 :: 0x00000000 -> 5 maps`, `10/18 :: 0x00000000 -> 4 maps`, and `10/18 :: 0x00000001 -> 3 maps`. The checked header-cluster export keeps the same root scan bounded to only `3` families: `0x00000000 / 0x00000000 -> 27 maps`, `0xcdcdcdcd / 0xcdcdcdcd -> 9 maps`, and `0x10000000 / 0x00009000 -> 1 map` (`Alternate USA.gmp`). The load-side handoff is narrower now too: `0x004120b0` explicitly reads `[candidate+0xba]` and `[candidate+0xbb]` as one-byte stream fields, and the very next projection owner `0x00412d70` immediately consumes those bytes in two passes, first `+0xba` and then `+0xbb`, to pick one seed row whose full `0x1f2`-dword body will be cloned or reused for each numbered runtime record. The stock decode side is narrower in the same direction: `0x00414490` does not just copy the `0xb8..0xbb` tail, it already derives the optional plane size from `[record+0xb8] * [record+0xb9] << 5` and uses the high nibble of `[record+0xba]` while materializing the four optional plane buffers at `[record+0xcf/+0xd3/+0xd7/+0xdb]`, before `0x00416ce0` remaps only the bare `port` / `warehouse` names and the later `0x00419230` rebank-or-clone pass consumes any bank-qualified owners. The same static pass rules out one lingering false lead too: the earlier suspected `0x00414500..0x00414b14` replay strip is not a separate serializer or import family at all, just the interior plane-decode band of `0x00414490`. The stock `BuildingTypes` corpus is narrower too: across `77` checked `.bca` files only `MachineShop.bca` carries nonzero selector bytes at `0xb8..0xbb`, while the broader nonzero stock signal lives in the `22`-file `.bty` alias-root family with `dword_0xbb = 0x000001f4`, especially the `TextileMill` branch that already covers `Port.bty` and `Warehouse.bty`. The active open question is therefore which later seed or projection seam turns that already-decoded stock-side shape or selector state together with the fixed numbered cluster into nonzero live `[candidate+0xba/+0xbb]` before `0x00412d70` and `0x00419230` consume it.
|
||||
Static progress on this head is close to the same boundary now: the stock decode chain, the bare-name remap callback, the rebank-or-clone owner, and the earlier suspected mid-range replay strip are all grounded, so the next honest step likely requires runtime tracing of which source rows actually enter the live bank-qualified seed set.
|
||||
- The Tier-2 building head remains preserved as a dynamic blocker around the seed/projection seam into `0x00412d70`.
|
||||
The stock decode chain, the bare-name remap callback, the rebank-or-clone owner, and the earlier suspected mid-range replay strip are all now grounded, so the next honest step likely requires runtime tracing of which source rows actually enter the live bank-qualified seed set.
|
||||
Preserved checked row-family detail now lives in [Tier2 candidate row families](rehost-queue/tier2-candidate-row-families-2026-04-21.md).
|
||||
Preserved checked stock selector-byte detail now lives in [Tier2 selector-byte sources](rehost-queue/tier2-selector-byte-sources-2026-04-21.md).
|
||||
Preserved checked rebuild sequencing detail now lives in [Tier2 rebuild sequencing](rehost-queue/tier2-rebuild-sequencing-2026-04-21.md).
|
||||
|
|
@ -29,6 +34,8 @@ This file is the short active queue for the current runtime and reverse-engineer
|
|||
## Preserved Detail
|
||||
|
||||
- [Archive snapshot](rehost-queue/archive-2026-04-19.md)
|
||||
- [RT3 format inventory](rehost-queue/format-inventory-2026-04-21.md)
|
||||
- [Locomotive descriptor tails](rehost-queue/locomotive-descriptor-tails-2026-04-21.md)
|
||||
- [Periodic company control lane](rehost-queue/periodic-company-control-lane-2026-04-21.md)
|
||||
- [Tier2 candidate row families](rehost-queue/tier2-candidate-row-families-2026-04-21.md)
|
||||
- [Tier2 rebuild sequencing](rehost-queue/tier2-rebuild-sequencing-2026-04-21.md)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,11 @@ This directory preserves older queue snapshots and long-form implementation note
|
|||
useful as evidence, but should not stay in the short active queue file.
|
||||
|
||||
- `archive-2026-04-19.md`: preserved detailed queue snapshot from the pre-index cleanup.
|
||||
- `format-inventory-2026-04-21.md`: current file-format inventory under `rt3/` and `rt3_105/`,
|
||||
including the RT3-native families we still do not parse.
|
||||
- `locomotive-descriptor-tails-2026-04-21.md`: checked `.gms + .gmx` local locomotive catalog
|
||||
census and the remaining external-corpus blocker around `Class QJ`, descriptor `452`, and the
|
||||
upper descriptor bands.
|
||||
- `periodic-company-control-lane-2026-04-21.md`: checked compact-dispatch/control-lane evidence
|
||||
for the active periodic-company queue head, including the top ordinary nondirect cluster carrier
|
||||
maps.
|
||||
|
|
|
|||
139
docs/rehost-queue/locomotive-descriptor-tails-2026-04-21.md
Normal file
139
docs/rehost-queue/locomotive-descriptor-tails-2026-04-21.md
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
# Locomotive Descriptor Tails (2026-04-21)
|
||||
|
||||
This note preserves the checked evidence behind the locomotives-page tail after the full local
|
||||
`.gms + .gmx` save-corpus pass, so the short queue can treat the remaining work honestly as an
|
||||
external-corpus or dynamic blocker rather than another repo-local static task.
|
||||
|
||||
## Local Save-Corpus Census
|
||||
|
||||
The checked [locomotive catalog tail census](../../artifacts/exports/rt3-1.06/locomotive-catalog-tail-census.json)
|
||||
now exhausts the full local save corpus under `rt3_wineprefix/drive_c`:
|
||||
|
||||
- `29` candidate saves found
|
||||
- `26` parsed samples
|
||||
- `5` saves with a save-side named locomotive table and derived `locomotive_catalog`
|
||||
- `26` saves with packed-event collections present
|
||||
- one save-stable catalog prefix through ordinal `58` (`VL80T`)
|
||||
- two observed tail clusters beyond that prefix:
|
||||
- one `63`-entry tail on `g.gms` / `Spanish Mainline.gmp`: `242 A1 / Class 460 / Class A1 /
|
||||
Class P8 / U1`
|
||||
- one `61`-entry tail on the four 1.05 save families: `GP 35 / U1 / Zephyr`
|
||||
|
||||
The added `18` `.gmx` sandbox saves still carry no reconstructed named locomotive table and no
|
||||
derived `locomotive_catalog`, so they widen the local event corpus without widening the save-native
|
||||
ordinal catalog evidence. The three classic `rt3/` `.gms` saves (`Autosave.gms`, `hh.gms`,
|
||||
`kk.gms`) remain catalog-free too, so the save-native tail evidence is still carried only by the
|
||||
same five 1.05 `.gms` saves.
|
||||
|
||||
The scan still skips the three classic `rt3/` sandbox saves (`Autosave.gmx`, `aaa.gmx`,
|
||||
`bbb.gmx`) at save-slice load time, so the currently parsed sample set is `26` rather than the
|
||||
full `29` candidate paths. That does not change the locomotive blocker: none of the successfully
|
||||
parsed `.gmx` samples widens the save-native catalog, places `Class QJ`, or surfaces descriptor
|
||||
carriers in `452` or `457..502`.
|
||||
|
||||
## Grounded Lower Bands
|
||||
|
||||
The lower descriptor bands are now grounded enough to execute through the existing save-native
|
||||
owner seam:
|
||||
|
||||
- availability descriptors `241..351` already map directly onto recovered locomotive ids `1..111`
|
||||
- cost descriptors `352..451` already map directly onto recovered locomotive ids `1..100`
|
||||
- the save-side named locomotive table already projects into `RuntimeState.locomotive_catalog` as
|
||||
one ordinal id-to-name map derived from row order
|
||||
- that means the remaining lower-tail rows `302..351` and `413..451` are no longer missing an
|
||||
owner seam; they are just later ordinals on the same catalog
|
||||
|
||||
The old “grounded executable prefix through save-backed locomotive id `61` (`Zephyr`)" boundary is
|
||||
therefore retired. The whole lower bands are executable whenever the save or overlay supplies the
|
||||
catalog context.
|
||||
|
||||
## Grounded Shipped Name Cohort
|
||||
|
||||
The remaining lower-tail labels are no longer blocked on missing shipped engine names.
|
||||
|
||||
The checked export [engine-type locomotive display census](../../artifacts/exports/rt3-1.06/engine-type-locomotive-display-census.json)
|
||||
now parses the fixed `.car` header fields for every shipped `Data/EngineTypes` locomotive pair:
|
||||
|
||||
- `66` shipped `.car` / `.lco` locomotive families
|
||||
- `61` primary display names that match the broader checked shipped-name prefix
|
||||
- `5` extra shipped named families not present in the current grounded prefix:
|
||||
- `242 A1`
|
||||
- `Class 460`
|
||||
- `Class A1`
|
||||
- `Class P8`
|
||||
- `Class QJ`
|
||||
|
||||
That means the remaining lower-tail uncertainty is no longer “what are the extra shipped
|
||||
locomotive names?” It is where those five named families land in the live ordinal catalog that the
|
||||
save-side named availability table mirrors.
|
||||
|
||||
The full local save corpus tightens that further. The only observed nonclassic tail in the checked
|
||||
census is `rt3_wineprefix/drive_c/rt3_105/Saved Games/g.gms`, which exposes one `63`-entry named
|
||||
locomotive table whose observed tail is:
|
||||
|
||||
- `59` `242 A1`
|
||||
- `60` `Class 460`
|
||||
- `61` `Class A1`
|
||||
- `62` `Class P8`
|
||||
- `63` `U1`
|
||||
|
||||
That observation matters because the four catalog-bearing 1.05 save families still carry the
|
||||
classic `59..61` tail `GP 35 / U1 / Zephyr`. So the currently honest static descriptor-name
|
||||
boundary is not the broader shipped-name prefix through `61`; it is the last save-stable prefix
|
||||
through ordinal `58` (`VL80T`). After that point, save-backed ordinal names are real and
|
||||
executable, but they are no longer universal enough to hard-code in the static semantic catalog.
|
||||
|
||||
The same checked local corpus still does **not** surface `Class QJ`, even though the shipped
|
||||
engine-type corpus proves that family exists on disk. So the current non-hook evidence only closes
|
||||
the dynamic tail through the observed `63`-entry family above; it does not yet place the fifth
|
||||
extra shipped name in any live ordinal slot.
|
||||
|
||||
The same checked local corpus also exposes no packed-event rows in descriptor range `452..502`, so
|
||||
the remaining `Unknown Loco Cost` and upper-band frontier is absent from the local save-backed
|
||||
event corpus as well as unmapped in the static descriptor metadata.
|
||||
|
||||
## Remaining Blocker
|
||||
|
||||
What is left is narrower and cleaner, but it is no longer a repo-local static task:
|
||||
|
||||
- ordinal placement of the scenario-dependent locomotive tail beyond the save-stable `1..58` prefix
|
||||
- descriptor `452` `Unknown Loco Cost`
|
||||
- upper availability band `457..474`
|
||||
- upper cost band `475..502`
|
||||
|
||||
The upper bands still carry only slot labels in the checked semantic catalog:
|
||||
|
||||
- `Upper-Band Locomotive Availability Slot 1..18`
|
||||
- `Upper-Band Locomotive Cost Slot 1..28`
|
||||
|
||||
The lower bands now split cleanly into two layers:
|
||||
|
||||
- ordinals `1..58` keep fixed checked descriptor labels through `VL80T`
|
||||
- ordinals `59+` stay executable through recovered ids plus save catalog context, but the checked
|
||||
semantic catalog keeps generic slot labels because the local save corpus already shows
|
||||
scenario-dependent tails
|
||||
|
||||
Unlike the lower bands, the current checked row summary metadata does not yet recover live
|
||||
locomotive ids for the upper-band descriptors at all.
|
||||
|
||||
## Blocker Result
|
||||
|
||||
The next question is no longer whether locomotive page descriptors can import through a save-native
|
||||
owner seam at all, or whether the shipped engine-type files even have stable names. The checked
|
||||
repo-local answer is already as tight as it can get:
|
||||
|
||||
- where the extra shipped named families (`242 A1`, `Class 460`, `Class A1`, `Class P8`,
|
||||
`Class QJ`) land across the scenario-dependent tail beyond the save-stable `1..58` prefix, and
|
||||
- whether the upper bands continue the same ordinal locomotive catalog after the lower `1..111` /
|
||||
`1..100` families, or
|
||||
- do they belong to a separate page-owned selector family that only sits adjacent in the recovered
|
||||
`EventEffects` table
|
||||
|
||||
Descriptor `452` should stay separate from that question until stronger evidence ties it to either
|
||||
the lower cost band or the upper tails.
|
||||
|
||||
The current repo-local blocker is therefore explicit:
|
||||
|
||||
- the next honest non-hook step needs a broader save corpus than the eight local saves already
|
||||
exhausted here
|
||||
- the next honest non-static step needs dynamic tracing or hooks
|
||||
|
|
@ -166,13 +166,16 @@ Implemented today:
|
|||
- the recovered locomotives-page availability bands can now import as full scalar overrides
|
||||
through `RuntimeState.locomotive_catalog` into `RuntimeState.named_locomotive_availability`;
|
||||
raw `.smp` inspection/export now reconstructs the save-side locomotive row family and derives the
|
||||
catalog directly into save-slice documents, so standalone save-slice imports can execute those
|
||||
rows whenever the save carries enough catalog entries, and the grounded executable lower prefix
|
||||
now extends through save-backed locomotive id `61` (`Zephyr`)
|
||||
- the grounded lower locomotive-cost band `352..409` now imports too through the same save-native
|
||||
or embedded catalog into the event-owned `RuntimeState.named_locomotive_cost` map when its
|
||||
scalar payloads are nonnegative; the unresolved lower tail and upper cost tail now stay on
|
||||
explicit parity instead of synthetic execution
|
||||
catalog directly into save-slice documents, so standalone save-slice imports can execute the
|
||||
full lower availability band `241..351` whenever the save carries enough catalog entries; the
|
||||
checked `29`-save `.gms + .gmx` `locomotive-catalog-tail-census.json` export now fixes the last
|
||||
save-stable static boundary at ordinal `58` (`VL80T`), leaving the upper bands `457..474`,
|
||||
`475..502`, plus descriptor `452` as external-corpus or dynamic blockers instead of active
|
||||
repo-local static work
|
||||
- the full lower locomotive-cost band `352..451` now imports too through the same save-native or
|
||||
embedded catalog into the event-owned `RuntimeState.named_locomotive_cost` map when its scalar
|
||||
payloads are nonnegative; the remaining unresolved tail is the separate descriptor `452` plus
|
||||
the upper cost band `475..502`
|
||||
- the remaining recovered scalar world families now execute as well: cargo-production `230..240`
|
||||
rows lower into slot-indexed `cargo_production_overrides`, and territory-access-cost descriptor
|
||||
`453` lowers into `world_restore.territory_access_cost`
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue