CARVE ANSWER (V6) - the '.' is the DEABF-RESOLVED name; B003DCE2 splits on '.', it never adds one¶
Answers the B003DCE2 canonicalizer follow-up (relayed 2026-07-18). Builds on
CARVE-ANSWER-LINKER-LOAD-ERROR52-V5.md.
Binary: D:\ND\500\nd-linker\linker-b01.dom.asm. All addresses ND-500 VAs (hex).
Tags: [V] = read from these disasm bytes; [I] = inferred; [OPEN] = not proven.
TL;DR¶
Your instinct "B003DCE2 appends a default that contains a ." is not how it works. B003DCE2
splits its input on . (0x2E); it never inserts one [V]. And b.0xBC is not a default-type
source - it is a scratch descriptor assembled from the input pointer [V]. The . that makes
parse-stage 4 has to be already present in the name B003DCE2 is handed - and the only thing in
this pipeline that turns B:NRF into a dot-form is DEABF's own resolution (your point: DEABF
resolves B:NRF -> B.NRF - that resolved string HAS the dot). So the real-HW . is the
DEABF-resolved on-disk name, and your bug is that the descriptor reaching B0040C3C is the raw
editor-line window {0xB0048FEC,5,9} = "B:NRF" instead of the resolved B.NRF.
Also: point 5 is incomplete - B003DCE2 is NOT MON-free. It calls the same dispatcher B004D4F4
(the DEABF one) at B003DDCD (selector 0x28) and B003DDEE (0x23). Those are the file-system
resolution calls whose emulation you need to check. [V that the calls exist; selector decode [I].]
1. B003DCE2 contract - byte for byte [V]¶
Entry B003DCE2 ents $0x104; clears working cells; copies the input descriptor and validates chars:
B003DCFA w bmove b.0x14,r.0x14,$0x3 ; input descriptor {ptr=b.0x14, lo=b.0x18, hi=b.0x1C}
B003DCFF call B0040711 ; pure char validator (your point 5: no MON here - correct)
B003DD06 w test r1 ; if = go +8 ; r1!=0 -> error 0x2F return (B003DD0A-0F)
.-splitter:
B003DD26 by1 := $0x2E ; '.'
B003DD2B by comp2 @b.0x14+,r1 ; scan input for '.'
B003DD2F if = go +8 -> B003DD37 ; FOUND '.'
B003DD31 d loopi b.0x40,b.0xB8 ; keep scanning
B003DD35 go +0x2E -> B003DD63 ; NOT FOUND
. found (B003DD37-DD61): builds two descriptors - b.0x78 = the part BEFORE the dot,
b.0x84 = the dot and after. The b.0xBC you saw is the scratch used to assemble these:
B003DD3F w3:=b.0x14 =: b.0xBC then B003DD43 by bmove b.0xBC,b.0x78,$0xC; and again
B003DD52 w1:=b.0x14 =: b.0xBC / B003DD56 bmove b.0xBC,b.0x84. So b.0xBC = the input pointer
b.0x14, reused as a build register - NOT a persistent default-type cell. [V, lines 73873-73885]
- . NOT found (B003DD63-68): b.0x78 := {0,0,0} (empty), b.0x84 := the whole input
descriptor. [V, lines 73887-73888]
Net: B003DCE2 never manufactures a .. It only partitions an existing . into name/type halves.
With no . in its input, it carries the input through unchanged (as b.0x84). So a colon-only
B:NRF stays dot-less through B003DCE2. [V]
2. Point 5 correction - B003DCE2 DOES call the dispatcher [V]¶
After the split/quote handling, B003DCE2 reaches a dispatcher block:
B003DDBD w move $0x28,b.0xCC ; selector 0x28
B003DDC3 by bmove b.0x14,b.0xBC ; name descriptor
B003DDC8 by bmove b.0x20,b.0xD4 ; second descriptor (b.0x20 = raw line 0xB0048FEC)
B003DDCD call B004D4F4,$0x9,b.0xCC,... ; SAME dispatcher that runs DEABF
B003DDE2 if -k go +8
B003DDEE call B004D4F4,$0x2,b.0xCC(=0x23) ; second op
B004D4F4 is exactly the dispatcher your break identified as DEABF at
B0040D5C (there the selector b.0xD8 = 0xAE). Here the selectors are 0x28 and 0x23. By the
same hex=decimal-MON pattern that gave 0xAE = 174 = 256B, 0x28 = 40 = 50B (OPEN) and
0x23 = 35 = 43B - [I], confirm by breaking at B003DDCD and reading b.0xCC + B004D4F4's actual
target. The point that matters: there IS file-system resolution inside B003DCE2's path, via the
dispatcher - your "no mis-emulated MON in the canonicalizer" conclusion skipped it. [V for the
calls existing.]
3. The three buffers - which pass errors [V math + I attribution]¶
0xB0035CEC"File name:NRF" with window hi = b.0x1C = 8 -> indices [0,8] = "File name" (the 9 chars 'F','i','l','e',' ','n','a','m','e'). That is the PROMPT LABEL, not the argument. The pass you broke on (instr 190891) is B003DCE2 processing the prompt template, notB:NRF. [V - the window arithmetic; "File name:NRF" = prompt "File name" + default type ":NRF" is [I].]0xB0048FEC"LOAD B:NRF" = the raw editor line.{0xB0048FEC,5,9}= "B:NRF" = the window that reaches the error-52 B0040C3C.
So there are multiple B003DCE2 passes; the one that errors is a LATER pass whose input is the
raw-line window B:NRF, not the prompt pass you caught. You must trace the pass whose B003DCE2
OUTPUT is {0xB0048FEC,5,9} and see what its dispatcher call (section 2) returned. [I - needs your
multi-pass trace.]
4. Q (net): what puts a '.' in B0040C3C's input on real HW [I, well-supported]¶
Chain of byte facts:
1. B0040C3C's parse-stage 4 requires a literal . in its input descriptor. [V, V5]
2. B003DCE2 never adds a .; it only splits on one. [V, section 1]
3. DEABF (the dispatcher op) RESOLVES B:NRF -> B.NRF - a dot-form on-disk name (your own
observation). [your live data]
Therefore the real-HW . is the DEABF-resolved name, and the correct data flow is: the
resolution op inside B003DCE2 (section 2) returns a descriptor pointing at the resolved B.NRF,
which B003DCE2 hands on as its output, so B0040C3C parses B.NRF (dot -> stage 4 -> pass) and then
the downstream MON 50B OPEN (B004CABC/B004E874) runs. On your emulator, the resolution op is not
propagating the resolved dot-form - B003DCE2 falls through to carrying the raw colon window
B:NRF, so B0040C3C sees no . -> error 52. The fix is in what the B003DCE2 dispatcher call
returns, not a default-append and not b.0x49. [I - coherent with every byte above; the exact
output-descriptor propagation is what your trace must confirm.]
5. Probes (give me these back and I can close it)¶
- Break at
B003DDCDin the erroring round (the pass whose input window isB:NRF, not the prompt pass). Dumpb.0xCC(selector), the name descriptorb.0xBC{ptr,lo,hi}+bytes BEFORE the call, and AFTER the call dumpb.0xBC/0xC0/0xC4/0xD4/0xD8/0xDC. Does any returned descriptor point at a dot-formB.NRF? That is the resolved name that must flow out. - Dump B003DCE2's OUTPUT descriptor (
r.0x14at itsret, = callerb.0x20) for that same pass - is it the resolvedB.NRFor the raw{0xB0048FEC,5,9}? - Trace every B003DCE2 + B0040C3C call in one LOAD round with input+output descriptors; find the
pass whose B0040C3C input is
{0xB0048FEC,5,9}and walk back to that B003DCE2's dispatcher result. - If
B003DDCD's op is yourMON 50B OPEN(selector 0x28), verify the emulated OPEN returns SINTRAN's canonical/expanded name descriptor (dot-form), not an echo of the raw colon input - that is the most likely emulator divergence.
Evidence register (linker-b01.dom.asm, PSEG VAs)¶
- B003DCE2 prologue + validator
B003DCE8-B003DD0F;.-scanB003DD26-B003DD35(04 CD 2E / 2D E5 14 D0 / C4 08 / BF 50 6E F5 / C0 2E). - split-found build
B003DD37-B003DD61; b.0xBC scratchB003DD3F/B003DD52. - no-
.pathB003DD63-B003DD68(FE 79 00 5E 03 / FE 79 45 61 03). - dispatcher calls
B003DDBD-B003DDF8(1A CD 28 73 ... C3 B0 04 D4 F4 09 ...and1A CD 23 73). - (from V5) gate
B0040D7Dcomp2 b.0x49,$4; '.'->4B0040CC1; downstream OPENB004CABC/B004E874.