The Draft/Own Split: A Reproducible Workflow for Generated Docs
Documentation generation fails less often because the model writes poorly and more often because nobody defined who owns the claims inside the generated text. A model can draft API references, quickstarts, and migration notes, but architecture rationale, security guarantees, and compatibility promises must stay with a human owner. This article defines a draft/own split, provides a small audit script, and shows where a free tier fits without becoming the owner of record.
The failure mode is ownership, not grammar
Most teams evaluate generated documentation by reading it, and that habit measures fluency instead of correctness. A doc comment that reads smoothly can still encode a wrong precondition, an outdated default, or a promise the code never made. The real question is whether someone with authority verified each claim, and that question never appears in the rendered output.
A practical signal exposes the problem quickly: track how many doc comments change in the same pull request that changes the code. If the docs never move when the code moves, the generation step produces decoration rather than documentation. If the docs move but no human reviewed the diff, the generation step produces unverified claims that later become integration failures.
The workflow
The draft/own split runs in five numbered steps, and each step names a single owner for its output.
Step 1: Inventory the API surface. Run a script that lists every exported symbol, its signature, and whether it carries a doc comment. This converts "we should document more" into a countable gap that the team can track over time.
Step 2: Classify each doc type. Apply the decision matrix below to decide whether the model drafts, the human owns, or both participate in the final text.
Step 3: Generate drafts for the low-risk classes. Let the model produce the first version of function references, quickstarts, and changelog entries, then review the diff before it reaches the main branch. I ran this step with MonkeyCode's free model access on their free server, so the drafting cost nothing for a small repository. Disclosure: This article was prepared as part of MonkeyCode's product outreach.
Step 4: Human owns the high-risk classes. Architecture decisions, security notes, and compatibility promises get written or rewritten by a human, and the model may only copy-edit afterward.
Step 5: Verify with the audit script. Re-run the inventory, confirm that every exported symbol has a doc comment, and route any claim words to a human check.
The decision matrix
| Doc type | Risk if wrong | Audience | Owner |
|---|---|---|---|
| Function and class references | Medium | Other developers | Model drafts, human verifies |
| Quickstart and setup guides | Low | New users | Model drafts, human verifies |
| Migration notes | High | Existing users | Human owns |
| Architecture rationale | High | Maintainers | Human owns |
| Security and permissions | Critical | Operators | Human owns |
| Changelog entries | Medium | All users | Model drafts from git log, human verifies |
The rule is simple: the model may draft anything a human can verify in under five minutes. The human owns anything whose failure sends a reader down the wrong integration path. Risk drives the split rather than the model's confidence, because confidence is not evidence.
The audit script
The script below inventories exported symbols in a CommonJS project and flags every export that lacks a JSDoc comment. It is deliberately small so you can read it in one pass and adapt it to your own conventions. A TypeScript variant would use the compiler API to resolve exported declarations, but the CommonJS version keeps the logic readable.
// doc-audit.mjs
import { readdirSync, readFileSync } from "node:fs";
import { join, extname } from "node:path";
const root = process.argv[2] ?? "src";
const files = [];
function walk(dir) {
for (const entry of readdirSync(dir, { withFileTypes: true })) {
const full = join(dir, entry.name);
if (entry.isDirectory()) walk(full);
else if (extname(entry.name) === ".js") files.push(full);
}
}
walk(root);
let missing = 0;
for (const file of files) {
const source = readFileSync(file, "utf8");
const lines = source.split("\n");
for (let i = 0; i < lines.length; i++) {
const match = lines[i].match(/export\s+(?:function|const|class)\s+(\w+)/);
if (!match) continue;
const before = lines.slice(Math.max(0, i - 10), i).join("\n");
const hasDoc = /\/\*\*[\s\S]*?\*\//.test(before);
if (!hasDoc) {
missing++;
console.log(`${file}:${i + 1} missing doc for ${match[1]}`);
}
}
}
console.log(`Total missing: ${missing}`);
Run it with node doc-audit.mjs src and the output lists every undocumented export with its file and line number. After the model drafts the missing comments, run the script again and the count should drop to zero for the draft-classified items.
The second verification pass targets claim words instead of mere presence, because a doc comment can exist and still be wrong. Grep the generated docs for terms like always, never, guaranteed, secure, and thread-safe, then send every match to the human owner. These words carry promises that a fluent sentence can hide, and they are exactly the claims the decision matrix reserves for human review. Run the audit script on your own repository this week, and you will see exactly where your documentation debt lives.
Where the free tier fits
The free tier from Step 3 made the drafting step affordable for a side project, but the economics are not the point of this workflow. The point is that the model produces a first version, the human owns the claims, and the audit script closes the loop. If you have no budget at all, the same workflow works with any local model, and the ownership rules remain unchanged.
Limitations
This workflow assumes a codebase with an explicit public API, so it fits libraries and services with clear boundaries. It does not fit monorepos with dozens of packages, because the inventory step needs a package-aware traversal that this script does not implement. It also does not fit primarily conceptual documentation such as tutorials, since a narrative arc cannot be captured by an ownership matrix. The audit script checks presence, not correctness, and presence is a necessary condition rather than a sufficient one.
Who should not use this
Teams without a human reviewer should not treat this split as a substitute for review, because the workflow degrades into unverified generation with a checkbox. Small scripts with a handful of functions may not need the inventory step, since the overhead outweighs the benefit when the API surface fits on one screen. If your team already skips code review under deadline pressure, it will skip this human step too, and the matrix becomes theater.
Top comments (0)