FIELD NOTES//LOG 04 · LANGUAGES
Per-symbol drift, beyond TypeScript
codument's drift detection began as a TypeScript feature. It now reads Python, Go, Rust, C#, Java, Kotlin, and single-file components the same way, and the site can only claim what the installed release ships.
One parser was never going to be enough
codument's whole trick is that it does not diff text. It resolves a change down to the symbol: which function moved, whether its signature changed, whether the doc that owns it needs to move too. That resolution needs a real parser for the language, not a regex. So for a long time it meant one language. TypeScript.
That was an honest limit, and also a narrow one. Teams do not ship one language. The checkout is Python, the sync engine is Go, the mobile core is Kotlin, the widget is a single .vue file. A gate that understands only one of those is a gate you route around on every other file.
The same resolution, across the stack
The per-symbol engine now runs on a parser per language. Same anchors, same drift analysis, same verdict path. codument doctor prints the roster it will actually judge:
gate languages: TypeScript (per-symbol) · Python (per-symbol) · Go (per-symbol) · Rust (per-symbol) · C# (per-symbol) · Java / Kotlin (per-symbol) · Vue / Svelte / Astro (blocks)
Nothing about the analysis changed when the language did. Here is a Python checkout file whose apply_discount grew a cap. One symbol changed; the sibling above it did not:
Changed by feature
pricing — src/pricing.py
Stale docs (source changed, mapped doc did not)
⚠ pricing: docs/features/pricing.md (changed: src/pricing.py)
Symbol drift — resolve each: update the doc, or ack a contract-neutral move
• apply_discount (changed) in pricing [signature changed]
contract changed → update docs/features/pricing.md at intent altitude
signature move → the symbol's signature changed — the doc's contract needs an update, not an ack
It named the function, saw that the signature moved, and pointed at the one doc that now owes an update. line_total, untouched, is nowhere in the report. That is what symbol grain buys you: the blast radius is the symbol, not the file.
The honest edges
Per-symbol holds where a real parser reaches. Single-file components (Vue, Svelte, Astro) resolve at block grain, because that is the honest unit there. Everything past the shipped languages is still tracked, just at file grain: registered, drift-detected across the whole file, never judged symbol by symbol. codument reports that gap instead of papering over it.
And the claim cannot outrun the code. The "works with your stack" strip on the landing page is generated at build time from the installed release's own language manifest, and a check fails the build if the page names a language the package does not ship. The roster you read is the roster you get.
What changed
Not the idea. The reach. The same defensible, per-symbol verdict codument always produced for TypeScript now covers the languages a real team actually merges in a day.
More field notes
Keeping AI off the verdict path
Why a safety layer for agent output has to be deterministic all the way down, and what that rules out by design.
The diff is not the deliverable
When an agent writes the code, review stops being a courtesy and starts being the product. What a reviewer actually owes the merge.
Your agent changed 14 files. Which docs went stale?
The failure mode of AI-assisted development is quiet. Nothing crashes, the tests pass, the diff merges. And somewhere in your docs, a paragraph that used to be true just stopped being true.