code wiki / (root) / nx_build_plan_sim.nx

nx_build_plan_sim.nx source

↩ module page · 127 lines · 5164 B

1// nx_build_plan_sim.nx -- simulator for the multi-process build plan. 2// 3// ===================================================================== 4// CARDINAL: [[feedback-simulation-discipline-for-every-substrate]] 5// 6// Second-substrate demonstration of the simulation discipline. First 7// stone was nx_print_sim (3d-print physics). THIS file applies the 8// same SimulatorState + step + sealed-enum issue framework to a 9// completely different substrate (multi-process schedule solver) -- 10// proving the discipline generalizes. 11// 12// Industry: there is no production cross-process build-plan 13// scheduler at all (humans + spreadsheets coordinate today), let 14// alone a simulator that predicts schedule failures. 15// 16// What this simulator predicts on a SOLVED build plan: 17// DEADLINE_MISSED total schedule > caller-supplied deadline 18// POST_CURE_OVERRUN any part's post-cure > caller max 19// PRINTER_IDLE_WASTE one process's printer idle most of its 20// used window (heuristic candidate -- queued 21// per the cardinal's no-heuristic rule) 22// 23// FIRST STONE here ships the first two (real time-arithmetic, not 24// heuristic). PRINTER_IDLE_WASTE deferred until we have a clearer 25// physical definition. 26// ===================================================================== 27// 28// license_tier: ORIGINAL 29 30import "nx_syscalls.nx" 31import "nx_print_process.nx" 32import "nx_build_plan.nx" 33 34// ===== sealed issue-kind enum ==================================== 35 36const NX_BUILD_SIM_ISSUE_NONE: i64 = 0 37const NX_BUILD_SIM_ISSUE_DEADLINE_MISSED: i64 = 1 38const NX_BUILD_SIM_ISSUE_POST_CURE_OVERRUN: i64 = 2 39const NX_BUILD_SIM_ISSUE_PRINTER_IDLE_WASTE: i64 = 3 // queued (next stone) 40const NX_BUILD_SIM_ISSUE_N: i64 = 4 41 42func nx_build_sim_issue_is_valid(k: i64) -> i64 { 43 if k < 0 { return 0 } 44 if k >= NX_BUILD_SIM_ISSUE_N { return 0 } 45 return 1 46} 47 48// ===== issue record ============================================== 49// 50// part_id: index into plan.parts (or -1 for plan-wide). 51// magnitude_min: severity in minutes (e.g., overshoot of deadline). 52 53struct NxBuildPlanSimIssue { 54 kind: i64, 55 part_id: i64, 56 magnitude_min: i64, 57 reserved: i64, // pad to 32 bytes for future use 58} 59 60const NX_BUILD_PLAN_SIM_ISSUE_BYTES: i64 = 32 61 62// ===== simulator check =========================================== 63// 64// Runs all failure-prediction checks on a SOLVED build plan. Writes 65// NxBuildPlanSimIssue records into out_issues (caller-supplied 66// buffer of capacity out_issues_cap). Returns the number of issues 67// written, capped at out_issues_cap. 68// 69// Caller responsibility: nx_build_plan_solve(plan) must have been 70// called BEFORE this function (so end_time_min fields are populated). 71// 72// Inputs (caller-supplied constraints): 73// deadline_min total wall-clock the schedule must fit within 74// max_cure_min longest acceptable per-part post-cure 75// 76// Returns 0 if no issues (schedule fits all constraints). 77 78func nx_build_plan_sim_check(plan: *NxBuildPlan, 79 deadline_min: i64, 80 max_cure_min: i64, 81 out_issues: *NxBuildPlanSimIssue, 82 out_issues_cap: i64) -> i64 { 83 if (plan as i64) == 0 { return 0 } 84 if (out_issues as i64) == 0 { return 0 } 85 if out_issues_cap <= 0 { return 0 } 86 87 var n_written: i64 = 0 88 89 // ---- Check 1: DEADLINE_MISSED ---- 90 // Real time arithmetic: plan.total_minutes vs caller deadline. 91 // No heuristic threshold; the deadline is the operator's actual 92 // constraint. 93 if deadline_min > 0 { 94 if plan.total_minutes > deadline_min { 95 if n_written < out_issues_cap { 96 let ip: *NxBuildPlanSimIssue = (((out_issues as i64) + n_written * NX_BUILD_PLAN_SIM_ISSUE_BYTES)) as *NxBuildPlanSimIssue 97 ip.kind = NX_BUILD_SIM_ISSUE_DEADLINE_MISSED 98 ip.part_id = -1 // plan-wide 99 ip.magnitude_min = plan.total_minutes - deadline_min 100 ip.reserved = 0 101 n_written = n_written + 1 102 } 103 } 104 } 105 106 // ---- Check 2: POST_CURE_OVERRUN ---- 107 // Real per-part comparison against caller's max. 108 if max_cure_min > 0 { 109 var pi: i64 = 0 110 while pi < plan.n_parts { 111 let pp: *NxBuildPart = (((plan.parts as i64) + pi * NX_BUILD_PART_BYTES)) as *NxBuildPart 112 if pp.post_cure_minutes > max_cure_min { 113 if n_written < out_issues_cap { 114 let ip2: *NxBuildPlanSimIssue = (((out_issues as i64) + n_written * NX_BUILD_PLAN_SIM_ISSUE_BYTES)) as *NxBuildPlanSimIssue 115 ip2.kind = NX_BUILD_SIM_ISSUE_POST_CURE_OVERRUN 116 ip2.part_id = pi 117 ip2.magnitude_min = pp.post_cure_minutes - max_cure_min 118 ip2.reserved = 0 119 n_written = n_written + 1 120 } 121 } 122 pi = pi + 1 123 } 124 } 125 126 return n_written 127}