Compact debug source paths

Issue #704 implements the first size opportunity from the optimization survey. Repeated source paths now live in a per-module table. DEBUG entries keep all function, block, instruction, UTF-16 range and inline-parent fields; source line/column records are unchanged. Rust shares path ranges in admitted bytes; Kotlin shares pooled text objects. Small tables keep inline paths when the extra table and directory entry would increase size. The writer compares aligned physical costs before constructing legacy rows, so compact output can fit a limit that legacy metadata exceeds.

Baseline parent: 6528a680; baseline VM: 18103f01963874510fa25d4396a2dc3e7ee47640. Updated VM: 190479a. The compiler freshly regenerated all six builtins and the two larger collection artifacts on the same workstation. Before byte sizes and SHA-256 values are preserved in the earlier survey. KiB = 1024 bytes.

Artifact Before, KiB After, KiB Reduction
boot 39.96 37.54 6.04%
edit 214.96 177.53 17.41%
kotlinc 39.79 35.40 11.02%
shell 145.18 124.15 14.48%
vmbench-agent 42.00 36.62 12.80%
vmbench 47.53 42.57 10.44%
kotlin-map-not-null 548.02 388.43 29.12%
kotlin-mutable-list 409.59 284.10 30.64%

The editor falls from 220116 to 181788 bytes; the large mapNotNull example falls from 561176 to 397752 bytes. These are physical executable sizes, without compression. No interpreter speedup is claimed by this change.

Follow-up: compact GC root ranges and combined size results. The table above remains the measured path-pooling stage.

Equivalence and compatibility

Expanding the new path pool into legacy DEBUG records, removing DEBUG_PATHS and rebuilding the container produces exactly the earlier artifact SHA-256 for all eight files. This checks every semantic section, every diagnostic entry, source position, inline parent and all other payload bytes against the recorded baseline. It does not merely compare counts or source filenames. The updated native public verifier accepts all eight compact files.

The critical, nonsemantic DEBUG_PATHS section (0x0111, flags 1) selects the compact DEBUG representation. Readers without support reject it; updated readers also accept old inline-path artifacts. Container format 3.0, semantic Runtime ABI 1.15 and native C ABI 20 remain unchanged. The frozen baseline Runtime 0.20.0 benchmark binary rejects compact boot with BadSection: unknown required or semantic section, as intended. See the active ABI reference for encoding details.

Published Runtime 0.20.0 bundles do not contain this reader. Use source-built natives from the updated VM. A future immutable Runtime release and parent bundle-pin update are needed before packaging compact compiler output with published natives. No published pins were advanced to nonexistent assets, and this work does not claim release readiness.

Verification

Exact sizes and equivalence hashes, section inventories, verification commands.

Reproduce after regenerating the inputs, from the repository root:

python3 docs/benchmarks/debug-paths-704-2026-10-07/verify_legacy_equivalence.py
python3 docs/_tools/analyze_artifact_size.py modules/common/compiler-k2/build/generated/system/*.cpkt

The equivalence script reads artifacts and the archived baseline, expands only in memory, and checks the exact baseline hashes before printing JSON. It does not write executable artifacts or substitute for native verification.