DEV Community

Avery Lin
Avery Lin

Posted on

Enforce a Draft/Own Contract with a Config-Driven Doc Check

The usual failure mode for AI-generated documentation is not the model's prose. It's the review model. Teams dump a large autogenerated file into a PR and ask a senior engineer to "check it". The engineer reads paragraphs of plausible text, finds two wrong parameter names, and then re-reads everything else with suspicion. That costs more than writing the doc from scratch. The solution is to stop reviewing prose and start enforcing a contract: the model may draft only sections that are factual extractions, and humans must own sections that require judgment. You can encode that contract in a configuration file and a CI script.

I will show you a small, runnable contract that separates human sections from draft sections. The script fails a build when a human-owned file contains an AI-draft marker, or when a draft-owned file lacks a human verification marker. The workflow runs locally with a free server and free models, so the contract costs nothing to enforce and does not require sending proprietary docs to a remote API.

Why an ownership contract works better than a review budget

A review budget tells people how much time to spend, but it does not tell them where to spend it. An ownership contract tells the model what it is allowed to produce and tells the human what they must produce themselves. The model is good at extracting error tables, parameter descriptions, and reference lists from code. It is bad at making decisions about tradeoffs, migration strategies, and API design rationale. Mislocating those two types of content is the real root cause of documentation drift.

Define the contract in a YAML file

Create docs-ownership.yaml in your repository root. The file maps glob patterns to two ownership tiers: human and draft. A human file must be authored by a person and must not carry the AI-draft marker. A draft file may be generated, but it must contain a verified-by marker with your username before CI passes.

# docs-ownership.yaml
ownership:
  - pattern: "docs/guides/**"
    owner: human
  - pattern: "docs/api/**"
    owner: human
  - pattern: "docs/reference/errors.md"
    owner: draft
  - pattern: "docs/reference/parameters/*.md"
    owner: draft
  - pattern: "docs/architecture/**"
    owner: human
Enter fullscreen mode Exit fullscreen mode

The pattern matching is literal; adjust it to your structure. The earlier in the list a pattern appears, the more specific you can make it.

Enforce it with a Python script

The following script is intentionally portable. It walks the docs/ directory, loads the YAML config, and checks every file's markers. You can run it locally and also inside a GitHub Actions job.

#!/usr/bin/env python3
import sys
import pathlib
import yaml

def owner_for(path, rules):
    for rule in rules:
        if path.match(rule["pattern"]):
            return rule["owner"]
    return None

def main():
    config = yaml.safe_load(pathlib.Path("docs-ownership.yaml").read_text())
    rules = config["ownership"]
    errors = []

    for path in pathlib.Path("docs").rglob("*.md"):
        owner = owner_for(path, rules)
        if owner is None:
            continue  # unmanaged file, skip or fail if you prefer
        text = path.read_text()
        ai_drafted = "<!-- ai-drafted -->" in text
        verified = "<!-- verified-by:" in text

        if owner == "human" and ai_drafted:
            errors.append(f"{path}: human-owned file must not contain ai-drafted marker")
        if owner == "draft" and not ai_drafted:
            errors.append(f"{path}: draft-owned file must contain ai-drafted marker")
        if owner == "draft" and not verified:
            errors.append(f"{path}: draft-owned file must contain verified-by marker")

    if errors:
        print("\n".join(errors))
        sys.exit(1)
    print("All docs comply with the ownership contract.")

if __name__ == "__main__":
    main()
Enter fullscreen mode Exit fullscreen mode

The script uses PyYAML, so add pyyaml to your dev dependencies. The markers are lightweight HTML comments, so they do not disturb rendered documentation.

Wire it into CI

Add a job that runs the check on every pull request. Use a minimal Ubuntu runner with Python.

name: docs-ownership
on: [pull_request]
jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"
      - run: pip install pyyaml
      - run: python scripts/check_ownership.py
Enter fullscreen mode Exit fullscreen mode

Now a PR fails before anyone reads a single generated paragraph. That is the point: you get fast feedback about contract violations, not about prose quality.

Run the drafting step with a free local server

At this point you have a contract but no drafts. You can generate the draft sections with MonkeyCode's free model access. Since the free server runs locally, you keep sensitive code and docs on your machine. This fits the workflow cleanly: the model looks only at the paths your config marks as draft, and the human writes or edits the human paths directly. The verification marker is added after the human actually checks the draft against the source, not after a quick skim.

Disclosure: This article was prepared as part of MonkeyCode's product outreach.

The script catches two common compliance mistakes. If a human edits a generated file and removes the ai-drafted marker, the draft-owned rule fails because the marker is missing. If a human merges a draft without adding verified-by, the check fails as well. Those two failure modes cover the most common ways ownership contracts degrade.

Limitations and who should not use this

The markers are a heuristic. A determined person can remove a marker and pretend they wrote something they did not. The script does not evaluate whether the human actually verified the content; it only records that they claimed to. For serious legal or security documentation, add a second reviewer gate. Also, the free models in MonkeyCode are suitable for extracting factual content from a small codebase, but not for synthesizing high-level design documents in a large monorepo. If your docs are already written and maintained by a dedicated technical writer who owns the domain, this contract adds bureaucratic noise. And if your project has no CI, you need to set that up first; otherwise the check becomes a manual ritual that people skip.

Use the contract when the team is small, the code changes often, and you need a low-cost boundary between what a machine can draft and what a human must own.

Top comments (0)