code wiki / _hdl_build / nx_memorph.nx

nx_memorph.nx source

↩ module page · 241 lines · 10610 B

1// nx_memorph.nx -- emit a CATALOGUE of orphaned memories so unreachable knowledge becomes findable. 2// 3// CONVERTED TO nx_memplane_lib 2026-08-06: the getdents walk, name table, index, bounded read, path 4// join and link scanner were hand-copied into six organs; the copies drifted and the drift WAS the 5// bug (memroot lacked the dump-exclusion its siblings had and reported a false GREEN). This organ now 6// owns only what is specific to it: the description snippet and the catalogue layout. 7// 8// THE PROBLEM, MEASURED 2026-08-06 9// -------------------------------- 10// 2,180 .md files / 25.5 MB. MEMORY.md can name ~35 of them before the measured 25,000 B cliff. 11// 623 files have no path to them from ORIGIN: written, then invisible. Among them are 141 KB scenario 12// blueprints and rubrics that cost real work. 13// 14// A dangling reference points at knowledge that DOES NOT EXIST -- unrecoverable, and "repairing" it 15// would fabricate the doctrine it cites. An orphan IS the knowledge, with no path to it. 16// ★ WHEN THE ARTEFACT SURVIVES AND ONLY THE PATH IS MISSING, BUILD THE PATH. 17// 18// ⚠ THE METRIC MUST NOT MEASURE THE INSTRUMENT. Once this catalogue exists it cites every orphan, so 19// a naive inbound count would read ZERO forever and the problem would look solved while nothing 20// changed. nx_memhealth excludes it from BOTH the link scan and the orphan count; the exclusion list 21// now lives in mp_is_dump so the next organ cannot forget it. 22// 23// DERIVED, NEVER AUTHORED: regenerated wholly on each run; hand edits are lost by design. 24// 25// usage: nx_memorph [--dir <memdir>] [--apply] 26// exit: 0 = written (or dry run); 1 = refused 27// Sovereign: imports nx_memplane_lib. license_tier: ORIGINAL 28import "nx_memplane_lib.nx" 29 30const MO_DIR: *u8 = "/mnt/c/Users/elder/.claude/projects/C--Users-elder/memory" 31const MO_OUT: *u8 = "reference-orphan-catalogue.md" 32const MO_FBUF: i64 = 1048576 33const MO_OBUF: i64 = 4194304 34const MO_MSG: i64 = 8192 35const MO_DESC: i64 = 150 36 37// pull a one-line summary: the frontmatter `description:` if present, else the first line of prose. 38// Quotes and newlines are stripped so a row can never break the catalogue's own markdown. 39func mo_desc(buf: *u8, n: i64, out: *u8) -> i64 { 40 var s: i64 = 0 - 1 41 var i: i64 = 0 42 let pat: *u8 = "description:" as *u8 43 let pl: i64 = mp_len(pat) 44 while i + pl < n { 45 var j: i64 = 0 46 var okm: i64 = 1 47 while j < pl { if buf[i + j] != pat[j] { okm = 0; j = pl } else { j = j + 1 } } 48 if okm == 1 { s = i + pl; i = n } else { i = i + 1 } 49 } 50 if s < 0 { 51 var k: i64 = 0 52 var lines: i64 = 0 53 while k < n { 54 if buf[k] == (10 as u8) { 55 lines = lines + 1 56 if lines >= 1 { 57 let p2: i64 = k + 1 58 if p2 < n { 59 if buf[p2] != (45 as u8) { if buf[p2] != (35 as u8) { if buf[p2] != (10 as u8) { s = p2; k = n } } } 60 } 61 } 62 } 63 k = k + 1 64 } 65 } 66 if s < 0 { out[0] = 0 as u8; return 0 } 67 var o: i64 = 0 68 var p: i64 = s 69 while p < n { 70 if o >= MO_DESC { p = n } else { 71 let c: u8 = buf[p] 72 if c == (10 as u8) { p = n } else { 73 var skip: i64 = 0 74 if c == (34 as u8) { skip = 1 } 75 if c == (13 as u8) { skip = 1 } 76 if c == (124 as u8) { skip = 1 } 77 if o == 0 { if c == (32 as u8) { skip = 1 } } 78 if skip == 0 { out[o] = c; o = o + 1 } 79 p = p + 1 80 } 81 } 82 } 83 out[o] = 0 as u8 84 return o 85} 86 87func main(argc: i64, argv: *i64) -> i64 { 88 var dir: *u8 = MO_DIR 89 var apply: i64 = 0 90 var ai: i64 = 1 91 while ai < argc { 92 let a: *u8 = argv[ai] as *u8 93 if mp_streq(a, "--apply" as *u8) == 1 { apply = 1 } 94 if mp_streq(a, "--dir" as *u8) == 1 { if ai + 1 < argc { dir = argv[ai + 1] as *u8; ai = ai + 1 } } 95 ai = ai + 1 96 } 97 98 let msg: *u8 = sys_mmap(MO_MSG) 99 let names: *u8 = sys_mmap(MP_MAXF * MP_SLOT) 100 let tbl: *i64 = sys_mmap(8 * MP_HASH) as *i64 101 let inref: *i64 = sys_mmap(8 * MP_MAXF) as *i64 102 let fbuf: *u8 = sys_mmap(MO_FBUF) 103 let obuf: *u8 = sys_mmap(MO_OBUF) 104 let path: *u8 = sys_mmap(4096) 105 let probe: *u8 = sys_mmap(1024) 106 let dbuf: *u8 = sys_mmap(1024) 107 let out: *i64 = sys_mmap(64) as *i64 108 109 let cnt: i64 = mp_scan(dir, names, tbl, MP_MAXF) 110 if cnt < 0 { 111 var e: i64 = mp_cat(msg, 0, "nx_memorph: REFUSED -- cannot open the memory dir.\n" as *u8) 112 mp_say(msg, e) 113 return 1 114 } 115 var i: i64 = 0 116 while i < cnt { inref[i] = 0; i = i + 1 } 117 118 // count inbound links, SKIPPING this catalogue so it cannot silence the metric that justifies it 119 var f: i64 = 0 120 while f < cnt { 121 let fname: *u8 = mp_nameptr(names, f) 122 // ⚠ SKIP EVERY DUMP, NOT JUST THIS ORGAN'S OWN OUTPUT. 123 // Measured the moment this organ was converted: reference-memory-lineage.md (283 KB, emitted 124 // by nx_memroot) lists every FLOATING node as a link, so counting its citations collapsed the 125 // orphan count from 581 to 1 -- and the 16-tooth gate passed, because its fixtures were too 126 // small to contain a dump of that shape. 127 // ★★★★★★ A SECOND DERIVED ARTEFACT SILENCED THE METRIC THE FIRST ONE WAS ALREADY GUARDED 128 // AGAINST. Guarding against the dump you know about is not guarding against dumps. 129 if mp_is_dump(fname) == 0 { 130 mp_join(path, dir, fname) 131 var total: i64 = mp_readf(path, fbuf, MO_FBUF) 132 // ASK THE FILE, don't consult a list: a generated artefact declares itself, so a NEW 133 // generator cannot silently supply inbound links the way reference-memory-lineage.md did. 134 if mp_is_derived(fbuf, total) == 1 { total = 0 } 135 if total > 0 { 136 var from: i64 = 0 137 var go: i64 = 1 138 while go == 1 { 139 if mp_link_next(fbuf, total, from, out) == 1 { 140 from = out[3] 141 let hit: i64 = mp_resolve(fbuf, out, names, tbl, probe) 142 if hit >= 0 { if hit != f { inref[hit] = inref[hit] + 1 } } 143 } else { go = 0 } 144 } 145 } 146 } 147 f = f + 1 148 } 149 150 // ---- emit the catalogue ---- 151 var o: i64 = 0 152 o = mp_cat(obuf, o, "# Orphan catalogue -- GENERATED by nx_memorph, do not hand-edit\n" as *u8) 153 o = mp_cat(obuf, o, MP_DERIVED_MARK) // self-declare, so no organ needs a name list entry 154 o = mp_cat(obuf, o, "\n\n" as *u8) 155 o = mp_cat(obuf, o, "Every memory below exists on disk and has **zero inbound links** from any other file. It was\nwritten and then became unreachable: nothing in MEMORY.md, and nothing any other memory cites, leads\nhere. MEMORY.md can only name ~35 files before the measured 25,000 B harness cliff, so a catalogue is\nthe only way this knowledge is findable at all.\n\n" as *u8) 156 o = mp_cat(obuf, o, "This is a CATALOGUE, NOT CURATION -- being listed here says a file is findable, not that it is\ncorrect, current, or worth reading. Regenerate with `nx_memorph.elf --apply`.\n\n" as *u8) 157 158 var orph: i64 = 0 159 var bytes: i64 = 0 160 i = 0 161 while i < cnt { 162 let nm2: *u8 = mp_nameptr(names, i) 163 var skip: i64 = 0 164 if inref[i] != 0 { skip = 1 } 165 if mp_is_dump(nm2) == 1 { skip = 1 } // a derived dump is not lost knowledge 166 if mp_streq(nm2, "MEMORY.md" as *u8) == 1 { skip = 1 } 167 // A DERIVED ARTEFACT IS NOT LOST KNOWLEDGE. The first cut only stopped derived files 168 // SUPPLYING links; a self-declared file with a novel name then appeared in the catalogue as 169 // an orphan (2 real orphans reported as 3). Both sides of the question must ask the FILE, not 170 // the name -- excluding it from one and not the other is half a defence. 171 var tl: i64 = 0 172 if skip == 0 { 173 mp_join(path, dir, nm2) 174 tl = mp_readf(path, fbuf, MO_FBUF) 175 if mp_is_derived(fbuf, tl) == 1 { skip = 1 } 176 } 177 if skip == 0 { 178 if tl > 0 { bytes = bytes + tl } 179 mo_desc(fbuf, tl, dbuf) 180 o = mp_cat(obuf, o, "- [" as *u8) 181 o = mp_cat(obuf, o, nm2) 182 o = mp_cat(obuf, o, "](" as *u8) 183 o = mp_cat(obuf, o, nm2) 184 o = mp_cat(obuf, o, ") " as *u8) 185 o = mp_catn(obuf, o, tl / 1024) 186 o = mp_cat(obuf, o, " KB" as *u8) 187 if dbuf[0] != (0 as u8) { 188 o = mp_cat(obuf, o, " -- " as *u8) 189 o = mp_cat(obuf, o, dbuf) 190 } 191 o = mp_cat(obuf, o, "\n" as *u8) 192 orph = orph + 1 193 } 194 i = i + 1 195 } 196 o = mp_cat(obuf, o, "\nTOTAL orphaned memories: " as *u8) 197 o = mp_catn(obuf, o, orph) 198 o = mp_cat(obuf, o, " (" as *u8) 199 o = mp_catn(obuf, o, bytes / 1024) 200 o = mp_cat(obuf, o, " KB of written work with no path to it)\n" as *u8) 201 202 if apply == 1 { 203 mp_join(path, dir, MO_OUT) 204 let tmp: *u8 = ((path as i64) + 2048) as *u8 205 var t2: i64 = mp_cat(tmp, 0, path) 206 t2 = mp_cat(tmp, t2, ".motmp" as *u8) 207 tmp[t2] = 0 as u8 208 let wfd: i64 = sys_openat_wr(tmp, 420) 209 if wfd < 0 { 210 var e2: i64 = mp_cat(msg, 0, "nx_memorph: REFUSED -- cannot open the temp file.\n" as *u8) 211 mp_say(msg, e2) 212 return 1 213 } 214 let wrote: i64 = mp_write_all(wfd, obuf, o) 215 sys_close(wfd) 216 if wrote != o { 217 var e3: i64 = mp_cat(msg, 0, "nx_memorph: REFUSED -- short write; catalogue not installed.\n" as *u8) 218 mp_say(msg, e3) 219 return 1 220 } 221 if sys_renameat(tmp, path) != 0 { 222 var e4: i64 = mp_cat(msg, 0, "nx_memorph: REFUSED -- atomic rename failed.\n" as *u8) 223 mp_say(msg, e4) 224 return 1 225 } 226 } 227 228 var m: i64 = mp_cat(msg, 0, "nx_memorph: " as *u8) 229 m = mp_catn(msg, m, orph) 230 m = mp_cat(msg, m, " orphaned memories (" as *u8) 231 m = mp_catn(msg, m, bytes / 1024) 232 m = mp_cat(msg, m, " KB) catalogued into " as *u8) 233 m = mp_cat(msg, m, MO_OUT) 234 m = mp_cat(msg, m, ", " as *u8) 235 m = mp_catn(msg, m, o / 1024) 236 m = mp_cat(msg, m, " KB" as *u8) 237 if apply == 0 { m = mp_cat(msg, m, " (DRY RUN -- nothing written; pass --apply)" as *u8) } 238 m = mp_cat(msg, m, ".\n" as *u8) 239 mp_say(msg, m) 240 return 0 241}