@jetta/cargo-stabilizer 0.1.0-9 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. package/README.md +17 -11
  2. package/build/core/adapters/axle_adapter.d.ts +1 -0
  3. package/build/core/adapters/axle_adapter.d.ts.map +1 -1
  4. package/build/core/adapters/axle_adapter.js +3 -18
  5. package/build/core/adapters/axle_load_evaluation.d.ts +8 -0
  6. package/build/core/adapters/axle_load_evaluation.d.ts.map +1 -0
  7. package/build/core/adapters/axle_load_evaluation.js +1 -0
  8. package/build/core/adapters/build_axle_request.d.ts +2 -9
  9. package/build/core/adapters/build_axle_request.d.ts.map +1 -1
  10. package/build/core/adapters/build_axle_request.js +52 -24
  11. package/build/core/adapters/compute_axle_excess_kg.d.ts +8 -0
  12. package/build/core/adapters/compute_axle_excess_kg.d.ts.map +1 -0
  13. package/build/core/adapters/compute_axle_excess_kg.js +19 -0
  14. package/build/core/adapters/coordinate_mapper.d.ts +1 -1
  15. package/build/core/adapters/coordinate_mapper.js +3 -3
  16. package/build/core/adapters/evaluate_axle_load.d.ts +10 -0
  17. package/build/core/adapters/evaluate_axle_load.d.ts.map +1 -0
  18. package/build/core/adapters/evaluate_axle_load.js +32 -0
  19. package/build/core/adapters/map_item_to_stacking_item.d.ts +14 -0
  20. package/build/core/adapters/map_item_to_stacking_item.d.ts.map +1 -0
  21. package/build/core/adapters/map_item_to_stacking_item.js +40 -0
  22. package/build/core/adapters/run_axle_calculator.d.ts.map +1 -1
  23. package/build/core/adapters/run_axle_calculator.js +21 -16
  24. package/build/core/candidates/candidate_validation.d.ts.map +1 -1
  25. package/build/core/candidates/candidate_validation.js +4 -0
  26. package/build/core/candidates/is_candidate_stacking_valid.d.ts +14 -0
  27. package/build/core/candidates/is_candidate_stacking_valid.d.ts.map +1 -0
  28. package/build/core/candidates/is_candidate_stacking_valid.js +43 -0
  29. package/build/core/constants/TieRatioOrientation.d.ts +6 -0
  30. package/build/core/constants/TieRatioOrientation.d.ts.map +1 -0
  31. package/build/core/constants/TieRatioOrientation.js +5 -0
  32. package/build/core/evaluation/compare_search_states.d.ts +12 -0
  33. package/build/core/evaluation/compare_search_states.d.ts.map +1 -0
  34. package/build/core/evaluation/compare_search_states.js +12 -0
  35. package/build/core/evaluation/evaluate_search_gates.d.ts +18 -0
  36. package/build/core/evaluation/evaluate_search_gates.d.ts.map +1 -0
  37. package/build/core/evaluation/evaluate_search_gates.js +30 -0
  38. package/build/core/evaluation/evaluation_result.d.ts +15 -0
  39. package/build/core/evaluation/evaluation_result.d.ts.map +1 -0
  40. package/build/core/evaluation/evaluation_result.js +1 -0
  41. package/build/core/evaluation/genetic_fitness.d.ts +9 -0
  42. package/build/core/evaluation/genetic_fitness.d.ts.map +1 -0
  43. package/build/core/evaluation/genetic_fitness.js +16 -0
  44. package/build/core/evaluation/is_non_axle_gates_pass.d.ts +8 -0
  45. package/build/core/evaluation/is_non_axle_gates_pass.d.ts.map +1 -0
  46. package/build/core/evaluation/is_non_axle_gates_pass.js +8 -0
  47. package/build/core/evaluation/is_search_trial_admissible.d.ts +10 -0
  48. package/build/core/evaluation/is_search_trial_admissible.d.ts.map +1 -0
  49. package/build/core/evaluation/is_search_trial_admissible.js +17 -0
  50. package/build/core/evaluation/is_waypoint_order_valid.d.ts +10 -0
  51. package/build/core/evaluation/is_waypoint_order_valid.d.ts.map +1 -0
  52. package/build/core/evaluation/is_waypoint_order_valid.js +14 -0
  53. package/build/core/evaluation/state_evaluator.d.ts +2 -10
  54. package/build/core/evaluation/state_evaluator.d.ts.map +1 -1
  55. package/build/core/evaluation/state_evaluator.js +6 -26
  56. package/build/core/factory/read_stabilizer_config.d.ts +3 -2
  57. package/build/core/factory/read_stabilizer_config.d.ts.map +1 -1
  58. package/build/core/factory/read_stabilizer_config_helpers.d.ts +9 -5
  59. package/build/core/factory/read_stabilizer_config_helpers.d.ts.map +1 -1
  60. package/build/core/factory/read_stabilizer_config_helpers.js +12 -1
  61. package/build/core/filters/collect_movable_items.d.ts +18 -0
  62. package/build/core/filters/collect_movable_items.d.ts.map +1 -0
  63. package/build/core/filters/collect_movable_items.js +53 -0
  64. package/build/core/filters/collect_pinned_floor_tie_ratio_group_ids.d.ts +8 -0
  65. package/build/core/filters/collect_pinned_floor_tie_ratio_group_ids.d.ts.map +1 -0
  66. package/build/core/filters/collect_pinned_floor_tie_ratio_group_ids.js +41 -0
  67. package/build/core/filters/is_item_on_cm_floor.d.ts +8 -0
  68. package/build/core/filters/is_item_on_cm_floor.d.ts.map +1 -0
  69. package/build/core/filters/is_item_on_cm_floor.js +9 -0
  70. package/build/core/geometry/has_penetrating_overlap.d.ts +9 -0
  71. package/build/core/geometry/has_penetrating_overlap.d.ts.map +1 -0
  72. package/build/core/geometry/has_penetrating_overlap.js +27 -0
  73. package/build/core/orchestration/StabilizerFlow.d.ts.map +1 -1
  74. package/build/core/orchestration/StabilizerFlow.js +1 -1
  75. package/build/core/orchestration/build_reorder_context.d.ts.map +1 -1
  76. package/build/core/orchestration/build_reorder_context.js +3 -5
  77. package/build/core/strategies/reorder/BeamSearchReorder.d.ts.map +1 -1
  78. package/build/core/strategies/reorder/BeamSearchReorder.js +10 -12
  79. package/build/core/strategies/reorder/GeneticReorder.d.ts.map +1 -1
  80. package/build/core/strategies/reorder/GeneticReorder.js +2 -1
  81. package/build/core/strategies/reorder/SimulatedAnnealingReorder.d.ts.map +1 -1
  82. package/build/core/strategies/reorder/SimulatedAnnealingReorder.js +14 -5
  83. package/build/core/strategies/reorder/append_admitted_trial.d.ts +11 -0
  84. package/build/core/strategies/reorder/append_admitted_trial.d.ts.map +1 -0
  85. package/build/core/strategies/reorder/append_admitted_trial.js +22 -0
  86. package/build/core/strategies/reorder/beam_context.d.ts +1 -0
  87. package/build/core/strategies/reorder/beam_context.d.ts.map +1 -1
  88. package/build/core/strategies/reorder/compare_beam_states.d.ts +9 -0
  89. package/build/core/strategies/reorder/compare_beam_states.d.ts.map +1 -0
  90. package/build/core/strategies/reorder/compare_beam_states.js +26 -0
  91. package/build/core/strategies/reorder/greedy_improvement.d.ts.map +1 -1
  92. package/build/core/strategies/reorder/greedy_improvement.js +3 -2
  93. package/build/core/strategies/reorder/is_improving_greedy_trial.d.ts +10 -0
  94. package/build/core/strategies/reorder/is_improving_greedy_trial.d.ts.map +1 -0
  95. package/build/core/strategies/reorder/is_improving_greedy_trial.js +17 -0
  96. package/build/core/strategies/reorder/select_surviving_beam.d.ts +11 -0
  97. package/build/core/strategies/reorder/select_surviving_beam.d.ts.map +1 -0
  98. package/build/core/strategies/reorder/select_surviving_beam.js +13 -0
  99. package/build/core/validation/contract/cargo_movement_wire_field_map.d.ts +37 -3
  100. package/build/core/validation/contract/cargo_movement_wire_field_map.d.ts.map +1 -1
  101. package/build/core/validation/contract/cargo_movement_wire_field_map.js +40 -6
  102. package/build/core/validation/contract/cargo_movement_wire_mapper.d.ts.map +1 -1
  103. package/build/core/validation/contract/cargo_movement_wire_mapper.js +10 -1
  104. package/build/core/validation/contract/map_contract_to_wire_shape.d.ts.map +1 -1
  105. package/build/core/validation/contract/map_contract_to_wire_shape.js +12 -21
  106. package/build/core/validation/contract/map_input_config.d.ts +9 -0
  107. package/build/core/validation/contract/map_input_config.d.ts.map +1 -0
  108. package/build/core/validation/contract/map_input_config.js +40 -0
  109. package/build/core/validation/contract/map_wire_input_to_contract_shape.d.ts.map +1 -1
  110. package/build/core/validation/contract/map_wire_input_to_contract_shape.js +28 -22
  111. package/build/core/validation/contract/map_wire_item_stacking.d.ts +7 -0
  112. package/build/core/validation/contract/map_wire_item_stacking.d.ts.map +1 -0
  113. package/build/core/validation/contract/map_wire_item_stacking.js +40 -0
  114. package/build/core/validation/contract/map_wire_item_to_contract.d.ts +1 -5
  115. package/build/core/validation/contract/map_wire_item_to_contract.d.ts.map +1 -1
  116. package/build/core/validation/contract/map_wire_item_to_contract.js +16 -14
  117. package/build/core/validation/contract/parse_stabilizer_input.d.ts +49 -7
  118. package/build/core/validation/contract/parse_stabilizer_input.d.ts.map +1 -1
  119. package/build/core/validation/contract/parse_stabilizer_input.js +2 -0
  120. package/build/core/validation/contract/parse_stabilizer_output.d.ts +34 -5
  121. package/build/core/validation/contract/parse_stabilizer_output.d.ts.map +1 -1
  122. package/build/core/validation/contract/reject_forbidden_input_fields.d.ts +6 -0
  123. package/build/core/validation/contract/reject_forbidden_input_fields.d.ts.map +1 -0
  124. package/build/core/validation/contract/reject_forbidden_input_fields.js +53 -0
  125. package/build/core/validation/contract/stabilizer_domain_schema.d.ts +36 -65
  126. package/build/core/validation/contract/stabilizer_domain_schema.d.ts.map +1 -1
  127. package/build/core/validation/contract/stabilizer_domain_schema.js +16 -38
  128. package/build/core/validation/contract/stabilizer_env_schema.d.ts +112 -0
  129. package/build/core/validation/contract/stabilizer_env_schema.d.ts.map +1 -0
  130. package/build/core/validation/contract/stabilizer_env_schema.js +38 -0
  131. package/build/core/validation/contract/stabilizer_input_schema.d.ts +51 -7
  132. package/build/core/validation/contract/stabilizer_input_schema.d.ts.map +1 -1
  133. package/build/core/validation/contract/stabilizer_input_schema.js +2 -2
  134. package/build/core/validation/contract/stabilizer_item_schema.d.ts +25 -0
  135. package/build/core/validation/contract/stabilizer_item_schema.d.ts.map +1 -0
  136. package/build/core/validation/contract/stabilizer_item_schema.js +23 -0
  137. package/build/core/validation/contract/stabilizer_output_schema.d.ts +68 -10
  138. package/build/core/validation/contract/stabilizer_output_schema.d.ts.map +1 -1
  139. package/build/core/validation/contract/uniquify_contract_item_ids.d.ts +14 -0
  140. package/build/core/validation/contract/uniquify_contract_item_ids.d.ts.map +1 -0
  141. package/build/core/validation/contract/uniquify_contract_item_ids.js +54 -0
  142. package/build/core/validation/schemas/stabilizer_config_schema.d.ts +2 -1
  143. package/build/core/validation/schemas/stabilizer_config_schema.d.ts.map +1 -1
  144. package/build/core/validation/schemas/stabilizer_config_schema.js +2 -1
  145. package/build/index.d.ts +11 -12
  146. package/build/index.d.ts.map +1 -1
  147. package/build/index.js +29 -21
  148. package/package.json +28 -13
  149. package/CHANGELOG.md +0 -38
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @jetta/cargo-stabilizer
2
2
 
3
- TypeScript library that reorders **loose items only** to improve **whole-cargo transport stability** while keeping compound blocks pinned. The reorder objective is `transport_score` (loose-item score sum is a tie-break). Implements five config-selectable strategies with organization gates (waypoint order, milkrun wall reservation) and empty-space candidate discovery (JET-2262).
3
+ TypeScript library that reorders items to improve **whole-cargo transport stability**. By default every item is movable; set `cargo_stabilizer.pin_tie_ratio_blocks` to pin **floor five-slot** `3_2`/`2_3` walls. Stacked tie-ratio pieces and generic groups stay movable one item at a time. The reorder objective is `transport_score` (loose-item score sum is a tie-break). Implements five config-selectable strategies with organization gates (waypoint order, milkrun wall reservation) and empty-space candidate discovery (JET-2262).
4
4
 
5
5
  ## Requirements
6
6
 
@@ -14,7 +14,7 @@ npm ci
14
14
  npm run build
15
15
  ```
16
16
 
17
- Local monorepo development uses `file:` links to `cargo-stability`, `@jetta/axle-load-calculator`, and `@jetta/empty-spaces-manager`.
17
+ Local monorepo development uses `file:` links to `cargo-stability`, `@jetta/axle-load-calculator`, `@jetta/empty-spaces-manager`, `@jetta/number-compare`, and `@jetta/stacking-constraints`.
18
18
 
19
19
  ## Usage
20
20
 
@@ -49,21 +49,23 @@ if (response.status === 'success') {
49
49
 
50
50
  ## I/O contract
51
51
 
52
- The stabilizer uses a **strict English contract** internally (`src/core/validation/contract/`). Cargo-movement wire payloads keep legacy Portuguese keys; a bidirectional mapper translates at the public boundary.
52
+ `parse_stabilizer_input(unknown)` is the only untyped boundary. `run_stabilize(input: StabilizerInput)` returns a typed `StabilizerResponse`. Wire aliases (`_id`, `w`/`h`/`d`, `eixos`, `algoritmo`) are mapped then stripped; `original_input` and item `attributes` bags are rejected.
53
+
54
+ Success `data` is English `cargo_state` (items mutated in `x,y,z` only). Cargo-movement copies those poses onto existing items by `_id`.
53
55
 
54
56
  | CM wire | Contract (English) |
55
57
  |---------|-------------------|
56
58
  | `_id` | `item_id` |
57
59
  | `groupId` | `group_id` |
58
60
  | `w`, `h`, `d` | `width`, `height`, `depth` |
59
- | `peso` | `weight` |
61
+ | `peso` / `wg` | `weight` |
60
62
  | `sequencia` | `sequence` |
61
63
  | `largura`, `altura`, `comprimento` | `width`, `height`, `length` |
62
64
  | `eixos` | `axles` |
63
65
 
64
- Flow: `map_wire_input_to_contract` → strict Zod parse → stabilizer flow → output validation → `map_contract_to_wire_output`.
66
+ Flow: `map_wire_input_to_contract` → strict Zod parse → `run_stabilize` → output validation.
65
67
 
66
- Exported parsers: `parse_stabilizer_input`, `parse_stabilizer_output`, `safe_parse_*`.
68
+ Exported parsers: `parse_stabilizer_input`, `parse_stabilizer_output`, `safe_parse_*`, `run_stabilize`.
67
69
 
68
70
  ## Configuration
69
71
 
@@ -73,6 +75,7 @@ Exported parsers: `parse_stabilizer_input`, `parse_stabilizer_output`, `safe_par
73
75
  | `cargo_stabilizer.transport_stability_floor` | `0` | Hard minimum transport stability score (gate, not the maximize objective) |
74
76
  | `cargo_stabilizer.max_iteration` | `10` | Greedy / SA iteration budget |
75
77
  | `cargo_stabilizer.preserve_tie_block_organization` | `true` | When true, enforce waypoint Z zones and macro delivery order |
78
+ | `cargo_stabilizer.pin_tie_ratio_blocks` | `false` | When true, do not move floor five-slot `3_2`/`2_3` walls; stacked tie-ratio items and other groups remain movable |
76
79
  | `cargo_stabilizer.enforce_milkrun_wall_reservation` | `false` | When true, reserve rear compound-wall Z bands using profile key below |
77
80
  | `number_of_wall_to_allocate_from_last_waypoints` | `0` | Count of trailing waypoints whose compound walls are reserved (read from `cargo_state.config.algoritmo` when milkrun enforcement is enabled) |
78
81
  | `folga_de_peso_nos_eixos` | `0` | Axle folga percent |
@@ -95,6 +98,8 @@ Runtime integrations (all declared in `package.json`):
95
98
  - `@jetta/cargo-stability` — transport stability scoring gate and objective (`stability_adapter`)
96
99
  - `@jetta/axle-load-calculator` — axle load validation gate (`axle_adapter`)
97
100
  - `@jetta/empty-spaces-manager` — empty-region candidate slot discovery (`empty_space_adapter`)
101
+ - `@jetta/number-compare` — face-touch interval tests (`has_penetrating_overlap`)
102
+ - `@jetta/stacking-constraints` — family and supported-weight gate on candidate moves
98
103
  - `@jetta/logger` — structured logging at orchestration boundary (transitive via cargo-stability)
99
104
  - `zod` — I/O contract validation
100
105
 
@@ -102,7 +107,7 @@ Runtime integrations (all declared in `package.json`):
102
107
 
103
108
  | Command | Description |
104
109
  |---------|-------------|
105
- | `npm test` | Mocha tests (126 cases) |
110
+ | `npm test` | Mocha tests (208 cases) |
106
111
  | `npm run lint` | ESLint |
107
112
  | `npm run build` | TypeScript compile to `build/` |
108
113
  | `npm run coverage` | Tests with **80%** coverage gate (local) |
@@ -111,11 +116,11 @@ Runtime integrations (all declared in `package.json`):
111
116
 
112
117
  ## Layout
113
118
 
114
- - `src/index.ts` — public API (`stabilize`)
119
+ - `src/index.ts` — public API (`stabilize`, `run_stabilize`)
115
120
  - `src/core/validation/contract/` — strict English I/O contract and CM wire mapper
116
121
  - `src/core/strategies/reorder/` — five reorder algorithms
117
- - `src/core/evaluation/` — shared stability + axle + waypoint gates
118
- - `src/core/candidates/` — empty-space slot discovery and candidate ranking
122
+ - `src/core/evaluation/` — shared stability + axle + waypoint gates and search admission
123
+ - `src/core/candidates/` — empty-space slot discovery, stacking gate, and candidate ranking
119
124
  - `test/src/` — mirrors `src/`; fixtures under `test/data/src/`
120
125
 
121
126
  ## Testing and coverage
@@ -138,6 +143,7 @@ npm test -- --grep "apply_move"
138
143
  npm test -- --grep "state_evaluator"
139
144
  npm test -- --grep "gravity_compaction"
140
145
  npm test -- --grep "reorder_strategy_depth"
141
- npm test -- --grep "strategy_factory"
146
+ npm test -- --grep "is_search_trial_admissible"
147
+ npm test -- --grep "is_candidate_stacking_valid"
142
148
  npm run coverage
143
149
  ```
@@ -8,6 +8,7 @@ import type { StabilizerEnv } from '../validation/contract/stabilizer_domain_sch
8
8
  export declare function exceeds_with_folga(final_kg: number, max_kg: number, folga_pct: number): boolean;
9
9
  /**
10
10
  * Validates axle loads for an env using axle-load-calculator.
11
+ * Layout overlap from the calculator is a failed gate, not a skip of kg checks.
11
12
  * @param env - Stabilizer env with containers and axles.
12
13
  * @param folga_pct - Axle load margin percent.
13
14
  * @returns True when all axles are within limits.
@@ -1 +1 @@
1
- {"version":3,"file":"axle_adapter.d.ts","sourceRoot":"","sources":["../../../src/core/adapters/axle_adapter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oDAAoD,CAAA;AAEvF;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAC9B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAClB,OAAO,CAGT;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAejF"}
1
+ {"version":3,"file":"axle_adapter.d.ts","sourceRoot":"","sources":["../../../src/core/adapters/axle_adapter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oDAAoD,CAAA;AAEvF;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAC9B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAClB,OAAO,CAGT;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAGjF"}
@@ -1,4 +1,4 @@
1
- import { run_axle_calculator } from './run_axle_calculator.js';
1
+ import { evaluate_axle_load } from './evaluate_axle_load.js';
2
2
  /**
3
3
  * @param final_kg - Loaded weight including tare.
4
4
  * @param max_kg - Axle supported max.
@@ -10,26 +10,11 @@ export function exceeds_with_folga(final_kg, max_kg, folga_pct) {
10
10
  }
11
11
  /**
12
12
  * Validates axle loads for an env using axle-load-calculator.
13
+ * Layout overlap from the calculator is a failed gate, not a skip of kg checks.
13
14
  * @param env - Stabilizer env with containers and axles.
14
15
  * @param folga_pct - Axle load margin percent.
15
16
  * @returns True when all axles are within limits.
16
17
  */
17
18
  export function is_axle_load_valid(env, folga_pct) {
18
- if (!env.axles || env.axles.length === 0) {
19
- return true;
20
- }
21
- const result = run_axle_calculator(env);
22
- if (!result.calculated) {
23
- return false;
24
- }
25
- const containers = (result.env.containers ?? []);
26
- return containers.every(container => container_axles_within_folga(container, folga_pct));
27
- }
28
- function container_axles_within_folga(container, folga_pct) {
29
- const axles = (container.pesoEixos ?? []);
30
- return axles.every(axle => {
31
- const final_kg = Number(axle.pesoCarregadoFinal ?? 0);
32
- const max_kg = Number(axle.pesoMaxFinal ?? 0);
33
- return !exceeds_with_folga(final_kg, max_kg, folga_pct);
34
- });
19
+ return evaluate_axle_load(env, folga_pct).valid;
35
20
  }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Result of one axle-load calculator pass.
3
+ */
4
+ export interface AxleLoadEvaluation {
5
+ valid: boolean;
6
+ excess_kg: number;
7
+ }
8
+ //# sourceMappingURL=axle_load_evaluation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"axle_load_evaluation.d.ts","sourceRoot":"","sources":["../../../src/core/adapters/axle_load_evaluation.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAE/B,KAAK,EAAE,OAAO,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;CACpB"}
@@ -0,0 +1 @@
1
+ export {};
@@ -1,14 +1,7 @@
1
1
  import type { StabilizerEnv } from '../validation/contract/stabilizer_domain_schema.js';
2
2
  /**
3
- * Builds the axle-load-calculator request for a single env.
4
- *
5
- * The calculator physics reads `peso`, `largura`, `altura` and `comprimento`
6
- * (ItemTemplates and JavaMassCenter), none of which exist in the
7
- * cargo-movement wire item shape (`wg`, `w`, `h`, `d`). Without these aliases
8
- * every item weighs zero and the axle gate can never reject a layout, so the
9
- * contract values are stamped onto each request item here. Longitudinal extent
10
- * is `depth`, matching the wire `y` axis the calculator uses for equilibrium.
11
- * @param env - Stabilizer env with containers and axles.
3
+ * Builds the axle-load-calculator request from typed stabilizer env fields.
4
+ * @param env - Stabilizer env with containers, vehicle, and axles.
12
5
  * @returns Calculator request payload.
13
6
  */
14
7
  export declare function build_axle_request(env: StabilizerEnv): Record<string, unknown>;
@@ -1 +1 @@
1
- {"version":3,"file":"build_axle_request.d.ts","sourceRoot":"","sources":["../../../src/core/adapters/build_axle_request.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAER,aAAa,EAEhB,MAAM,oDAAoD,CAAA;AAE3D;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAS9E"}
1
+ {"version":3,"file":"build_axle_request.d.ts","sourceRoot":"","sources":["../../../src/core/adapters/build_axle_request.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAER,aAAa,EAGhB,MAAM,oDAAoD,CAAA;AAE3D;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAkB9E"}
@@ -1,36 +1,64 @@
1
- import { map_contract_to_wire_output } from '../validation/contract/cargo_movement_wire_mapper.js';
2
1
  /**
3
- * Builds the axle-load-calculator request for a single env.
4
- *
5
- * The calculator physics reads `peso`, `largura`, `altura` and `comprimento`
6
- * (ItemTemplates and JavaMassCenter), none of which exist in the
7
- * cargo-movement wire item shape (`wg`, `w`, `h`, `d`). Without these aliases
8
- * every item weighs zero and the axle gate can never reject a layout, so the
9
- * contract values are stamped onto each request item here. Longitudinal extent
10
- * is `depth`, matching the wire `y` axis the calculator uses for equilibrium.
11
- * @param env - Stabilizer env with containers and axles.
2
+ * Builds the axle-load-calculator request from typed stabilizer env fields.
3
+ * @param env - Stabilizer env with containers, vehicle, and axles.
12
4
  * @returns Calculator request payload.
13
5
  */
14
6
  export function build_axle_request(env) {
15
- const wire = map_contract_to_wire_output({ envs: [env] });
16
- const wire_env = wire.envs[0];
17
- const wire_containers = (wire_env.containers ?? []);
18
- wire_env.containers = wire_containers.map((wire_container, index) => stamp_container_physics_aliases(wire_container, env.containers[index]));
19
- return { envs: wire.envs };
7
+ const wire_env = {
8
+ ...map_vehicle_to_wire(env.vehicle),
9
+ containers: env.containers.map(map_container_to_axle_wire)
10
+ };
11
+ if (env.axles !== undefined) {
12
+ wire_env.eixos = env.axles.map(axle => ({
13
+ distanciaOrigem: axle.distance_from_origin,
14
+ pesoMaxSuportado: axle.max_supported_weight,
15
+ pesoDnit: axle.dnit_weight,
16
+ tara: axle.tare,
17
+ sequenciaContainer: axle.container_sequence,
18
+ sequence: axle.sequence
19
+ }));
20
+ }
21
+ return { envs: [wire_env] };
20
22
  }
21
- function stamp_container_physics_aliases(wire_container, container) {
22
- const wire_items = (wire_container.items ?? []);
23
+ function map_vehicle_to_wire(vehicle) {
24
+ if (vehicle === undefined) {
25
+ return {};
26
+ }
23
27
  return {
24
- ...wire_container,
25
- items: wire_items.map((wire_item, index) => stamp_item_physics_aliases(wire_item, container?.items[index]))
28
+ _id: vehicle.vehicle_id,
29
+ tipoVeiculo: vehicle.vehicle_type,
30
+ tipoVersao: vehicle.version_type,
31
+ tipoSuspensao: vehicle.suspension_type,
32
+ primeiroEixo: vehicle.first_axle,
33
+ tara: vehicle.tare,
34
+ pesoMaxSuportado: vehicle.max_supported_weight,
35
+ qtd: vehicle.quantity
26
36
  };
27
37
  }
28
- function stamp_item_physics_aliases(wire_item, item) {
29
- if (item === undefined) {
30
- return wire_item;
31
- }
38
+ function map_container_to_axle_wire(container) {
39
+ return {
40
+ sequencia: container.sequence,
41
+ largura: container.width,
42
+ altura: container.height,
43
+ comprimento: container.length,
44
+ distPinoRei: container.kingpin_distance,
45
+ containerDistanceAhead: container.container_distance_ahead,
46
+ pesoMaxSuportado: container.max_supported_weight,
47
+ tara: container.tare,
48
+ pesoDeCarga: container.cargo_weight,
49
+ grouper: container.grouper,
50
+ items: container.items.map(map_item_to_axle_wire)
51
+ };
52
+ }
53
+ function map_item_to_axle_wire(item) {
32
54
  return {
33
- ...wire_item,
55
+ _id: item.item_id,
56
+ x: item.x,
57
+ y: item.z,
58
+ z: item.y,
59
+ w: item.width,
60
+ h: item.height,
61
+ d: item.depth,
34
62
  peso: item.weight ?? 0,
35
63
  largura: item.width,
36
64
  altura: item.height,
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Sums kilograms over the folga limit across container axle rows.
3
+ * @param axles - Calculator pesoEixos rows.
4
+ * @param folga_pct - Axle load margin percent.
5
+ * @returns Total excess kilograms; zero when all axles are within limits.
6
+ */
7
+ export declare function compute_axle_excess_kg(axles: Record<string, unknown>[], folga_pct: number): number;
8
+ //# sourceMappingURL=compute_axle_excess_kg.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compute_axle_excess_kg.d.ts","sourceRoot":"","sources":["../../../src/core/adapters/compute_axle_excess_kg.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAClC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAChC,SAAS,EAAE,MAAM,GAClB,MAAM,CAQR"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Sums kilograms over the folga limit across container axle rows.
3
+ * @param axles - Calculator pesoEixos rows.
4
+ * @param folga_pct - Axle load margin percent.
5
+ * @returns Total excess kilograms; zero when all axles are within limits.
6
+ */
7
+ export function compute_axle_excess_kg(axles, folga_pct) {
8
+ let excess_kg = 0;
9
+ for (const axle of axles) {
10
+ excess_kg += axle_row_excess_kg(axle, folga_pct);
11
+ }
12
+ return excess_kg;
13
+ }
14
+ function axle_row_excess_kg(axle, folga_pct) {
15
+ const final_kg = Number(axle.pesoCarregadoFinal ?? 0);
16
+ const max_kg = Number(axle.pesoMaxFinal ?? 0);
17
+ const limit_kg = max_kg * (1 + folga_pct / 100);
18
+ return Math.max(0, final_kg - limit_kg);
19
+ }
@@ -15,7 +15,7 @@ export interface StabilityContainerPayload {
15
15
  item_list: StabilityItemPayload[];
16
16
  }
17
17
  /**
18
- * Maps contract coordinates to cargo-stability payload coordinates.
18
+ * Maps contract coordinates onto cargo-stability axes (y = height, z = length).
19
19
  * @param item - Stabilizer item record.
20
20
  * @returns Stability item payload entry.
21
21
  */
@@ -1,14 +1,14 @@
1
1
  import { item_to_box } from '../geometry/box_geometry.js';
2
2
  /**
3
- * Maps contract coordinates to cargo-stability payload coordinates.
3
+ * Maps contract coordinates onto cargo-stability axes (y = height, z = length).
4
4
  * @param item - Stabilizer item record.
5
5
  * @returns Stability item payload entry.
6
6
  */
7
7
  export function map_item_to_stability(item) {
8
8
  return {
9
9
  x: item.x,
10
- y: item.z,
11
- z: item.y,
10
+ y: item.y,
11
+ z: item.z,
12
12
  w: item.width,
13
13
  h: item.height,
14
14
  l: item.depth
@@ -0,0 +1,10 @@
1
+ import type { StabilizerEnv } from '../validation/contract/stabilizer_domain_schema.js';
2
+ import type { AxleLoadEvaluation } from './axle_load_evaluation.js';
3
+ /**
4
+ * Evaluates axle legality and excess kilograms in one calculator pass.
5
+ * @param env - Stabilizer env with containers and axles.
6
+ * @param folga_pct - Axle load margin percent.
7
+ * @returns Validity and excess over the folga-adjusted max.
8
+ */
9
+ export declare function evaluate_axle_load(env: StabilizerEnv, folga_pct: number): AxleLoadEvaluation;
10
+ //# sourceMappingURL=evaluate_axle_load.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evaluate_axle_load.d.ts","sourceRoot":"","sources":["../../../src/core/adapters/evaluate_axle_load.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oDAAoD,CAAA;AACvF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAA;AAEnE;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,GAAG,kBAAkB,CAc5F"}
@@ -0,0 +1,32 @@
1
+ import { run_axle_calculator } from './run_axle_calculator.js';
2
+ import { compute_axle_excess_kg } from './compute_axle_excess_kg.js';
3
+ /**
4
+ * Evaluates axle legality and excess kilograms in one calculator pass.
5
+ * @param env - Stabilizer env with containers and axles.
6
+ * @param folga_pct - Axle load margin percent.
7
+ * @returns Validity and excess over the folga-adjusted max.
8
+ */
9
+ export function evaluate_axle_load(env, folga_pct) {
10
+ if (!env.axles || env.axles.length === 0) {
11
+ return { valid: true, excess_kg: 0 };
12
+ }
13
+ const result = run_axle_calculator(env);
14
+ if (!result.calculated) {
15
+ return { valid: false, excess_kg: Number.POSITIVE_INFINITY };
16
+ }
17
+ return evaluation_from_calculated_env(result.env, folga_pct);
18
+ }
19
+ function evaluation_from_calculated_env(calculated_env, folga_pct) {
20
+ const containers = (calculated_env.containers ?? []);
21
+ const axles = collect_container_axle_rows(containers);
22
+ const excess_kg = compute_axle_excess_kg(axles, folga_pct);
23
+ return { valid: excess_kg === 0, excess_kg };
24
+ }
25
+ function collect_container_axle_rows(containers) {
26
+ const rows = [];
27
+ for (const container of containers) {
28
+ const axles = (container.pesoEixos ?? []);
29
+ rows.push(...axles);
30
+ }
31
+ return rows;
32
+ }
@@ -0,0 +1,14 @@
1
+ import { type Item } from '@jetta/stacking-constraints';
2
+ import type { StabilizerItem } from '../validation/contract/stabilizer_domain_schema.js';
3
+ /**
4
+ * Maps a stabilizer item onto a stacking-constraints Item.
5
+ * @param item - Stabilizer item.
6
+ * @param position - Optional pose override for a candidate slot.
7
+ * @returns Stacking-constraints item.
8
+ */
9
+ export declare function map_item_to_stacking_item(item: StabilizerItem, position?: {
10
+ x: number;
11
+ y: number;
12
+ z: number;
13
+ }): Item;
14
+ //# sourceMappingURL=map_item_to_stacking_item.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"map_item_to_stacking_item.d.ts","sourceRoot":"","sources":["../../../src/core/adapters/map_item_to_stacking_item.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0B,KAAK,IAAI,EAAsB,MAAM,6BAA6B,CAAA;AACnG,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oDAAoD,CAAA;AAKxF;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACrC,IAAI,EAAE,cAAc,EACpB,QAAQ,CAAC,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,GAC/C,IAAI,CAYN"}
@@ -0,0 +1,40 @@
1
+ import { default_stacking_rules } from '@jetta/stacking-constraints';
2
+ const ALLOWED_FAMILIES_CONSTRAINT = 'ALLOWED_FAMILIES';
3
+ const SUPPORTED_WEIGHT_UNIT = 'supportedWeight';
4
+ /**
5
+ * Maps a stabilizer item onto a stacking-constraints Item.
6
+ * @param item - Stabilizer item.
7
+ * @param position - Optional pose override for a candidate slot.
8
+ * @returns Stacking-constraints item.
9
+ */
10
+ export function map_item_to_stacking_item(item, position) {
11
+ return {
12
+ itemId: item.item_id,
13
+ x: position?.x ?? item.x,
14
+ y: position?.y ?? item.y,
15
+ z: position?.z ?? item.z,
16
+ width: item.width,
17
+ height: item.height,
18
+ length: item.depth,
19
+ stackingRules: build_stacking_rules(item)
20
+ };
21
+ }
22
+ function build_stacking_rules(item) {
23
+ const rules = default_stacking_rules();
24
+ return {
25
+ ...rules,
26
+ family: item.family ?? rules.family,
27
+ allowedFamilies: item.supported_families ?? [...rules.allowedFamilies],
28
+ enableOnlyAllowedFamilies: is_family_constraint_enabled(item),
29
+ weight: item.weight !== undefined && item.weight > 0 ? item.weight : rules.weight,
30
+ enableMaximumStackingWeight: item.stacking_unit === SUPPORTED_WEIGHT_UNIT,
31
+ maximumStackingWeight: item.supported_weight ?? rules.maximumStackingWeight,
32
+ enableStackSameItemOnly: item.stack_same_item === true,
33
+ enableStackSameAreaOnly: item.stack_same_area === true,
34
+ priority: item.priority ?? rules.priority,
35
+ ...(item.waypoint_id !== undefined ? { waypoint_id: item.waypoint_id } : {})
36
+ };
37
+ }
38
+ function is_family_constraint_enabled(item) {
39
+ return item.constraint === ALLOWED_FAMILIES_CONSTRAINT || item.stack_families === true;
40
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"run_axle_calculator.d.ts","sourceRoot":"","sources":["../../../src/core/adapters/run_axle_calculator.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oDAAoD,CAAA;AASvF,MAAM,MAAM,oBAAoB,GAC1B;IAAE,UAAU,EAAE,IAAI,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAClD;IAAE,UAAU,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAE3C;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,aAAa,GAAG,oBAAoB,CAoB5E"}
1
+ {"version":3,"file":"run_axle_calculator.d.ts","sourceRoot":"","sources":["../../../src/core/adapters/run_axle_calculator.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oDAAoD,CAAA;AAEvF,MAAM,MAAM,oBAAoB,GAC1B;IAAE,UAAU,EAAE,IAAI,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAClD;IAAE,UAAU,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAE3C;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,aAAa,GAAG,oBAAoB,CAW5E"}
@@ -1,13 +1,7 @@
1
- import { calculate_weight_on_axles_physics } from '@jetta/axle-load-calculator';
1
+ import { calculate_weight_on_axles_physics, ItemOverlapError } from '@jetta/axle-load-calculator';
2
2
  import { build_axle_request } from './build_axle_request.js';
3
3
  import { AxleCalculationError } from '../exceptions/AxleCalculationError.js';
4
4
  import { stabilizer_logger } from '../logging/stabilizer_logger.js';
5
- /**
6
- * Calculator failures caused by the candidate layout rather than by the vehicle
7
- * or item configuration. These reject the candidate layout; every other failure
8
- * means the env can never be evaluated and aborts the run.
9
- */
10
- const LAYOUT_REJECTION_MESSAGES = Object.freeze(['Item overlap error']);
11
5
  /**
12
6
  * Runs the axle-load calculator for a candidate env layout.
13
7
  * @param env - Stabilizer env with containers and axles.
@@ -16,17 +10,28 @@ const LAYOUT_REJECTION_MESSAGES = Object.freeze(['Item overlap error']);
16
10
  */
17
11
  export function run_axle_calculator(env) {
18
12
  const request = build_axle_request(env);
19
- const output = JSON.parse(calculate_weight_on_axles_physics(JSON.stringify(request)));
13
+ try {
14
+ return calculated_env_from_physics(request);
15
+ }
16
+ catch (error) {
17
+ return handle_calculator_failure(error);
18
+ }
19
+ }
20
+ function calculated_env_from_physics(request) {
21
+ const output = calculate_weight_on_axles_physics(request);
20
22
  if (Array.isArray(output.envs) && output.envs.length > 0) {
21
23
  return { calculated: true, env: output.envs[0] };
22
24
  }
23
- const reason = output.apiError ?? 'calculator returned no envs';
24
- if (!is_layout_rejection(reason)) {
25
- throw new AxleCalculationError(reason);
26
- }
27
- stabilizer_logger.debug('axle gate rejected candidate layout: ' + reason);
28
- return { calculated: false, reason };
25
+ throw new AxleCalculationError('calculator returned no envs');
29
26
  }
30
- function is_layout_rejection(reason) {
31
- return LAYOUT_REJECTION_MESSAGES.some(message => reason.includes(message));
27
+ function handle_calculator_failure(error) {
28
+ if (error instanceof ItemOverlapError) {
29
+ stabilizer_logger.debug('axle gate rejected candidate layout: ' + error.message);
30
+ return { calculated: false, reason: error.message };
31
+ }
32
+ if (error instanceof AxleCalculationError) {
33
+ throw error;
34
+ }
35
+ const message = error instanceof Error ? error.message : String(error);
36
+ throw new AxleCalculationError(message);
32
37
  }
@@ -1 +1 @@
1
- {"version":3,"file":"candidate_validation.d.ts","sourceRoot":"","sources":["../../../src/core/candidates/candidate_validation.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAA;AAGxE;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAC9B,OAAO,EAAE,0BAA0B,EACnC,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9C,OAAO,CAeT"}
1
+ {"version":3,"file":"candidate_validation.d.ts","sourceRoot":"","sources":["../../../src/core/candidates/candidate_validation.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAA;AAIxE;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAC9B,OAAO,EAAE,0BAA0B,EACnC,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9C,OAAO,CAmBT"}
@@ -4,6 +4,7 @@ import { is_position_in_zone } from '../waypoint/build_waypoint_zones.js';
4
4
  import { is_position_in_milkrun_reserved_band } from '../waypoint/milkrun_wall_reservation.js';
5
5
  import { resolve_item_waypoint_id } from '../waypoint/validate_waypoint_ids.js';
6
6
  import { is_elevated_on_supporter_origin } from './is_elevated_on_supporter_origin.js';
7
+ import { is_candidate_stacking_valid } from './is_candidate_stacking_valid.js';
7
8
  /**
8
9
  * Validates geometry and waypoint constraints for a candidate position.
9
10
  * @param context - Candidate generation context.
@@ -21,6 +22,9 @@ export function is_candidate_valid(context, target_index, position) {
21
22
  if (!is_candidate_milkrun_valid(context, target_index, position)) {
22
23
  return false;
23
24
  }
25
+ if (!is_candidate_stacking_valid(context, target_index, position)) {
26
+ return false;
27
+ }
24
28
  return is_candidate_waypoint_valid(context, target_index, position);
25
29
  }
26
30
  function is_candidate_milkrun_valid(context, target_index, position) {
@@ -0,0 +1,14 @@
1
+ import type { CandidateGenerationContext } from './candidate_context.js';
2
+ /**
3
+ * Returns true when placing the loose item at position keeps stacking legal.
4
+ * @param context - Candidate generation context.
5
+ * @param target_index - Target container index.
6
+ * @param position - Candidate pose.
7
+ * @returns True when stacking-constraints accepts the pose.
8
+ */
9
+ export declare function is_candidate_stacking_valid(context: CandidateGenerationContext, target_index: number, position: {
10
+ x: number;
11
+ y: number;
12
+ z: number;
13
+ }): boolean;
14
+ //# sourceMappingURL=is_candidate_stacking_valid.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"is_candidate_stacking_valid.d.ts","sourceRoot":"","sources":["../../../src/core/candidates/is_candidate_stacking_valid.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAA;AAIxE;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CACvC,OAAO,EAAE,0BAA0B,EACnC,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9C,OAAO,CAcT"}
@@ -0,0 +1,43 @@
1
+ import { StackingFeasibilityChecker } from '@jetta/stacking-constraints';
2
+ import { map_item_to_stacking_item } from '../adapters/map_item_to_stacking_item.js';
3
+ const Y_SUPPORT_EPSILON = 1e-6;
4
+ /**
5
+ * Returns true when placing the loose item at position keeps stacking legal.
6
+ * @param context - Candidate generation context.
7
+ * @param target_index - Target container index.
8
+ * @param position - Candidate pose.
9
+ * @returns True when stacking-constraints accepts the pose.
10
+ */
11
+ export function is_candidate_stacking_valid(context, target_index, position) {
12
+ const remaining = context.containers[target_index].items
13
+ .filter(item => item.item_id !== context.loose.item_id)
14
+ .map(item => map_item_to_stacking_item(item));
15
+ const mover = map_item_to_stacking_item(context.loose.item, position);
16
+ try {
17
+ return build_checker(remaining).clone().validate_stackings(mover);
18
+ }
19
+ catch {
20
+ return false;
21
+ }
22
+ }
23
+ function build_checker(remaining) {
24
+ if (remaining.length === 0) {
25
+ return new StackingFeasibilityChecker(1, { y_support_epsilon: Y_SUPPORT_EPSILON });
26
+ }
27
+ try {
28
+ return StackingFeasibilityChecker.from_allocated(remaining, {
29
+ y_support_epsilon: Y_SUPPORT_EPSILON
30
+ });
31
+ }
32
+ catch {
33
+ return hydrate_bottom_up(remaining);
34
+ }
35
+ }
36
+ function hydrate_bottom_up(remaining) {
37
+ const checker = new StackingFeasibilityChecker(1, { y_support_epsilon: Y_SUPPORT_EPSILON });
38
+ const ordered = [...remaining].sort((left, right) => left.y - right.y);
39
+ for (const item of ordered) {
40
+ checker.validate_stackings(item);
41
+ }
42
+ return checker;
43
+ }
@@ -0,0 +1,6 @@
1
+ export declare const TIE_RATIO_ORIENTATION: Readonly<{
2
+ THREE_TWO: "3_2";
3
+ TWO_THREE: "2_3";
4
+ }>;
5
+ export declare const TIE_RATIO_ORIENTATION_VALUES: readonly ("3_2" | "2_3")[];
6
+ //# sourceMappingURL=TieRatioOrientation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TieRatioOrientation.d.ts","sourceRoot":"","sources":["../../../src/core/constants/TieRatioOrientation.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,qBAAqB;;;EAGhC,CAAA;AAEF,eAAO,MAAM,4BAA4B,4BAExC,CAAA"}
@@ -0,0 +1,5 @@
1
+ export const TIE_RATIO_ORIENTATION = Object.freeze({
2
+ THREE_TWO: '3_2',
3
+ TWO_THREE: '2_3'
4
+ });
5
+ export const TIE_RATIO_ORIENTATION_VALUES = Object.freeze(Object.values(TIE_RATIO_ORIENTATION));
@@ -0,0 +1,12 @@
1
+ export interface SearchRankFields {
2
+ axle_excess_kg: number;
3
+ objective: number;
4
+ }
5
+ /**
6
+ * Ranks search states: lower axle excess first, then higher stability objective.
7
+ * @param left - Left state.
8
+ * @param right - Right state.
9
+ * @returns Negative when left ranks ahead of right.
10
+ */
11
+ export declare function compare_search_states(left: SearchRankFields, right: SearchRankFields): number;
12
+ //# sourceMappingURL=compare_search_states.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compare_search_states.d.ts","sourceRoot":"","sources":["../../../src/core/evaluation/compare_search_states.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAE7B,cAAc,EAAE,MAAM,CAAA;IACtB,SAAS,EAAE,MAAM,CAAA;CACpB;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,EAAE,gBAAgB,GAAG,MAAM,CAO7F"}