← Changelog

The measurements that justified path resolution are now reproducible, and they moved

Every default in resolve-path.ts was argued from a table nobody could re-run. The script that regenerates it is now committed — and it turns out the original count treated image embeds as navigational links, which shifted every percentage that used the corpus as a denominator. All six conclusions survive; only the digits moved.

The measurements that justified path resolution are now reproducible, and they moved

src/utils/resolve-path.ts has fifteen config options and, deliberately, no baked-in policy. The few things it does decide by default — that there is an index at all, that basename is in the cascade, that a collision refuses to guess, that matching is case- and separator-insensitive — were each argued from a measurement rather than from taste.

That was the right instinct and it was undermined by the execution: the tables lived in a published package’s README, and the scripts that produced them were throwaway and never committed. Nobody could check them. A number nobody can re-derive is not a measurement, it is a claim with a table around it.

What changed

scripts/measure-vault.mjs regenerates every quoted figure, takes about a second, and accepts --json. It also measures the README’s four-route resolve-rate, which previously could not be verified at all because the route config behind the claim had never been written down.

node scripts/measure-vault.mjs            # ../content by default
node scripts/measure-vault.mjs --json     # machine-readable

The numbers moved, and one of them was an error

The original sweep counted ![[embeds]] as wikilinks. The resolver is never asked to route an embed — it is an image, not navigation — so including them inflated the corpus and every percentage computed against it.

claimed 2026-08-23re-derived 2026-09-08
Navigational wikilinks13,84613,556
Wikilinks with no folder3,839 — 28%3,624 — 26.7%
Files with a unique basename4,622 — 98.4%4,563 — 97.0%
Colliding basenames73 (153 files)66 (139 files)
Bare links hitting a collision25 — 0.7%17 — 0.5%
Exact hits among pathed links8,956 — 89.8%9,108 — 91.7%
Resolution cost5.09 µs/link7.65 µs/link

Every conclusion survives. Better than a quarter of the corpus is still written without a folder, so the index is still load-bearing and prefix rules alone would still miss it. Basenames are still unique far more often than not, so the tier stays. Collisions are still rare enough that refusing to guess costs almost nothing. The headline reproduces almost exactly — 79.2% against the documented 79%.

The one number worth restating plainly: resolution is 7.65 µs per link, not 5.09. That is 50% slower than claimed and still ~104 ms to resolve the entire vault, so the design doc’s performance argument is unchanged. It is recorded because a shared library should not round its own cost down.

The old entry was corrected, not rewritten

changelog/2026-08-23_01.md keeps its original table with a correction note pointing here. A ship log records what was shipped, including the parts that were wrong at the time. Rewriting it would erase the more useful fact — that a published package carried unverifiable statistics for two weeks.

Why this was blocking

Version 0.6.0 has been sitting unreleased on wip/wikilink-path-resolution since 2026-08-23, and this overclaim was the stated reason. With the script committed and the tables re-derived, that objection is resolved.

The other caveat from the parking commit still stands: the 806 lines of resolve-path.ts have not had a human read them.

  • context-v/Maintain-Path-Resolution-for-Wikilinks.md — the design record
  • changelog/2026-08-23_01.md — the original release entry, with its correction
  • test/resolve-path.test.mjs — 39 assertions pinning the two invariants