nx_compare_ladder_isolated_lib.nx source
↩ module page · 376 lines · 21547 B
1// nx_compare_ladder_isolated_lib.nx -- Computes and compares rankings of nodes in a plan structure using SHA-256 hashing and string operations.
2import "nx_swcompare_lib.nx"
3// Additive shared dependency projection. Parsed declarations are not verified readiness.
4// Owned by nx_swcompare_lib; no main, filesystem writes, publication or dispatch.
5import "nx_sha256.nx"
6const SGP_FIELDS: i64 = 8
7const SGP_PATH_CAP: i64 = 600
8const SGP_I64_MAX: i64 = 9223372036854775807
9struct SgPlan {
10 plan: *u8
11 plan_bytes: i64
12 plan_sha: *u8
13 matrix_sha: *u8
14 matrix_bytes: i64
15 rank_sha: *u8
16 rank_bytes: i64
17 nodes: *i64
18 count: i64
19 declared: i64
20 edges: *i64
21 edge_count: i64
22 malformed: i64
23 duplicate_ids: i64
24 duplicate_edges: i64
25 missing_deps: i64
26 cyclic_nodes: i64
27 target_rows: i64
28 role_rows: i64
29 risk_rows: i64
30 log_rows: i64
31 rank_count: i64
32 rank_mismatches: i64
33 binding_rows: i64
34 binding_ok: i64
35}
36func sg_len(s: *u8) -> i64 { var i: i64 = 0; while s[i] != (0 as u8) { i = i + 1 } return i }
37func sg_id(s: *u8, n: i64) -> i64 {
38 if n <= 0 { return 0 }
39 var i: i64 = 0
40 while i < n {
41 let c: i64 = s[i] as i64
42 var ok: i64 = 0
43 if c >= 48 { if c <= 57 { ok = 1 } }
44 if c >= 65 { if c <= 90 { ok = 1 } }
45 if c >= 97 { if c <= 122 { ok = 1 } }
46 if c == 95 { ok = 1 }; if c == 45 { ok = 1 }
47 if ok == 0 { return 0 }; i = i + 1
48 }
49 return 1
50}
51// Unlike splitpipe, count every field even when the caller's pointer reserve is full.
52func sg_split(s: *u8, f: *i64, capacity: i64, delimiter: i64) -> i64 {
53 var count: i64 = 1; var i: i64 = 0; f[0] = s as i64
54 while s[i] != (0 as u8) {
55 if s[i] == (delimiter as u8) { s[i] = 0 as u8; if count < capacity { f[count] = s as i64 + i + 1 }; count = count + 1 }
56 i = i + 1
57 }
58 return count
59}
60func sg_decimal(s: *u8) -> i64 {
61 if s[0] == (0 as u8) { return 0 - 1 }
62 var v: i64 = 0; var i: i64 = 0
63 while s[i] != (0 as u8) {
64 let c: i64 = s[i] as i64; if c < 48 { return 0 - 1 }; if c > 57 { return 0 - 1 }
65 let d: i64 = c - 48; if v > (SGP_I64_MAX - d) / 10 { return 0 - 1 }
66 v = v * 10 + d; i = i + 1
67 }
68 return v
69}
70func sg_sha(b: *u8, n: i64) -> *u8 {
71 let raw: *u8 = sys_mmap(32); let text: *u8 = sys_mmap(65)
72 if (raw as i64) <= 0 { return "" as *u8 }; if (text as i64) <= 0 { return "" as *u8 }
73 sha256_digest(b, n, raw)
74 let digits: *u8 = "0123456789abcdef" as *u8
75 var i: i64 = 0
76 while i < 32 { let c: i64 = raw[i] as i64; text[i*2] = digits[c / 16]; text[i*2+1] = digits[c % 16]; i = i + 1 }
77 text[64] = 0 as u8; return text
78}
79func sg_find(m: *SgPlan, name: *u8, length: i64) -> i64 {
80 var i: i64 = 0
81 while i < m.count {
82 let id: *u8 = m.nodes[i*SGP_FIELDS + 1] as *u8
83 if sg_len(id) == length {
84 var j: i64 = 0; var equal: i64 = 1
85 while j < length { if id[j] != name[j] { equal = 0 }; j = j + 1 }
86 if equal == 1 { return i }
87 }
88 i = i + 1
89 }
90 return 0 - 1
91}
92func sg_prefix_decimal(s: *u8, key: *u8) -> i64 {
93 if starts(s, key) == 0 { return 0 - 1 }
94 return sg_decimal((s as i64 + sg_len(key)) as *u8)
95}
96func sg_rank(m: *SgPlan, raw: *u8, n: i64) -> i64 {
97 m.rank_count = 0 - 1
98 if n <= 0 { return 0 }
99 if n == SGP_I64_MAX { m.rank_mismatches = m.rank_mismatches + 1; return 0 }
100 m.rank_sha = sg_sha(raw, n); m.rank_bytes = n
101 if sg_len(m.rank_sha) != 64 { m.rank_mismatches = m.rank_mismatches + 1; return 0 }
102 let b: *u8 = sys_mmap(n + 1); var c: i64 = 0
103 if (b as i64) <= 0 { m.rank_mismatches = m.rank_mismatches + 1; return 0 }
104 while c < n { if raw[c] == (0 as u8) { m.rank_mismatches = m.rank_mismatches + 1; return 0 }; b[c] = raw[c]; c = c + 1 }; b[n] = 0 as u8
105 let f: *i64 = sys_mmap(12 * 8) as *i64
106 if (f as i64) <= 0 { m.rank_mismatches = m.rank_mismatches + 1; return 0 }
107 var pos: i64 = 0; var stamps: i64 = 0
108 while pos < n {
109 var end: i64 = pos; while end < n { if b[end] == (10 as u8) { break }; end = end + 1 }
110 b[end] = 0 as u8; if end > pos { if b[end-1] == (13 as u8) { b[end-1] = 0 as u8 } }
111 let line: *u8 = (b as i64 + pos) as *u8; pos = end + 1
112 if starts(line, "# inputs_v=" as *u8) == 1 {
113 m.binding_rows = m.binding_rows + 1
114 let nf: i64 = sg_split(line, f, 12, 32)
115 if nf == 6 {
116 if streq(f[1] as *u8, "inputs_v=1" as *u8) == 1 {
117 let ps: *u8 = f[2] as *u8; let ms: *u8 = f[4] as *u8
118 if starts(ps, "plan_sha256=" as *u8) == 1 { if starts(ms, "matrix_sha256=" as *u8) == 1 {
119 if streq((ps as i64 + 12) as *u8, m.plan_sha) == 1 { if streq((ms as i64 + 14) as *u8, m.matrix_sha) == 1 {
120 if sg_prefix_decimal(f[3] as *u8, "plan_bytes=" as *u8) == m.plan_bytes {
121 if sg_prefix_decimal(f[5] as *u8, "matrix_bytes=" as *u8) == m.matrix_bytes { m.binding_ok = 1 }
122 }
123 } }
124 } }
125 }
126 }
127 } else {
128 if starts(line, "# asof=" as *u8) == 1 {
129 stamps = stamps + 1
130 let nf: i64 = sg_split(line, f, 12, 32)
131 if nf > 12 { m.rank_mismatches = m.rank_mismatches + 1 } else {
132 var z: i64 = 0; var found: i64 = 0
133 while z < nf { if starts(f[z] as *u8, "rungs=" as *u8) == 1 { found = found + 1; m.rank_count = sg_prefix_decimal(f[z] as *u8, "rungs=" as *u8) }; z = z + 1 }
134 if found != 1 { m.rank_mismatches = m.rank_mismatches + 1 }
135 }
136 } else {
137 if starts(line, "rank|" as *u8) == 1 {
138 let nf: i64 = sg_split(line, f, 12, 124)
139 if nf != 10 { m.rank_mismatches = m.rank_mismatches + 1 } else {
140 let id: *u8 = f[3] as *u8; let idx: i64 = sg_find(m, id, sg_len(id))
141 if idx < 0 { m.rank_mismatches = m.rank_mismatches + 1 } else {
142 if streq(f[9] as *u8, m.nodes[idx*SGP_FIELDS+3] as *u8) == 0 { m.rank_mismatches = m.rank_mismatches + 1 }
143 }
144 }
145 }
146 }
147 }
148 }
149 if stamps != 1 { m.rank_mismatches = m.rank_mismatches + 1 }
150 if m.binding_rows != 1 { m.binding_ok = 0 }
151 if m.matrix_bytes <= 0 { m.binding_ok = 0 }
152 return 0
153}
154func sg_parse(raw: *u8, n: i64, rank: *u8, rn: i64, matrix: *u8, mn: i64) -> *SgPlan {
155 // SgPlan stores 25 pointer/i64 fields, each one native 64-bit word.
156 let m: *SgPlan = sys_mmap(25 * 8) as *SgPlan
157 if (m as i64) <= 0 { return 0 as *SgPlan }
158 m.rank_count = 0 - 1; m.matrix_bytes = mn
159 m.plan_sha = "" as *u8; m.matrix_sha = "" as *u8; m.rank_sha = "" as *u8
160 if n <= 0 { m.malformed = 1; return m }
161 if (raw as i64) <= 0 { m.malformed = 1; return m }
162 // Reserve arithmetic is bounded by the input byte count, not a policy cutoff.
163 if n > SGP_I64_MAX / (SGP_FIELDS * 8) - 1 { m.malformed = 1; return m }
164 if rn < 0 { m.malformed = 1; return m }; if mn < 0 { m.malformed = 1; return m }
165 if rn > 0 { if (rank as i64) <= 0 { m.malformed = 1; return m } }
166 if mn > 0 { if (matrix as i64) <= 0 { m.malformed = 1; return m } }
167 m.plan_bytes = n; m.plan_sha = sg_sha(raw, n)
168 if sg_len(m.plan_sha) != 64 { m.malformed = 1; return m }
169 if mn > 0 { m.matrix_sha = sg_sha(matrix, mn); if sg_len(m.matrix_sha) != 64 { m.malformed = 1; return m } }
170 let b: *u8 = sys_mmap(n + 1); m.plan = b
171 if (b as i64) <= 0 { m.malformed = 1; return m }
172 var maxrows: i64 = 1; var maxedges: i64 = 1; var c: i64 = 0
173 while c < n {
174 if raw[c] == (0 as u8) { m.malformed = m.malformed + 1 }
175 if raw[c] == (10 as u8) { maxrows = maxrows + 1; maxedges = maxedges + 1 }
176 if raw[c] == (44 as u8) { maxedges = maxedges + 1 }
177 b[c] = raw[c]; c = c + 1
178 }
179 b[n] = 0 as u8
180 m.nodes = sys_mmap(maxrows * SGP_FIELDS * 8) as *i64
181 m.edges = sys_mmap(maxedges * 2 * 8) as *i64
182 let f: *i64 = sys_mmap(SGP_FIELDS * 8) as *i64
183 if (m.nodes as i64) <= 0 { m.malformed = 1; return m }
184 if (m.edges as i64) <= 0 { m.malformed = 1; return m }
185 if (f as i64) <= 0 { m.malformed = 1; return m }
186 var pos: i64 = 0
187 while pos < n {
188 var end: i64 = pos; while end < n { if b[end] == (10 as u8) { break }; end = end + 1 }
189 b[end] = 0 as u8; if end > pos { if b[end-1] == (13 as u8) { b[end-1] = 0 as u8 } }
190 let line: *u8 = (b as i64 + pos) as *u8; pos = end + 1
191 if starts(line, "sotatarget|" as *u8) == 1 { m.target_rows = m.target_rows + 1 }
192 if starts(line, "rungrole|" as *u8) == 1 { m.role_rows = m.role_rows + 1 }
193 if starts(line, "risk|" as *u8) == 1 { m.risk_rows = m.risk_rows + 1 }
194 if starts(line, "log|" as *u8) == 1 { m.log_rows = m.log_rows + 1 }
195 if starts(line, "rung|" as *u8) == 1 {
196 m.declared = m.declared + 1
197 let nf: i64 = sg_split(line, f, SGP_FIELDS, 124)
198 if nf != SGP_FIELDS { m.malformed = m.malformed + 1 } else {
199 let id: *u8 = f[1] as *u8
200 if sg_id(id, sg_len(id)) == 0 { m.malformed = m.malformed + 1 } else {
201 if sg_find(m, id, sg_len(id)) >= 0 { m.duplicate_ids = m.duplicate_ids + 1 } else {
202 var j: i64 = 0; while j < SGP_FIELDS { m.nodes[m.count*SGP_FIELDS+j] = f[j]; j = j + 1 }
203 m.count = m.count + 1
204 }
205 }
206 }
207 }
208 }
209 var node: i64 = 0
210 while node < m.count {
211 let deps: *u8 = m.nodes[node*SGP_FIELDS+7] as *u8
212 if streq(deps, "-" as *u8) == 0 {
213 var start: i64 = 0; var at: i64 = 0; var more: i64 = 1
214 while more == 1 {
215 var delimiter: i64 = 0
216 if deps[at] == (0 as u8) { more = 0; delimiter = 1 }
217 if deps[at] == (44 as u8) { delimiter = 1 }
218 if delimiter == 1 {
219 let length: i64 = at - start
220 let name: *u8 = (deps as i64 + start) as *u8
221 if sg_id(name, length) == 0 { m.malformed = m.malformed + 1 } else {
222 let dep: i64 = sg_find(m, name, length)
223 if dep < 0 { m.missing_deps = m.missing_deps + 1 } else {
224 var duplicate: i64 = 0; var e: i64 = 0
225 while e < m.edge_count { if m.edges[e*2] == dep { if m.edges[e*2+1] == node { duplicate = 1 } }; e = e + 1 }
226 if duplicate == 1 { m.duplicate_edges = m.duplicate_edges + 1 } else {
227 m.edges[m.edge_count*2] = dep; m.edges[m.edge_count*2+1] = node; m.edge_count = m.edge_count + 1
228 }
229 }
230 }
231 start = at + 1
232 }
233 at = at + 1
234 }
235 }
236 node = node + 1
237 }
238 let degree: *i64 = sys_mmap((m.count+1)*8) as *i64
239 let visited: *i64 = sys_mmap((m.count+1)*8) as *i64
240 if (degree as i64) <= 0 { m.malformed = 1; return m }
241 if (visited as i64) <= 0 { m.malformed = 1; return m }
242 var e: i64 = 0; while e < m.edge_count { let to: i64 = m.edges[e*2+1]; degree[to] = degree[to] + 1; e = e + 1 }
243 var removed: i64 = 0; var progress: i64 = 1
244 while progress == 1 {
245 progress = 0; var i: i64 = 0
246 while i < m.count {
247 if visited[i] == 0 { if degree[i] == 0 {
248 visited[i] = 1; removed = removed + 1; progress = 1
249 var j: i64 = 0; while j < m.edge_count { if m.edges[j*2] == i { let to: i64 = m.edges[j*2+1]; degree[to] = degree[to] - 1 }; j = j + 1 }
250 } }
251 i = i + 1
252 }
253 }
254 m.cyclic_nodes = m.count - removed
255 sg_rank(m, rank, rn)
256 return m
257}
258func sg_valid(m: *SgPlan) -> i64 {
259 if (m as i64) <= 0 { return 0 }
260 if m.malformed + m.duplicate_ids + m.duplicate_edges + m.missing_deps + m.cyclic_nodes != 0 { return 0 }
261 return 1
262}
263func sg_rank_state(m: *SgPlan) -> *u8 {
264 if m.rank_bytes <= 0 { return "UNAVAILABLE" as *u8 }
265 if m.rank_count != m.declared { return "STALE_INCONSISTENT" as *u8 }
266 if m.rank_mismatches > 0 { return "STALE_INCONSISTENT" as *u8 }
267 if m.binding_rows > 1 { return "INVALID_BINDING" as *u8 }
268 if m.binding_rows == 1 { if m.binding_ok == 0 { return "STALE_OR_INVALID_BINDING" as *u8 } }
269 if m.binding_ok == 1 { return "PLAN_MATRIX_BOUND_ONLY" as *u8 }
270 return "UNBOUND" as *u8
271}
272func sg_load(domain: *u8) -> *SgPlan {
273 let path: *u8 = sys_mmap(SGP_PATH_CAP)
274 if (path as i64) <= 0 { return 0 as *SgPlan }
275 let prefix: *u8 = "knowledge/compare/" as *u8
276 let dn: i64 = sg_len(domain)
277 if dn + sg_len(prefix) + sg_len(".matrix") + 1 > SGP_PATH_CAP { return 0 as *SgPlan }
278 if sg_id(domain, dn) == 0 { return 0 as *SgPlan }
279 let base: i64 = scopy(path, 0, prefix)
280 let tail: i64 = scopy(path, base, domain)
281 let plen: *i64 = sys_mmap(16) as *i64; let rlen: *i64 = sys_mmap(16) as *i64; let mlen: *i64 = sys_mmap(16) as *i64
282 if (plen as i64) <= 0 { return 0 as *SgPlan }; if (rlen as i64) <= 0 { return 0 as *SgPlan }; if (mlen as i64) <= 0 { return 0 as *SgPlan }
283 var end: i64 = scopy(path, tail, ".plan" as *u8); path[end] = 0 as u8
284 let p: *u8 = sys_read_file(path, plen)
285 if (p as i64) == 0 { return 0 as *SgPlan }
286 end = scopy(path, tail, ".rank" as *u8); path[end] = 0 as u8
287 let r: *u8 = sys_read_file(path, rlen)
288 if (r as i64) == 0 { rlen[0] = 0 }
289 end = scopy(path, tail, ".matrix" as *u8); path[end] = 0 as u8
290 let x: *u8 = sys_read_file(path, mlen)
291 if (x as i64) == 0 { mlen[0] = 0 }
292 return sg_parse(p, plen[0], r, rlen[0], x, mlen[0])
293}
294func sg_json(m: *SgPlan, fd: i64) -> i64 {
295 w(fd, ",\"ladder\":{\"v\":1,\"availability\":" as *u8)
296 if (m as i64) == 0 { w(fd, "\"UNAVAILABLE\"}" as *u8); return 0 }
297 w(fd, "\"CAPTURED\"," as *u8); kv_s(fd, "plan_sha256" as *u8, m.plan_sha); wc(fd, 44); kv_n(fd, "plan_bytes" as *u8, m.plan_bytes)
298 wc(fd, 44); kv_s(fd, "matrix_sha256" as *u8, m.matrix_sha); wc(fd, 44); kv_n(fd, "matrix_bytes" as *u8, m.matrix_bytes)
299 wc(fd, 44); kv_s(fd, "rank_sha256" as *u8, m.rank_sha); wc(fd, 44); kv_n(fd, "rank_bytes" as *u8, m.rank_bytes)
300 wc(fd, 44); kv_s(fd, "rank_binding" as *u8, sg_rank_state(m)); wc(fd, 44); kv_n(fd, "rank_declared_nodes" as *u8, m.rank_count)
301 wc(fd, 44); kv_n(fd, "rank_symbol_or_shape_errors" as *u8, m.rank_mismatches)
302 wc(fd, 44); kv_n(fd, "declared_nodes" as *u8, m.declared); wc(fd, 44); kv_n(fd, "parsed_nodes" as *u8, m.count)
303 wc(fd, 44); kv_n(fd, "declared_graph_valid" as *u8, sg_valid(m))
304 wc(fd, 44); kv_n(fd, "malformed" as *u8, m.malformed); wc(fd, 44); kv_n(fd, "duplicate_ids" as *u8, m.duplicate_ids)
305 wc(fd, 44); kv_n(fd, "duplicate_dependencies" as *u8, m.duplicate_edges); wc(fd, 44); kv_n(fd, "missing_dependencies" as *u8, m.missing_deps)
306 wc(fd, 44); kv_n(fd, "cyclic_or_cycle_dependent_nodes" as *u8, m.cyclic_nodes)
307 wc(fd, 44); kv_n(fd, "target_rows" as *u8, m.target_rows); wc(fd, 44); kv_n(fd, "role_rows" as *u8, m.role_rows)
308 wc(fd, 44); kv_n(fd, "unprojected_risk_rows" as *u8, m.risk_rows); wc(fd, 44); kv_n(fd, "worklog_rows" as *u8, m.log_rows)
309 w(fd, ",\"defaults\":{\"implementation\":\"UNKNOWN\",\"verification\":\"UNVERIFIED\",\"eligibility\":\"UNVERIFIED\",\"target_binding\":\"UNVERIFIED\",\"responsible\":null,\"accountable\":null,\"verifier\":null},\"eligible_now\":[],\"eligible_set_complete\":false,\"recommended\":[],\"recommendation_state\":\"WITHHELD\",\"changed_since_supported\":false,\"next_cursor\":null,\"nodes\":[" as *u8)
310 if sg_valid(m) == 1 {
311 var i: i64 = 0
312 while i < m.count {
313 if i > 0 { wc(fd, 44) }; wc(fd, 123)
314 kv_s(fd, "id" as *u8, m.nodes[i*SGP_FIELDS+1] as *u8); wc(fd, 44); kv_s(fd, "title" as *u8, m.nodes[i*SGP_FIELDS+2] as *u8)
315 wc(fd, 44); kv_s(fd, "contract_symbol" as *u8, m.nodes[i*SGP_FIELDS+3] as *u8)
316 wc(fd, 44); kv_s(fd, "acceptance_authored" as *u8, m.nodes[i*SGP_FIELDS+4] as *u8)
317 wc(fd, 44); kv_s(fd, "executor_kind_authored" as *u8, m.nodes[i*SGP_FIELDS+5] as *u8)
318 wc(fd, 44); kv_s(fd, "effort_authored" as *u8, m.nodes[i*SGP_FIELDS+6] as *u8)
319 w(fd, ",\"forecast\":false,\"prerequisites\":[" as *u8)
320 var e: i64 = 0; var shown: i64 = 0
321 while e < m.edge_count {
322 if m.edges[e*2+1] == i { if shown > 0 { wc(fd, 44) }; let from: i64 = m.edges[e*2]; wq(fd); wj(fd, m.nodes[from*SGP_FIELDS+1] as *u8); wq(fd); shown = shown + 1 }
323 e = e + 1
324 }
325 w(fd, "]}" as *u8); i = i + 1
326 }
327 }
328 w(fd, "]}" as *u8); return 0
329}
330// Literal authored fields use the existing text escaper; citation expansion is not needed here.
331func sg_text(fd: i64, s: *u8) -> i64 {
332 let n: i64 = sg_len(s)
333 if n > (SGP_I64_MAX - IA_SEP_AND_NUL) / IA_MAX_EXPANSION - 1 { w(fd, "[text unavailable]" as *u8); return 0 }
334 let cap: i64 = (n + 1) * IA_MAX_EXPANSION + IA_SEP_AND_NUL
335 let out: *u8 = sys_mmap(cap); let cut: *i64 = sys_mmap(8) as *i64
336 if (out as i64) <= 0 { w(fd, "[text unavailable]" as *u8); return 0 }
337 if (cut as i64) <= 0 { w(fd, "[text unavailable]" as *u8); return 0 }
338 let written: i64 = ia_esc_text(out, 0, s, cap, cut)
339 if cut[0] != 0 { w(fd, "[text unavailable]" as *u8); return 0 }
340 w(fd, out); return written
341}
342func sg_html(m: *SgPlan, fd: i64) -> i64 {
343 w(fd, "<section class='ladder-model' aria-label='Declared prerequisite paths'><h2>Inspect a rung and its prerequisites</h2>" as *u8)
344 if (m as i64) == 0 { w(fd, "<p>Plan unavailable; no path or eligibility can be established.</p></section>" as *u8); return 0 }
345 w(fd, "<p>Declared nodes " as *u8); wn(fd, m.declared); w(fd, ". Rank input binding: <b>" as *u8); w(fd, sg_rank_state(m))
346 w(fd, "</b>. Dependency order is authored. Implementation, acceptance evidence, authority and resource readiness are unverified. No action is recommended or dispatched here.</p><p>Plan SHA-256 <code>" as *u8); w(fd, m.plan_sha); w(fd, "</code>. Target rows " as *u8); wn(fd, m.target_rows)
347 w(fd, "; role rows " as *u8); wn(fd, m.role_rows); w(fd, ". Existing risks and release worklog retain their own scope; no node completion is inferred.</p>" as *u8)
348 if sg_valid(m) == 0 {
349 w(fd, "<p><b>Invalid declared graph.</b> Malformed rows or IDs " as *u8); wn(fd, m.malformed); w(fd, "; duplicate IDs " as *u8); wn(fd, m.duplicate_ids)
350 w(fd, "; duplicate prerequisites " as *u8); wn(fd, m.duplicate_edges); w(fd, "; missing prerequisites " as *u8); wn(fd, m.missing_deps)
351 w(fd, "; cyclic or cycle-dependent nodes " as *u8); wn(fd, m.cyclic_nodes); w(fd, ". Node paths withheld.</p></section>" as *u8); return 0
352 }
353 w(fd, "<p>Use Enter or Space on a rung to inspect its contract. Prerequisite links locate another rung in this list; open its summary to inspect it. Estimates are authored effort, not forecasts.</p><ol class='ladder-nodes'>" as *u8)
354 var i: i64 = 0
355 while i < m.count {
356 let id: *u8 = m.nodes[i*SGP_FIELDS+1] as *u8
357 w(fd, "<li><details id='ladder-node-" as *u8); w(fd, id); w(fd, "'><summary>" as *u8); w(fd, id); w(fd, " — " as *u8); sg_text(fd, m.nodes[i*SGP_FIELDS+2] as *u8)
358 w(fd, "</summary><p><b>Prerequisites:</b> " as *u8)
359 var e: i64 = 0; var shown: i64 = 0
360 while e < m.edge_count {
361 if m.edges[e*2+1] == i {
362 let from: i64 = m.edges[e*2]; let dep: *u8 = m.nodes[from*SGP_FIELDS+1] as *u8
363 if shown > 0 { w(fd, ", " as *u8) }; w(fd, "<a href='#ladder-node-" as *u8); w(fd, dep); w(fd, "'>" as *u8); w(fd, dep); w(fd, "</a> (acceptance unverified)" as *u8); shown = shown + 1
364 }; e = e + 1
365 }
366 if shown == 0 { w(fd, "None declared; this does not establish execution eligibility." as *u8) }
367 w(fd, "</p><p><b>Contract:</b> <code>" as *u8); sg_text(fd, m.nodes[i*SGP_FIELDS+3] as *u8); w(fd, "</code></p><p><b>Acceptance:</b> " as *u8); sg_text(fd, m.nodes[i*SGP_FIELDS+4] as *u8)
368 w(fd, "</p><p><b>Authored effort:</b> " as *u8); sg_text(fd, m.nodes[i*SGP_FIELDS+6] as *u8); w(fd, ". <b>Executor kind:</b> " as *u8); sg_text(fd, m.nodes[i*SGP_FIELDS+5] as *u8)
369 w(fd, ". Responsible, accountable and verifier not established. <a href='#worklog'>Inspect retained worklog</a>.</p></details></li>" as *u8); i = i + 1
370 }
371 w(fd, "</ol></section>" as *u8); return 0
372}
373func sg_css(fd: i64) -> i64 {
374 w(fd, ".ladder-model{min-width:0}.ladder-model p{max-width:var(--nx-layout-measure)}.ladder-model code{overflow-wrap:anywhere}.ladder-nodes{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(100%,var(--nx-layout-capmin)),1fr));gap:var(--nx-layout-capgap);padding-inline-start:1.5em}.ladder-nodes li{min-width:0}.ladder-nodes details{display:block}.ladder-nodes summary{display:list-item;cursor:pointer;list-style:revert;font-size:1rem;line-height:1.5}.ladder-nodes summary::after{content:none}.ladder-nodes summary:focus-visible,.ladder-nodes a:focus-visible{outline:3px solid var(--ac);outline-offset:2px}.ladder-nodes details:target{outline:2px solid var(--ac);outline-offset:4px}\n" as *u8)
375 return 0
376}