code wiki / _hdl_build / nx_deltaclass_lib.nx

nx_deltaclass_lib.nx source

↩ module page · 159 lines · 6667 B

1// nx_deltaclass_lib.nx -- WHY a headline ratio moved: SCOPE vs EXECUTION, decomposed EXACTLY. 2// 3// THE DEBT THIS EATS: the ecomat headline went 500 -> 418 permil over two weeks and READ AS DECAY. 4// It was not decay. Delivery rose 34 -> 51 levels (+250 permil at a FIXED bar) while the bar itself 5// rose 68 -> 122 (-332 permil of pure requirement growth). Net -82. Nobody could tell those apart 6// without deriving it by hand, so a marathon had no defined start and no defined end. 7// 8// THE DECOMPOSITION IS EXACT, not a heuristic. For ratio = cur/bar: 9// exec_effect = permil(cur1,bar0) - permil(cur0,bar0) <- what DELIVERY did, bar held FIXED 10// scope_effect = permil(cur1,bar1) - permil(cur1,bar0) <- what the REQUIREMENT move did 11// total = permil(cur1,bar1) - permil(cur0,bar0) 12// residual = total - exec - scope <- integer truncation, EMITTED not hidden 13// Both effects are computed INDEPENDENTLY and the residual is PRINTED rather than derived away, so 14// truncation stays visible. Deriving one term from the other would force residual==0 by construction 15// and hide the very rounding the integer-truncation law says goes silent. 16// 17// TWO ORTHOGONAL AXES, deliberately NOT collapsed into one label: a sample can raise the bar AND 18// deliver in the same window, and flattening that into a single enum is exactly how real progress 19// gets misread as thrashing. 20// 21// license_tier: ORIGINAL No hw writes (Rule 26). 22import "nx_syscalls.nx" 23 24const DC_PERMIL: i64 = 1000 25 26// scope axis -- what the BAR (the requirement) did 27const DCS_FLAT: i64 = 0 28const DCS_ADMIT: i64 = 1 29const DCS_RAISE: i64 = 2 30const DCS_LOWER: i64 = 3 31 32// execution axis -- what the NUMERATOR (delivery) did 33const DCE_FLAT: i64 = 0 34const DCE_GAIN: i64 = 1 35const DCE_LOSS: i64 = 2 36 37// marathon verdict -- THE START/END CRITERION 38const DCV_CONVERGING: i64 = 0 39const DCV_SCOPE_BOUND: i64 = 1 40const DCV_DIVERGING: i64 = 2 41const DCV_STALLED: i64 = 3 42const DCV_THRASH: i64 = 4 43// A LOSS is not a STALL. Lumping them together tells the operator "nothing moved" while ground is 44// being given up -- the worst direction for a status word to be wrong. Found by running the CLI on 45// the live ledger: a 52->51 window reported STALLED. 46const DCV_REGRESSION: i64 = 5 47 48// -1 sentinel = evidence absent. NEVER a silent 0: an UNMEASURED gap must not read as a CLOSED one. 49func dc_unmeasured() -> i64 { return 0 - 1 } 50 51func dc_abs(v: i64) -> i64 { if v < 0 { return 0 - v } return v } 52 53func dc_permil(cur: i64, bar: i64) -> i64 { 54 if bar <= 0 { return dc_unmeasured() } 55 if cur < 0 { return dc_unmeasured() } 56 return cur * DC_PERMIL / bar 57} 58 59// The bar moved -> requirements changed. ADMIT (new territory scoped in) is distinguished from 60// RAISE (same territory, higher target) because they demand OPPOSITE responses: admit is a 61// deliberate widening, raise is a standard tightening. 62func dc_scope_class(bar0: i64, bar1: i64, dom0: i64, dom1: i64) -> i64 { 63 if bar1 < bar0 { return DCS_LOWER } 64 if bar1 > bar0 { 65 if dom1 > dom0 { return DCS_ADMIT } 66 return DCS_RAISE 67 } 68 return DCS_FLAT 69} 70 71func dc_exec_class(cur0: i64, cur1: i64) -> i64 { 72 if cur1 > cur0 { return DCE_GAIN } 73 if cur1 < cur0 { return DCE_LOSS } 74 return DCE_FLAT 75} 76 77// what the ratio would have done had the BAR NOT MOVED 78func dc_exec_effect(cur0: i64, cur1: i64, bar0: i64) -> i64 { 79 let a: i64 = dc_permil(cur1, bar0) 80 let b: i64 = dc_permil(cur0, bar0) 81 if a == dc_unmeasured() { return dc_unmeasured() } 82 if b == dc_unmeasured() { return dc_unmeasured() } 83 return a - b 84} 85 86// what the BAR MOVE alone did, holding delivery at its NEW value 87func dc_scope_effect(cur1: i64, bar0: i64, bar1: i64) -> i64 { 88 let a: i64 = dc_permil(cur1, bar1) 89 let b: i64 = dc_permil(cur1, bar0) 90 if a == dc_unmeasured() { return dc_unmeasured() } 91 if b == dc_unmeasured() { return dc_unmeasured() } 92 return a - b 93} 94 95func dc_total(cur0: i64, bar0: i64, cur1: i64, bar1: i64) -> i64 { 96 let a: i64 = dc_permil(cur1, bar1) 97 let b: i64 = dc_permil(cur0, bar0) 98 if a == dc_unmeasured() { return dc_unmeasured() } 99 if b == dc_unmeasured() { return dc_unmeasured() } 100 return a - b 101} 102 103// the truncation artifact, MADE VISIBLE. Bounded small; a large residual means the inputs lied. 104func dc_residual(cur0: i64, bar0: i64, cur1: i64, bar1: i64) -> i64 { 105 let t: i64 = dc_total(cur0, bar0, cur1, bar1) 106 let e: i64 = dc_exec_effect(cur0, cur1, bar0) 107 let s: i64 = dc_scope_effect(cur1, bar0, bar1) 108 if t == dc_unmeasured() { return dc_unmeasured() } 109 if e == dc_unmeasured() { return dc_unmeasured() } 110 if s == dc_unmeasured() { return dc_unmeasured() } 111 return t - e - s 112} 113 114// levels still owed. Clamped at 0: delivery above bar is a bar that needs raising, not a negative gap. 115func dc_gap(cur: i64, bar: i64) -> i64 { 116 if bar < cur { return 0 } 117 return bar - cur 118} 119 120// THE NUMBER THAT ENDS THE ARGUMENT: is the bar growing faster than we close it? 121// If yes there is no ETA at any effort level -- the remedy is a scope decision, not more hours. 122func dc_diverging(cur0: i64, bar0: i64, cur1: i64, bar1: i64) -> i64 { 123 let db: i64 = bar1 - bar0 124 let dc: i64 = cur1 - cur0 125 if db <= 0 { return 0 } 126 if db > dc { return 1 } 127 return 0 128} 129 130// windows remaining at the OBSERVED net rate; unmeasured when there is no finite answer. 131// Ceiling division so a partial window counts as a whole one -- never round an ETA down. 132func dc_eta(cur0: i64, bar0: i64, cur1: i64, bar1: i64) -> i64 { 133 if bar1 <= 0 { return dc_unmeasured() } 134 if dc_diverging(cur0, bar0, cur1, bar1) == 1 { return dc_unmeasured() } 135 let net: i64 = (cur1 - cur0) - (bar1 - bar0) 136 if net <= 0 { return dc_unmeasured() } 137 let g: i64 = dc_gap(cur1, bar1) 138 if g == 0 { return 0 } 139 return (g + net - 1) / net 140} 141 142// moved==1 means the window contained real movement that netted out (a cycle), not a flat line. 143// Without that flag a stalled run and a thrashing run are indistinguishable at the endpoints. 144func dc_verdict(cur0: i64, bar0: i64, cur1: i64, bar1: i64, moved: i64) -> i64 { 145 if bar0 <= 0 { return dc_unmeasured() } 146 if bar1 <= 0 { return dc_unmeasured() } 147 if dc_diverging(cur0, bar0, cur1, bar1) == 1 { return DCV_DIVERGING } 148 if bar1 != bar0 { 149 let e: i64 = dc_exec_effect(cur0, cur1, bar0) 150 let s: i64 = dc_scope_effect(cur1, bar0, bar1) 151 if dc_abs(s) > dc_abs(e) { return DCV_SCOPE_BOUND } 152 } 153 if cur1 > cur0 { return DCV_CONVERGING } 154 if cur1 == cur0 { 155 if moved == 1 { return DCV_THRASH } 156 return DCV_STALLED 157 } 158 return DCV_REGRESSION 159}