code wiki / _hdl_build / nx_wflow_approve_gate.nx

nx_wflow_approve_gate.nx source

↩ module page · 116 lines · 5925 B

1// nx_wflow_approve_gate.nx -- R4 HUMAN-IN-THE-LOOP approvals gate. An `approve` step PARKS the run 2// (status=WAIT, in-flight -- neither DONE nor FAILED) until an operator decision record lands on the 3// SAME event-sourced ledger (WFDEC ... decision=APPROVED|DENIED by=<who>); wf_resume then completes or 4// fail-stops it. DENY WINS (fail-safe). Proves: parked run gates later steps; resume WITHOUT a decision 5// never fabricates approval; APPROVED unlocks exactly once (no re-exec of OK steps); DENIED fail-stops; 6// bad decision word refused; a decision for the WRONG step does NOT unlock. ZERO forks. 7// license_tier: ORIGINAL expect_exit: 0 8import "nx_wflow_engine.nx" 9 10func ag_n(led: *u8, ridtok: *u8, st: *u8) -> i64 { 11 let szp: *i64 = sys_mmap(8) as *i64 12 let b: *u8 = wf_readall(led, szp) 13 if (b as i64) == 0 { return 0 - 1 } 14 return wf_lines_with2(b, szp[0], ridtok, st) 15} 16 17func main() -> i64 { 18 p("=== NX-WFLOW-APPROVE GATE (R4: approve step parks the run until an operator decision; deny wins) ===\n" as *u8) 19 var ok: i64 = 1 20 let now: i64 = wf_now() 21 let led: *u8 = sys_mmap(128) 22 var lo: i64 = 0 23 lo = wf_cat(led, lo, "/tmp/wfappr_" as *u8) 24 lo = wf_catn(led, lo, now) 25 lo = wf_cat(led, lo, ".log" as *u8) 26 led[lo] = 0 as u8 27 28 let flows: *i64 = sys_mmap(8 * 4) as *i64 29 flows[0] = "fa1|expense|-" as *u8 as i64 30 let steps: *i64 = sys_mmap(8 * 8) as *i64 31 steps[0] = "fa1|1|create-task|-|File the venue request|1" as *u8 as i64 32 steps[1] = "fa1|2|approve|operator|Spend 500 on the pavilion hire|1" as *u8 as i64 33 steps[2] = "fa1|3|notify|-|Approved and booked|1" as *u8 as i64 34 35 let cx: *i64 = sys_mmap(32) as *i64 36 cx[0] = steps as i64 37 cx[1] = 3 38 cx[2] = led as i64 39 cx[3] = 0 40 41 // T0 load validation: approve needs an approver name 42 let l0: i64 = wf_load(steps, 3) 43 let bad: *i64 = sys_mmap(16) as *i64 44 bad[0] = "f9|1|approve|-|x|1" as *u8 as i64 45 let lb: i64 = wf_load(bad, 1) 46 p(" T0 load=" as *u8); pn(l0); p(" badNoApprover=" as *u8); pn(lb); p("\n" as *u8) 47 if l0 != 3 { ok = 0 } 48 if lb != (0 - 1) { ok = 0 } 49 50 // T1 fire -> step1 OK, step2 PARKS (WAIT), step3 gated, run in-flight (no DONE, no FAILED) 51 let r1: i64 = wf_fire(cx, flows, 1, "expense~amount=500~id=A1" as *u8) 52 let w1: i64 = ag_n(led, " rid=A1.fa1 " as *u8, "status=WAIT" as *u8) 53 let d1: i64 = ag_n(led, " rid=A1.fa1 " as *u8, "status=DONE" as *u8) 54 let f1: i64 = ag_n(led, " rid=A1.fa1 " as *u8, "status=FAILED" as *u8) 55 let s3a: i64 = ag_n(led, " rid=A1.fa1 " as *u8, " step=3 " as *u8) 56 p(" T1 parked started=" as *u8); pn(r1); p(" wait=" as *u8); pn(w1); p(" done=" as *u8); pn(d1); p(" failed=" as *u8); pn(f1); p(" step3lines=" as *u8); pn(s3a); p("\n" as *u8) 57 if r1 != 1 { ok = 0 } 58 if w1 != 1 { ok = 0 } 59 if d1 != 0 { ok = 0 } 60 if f1 != 0 { ok = 0 } 61 if s3a != 0 { ok = 0 } 62 63 // T2 resume WITHOUT a decision -> still parked, approval is never fabricated 64 let rs1: i64 = wf_resume(cx) 65 let w2: i64 = ag_n(led, " rid=A1.fa1 " as *u8, "status=WAIT" as *u8) 66 let d2: i64 = ag_n(led, " rid=A1.fa1 " as *u8, "status=DONE" as *u8) 67 let s3b: i64 = ag_n(led, " rid=A1.fa1 " as *u8, " step=3 " as *u8) 68 p(" T2 nofabricate resumed=" as *u8); pn(rs1); p(" wait=" as *u8); pn(w2); p(" done=" as *u8); pn(d2); p(" step3lines=" as *u8); pn(s3b); p("\n" as *u8) 69 if rs1 != 1 { ok = 0 } 70 if w2 != 2 { ok = 0 } 71 if d2 != 0 { ok = 0 } 72 if s3b != 0 { ok = 0 } 73 74 // T3 APPROVED -> resume completes step2 + step3, DONE; step1 never re-executed 75 let dc: i64 = wf_decide(cx, "A1.fa1" as *u8, 2, "APPROVED" as *u8, "operator" as *u8) 76 let rs2: i64 = wf_resume(cx) 77 let d3: i64 = ag_n(led, " rid=A1.fa1 " as *u8, "status=DONE" as *u8) 78 let s1once: i64 = ag_n(led, " rid=A1.fa1 " as *u8, " step=1 status=OK" as *u8) 79 let s3c: i64 = ag_n(led, " rid=A1.fa1 " as *u8, " step=3 status=OK" as *u8) 80 p(" T3 approved deciderc=" as *u8); pn(dc); p(" resumed=" as *u8); pn(rs2); p(" done=" as *u8); pn(d3); p(" step1okOnce=" as *u8); pn(s1once); p(" step3ok=" as *u8); pn(s3c); p("\n" as *u8) 81 if dc != 0 { ok = 0 } 82 if rs2 != 1 { ok = 0 } 83 if d3 != 1 { ok = 0 } 84 if s1once != 1 { ok = 0 } 85 if s3c != 1 { ok = 0 } 86 87 // T4 DENIED path -> run fail-stops at the approval, step3 never runs 88 wf_fire(cx, flows, 1, "expense~amount=9000~id=A2" as *u8) 89 wf_decide(cx, "A2.fa1" as *u8, 2, "DENIED" as *u8, "operator" as *u8) 90 let rs3: i64 = wf_resume(cx) 91 let f4: i64 = ag_n(led, " rid=A2.fa1 " as *u8, "status=FAILED" as *u8) 92 let d4: i64 = ag_n(led, " rid=A2.fa1 " as *u8, "status=DONE" as *u8) 93 let s3d: i64 = ag_n(led, " rid=A2.fa1 " as *u8, " step=3 status=OK" as *u8) 94 p(" T4 denied resumed=" as *u8); pn(rs3); p(" failed=" as *u8); pn(f4); p(" done=" as *u8); pn(d4); p(" step3ok=" as *u8); pn(s3d); p("\n" as *u8) 95 if rs3 != 1 { ok = 0 } 96 if f4 != 1 { ok = 0 } 97 if d4 != 0 { ok = 0 } 98 if s3d != 0 { ok = 0 } 99 100 // T5 negctl precision: bad decision word refused; a decision for the WRONG step does not unlock 101 let db: i64 = wf_decide(cx, "A3.fa1" as *u8, 2, "MAYBE" as *u8, "operator" as *u8) 102 wf_fire(cx, flows, 1, "expense~amount=42~id=A3" as *u8) 103 wf_decide(cx, "A3.fa1" as *u8, 1, "APPROVED" as *u8, "operator" as *u8) 104 let rs4: i64 = wf_resume(cx) 105 let d5: i64 = ag_n(led, " rid=A3.fa1 " as *u8, "status=DONE" as *u8) 106 let w5: i64 = ag_n(led, " rid=A3.fa1 " as *u8, "status=WAIT" as *u8) 107 p(" T5 negctl badword=" as *u8); pn(db); p(" resumed=" as *u8); pn(rs4); p(" done=" as *u8); pn(d5); p(" waits=" as *u8); pn(w5); p("\n" as *u8) 108 if db != (0 - 1) { ok = 0 } 109 if d5 != 0 { ok = 0 } 110 if w5 < 2 { ok = 0 } 111 112 p("NX-WFLOW-APPROVE-GATE ledger=" as *u8); p(led); p(" forks=0 " as *u8) 113 if ok == 1 { p("verdict=GREEN\n" as *u8); return 0 } 114 p("verdict=RED\n" as *u8) 115 return 1 116}