code wiki / _hdl_build / nx_gate_loop_register.nx
nx_gate_loop_register.nx source
↩ module page · 124 lines · 5745 B
1// nx_gate_loop_register.nx -- GOVERNED registration of the gate loop daemon
2// (GAME arc G5). ENGINEER verdict, all mechanical:
3// (a) pidfile names a LIVE pid (/proc/<pid>/comm opens);
4// (b) a second start REFUSES (singleton; exit 3) -- two loops would race
5// the gate's shared /tmp artifacts (observed corrupting verdicts);
6// (c) at least one GATELOOP beat line exists in the loop log.
7// Also flags the __syscall translation-table gap found during the build:
8// rv64 getpid (172) is NOT translated -> x86 received 172=iopl -> -ENOSYS.
9// license_tier: ORIGINAL
10import "nx_cap_register.nx"
11import "nx_pm_review_log.nx"
12import "nx_syscalls.nx"
13
14const GLR_LAYER: i64 = 4
15const GLR_STATUS: i64 = 2
16const GLR_IDX: i64 = 218
17const GLR_NLAYERS: i64 = 6
18
19func glr_run0(path: *u8) -> i64 {
20 let pid: i64 = sys_fork()
21 if pid == 0 {
22 let devnull: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
23 if devnull >= 0 { sys_dup3(devnull, 1, 0) }
24 let argv: *i64 = sys_mmap(32) as *i64; argv[0] = path as i64; argv[1] = 0
25 let envp: *i64 = sys_mmap(16) as *i64; envp[0] = "PATH=/usr/bin:/bin" as *u8 as i64; envp[1] = 0
26 sys_execve(path, argv, envp); sys_exit(127)
27 }
28 let st: *i64 = sys_mmap(16) as *i64
29 sys_wait4(pid, st, 0)
30 let sig: i64 = st[0] & 0x7f
31 if sig != 0 { return 128 + sig }
32 return (st[0] >> 8) & 0xff
33}
34
35func glr_cat(dst: *u8, off: i64, s: *u8) -> i64 { var i: i64 = 0; while s[i] != (0 as u8) { dst[off+i] = s[i]; i = i + 1 } return off + i }
36func glr_cat_n(dst: *u8, off: i64, v: i64) -> i64 {
37 var o: i64 = off
38 var m: i64 = v
39 if m < 0 { dst[o] = 45; o = o + 1; m = 0 - m }
40 let t: *u8 = sys_mmap(28)
41 var k: i64 = 0
42 if m == 0 { t[0] = 48; k = 1 }
43 while m > 0 { t[k] = 48 + (m % 10); m = m / 10; k = k + 1 }
44 var i: i64 = 0
45 while i < k { dst[o+i] = t[k-1-i]; i = i + 1 }
46 return o + k
47}
48
49func glr_read_pidfile() -> i64 {
50 let len_p: *i64 = sys_mmap(8) as *i64
51 let buf: *u8 = sys_read_file("/tmp/nishi_game_gate_loop.pid" as *u8, len_p)
52 if (buf as i64) == 0 { return 0 - 1 }
53 let n: i64 = len_p[0]
54 var v: i64 = 0
55 var any: i64 = 0
56 var i: i64 = 0
57 while i < n {
58 let c: i64 = buf[i] as i64
59 if c >= 48 { if c <= 57 { v = v * 10 + (c - 48); any = 1 } }
60 i = i + 1
61 }
62 if any == 0 { return 0 - 1 }
63 return v
64}
65
66func glr_pid_alive(pid: i64) -> i64 {
67 if pid <= 0 { return 0 }
68 let p: *u8 = sys_mmap(64)
69 var o: i64 = 0
70 o = glr_cat(p, o, "/proc/" as *u8)
71 o = glr_cat_n(p, o, pid)
72 o = glr_cat(p, o, "/comm" as *u8)
73 p[o] = 0 as u8
74 let fd: i64 = sys_openat_rd(p)
75 if fd < 0 { return 0 }
76 sys_close(fd)
77 return 1
78}
79
80func main() -> i64 {
81 // (a) live daemon per pidfile
82 let dpid: i64 = glr_read_pidfile()
83 let alive: i64 = glr_pid_alive(dpid)
84 cr_w(1, "ENGINEER: pidfile pid=" as *u8); cr_wn(1, dpid)
85 cr_w(1, " alive=" as *u8); cr_wn(1, alive); cr_w(1, " (need 1)\n" as *u8)
86
87 // (b) singleton refusal
88 let rc2: i64 = glr_run0("/tmp/nx_gate_loop.sov.elf" as *u8)
89 cr_w(1, "ENGINEER: second-start exit=" as *u8); cr_wn(1, rc2); cr_w(1, " (need 3 = refused)\n" as *u8)
90
91 // (c) beat evidence
92 let len_p: *i64 = sys_mmap(8) as *i64
93 let lbuf: *u8 = sys_read_file("/tmp/nishi_game_gate_loop.log" as *u8, len_p)
94 var beats: i64 = 0
95 if (lbuf as i64) != 0 { if len_p[0] > 0 { beats = 1 } }
96 cr_w(1, "ENGINEER: loop log non-empty=" as *u8); cr_wn(1, beats); cr_w(1, " (need 1)\n" as *u8)
97
98 var exit_ok: i64 = 0
99 if alive == 1 { if rc2 == 3 { if beats == 1 { exit_ok = 1 } } }
100 let eng: i64 = ig_engineer(1, 1, 1, exit_ok)
101
102 let cat: i64 = sys_openat_rd("knowledge/CAPABILITY_CATALOG.md" as *u8)
103 var documented: i64 = 0
104 if cat >= 0 { documented = ig_documented(1, 1); sys_close(cat) }
105 let council: i64 = ig_council(eng, 1, 1, 2)
106 let decision: i64 = ig_decision(eng, council, documented)
107
108 let pm: i64 = pm_open("/tmp/nishi_pm_review.log" as *u8)
109 if decision == IG_INGEST {
110 pm_deliverable(pm, "game-engine/gates" as *u8, "nx_gate_loop" as *u8, "GAME-G5 CLOSED: singleton loop daemon (pidfile+/proc aliveness, fork+setsid detach) runs nx_gate_sentinel every 30min; beats -> /tmp/nishi_game_gate_loop.log; regressions auto-escalate via the sentinel; grades now refresh with NO human/LLM trigger" as *u8)
111 }
112 pm_gap(pm, "toolchain/compiler" as *u8, "NEEDS-FIX" as *u8, "__syscall rv64 translation table incomplete" as *u8, "rv64 getpid(172) is NOT in the rv64->x86 translation table: x86 received raw 172=iopl -> -ENOSYS; a pidfile silently filled with -38 and the loop singleton failed open (two daemons raced the gate). Audit the table for other missing common numbers (getppid/kill/getuid...); meanwhile /proc/self/stat is the table-independent getpid." as *u8)
113 sys_close(pm)
114 cr_w(1, "GOVERNED decision=" as *u8); cr_wn(1, decision); cr_w(1, " (1=INGEST); PM log updated\n" as *u8)
115
116 if decision != IG_INGEST { sys_exit(1) }
117 if cr_can_register(GLR_LAYER, GLR_STATUS, GLR_NLAYERS, decision) != 1 { cr_w(1, "REFUSED\n" as *u8); sys_exit(1) }
118 let fd: i64 = sys_openat_append("/tmp/nishi_cap_registry.log" as *u8, 0x1a4)
119 cr_write_entry(fd, GLR_IDX, GLR_LAYER, "CON GATE-LOOP -- singleton daemon (pidfile + /proc aliveness; fork+setsid; refuses double-start exit 3) running nx_gate_sentinel on a 30-min beat; beats logged to /tmp/nishi_game_gate_loop.log; closes GAME-G5: game-engine grades refresh autonomously, regressions escalate to the PM review log with no LLM in the loop" as *u8, GLR_STATUS)
120 sys_close(fd)
121 cr_w(1, "CAPREG idx=" as *u8); cr_wn(1, GLR_IDX); cr_w(1, " REGISTERED\n" as *u8)
122 sys_exit(0)
123 return 0
124}