Skip to the content.

0002: A committed docs-only opt-in, read at the bound commit

Status: draft. Author: drafted by the AI operations agent at Le Chen’s request. Created: 2026-10-17. Decided: (date and maintainer, once accepted or declined). Implemented in: (release).

Summary

The docs-only opt-in moves from the author’s private registry into a small file committed in the package, lean-pkg-binding.yaml, with the keys docs_descendants and, optionally, build_inputs. Every command that binds a receipt to its commit X reads the file at X and nowhere else, so a later commit cannot grant itself the rule. An outside referee running receipt check, and a public index check, can then apply the author’s opt-in without a registry and without taking the decision on the author’s behalf. The registry fields keep working through a deprecation period.

Motivation

A receipt binds commit X. HEAD may move past X with evidence only (always accepted) or, when the package opted in, with files the build does not read, such as a README or notes (the docs-only rule, docs/receipts.md). The opt-in is the record field docs_descendants: true in the author’s registry.

Two readers cannot see that registry:

After #205 every published page needs one page --write, so the docs-only descendant is the normal state of a published package, and the referee’s flag is the normal way to pass. The opt-in should be the author’s, committed, visible and bound like everything else the receipt binds.

Design

The file

lean-pkg-binding.yaml in the package directory (the repository root, or the package’s subdirectory in a monorepo):

schema: lean-pkg-binding/1
docs_descendants: true
build_inputs:            # optional: files the build reads that Lake does not declare
  - data/*.csv
  - Verify/strings.txt
Key Rule
schema lean-pkg-binding/1
docs_descendants required, true or false; only the literal true opts in
build_inputs optional list of globs, the same rule as the registry field today (package-relative, no leading /, no .., fnmatch, a glob without / also matches a basename, never matches under .lean-receipts/)

Strict: unknown keys, repeated keys and values of the wrong type are refused, naming the key. The file must be a regular file (git mode 100644 or 100755) at X; a symlink or a gitlink at that path is refused.

The rule: read at X, and only at X

For a receipt bound to X and a later commit H (HEAD, a release tag, the commit a receipt is committed in):

  1. The opt-in is the file at X: git show X:<pkgdir>/lean-pkg-binding.yaml. The working tree, H, REF and any commit between X and H are never read for it.
  2. A file that exists at H but not at X has no effect. Under the evidence-only rule it is ordinary drift; the refusal adds the clause lean-pkg-binding.yaml was added after <X12>; the opt-in is read at the bound commit only.
  3. The file is itself a build input under the docs-only rule: any change to it between X and H (added, edited, removed) refuses, as claims.yaml does today. So the file a reader sees at H is either absent or byte-identical to the one that bound X, and no output has to say which copy it read.
  4. A file at X that does not validate does not opt in (fail closed): the evidence-only rule binds, and the output names the file and the key.
  5. Only the package’s own directory counts. A copy under .lean-receipts/, at the repository root above a subdirectory package, or in a nested registered package’s directory is never this package’s opt-in.

The docs-only rule itself (which paths are build inputs, what is always refused) does not change. build_inputs is the union of the file’s globs at X and the registry record’s, so the registry can only add inputs.

Registry precedence (commands that read a registry)

File at X Registry docs_descendants Rule applied Output
absent absent or false evidence-only unchanged
absent true docs-only, during the deprecation period WARN naming the migration command
true absent or true docs-only opted in at <X12> (lean-pkg-binding.yaml)
true false, set explicitly with --no-accept-docs-descendants evidence-only the registry’s refusal is named
false or invalid any evidence-only (registry true is ignored once a file exists) names the file

A registry operator can therefore still refuse the rule for a package it coordinates; it can no longer grant it where the author’s committed file does not.

How each command reads it

Compatibility and migration

Trust model

Yes, this changes what two checks accept.

What a dishonest or mistaken author could get accepted that they could not before.

What the registry operator loses. It can no longer be the only place the opt-in lives, but it keeps a veto (docs_descendants: false).

Unchanged. What a receipt proves about X; the list of paths the docs-only rule always refuses; the evidence-only rule, still tried first; the honesty assumption that build_inputs is complete (trust model), which lean-pkg still cannot check.

Unknown. Whether outside referees read the binding line’s path list or treat a PASS as “nothing changed after X”. The page’s Reproduce section should say which rule bound the published ref.

Tests that pin the refusals: a file added at H only; a file edited, and one removed, between X and H; a symlink at the file’s path at X; a copy under .lean-receipts/; a copy at the repository root for a subdirectory package; a nested package’s copy; an invalid file (fail closed); an explicit registry false over a committed true; build_inputs as the union of file and registry; receipt check --evidence-only over a committed opt-in.

Alternatives

Open questions

  1. The file name: lean-pkg-binding.yaml, or the claims.yaml key above.
  2. page --write turns on the docs-only exception itself (accepted for stage 2 in decision 0007, #209). It runs after X, so it cannot commit the file at X. Recommendation: for a package without the file at X it keeps setting the registry field (with the deprecation warning) and writes the file into the working tree for the next verify run.
  3. new: should a new package start with the file, docs_descendants: true and no build_inputs? Recommendation: yes, with a comment saying what it permits, since every published page has a docs-only descendant; new --evidence-only would leave it out.
  4. receipt check default: apply the committed opt-in by default (recommended, with --evidence-only), or keep the evidence-only default and only print that the author opted in.
  5. When the registry route is removed: at the 1.0 freeze, or one minor release after this ships, whichever is later.

AI assistance

Drafted by Claude (Anthropic), the lean-pkg operations agent, from the receipt check pull request (#198), its recommendation to write this proposal, and the source of the docs-only rule. To be reviewed and decided by the maintainer.