DEV Community

Avery Lin
Avery Lin

Posted on

Freeze a Repo Contract Before Drafting Contributor Orientation

Generated contributor pages fail when a drafting model is allowed to invent owners, secrets, and license duties. Teams should freeze those facts in a repo contract before any orientation narrative is written at all. The model may explain existing contract entries in plain language, but it may not create new entries. A local checker can then reject drafts that cite missing identifiers or insert unsupported product claims.

This split matters because onboarding text can look authoritative even when nobody has reviewed its hidden assumptions. A new contributor may treat a generated path owner as if it were a real review rule. The same reader may copy a generated secret location into a shell script before anyone notices the error. The contract file keeps those high-impact lines explicit, reviewable, and separate from ordinary prose style choices.

Public drafting tools have made this particular failure cheaper to produce and easier to merge unnoticed. A short prompt can expand a plain README into a welcoming guide that sounds unusually specific. Specificity is not the same thing as custody, because a fluent sentence can name a path that no human approved. The workflow below treats custody as a reviewed file, and it treats fluency as a later pass.

What the model may draft

The model may draft transitions, definitions, and step explanations that cite identifiers already present in the contract. It may also propose heading order, a glossary paraphrase, and a short where-to-look-next close. Those drafts should stay inside a marked section so review tools can scan them apart from owned facts. If a sentence needs a new owner, secret, license, or version, the model should stop and leave a gap.

That boundary is narrower than a blanket request to write the entire onboarding page from scratch. Narrative help is allowed only when every concrete noun in the sentence is already an identifier. Allowed sentences include pointers to [[cmd-test]] and short reminders that the reader should open [[lic-apache]] next. Disallowed sentences include new support windows, new token quotas, and new claims about which service is free.

The checker below enforces the easy cases and leaves harder judgment calls to the named human owner. It does not understand intent, and it will not rescue a prompt that asks for new facts. Reviewers should still read the draft, because a clean citation can sit beside a misleading verb.

What a human must own

A human owner must freeze path ownership, secret names, license identifiers, and the commands a new contributor is expected to run. The same person, or a named delegate, must freeze which version strings may appear in the draft. Ownership here means the right to change the contract, not a vague note that docs already reviewed this. The owner stamp belongs in the contract file and again beside the human-owned heading in the page.

Humans must also own any sentence that could change legal, security, or support behavior if it were wrong. That set includes where credentials live, which files require review, and which license text actually applies. A model can restate those rows after they exist, using the citation marks defined in the artifact below. It cannot be the source of the row, even when the generated wording sounds more polished than the table.

Permission boundary

Read the table as a permission boundary, not as a style guide for tone or length. Rows marked for humans stay in the contract even when the model could guess a plausible value. Rows marked for the model still have to cite an identifier when they mention a concrete repo fact. The checker implements only the rows that a surface pattern can see, so the table remains the editorial rule.

Claim in the orientation page Model may draft Human must own
Heading order and transitions Yes, inside Model draft No
Restatement of an existing contract id Yes, with a [[id]] citation The source row
Path reviewer No Yes, in the owners table
Secret handling rule No Yes, in the secrets table
License identity No Yes, in the licenses table
Command and expected result No Yes, in the commands table
Version string Only if already listed allowed_versions
Pricing, quota, uptime, or SLA No Out of scope for this page

Proposed artifact

The following files are a proposed local check, and they were not executed while this article was written. These examples use Python 3.11 because tomllib ships in the standard library from that version onward. The citation mark is a double-bracket identifier such as [[own-docs]], which is easy to grep and hard to confuse with Markdown links. You should treat the patterns as a starting gate, not as a proof that the prose is true.

Contract file, repo-contract.toml:

owner = "docs-platform"
reviewed = "2026-10-09"

allowed_versions = ["3.11", "3.12"]

[[owners]]
id = "own-docs"
path = "docs/"
reviewer = "@docs-platform"

[[secrets]]
id = "sec-none-local"
rule = "Local orientation uses no production secret."

[[licenses]]
id = "lic-apache"
spdx = "Apache-2.0"
note = "License text in LICENSE is the source."

[[commands]]
id = "cmd-test"
argv = "python -m unittest discover -s tests"
expect = "exit 0 on a clean tree"
Enter fullscreen mode Exit fullscreen mode

Checker, check_orientation.py:

#!/usr/bin/env python3
"""Proposed gate. Not executed for this article."""

from __future__ import annotations

import re
import sys
from pathlib import Path

try:
    import tomllib
except ModuleNotFoundError:  # Python older than 3.11
    sys.stderr.write("Python 3.11+ is required for tomllib\n")
    raise SystemExit(2)

FORBIDDEN = re.compile(
    r"\b(uptime|pricing|quota|sla|guarantee|free forever)\b",
    re.IGNORECASE,
)
CITE = re.compile(r"\[\[([A-Za-z0-9_-]+)\]\]")
VERSION = re.compile(r"\b\d+\.\d+(?:\.\d+)?\b")


def load_contract(path: Path) -> dict:
    data = tomllib.loads(path.read_text(encoding="utf-8"))
    ids = set()
    for section in ("owners", "secrets", "licenses", "commands"):
        for row in data.get(section, []):
            ids.add(row["id"])
    data["_ids"] = ids
    data["_versions"] = set(data.get("allowed_versions", []))
    if not data.get("owner"):
        raise ValueError("contract owner is required")
    return data


def check(markdown: str, contract: dict) -> list[str]:
    errors = []
    if "## Human-owned contract" not in markdown:
        errors.append("missing heading: Human-owned contract")
    if "## Model draft" not in markdown:
        errors.append("missing heading: Model draft")
    head, _, draft = markdown.partition("## Model draft")
    if f"owner: {contract['owner']}" not in head:
        errors.append("human owner stamp missing above the draft")
    for match in FORBIDDEN.finditer(draft):
        errors.append(f"forbidden claim in draft: {match.group(0)}")
    for match in CITE.finditer(draft):
        if match.group(1) not in contract["_ids"]:
            errors.append(f"unknown citation: {match.group(1)}")
    if not set(CITE.findall(draft)):
        errors.append("model draft cites no contract ids")
    for match in VERSION.finditer(draft):
        if match.group(0) not in contract["_versions"]:
            errors.append(f"version not in contract: {match.group(0)}")
    return errors


def main() -> int:
    if len(sys.argv) != 3:
        sys.stderr.write("usage: check_orientation.py repo-contract.toml PAGE.md\n")
        return 2
    contract = load_contract(Path(sys.argv[1]))
    page = Path(sys.argv[2]).read_text(encoding="utf-8")
    errors = check(page, contract)
    if errors:
        sys.stderr.write("\n".join(errors) + "\n")
        return 1
    print("orientation draft accepted")
    return 0


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

Sample page fragment, docs/orientation.md:

## Human-owned contract

owner: docs-platform

Facts below are copied from repo-contract.toml and are not model output.
Path docs/ is reviewed by the docs platform group. See [[own-docs]].

## Model draft

Run [[cmd-test]] after you clone the tree, and expect a clean exit on Python 3.12.
Do not add a production credential for this exercise, as [[sec-none-local]] already states.
The license pointer [[lic-apache]] is the only license identifier this page may name.
Enter fullscreen mode Exit fullscreen mode

Commands a reviewer can save and run later:

python3 check_orientation.py repo-contract.toml docs/orientation.md
git diff -- repo-contract.toml docs/orientation.md
Enter fullscreen mode Exit fullscreen mode

The first command is the citation gate, and a prose-only review will miss a changed owner row in the diff. None of these commands were run for this article, so copy them as a lab sketch rather than as a measured result. A useful negative case is a draft that cites [[own-missing]] or prints a version outside allowed_versions, which should exit non-zero. Keep that failing page beside the script so a later edit cannot silently drop the citation rule.

Numbered workflow

  1. A named human writes repo-contract.toml with path owners, secret rules, license identifiers, and the expected commands. Each row needs a stable id so later prose can cite the fact without quietly renaming it. The owner field names the person or team that is allowed to change those rows after review. Versions that may appear in prose go in allowed_versions, and every other version string should fail closed.

  2. The same human pastes only the rows they intend to publish into the page section named Human-owned contract. That section also carries the owner stamp that the checker expects to find above the draft. The stamp is a review handle, not a cryptographic signature, so your real approval still lives in the pull request. If the stamp and the contract owner disagree, the checker fails and the page should not merge.

  3. Only after that contract file is frozen should a model be asked to draft the narrative section. The prompt should include the contract text and should forbid new identifiers, new versions, and any availability or pricing language. Ask for citations in [[id]] form so the checker can see which rows the prose used. If the model cannot explain a step without a missing row, it should return a question instead of a guess.

  4. Run the checker in the repository, then read the contract diff separately from the prose diff. A green checker means citations and a few banned words are in bounds, not that the commands still succeed on a clean machine. You should execute the listed contract commands yourself whenever the page claims a newcomer can run them. Update the contract first if a command, an owner, or a license row changed during that review.

Where a free drafting workspace fits

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

MonkeyCode enters this workflow only as a drafting workspace with free model access and a free server option. Those two availability claims are enough to place the narrative step on a hosted workspace after the contract file exists locally. This article does not state model names, token quotas, hardware size, service regions, or a duration. Those details were not verified here as stable facts, so they stay outside the written method.

A practical split is to edit repo-contract.toml in the repository, then paste only that frozen file into the drafting session. The model returns the Model draft section, and the checker runs in CI or in a local shell before merge. A free server can hold that scratch session so the experiment does not require a paid workstation. The contract, the owner stamp, and a green checker belong in repository history, not only in the hosted session.

Do not upload production secrets, customer names, or unreleased security notes in order to obtain a smoother paragraph. The sample contract deliberately says local orientation uses no production secret, and that rule should stay intact. If the free offering's current terms are unclear, read them on the project page before you rely on the workspace. Published terms can change, and a documentation gate should not assume yesterday's limit is still today's limit.

Limitations

The regular expressions catch listed words and version-shaped numbers, and they miss paraphrases that imply the same claim. A sentence can avoid the word quota and still invent a limit, which means a human still has to read the draft. Citations prove that an identifier exists, not that the surrounding verb is fair to the row. A page can cite [[cmd-test]] and still describe the wrong expected result in the next clause.

The owner stamp is plain text, so it does not prove the identity of the editor. It will not stop someone with push access from editing the contract and the page together. Teams that need stronger custody should map the contract owner to their existing code review rules. Any interpreter older than Python 3.11 needs another TOML parser, which this sketch does not ship.

The sample was not executed here, so a defect in the script may still be waiting in your tree. Copy the files into a scratch branch and run the checker against both a good page and a bad page. A bad page should mention an unknown citation and a version that allowed_versions does not list. Keep that negative test beside the script so later edits cannot silently weaken the citation gate.

Who should skip this

Skip this gate if nobody will update the contract when path owners or license files change. A stale contract is worse than a short README, because the checker will bless prose that cites outdated rows. Skip it for security advisories, legal terms, and support commitments, where this pattern is too shallow to carry the risk. Skip it if the team would paste live credentials into a hosted model just to finish a paragraph.

Also skip it if you need measured quality scores, latency numbers, or a comparison against another assistant. This article provides a file layout and a proposed checker, not a benchmark against any other tool. Teams that already bind every generated sentence to a reviewed extract may not need a second gate with a different citation syntax. Use the approach when contributor orientation is drifting, and when a named human can keep the contract small.

Close

Freeze the repo contract, draft only cited orientation prose, and fail the page when a new fact appears outside that file. That order keeps a free drafting pass useful without letting it own path review, secrets, or license identity. If you want a hosted place to write the narrative after the contract is frozen, try a workspace only for that section. MonkeyCode's free model access and free server option are a reasonable place to start, after you confirm the current terms yourself.

Top comments (0)