code wiki / _hdl_build / nx_autonomy_meter.nx
nx_autonomy_meter.nx source
↩ module page · 155 lines · 7950 B
1// nx_autonomy_meter.nx -- X-AUT-002: the autonomy GRADE, MEASURED never asserted
2// (autonomy ladder spec 2026-06-11; declared W0 tutor-with-team scaffold -- and this
3// organ COUNTS ITSELF against the grade: it is tutor-authored, so A2 stays honest).
4// PLAIN LANGUAGE: how much of the work does the system do by itself? Four axes,
5// each 0..1000 permil, each from a ledger anyone can re-read:
6// A1 judged-DONE share : queue rows DONE carrying ||MARK= (machine-judged by
7// reconcile evidence) / all DONE rows. Hand-flipped DONEs drag the grade.
8// A2 emitter-authored share : ABSENT (named gap) -- registrations do not yet carry
9// an author= tag (row X-AUT-002a files it). Counted 0, never faked.
10// A3 daemon-run share : pulse runs fired by the autorun daemon (DAEMON-BEAT rows)
11// / all pulse runs (PULSE-RUN rows). Hand-run beats drag the grade.
12// A4 hands-off-heal share : ENG- defect rows DONE with MARK / all ENG- rows DONE.
13// Zero closed = 0 with a note, never a crash.
14// autonomy_permil = (A1+A2+A3+A4)/4 ; grade: <150 F, <500 D, <700 C, <850 B,
15// <900 A, >=900 S (the ladder's bars).
16// Durable: AUTMETER row -> knowledge/status/autonomy_meter.log. Exit 0 = measured
17// (any grade); exit 1 = could not read its world. argv[1]=queue argv[2]=pulselog
18// argv[3]=daemonlog argv[4]=outlog (gates use scratch).
19// license_tier: ORIGINAL
20import "nx_syscalls.nx"
21const K_MAGIC_1048576: i64 = 1048576
22const K_MAGIC_1048560: i64 = 1048560
23func _p(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
24func _fp(fd: i64, s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(fd,s,n); return 0 }
25func _fn(fd: i64, v: i64) -> i64 { let bb: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m}; let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=48 as u8;k=1}; while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1}; var i: i64=0; while i<k{bb[i]=t[k-1-i];i=i+1}; sys_write(fd,bb,k); return 0 }
26func am_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
27func am_read(path: *u8, buf: *u8, cap: i64) -> i64 {
28 let fd: i64 = sys_openat_rd(path)
29 if fd < 0 { return 0 }
30 var n: i64 = 0
31 var go: i64 = 1
32 while go == 1 { let base: i64 = buf as i64; let r: i64 = sys_read(fd, (base + n) as *u8, cap - n); if r <= 0 { go = 0 } else { n = n + r } if n >= cap { go = 0 } }
33 sys_close(fd)
34 return n
35}
36func am_slice_has(hay: *u8, a: i64, b: i64, pat: *u8) -> i64 {
37 let pl: i64 = am_len(pat)
38 if pl == 0 { return 0 }
39 var i: i64 = a
40 while i + pl <= b {
41 var k: i64 = 0
42 var hit: i64 = 1
43 while k < pl { if hay[i+k] != pat[k] { hit = 0; k = pl } else { k = k + 1 } }
44 if hit == 1 { return 1 }
45 i = i + 1
46 }
47 return 0
48}
49// count LINES holding p1 (and p2 if not the 1-byte sentinel '*')
50func am_lines2(buf: *u8, n: i64, p1: *u8, p2: *u8) -> i64 {
51 var cnt: i64 = 0
52 var i: i64 = 0
53 while i < n {
54 var le: i64 = i
55 var s: i64 = 1
56 while s == 1 { if le >= n { s = 0 } else { if buf[le] == (10 as u8) { s = 0 } else { le = le + 1 } } }
57 if am_slice_has(buf, i, le, p1) == 1 {
58 var two: i64 = 1
59 if p2[0] != (42 as u8) { two = am_slice_has(buf, i, le, p2) }
60 if two == 1 { cnt = cnt + 1 }
61 }
62 i = le + 1
63 }
64 return cnt
65}
66func am_axis(num: i64, den: i64) -> i64 {
67 if den <= 0 { return 0 }
68 // v2 small-N damping (X-AUT-002b, filed BEFORE the n=1 jump printed): one lucky
69 // heal must not print grade C -- axis_effective = axis * min(den,5) / 5
70 var dmin: i64 = den
71 if dmin > 5 { dmin = 5 }
72 return (((1000 * num) / den) * dmin) / 5
73}
74func am_grade(fd: i64, permil: i64) -> i64 {
75 if permil < 150 { _fp(fd, "F" as *u8); return 0 }
76 if permil < 500 { _fp(fd, "D" as *u8); return 0 }
77 if permil < 700 { _fp(fd, "C" as *u8); return 0 }
78 if permil < 850 { _fp(fd, "B" as *u8); return 0 }
79 if permil < 900 { _fp(fd, "A" as *u8); return 0 }
80 _fp(fd, "S" as *u8)
81 return 0
82}
83func main(argc: i64, argv: *i64) -> i64 {
84 var qp: *u8 = "knowledge/registry/assignment_queue.tsv" as *u8
85 var plp: *u8 = "knowledge/status/team_pulse.log" as *u8
86 var dlp: *u8 = "knowledge/status/pulse_daemon.log" as *u8
87 var olp: *u8 = "knowledge/status/autonomy_meter.log" as *u8
88 if argc >= 2 { qp = argv[1] as *u8 }
89 if argc >= 3 { plp = argv[2] as *u8 }
90 if argc >= 4 { dlp = argv[3] as *u8 }
91 if argc >= 5 { olp = argv[4] as *u8 }
92 _p("=== AUTONOMY METER: the grade is measured from ledgers, never asserted ===\n" as *u8)
93 let qb: *u8 = sys_mmap(K_MAGIC_1048576)
94 let qn: i64 = am_read(qp, qb, K_MAGIC_1048560)
95 if qn <= 0 { _p(" queue MISSING -- fail loud\n" as *u8); sys_exit(1); return 1 }
96 let pb: *u8 = sys_mmap(K_MAGIC_1048576)
97 let pn: i64 = am_read(plp, pb, K_MAGIC_1048560)
98 let db: *u8 = sys_mmap(K_MAGIC_1048576)
99 let dn: i64 = am_read(dlp, db, K_MAGIC_1048560)
100 let star: *u8 = "*" as *u8
101 // A1: DONE rows judged by MARK evidence / all DONE rows
102 let done_all: i64 = am_lines2(qb, qn, "\tDONE\t" as *u8, star)
103 let done_mark: i64 = am_lines2(qb, qn, "\tDONE\t" as *u8, "||MARK=" as *u8)
104 let a1: i64 = am_axis(done_mark, done_all)
105 // A2 v3: registrations carrying author= tags (the protocol starts 2026-06-12;
106 // untagged pre-protocol entries are excluded -- the share is over TAGGED only,
107 // and zero tagged entries reads 0 honestly, never ABSENT-faked-green)
108 let rb2: *u8 = sys_mmap(K_MAGIC_1048576)
109 let rn2: i64 = am_read("knowledge/status/cap_registry_durable.log" as *u8, rb2, K_MAGIC_1048560)
110 let auth_all: i64 = am_lines2(rb2, rn2, " author=" as *u8, star)
111 let auth_emit: i64 = am_lines2(rb2, rn2, " author=emitter" as *u8, star)
112 let a2: i64 = am_axis(auth_emit, auth_all)
113 // A3: daemon-fired pulse runs / all pulse runs
114 let runs_all: i64 = am_lines2(pb, pn, "PULSE-RUN " as *u8, star)
115 var runs_daemon: i64 = am_lines2(db, dn, "DAEMON-BEAT " as *u8, star)
116 if runs_daemon > runs_all { runs_daemon = runs_all }
117 let a3: i64 = am_axis(runs_daemon, runs_all)
118 // A4: ENG- defect rows healed hands-off (DONE with MARK) / ENG- rows DONE
119 let eng_done: i64 = am_lines2(qb, qn, "ENG-" as *u8, "\tDONE\t" as *u8)
120 let eng_mark: i64 = am_lines2(qb, qn, "ENG-" as *u8, "||MARK=" as *u8)
121 var eng_mark_done: i64 = eng_mark
122 if eng_done < eng_mark_done { eng_mark_done = eng_done }
123 let a4: i64 = am_axis(eng_mark_done, eng_done)
124 let permil: i64 = (a1 + a2 + a3 + a4) / 4
125 let lfd: i64 = sys_openat_append(olp, 0x1a4)
126 if lfd < 0 { _p(" meter log open failed\n" as *u8); sys_exit(1); return 1 }
127 _fp(lfd, "AUTMETER epoch=" as *u8); _fn(lfd, sys_now_realtime_sec())
128 _fp(lfd, " a1_judged_done=" as *u8); _fn(lfd, a1)
129 _fp(lfd, " a2_emitter_authored=" as *u8); _fn(lfd, a2)
130 _fp(lfd, " n2=" as *u8); _fn(lfd, auth_all)
131 _fp(lfd, " a3_daemon_runs=" as *u8); _fn(lfd, a3)
132 _fp(lfd, " a4_handsoff_heals=" as *u8); _fn(lfd, a4)
133 _fp(lfd, " n1=" as *u8); _fn(lfd, done_all)
134 _fp(lfd, " n3=" as *u8); _fn(lfd, runs_all)
135 _fp(lfd, " n4=" as *u8); _fn(lfd, eng_done)
136 _fp(lfd, " done_rows=" as *u8); _fn(lfd, done_all)
137 _fp(lfd, " pulse_runs=" as *u8); _fn(lfd, runs_all)
138 _fp(lfd, " permil=" as *u8); _fn(lfd, permil)
139 _fp(lfd, " grade=" as *u8); am_grade(lfd, permil)
140 _fp(lfd, "\n" as *u8)
141 sys_close(lfd)
142 _p(" AUTMETER permil=" as *u8)
143 let ob: *u8 = sys_mmap(28)
144 var m: i64 = permil
145 var k: i64 = 0
146 if m == 0 { ob[0] = 48 as u8; k = 1 }
147 while m > 0 { ob[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
148 var i: i64 = 0
149 let rb: *u8 = sys_mmap(28)
150 while i < k { rb[i] = ob[k-1-i]; i = i + 1 }
151 sys_write(1, rb, k)
152 _p(" (durable: autonomy_meter.log; the grade moves only when the ledgers move)\n" as *u8)
153 sys_exit(0)
154 return 0
155}