nx_sizeguard.nx source
↩ module page · 131 lines · 5861 B
1// nx_sizeguard.nx -- FAIL LOUD BEFORE A READER SILENTLY TRUNCATES (seq1469 root fix #1).
2//
3// THE CLASS: MEMORY.md is read by a loader that takes the first ~200 lines / ~25KB and DROPS THE REST
4// SILENTLY, TAIL-FIRST. No error, no marker, no count -- so the dropped lines are precisely the ones you
5// would need in order to learn they were dropped. That is the partial-as-complete defect this ecosystem
6// has banned repeatedly (L011 scancap, seq646, nx_debt truncation), sitting in the BOOT PATH.
7//
8// AND IT IS NOT ONE FILE. Append-only artefacts grow forever by design: knowledge/status/*.jrnl,
9// law_warden.jrnl, and -- MY OWN DEBT FROM THIS SESSION -- procchurn.jrnl and adopt_census.txt, both of
10// which I created with no size discipline while filing debt about exactly this.
11// LAW: AN APPEND-ONLY FILE WITH NO SIZE DISCIPLINE IS A FUTURE SILENT TRUNCATION.
12//
13// THE FIX IS A REFUSAL, NOT A REMINDER. Compaction is a workaround every session must repeat forever on
14// files that grow by design; a guard converts an invisible cliff into a loud verdict BEFORE it is crossed.
15// Lives in runtime/ (the PRIMITIVE layer) so any organ can reach it -- seq1450: build the primitive in the
16// layer its consumers can reach; imports nothing above its own layer.
17// argv: <path> <byte-cliff> <line-cliff> [amber-permil]
18// exit 0=GREEN 1=AMBER 2=RED(over cliff) 3=UNMEASURED. license_tier: ORIGINAL No hw writes (Rule 26).
19import "nx_syscalls.nx"
20
21const SG_READBUF: i64 = 65536
22const SG_PERMIL: i64 = 1000
23const SG_DEF_AMBER: i64 = 800
24const SG_NL: i64 = 10
25const SG_GREEN: i64 = 0
26const SG_AMBER: i64 = 1
27const SG_RED: i64 = 2
28const SG_UNMEASURED: i64 = 3
29
30// fill of a budget, in permil. -1 when the cliff is nonsense (never divide by it).
31func sg_fill_permil(cur: i64, cliff: i64) -> i64 {
32 if cliff <= 0 { return 0 - 1 }
33 if cur < 0 { return 0 - 1 }
34 return (cur * SG_PERMIL) / cliff
35}
36
37// Verdict over BOTH axes. A tail-first loader truncates on WHICHEVER limit is hit first, so a guard that
38// watches only bytes is blind to a line-count cliff and vice-versa -- the worst axis decides.
39// FAIL-CLOSED: an unmeasurable axis returns UNMEASURED rather than a comfortable GREEN.
40func sg_verdict(bytes: i64, lines: i64, byte_cliff: i64, line_cliff: i64, amber_permil: i64) -> i64 {
41 if amber_permil <= 0 { return SG_UNMEASURED }
42 let bf: i64 = sg_fill_permil(bytes, byte_cliff)
43 let lf: i64 = sg_fill_permil(lines, line_cliff)
44 if bf < 0 { return SG_UNMEASURED }
45 if lf < 0 { return SG_UNMEASURED }
46 var sev: i64 = SG_GREEN
47 if bf >= amber_permil { sev = SG_AMBER }
48 if lf >= amber_permil { sev = SG_AMBER }
49 if bf >= SG_PERMIL { sev = SG_RED }
50 if lf >= SG_PERMIL { sev = SG_RED }
51 return sev
52}
53
54// how many bytes may still be appended before the byte cliff; 0 once past it (never negative)
55func sg_headroom(cur: i64, cliff: i64) -> i64 {
56 if cliff <= 0 { return 0 - 1 }
57 if cur >= cliff { return 0 }
58 return cliff - cur
59}
60
61func sg_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
62func sg_num(v: i64) -> i64 {
63 let t: *u8 = sys_mmap(32)
64 let b: *u8 = sys_mmap(32)
65 var m: i64 = v
66 var p: i64 = 0
67 if m < 0 { b[p] = 45 as u8; p = p + 1; m = 0 - m }
68 var k: i64 = 0
69 if m == 0 { t[0] = 48 as u8; k = 1 }
70 while m > 0 { t[k] = (48 + (m - (m / 10) * 10)) as u8; m = m / 10; k = k + 1 }
71 var i: i64 = 0
72 while i < k { b[p + i] = t[k - 1 - i]; i = i + 1 }
73 sys_write(1, b, p + k)
74 sys_munmap(t, 32)
75 sys_munmap(b, 32)
76 return 0
77}
78func sg_atoi(s: *u8) -> i64 {
79 var v: i64 = 0
80 var i: i64 = 0
81 while s[i] != (0 as u8) {
82 let c: i64 = s[i] as i64
83 if c < 48 { return 0 - 1 }
84 if c > 57 { return 0 - 1 }
85 v = v * 10 + (c - 48)
86 i = i + 1
87 }
88 if i == 0 { return 0 - 1 }
89 return v
90}
91
92func main(argc: i64, argv: *i64) -> i64 {
93 if argc < 4 { sg_puts("usage: nx_sizeguard <path> <byte-cliff> <line-cliff> [amber-permil]\n" as *u8); return SG_UNMEASURED }
94 let path: *u8 = argv[1] as *u8
95 let bcliff: i64 = sg_atoi(argv[2] as *u8)
96 let lcliff: i64 = sg_atoi(argv[3] as *u8)
97 var amber: i64 = SG_DEF_AMBER
98 if argc >= 5 { let a: i64 = sg_atoi(argv[4] as *u8); if a > 0 { amber = a } }
99
100 let fd: i64 = sys_openat_rd(path)
101 if fd < 0 { sg_puts("NX-SIZEGUARD verdict=UNMEASURED why=unreadable path=" as *u8); sg_puts(path); sg_puts("\n" as *u8); return SG_UNMEASURED }
102 let buf: *u8 = sys_mmap(SG_READBUF)
103 var bytes: i64 = 0
104 var lines: i64 = 0
105 var r: i64 = sys_read(fd, buf, SG_READBUF)
106 while r > 0 {
107 bytes = bytes + r
108 var i: i64 = 0
109 while i < r { if buf[i] == (SG_NL as u8) { lines = lines + 1 } i = i + 1 }
110 r = sys_read(fd, buf, SG_READBUF)
111 }
112 sys_close(fd)
113 sys_munmap(buf, SG_READBUF)
114
115 let sev: i64 = sg_verdict(bytes, lines, bcliff, lcliff, amber)
116 sg_puts("NX-SIZEGUARD path=" as *u8); sg_puts(path)
117 sg_puts(" bytes=" as *u8); sg_num(bytes)
118 sg_puts("/" as *u8); sg_num(bcliff)
119 sg_puts(" (" as *u8); sg_num(sg_fill_permil(bytes, bcliff)); sg_puts("permil)" as *u8)
120 sg_puts(" lines=" as *u8); sg_num(lines)
121 sg_puts("/" as *u8); sg_num(lcliff)
122 sg_puts(" (" as *u8); sg_num(sg_fill_permil(lines, lcliff)); sg_puts("permil)" as *u8)
123 sg_puts(" headroom_bytes=" as *u8); sg_num(sg_headroom(bytes, bcliff))
124 sg_puts(" verdict=" as *u8)
125 if sev == SG_GREEN { sg_puts("GREEN" as *u8) }
126 if sev == SG_AMBER { sg_puts("AMBER -- compact BEFORE the reader starts dropping the tail" as *u8) }
127 if sev == SG_RED { sg_puts("RED -- PAST THE CLIFF: a reader is ALREADY dropping content SILENTLY" as *u8) }
128 if sev == SG_UNMEASURED { sg_puts("UNMEASURED" as *u8) }
129 sg_puts(" sev=" as *u8); sg_num(sev); sg_puts("\n" as *u8)
130 return sev
131}