Ovellum

3 min read · Updated

Orphans#

The hardest part of mixing auto-generated and hand-written documentation isn't the writing. It's what happens when the code moves.

When you rename a function, delete a class, or restructure a module, the auto-generated docs follow along — they're regenerated from scratch every build. But what about the hand-written notes you'd attached to the old shape of the code? Most tools either silently overwrite them or require you to find and migrate every block yourself before the next build will pass.

Ovellum treats your prose as valuable. If it can't find a home for a protected zone on the next build, the block doesn't get dropped. It gets quarantined.

What quarantine looks like#

When the merger sees a protected zone whose anchor no longer exists in the fresh IR, it writes that zone to a file under .ovellum/orphans/:

.ovellum/orphans/
  2026-05-15_src-format.ts-padZero.md
  2026-05-13_src-User.ts-User.constructor.md

Each file has full provenance frontmatter:

---
orphaned: 2026-05-15T14:32:17.493Z
source_file: docs/utils/format.md
anchor_id: src/utils/format.ts::padZero
manual_block_id: rationale
---

**Note.** We use `String#padStart` here instead of a manual loop because
V8 intrinsifies it and the manual version showed up in flamegraphs.

You see the orphan in the build summary too:

ovellum build complete in 219ms
  ...
  orphans:   1
  quarantined:
    ↪ .ovellum/orphans/2026-05-15_src-format.ts-padZero.md

What to do with an orphan#

Once you've reviewed an orphan file, you have three options:

1. Re-attach to a new anchor#

The symbol was renamed; the prose is still useful. Open the orphan file, copy the body into the new symbol's Markdown section as a <!-- @manual:start --> block, then delete the orphan file.

A future ovellum orphans subcommand will automate this prompt-by-prompt; for now it's a copy-paste step.

2. Delete it#

The symbol genuinely went away. The note doesn't apply anywhere any more. Delete the orphan file. Git history keeps the record if you ever need it.

3. Leave it#

Sometimes you'll want to keep the note around for context even if it has no current home — a postmortem about a removed code path, a design note about a deprecated API. Leave the orphan file where it is; commit it like any other file.

Why .ovellum/orphans/ is committed#

This is intentional. Orphan files are Markdown — human-readable, diffable, reviewable in PRs. Committing them means:

  • Your team-mate reviewing a PR can see when you deleted a function and notice the orphaned prose at the same time.
  • You can grep your repo for past notes that are no longer attached to live symbols.
  • Recovery is just git mv away.

If you'd rather treat orphans as ephemeral, set protect.orphanStrategy to 'warn' — the build will surface the warning but won't write a file.

When orphans pile up#

Each orphan file carries an orphaned: timestamp. A future ovellum orphans --stale subcommand will flag entries older than protect.orphanRetention days (default 90), making it easy to do a quarterly review and prune what's no longer relevant.

Until that subcommand lands you can do the same thing by hand:

# Orphans older than 90 days
find .ovellum/orphans -name '*.md' -mtime +90 -print

Edit this page