nx_asset_status.nx source
↩ module page · 158 lines · 8505 B
1// nx_asset_status.nx -- R5 "WHAT'S GOING ON" + "WHAT WE HAVE" aggregator.
2//
3// Computes the DASHBOARD STATISTICS over the asset catalog: total assets, counts by type, counts by
4// provenance class, freshness (how many is_current), and -- composing R4 -- the task-signal totals by
5// code. This is the data layer the live /wiki/assets.html dashboard renders; it is PURE / deterministic:
6// every number is COUNTED from the catalog snapshot (+ the R4 as_scan over it), never fabricated
7// (org_research.tsv CONFIRMED: status-awareness-dashboard, task-signals-derived).
8//
9// ZERO NEW STORAGE -- pure COMPOSITION (Rule 15, DRY):
10// * catalog enumeration + bytes + count -> nx_asset_catalog (cat_list / cat_get / cat_count)
11// * record field access -> nx_asset_record (ar_decode / ar_get)
12// * derived task signals -> nx_asset_signals (as_scan, + the 7 SIG_* code labels)
13//
14// HONESTY (Rule 4): as_scan needs two AUX inputs that cannot be answered from record bytes alone --
15// perceptual phashes (NEAR_DUP) and signed credentials (MISSING_PROVENANCE binding). The caller supplies
16// them PARALLEL to cat_list order; production passes ZEROS (no pixel decode / no credentials minted yet),
17// which makes NEAR_DUP impossible-to-claim and MISSING_PROVENANCE deny-by-default true for every record
18// -- the genuine current TO-DO state, not a flattering one. A future rung that decodes pixels / mints
19// credentials feeds real aux arrays here unchanged.
20//
21// No hardware/persistent-firmware writes (Rule 26). license_tier: ORIGINAL
22import "nx_syscalls.nx"
23import "nx_asset_record.nx"
24import "nx_asset_catalog.nx"
25import "nx_asset_signals.nx"
26const K_MAGIC_4096: i64 = 4096
27
28// ---- stats out-array layout (i64[], heap-mmap; offset accessors, no struct aliasing) ----
29// caller mmaps st_cap() i64 slots and passes the pointer; each accessor reads one field.
30func st_cap() -> i64 { return 32 }
31func ST_TOTAL() -> i64 { return 0 }
32func ST_T_DOC() -> i64 { return 1 }
33func ST_T_IMAGE() -> i64 { return 2 }
34func ST_T_VIDEO() -> i64 { return 3 }
35func ST_T_AUDIO() -> i64 { return 4 }
36func ST_T_DATASET() -> i64 { return 5 }
37func ST_T_PRODUCT() -> i64 { return 6 }
38func ST_T_OTHER() -> i64 { return 7 }
39func ST_P_MACHINE() -> i64 { return 8 }
40func ST_P_HUMAN() -> i64 { return 9 }
41func ST_P_DOWNLOAD() -> i64 { return 10 }
42func ST_P_NONE() -> i64 { return 11 }
43func ST_CURRENT() -> i64 { return 12 } // is_current == "1"
44func ST_NOTCURRENT() -> i64 { return 13 } // is_current != "1" (soft-retired / absent)
45func ST_SIG_TOTAL() -> i64 { return 14 }
46// per-signal-code totals (parallel to the 7 SIG_* labels)
47func ST_SIG_PROV() -> i64 { return 15 } // MISSING_PROVENANCE
48func ST_SIG_UNTAG() -> i64 { return 16 } // UNTAGGED
49func ST_SIG_META() -> i64 { return 17 } // MISSING_METADATA
50func ST_SIG_NEARDUP() -> i64 { return 18 } // NEAR_DUP
51func ST_SIG_STALE() -> i64 { return 19 } // STALE
52func ST_SIG_ORPHAN() -> i64 { return 20 } // ORPHANED
53func ST_SIG_UNTRANS() -> i64 { return 21 } // UNTRANSCODED
54
55func st_streq(a: *u8, b: *u8) -> i64 {
56 var i: i64 = 0
57 while 1 == 1 {
58 if a[i] != b[i] { return 0 }
59 if a[i] == (0 as u8) { return 1 }
60 i = i + 1
61 }
62 return 1
63}
64func st_present(v: *u8) -> i64 {
65 if (v as i64) == 0 { return 0 }
66 if v[0] == (0 as u8) { return 0 }
67 return 1
68}
69
70// ---- st_compute: fill the stats out-array from the catalog at `prefix` + the R4 signals over it ----
71// phashes / cred_ptr / cred_len / pubkey are the R4 aux arrays, PARALLEL to cat_list order (production
72// passes zeros; see header). out must be caller-mmap'd >= st_cap() i64 slots. Returns total assets.
73// PURE/deterministic over (snapshot, aux).
74func st_compute(prefix: *u8, phashes: *i64, cred_ptr: *i64, cred_len: *i64, pubkey: *u8, out: *i64) -> i64 {
75 // zero the stats array.
76 var z: i64 = 0
77 while z < st_cap() { out[z] = 0; z = z + 1 }
78
79 // 1) enumerate the catalog (snapshot order).
80 let lcap: i64 = K_MAGIC_4096
81 let cids: *i64 = sys_mmap(8 * lcap) as *i64
82 let n: i64 = cat_list(prefix, cids, lcap)
83 out[ST_TOTAL()] = n
84
85 // 2) per-record type / provenance / freshness tally.
86 let dk: *i64 = sys_mmap(8 * 64) as *i64
87 let dv: *i64 = sys_mmap(8 * 64) as *i64
88 let pp: *i64 = sys_mmap(16) as *i64
89 let ll: *i64 = sys_mmap(16) as *i64
90 var i: i64 = 0
91 while i < n {
92 let cid: *u8 = cids[i] as *u8
93 if cat_get(prefix, cid, pp, ll) == 1 {
94 let nf: i64 = ar_decode(pp[0] as *u8, ll[0], dk, dv, 64)
95 let typ: *u8 = ar_get(dk, dv, nf, "type\x00" as *u8)
96 let prov: *u8 = ar_get(dk, dv, nf, "prov_class\x00" as *u8)
97 let cur: *u8 = ar_get(dk, dv, nf, "is_current\x00" as *u8)
98 // type
99 if st_present(typ) == 1 {
100 if st_streq(typ, "doc\x00" as *u8) == 1 { out[ST_T_DOC()] = out[ST_T_DOC()] + 1 }
101 else { if st_streq(typ, "image\x00" as *u8) == 1 { out[ST_T_IMAGE()] = out[ST_T_IMAGE()] + 1 }
102 else { if st_streq(typ, "video\x00" as *u8) == 1 { out[ST_T_VIDEO()] = out[ST_T_VIDEO()] + 1 }
103 else { if st_streq(typ, "audio\x00" as *u8) == 1 { out[ST_T_AUDIO()] = out[ST_T_AUDIO()] + 1 }
104 else { if st_streq(typ, "dataset\x00" as *u8) == 1 { out[ST_T_DATASET()] = out[ST_T_DATASET()] + 1 }
105 else { if st_streq(typ, "product\x00" as *u8) == 1 { out[ST_T_PRODUCT()] = out[ST_T_PRODUCT()] + 1 }
106 else { out[ST_T_OTHER()] = out[ST_T_OTHER()] + 1 } } } } } }
107 } else { out[ST_T_OTHER()] = out[ST_T_OTHER()] + 1 }
108 // provenance class
109 if st_present(prov) == 1 {
110 if st_streq(prov, "machine\x00" as *u8) == 1 { out[ST_P_MACHINE()] = out[ST_P_MACHINE()] + 1 }
111 else { if st_streq(prov, "human\x00" as *u8) == 1 { out[ST_P_HUMAN()] = out[ST_P_HUMAN()] + 1 }
112 else { if st_streq(prov, "downloaded\x00" as *u8) == 1 { out[ST_P_DOWNLOAD()] = out[ST_P_DOWNLOAD()] + 1 }
113 else { out[ST_P_NONE()] = out[ST_P_NONE()] + 1 } } }
114 } else { out[ST_P_NONE()] = out[ST_P_NONE()] + 1 }
115 // freshness
116 var live: i64 = 0
117 if st_present(cur) == 1 { if st_streq(cur, "1\x00" as *u8) == 1 { live = 1 } }
118 if live == 1 { out[ST_CURRENT()] = out[ST_CURRENT()] + 1 } else { out[ST_NOTCURRENT()] = out[ST_NOTCURRENT()] + 1 }
119 }
120 i = i + 1
121 }
122
123 // 3) derived task signals (R4 as_scan), tallied by code.
124 let scap: i64 = K_MAGIC_4096
125 let sig: *i64 = sys_mmap(8 * 3 * scap) as *i64
126 let nsig: i64 = as_scan(prefix, phashes, cred_ptr, cred_len, pubkey, sig, scap)
127 out[ST_SIG_TOTAL()] = nsig
128 var s: i64 = 0
129 while s < nsig {
130 let code: *u8 = as_sig_code(sig, scap, s)
131 if st_streq(code, SIG_MISSING_PROVENANCE()) == 1 { out[ST_SIG_PROV()] = out[ST_SIG_PROV()] + 1 }
132 if st_streq(code, SIG_UNTAGGED()) == 1 { out[ST_SIG_UNTAG()] = out[ST_SIG_UNTAG()] + 1 }
133 if st_streq(code, SIG_MISSING_METADATA()) == 1 { out[ST_SIG_META()] = out[ST_SIG_META()] + 1 }
134 if st_streq(code, SIG_NEAR_DUP()) == 1 { out[ST_SIG_NEARDUP()] = out[ST_SIG_NEARDUP()] + 1 }
135 if st_streq(code, SIG_STALE()) == 1 { out[ST_SIG_STALE()] = out[ST_SIG_STALE()] + 1 }
136 if st_streq(code, SIG_ORPHANED()) == 1 { out[ST_SIG_ORPHAN()] = out[ST_SIG_ORPHAN()] + 1 }
137 if st_streq(code, SIG_UNTRANSCODED()) == 1 { out[ST_SIG_UNTRANS()] = out[ST_SIG_UNTRANS()] + 1 }
138 s = s + 1
139 }
140 return n
141}
142
143// production convenience: zero aux arrays (no pixel decode / no credentials minted yet -> honest TO-DO
144// state). Allocates the aux arrays sized to the live count, all zero. Returns total assets.
145func st_compute_live(prefix: *u8, out: *i64) -> i64 {
146 let lcap: i64 = K_MAGIC_4096
147 let phashes: *i64 = sys_mmap(8 * lcap) as *i64
148 let cred_ptr: *i64 = sys_mmap(8 * lcap) as *i64
149 let cred_len: *i64 = sys_mmap(8 * lcap) as *i64
150 var i: i64 = 0
151 while i < lcap { phashes[i] = 0; cred_ptr[i] = 0; cred_len[i] = 0; i = i + 1 }
152 let pubkey: *u8 = sys_mmap(32) // unused when cred_len all 0 (deny-by-default -> all MISSING_PROVENANCE)
153 var z: i64 = 0
154 while z < 32 { pubkey[z] = 0 as u8; z = z + 1 }
155 return st_compute(prefix, phashes, cred_ptr, cred_len, pubkey, out)
156}
157
158// library organ (no main); "UNDEFINED label: main" at build is EXPECTED.