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}