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}