code wiki / _hdl_build / nx_pipeline_spine.nx
nx_pipeline_spine.nx source
↩ module page · 118 lines · 4903 B
1// nx_pipeline_spine.nx -- R1: the SOVEREIGN PIPELINE SPINE (the missing chain). One seg-store
2// state machine that every stage organ plugs into, so discover->research->spec->build is ONE
3// system, not 23 scattered ones. A work-item advances ONE stage at a time and -- the load-bearing
4// invariant -- CANNOT skip: a capability can never reach BUILT/EXCEEDED without passing RESEARCH
5// and SPEC in order. That mechanically forbids fabricated completion (the discipline the scattered
6// organs lacked: any of them could just claim done). Reuses the proven ws_put_p/ws_get_p/ws_field
7// (idempotent, atomic commit) under a dedicated prefix -- NO TSV, sovereign. license_tier: ORIGINAL
8import "nx_workstream_store.nx"
9import "nx_seg_store.nx"
10import "nx_framed_append.nx"
11import "nx_syscalls.nx"
12const PL_MAGIC_1024: i64 = 1024
13
14const PL_PREFIX: *u8 = "knowledge/store/pl-"
15// ordered stages (data-driven, no magic numbers buried at call sites)
16const PL_DISCOVERED: i64 = 1
17const PL_RESEARCHED: i64 = 2
18const PL_SPECED: i64 = 3
19const PL_BUILT: i64 = 4
20const PL_EXCEEDED: i64 = 5
21
22func pl_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
23
24// parse the first `n` bytes of `s` as a non-negative decimal.
25func pl_atoi(s: *u8, n: i64) -> i64 {
26 var v: i64 = 0
27 var i: i64 = 0
28 while i < n {
29 if s[i] >= (48 as u8) { if s[i] <= (57 as u8) { v = v * 10 + ((s[i] as i64) - 48) } }
30 i = i + 1
31 }
32 return v
33}
34
35// "pl:" + id -> out (NUL-term). returns length.
36func pl_build_key(id: *u8, out: *u8) -> i64 {
37 out[0] = 112 as u8 // 'p'
38 out[1] = 108 as u8 // 'l'
39 out[2] = 58 as u8 // ':'
40 var t: i64 = 0
41 while id[t] != (0 as u8) { out[3 + t] = id[t]; t = t + 1 }
42 out[3 + t] = 0 as u8
43 return 3 + t
44}
45
46// build the 5-field record: id \t stage \t gap \t artifact \t ts (NUL-term). returns length.
47func pl_build_rec(id: *u8, stage: i64, gap: *u8, artifact: *u8, ts: i64, out: *u8) -> i64 {
48 var o: i64 = 0
49 o = fa_cat(out, o, id)
50 out[o] = 9 as u8; o = o + 1
51 o = fa_catn(out, o, stage)
52 out[o] = 9 as u8; o = o + 1
53 o = fa_cat(out, o, gap)
54 out[o] = 9 as u8; o = o + 1
55 o = fa_cat(out, o, artifact)
56 out[o] = 9 as u8; o = o + 1
57 o = fa_catn(out, o, ts)
58 out[o] = 0 as u8
59 return o
60}
61
62// current stage of `id` under `prefix`: 0 = never seeded (the honest UNKNOWN), else 1..5.
63func pl_stage_p(prefix: *u8, id: *u8) -> i64 {
64 let key: *u8 = sys_mmap(256)
65 pl_build_key(id, key)
66 let pq: *i64 = sys_mmap(16) as *i64
67 let lq: *i64 = sys_mmap(16) as *i64
68 if ws_get_p(prefix, key, pq, lq) != 1 { return 0 }
69 let fld: *u8 = sys_mmap(64)
70 let fl: i64 = ws_field(pq[0] as *u8, lq[0], 1, fld)
71 return pl_atoi(fld, fl)
72}
73
74// read field `f` of `id`'s record into out (for gap preservation across advances). returns len, -1 absent.
75func pl_field_p(prefix: *u8, id: *u8, f: i64, out: *u8) -> i64 {
76 let key: *u8 = sys_mmap(256)
77 pl_build_key(id, key)
78 let pq: *i64 = sys_mmap(16) as *i64
79 let lq: *i64 = sys_mmap(16) as *i64
80 if ws_get_p(prefix, key, pq, lq) != 1 { out[0] = 0 as u8; return 0 - 1 }
81 return ws_field(pq[0] as *u8, lq[0], f, out)
82}
83
84// seed a work-item at DISCOVERED (idempotent: if already present, returns its current stage).
85func pl_seed_p(prefix: *u8, id: *u8, gap: *u8) -> i64 {
86 let cur: i64 = pl_stage_p(prefix, id)
87 if cur > 0 { return cur }
88 let key: *u8 = sys_mmap(256)
89 pl_build_key(id, key)
90 let rec: *u8 = sys_mmap(PL_MAGIC_1024)
91 pl_build_rec(id, PL_DISCOVERED, gap, "-" as *u8, sys_now_realtime_sec(), rec)
92 ws_put_p(prefix, key, rec)
93 return PL_DISCOVERED
94}
95
96// THE INVARIANT: advance `id` from exactly `expect_from` to `expect_from`+1, attaching `artifact`.
97// Returns the new stage, or -1 if the item is NOT at `expect_from` (refuses skips / out-of-order /
98// re-advance) or is already at EXCEEDED. This is what forbids fabricated completion.
99func pl_advance_p(prefix: *u8, id: *u8, expect_from: i64, artifact: *u8) -> i64 {
100 let cur: i64 = pl_stage_p(prefix, id)
101 if cur != expect_from { return 0 - 1 }
102 if cur >= PL_EXCEEDED { return 0 - 1 }
103 let gap: *u8 = sys_mmap(512)
104 pl_field_p(prefix, id, 2, gap) // preserve the original gap desc
105 let key: *u8 = sys_mmap(256)
106 pl_build_key(id, key)
107 let rec: *u8 = sys_mmap(PL_MAGIC_1024)
108 pl_build_rec(id, cur + 1, gap, artifact, sys_now_realtime_sec(), rec)
109 ws_put_p(prefix, key, rec)
110 return cur + 1
111}
112
113// production-prefix conveniences.
114func pl_seed(id: *u8, gap: *u8) -> i64 { return pl_seed_p(PL_PREFIX, id, gap) }
115func pl_advance(id: *u8, expect_from: i64, artifact: *u8) -> i64 { return pl_advance_p(PL_PREFIX, id, expect_from, artifact) }
116func pl_stage(id: *u8) -> i64 { return pl_stage_p(PL_PREFIX, id) }
117
118// pure LIB (no main) so the gate + the future nx_pipeline_run driver import it.