원클릭으로
proof-comment-style
Writing, tightening, and auditing Lean doc comments in the ironwood soundness stack (issue
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Writing, tightening, and auditing Lean doc comments in the ironwood soundness stack (issue
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
| name | proof-comment-style |
| description | Writing, tightening, and auditing Lean doc comments in the ironwood soundness stack (issue |
The docstrings are the durable record of the proof structure: the argument must stay reproducible from the comments alone. Tightening is restructuring, not weakening — never drop an honest caveat or soften a claim's scope; move it to where it belongs and say it once.
House exemplar: Zcash/Security/BindingSignature/Balance.lean (PR #4) — its idiom at small
scale, carried by the structural conventions below at large scale. PR #4's narrative style alone
does not survive a 5,000-line composition (pre-#35 Soundness/Main.lean was written in it and
degraded into walls of text); the ledgers, route maps, and one-home-per-story below are what let
it scale.
A • V = (bsk − B) • R")
so the docstring reads without chasing references. Good leads from the codebase:
The deployed Orchard verifier is sound, opening derived: …Assumption: if the proof is accepted, there exist … (assumed defs say so up front)/-! ## … -/ section comment or a -- note above the declaration — and the docstring points
at it in one clause.P' = P − [v]g₀ + [ξ]S, ≤ deg/p,
assemble.eval = 0 — not "the adjusted commitment equation", "a small set", "the check").**Balance reduction (field level).**, **Orchard integer balance reduction (§4.14).**, **Deployed soundness, opening derived.** — so a file skims by its milestones.
Defs and supporting lemmas stay plain (NontrivialRelation, valueCommit,
DeployedAccepts). Don't bold mechanically: a label on everything is a label on nothing.NontrivialRelation.ofBundleModImbalance).Prop where a concrete relation was
expected — write the why as a named module-docstring section and point at it. Exemplars:
Balance.lean "How binding is expressed (and why not as 'no relation exists')";
Soundness/Main.lean "The reduction form". Cite external results for nontrivial side-claims
the way Balance.lean cites Jaeger–Tessaro (https://eprint.iacr.org/2020/1213).§ is for named or public sections only — an in-file section by its title
(`§ Binding reduction` below) or the protocol spec (§4.13/§4.14). Never bare
private plan numbers (§1/§2, "Step 4"): spell out what they name.CommitmentId: halo2 keys by std::ptr::eq;
a value-equality key would wrongly merge equal-valued slots), why an induction is set up the
way it is (Lookup.run_structure: indices are Fin (n + 1) with Fin.induction so the
succ case's hypothesis is exactly the predecessor row), why a statement quantifies over ℤ
rather than ℕ (value_zpow: Mathlib's SameCycle uses ℤ). The test: if a future session
would have to re-derive the trick before it could safely modify the proof, it is not written
down enough. Proof sketches have exactly one home: as -- step comments in the body
(preferred — they sit next to the tactics they explain), or in the docstring only when the
body has none. If the body already steps through the proof, the docstring says "stepped
through in the body" in one clause and does not retell it.0 mod r whose magnitude is < r is 0. This turns balance mod r into
integer balance." No clause-stacking, no symbol runs, no parenthetical doing a sentence's
job. But keep the load-bearing Lean anchors: the predicates and lemmas the statement is about
(IpaRelation, circuitSat) stay named — the budget is on symbol density, not presence.
Supporting lemmas: 1–4 lines. Milestones: ≤ ~7 lines, overflow going to
the module docstring or a section note. Specialisation wrappers do not retell the abstract
theorem's story — "foo specialised to SWPoint Vesta.curve; same hypotheses, plus the
Hasse bound" is enough. Drop role commentary the module docstring already carries, and drop
a "Named assumptions:" ledger when the text already names every hypothesis binder once —
ledgers are for hypothesis-heavy capstones (the ∨-shaped stack endpoints), not
three-hypothesis theorems.label").
Unpack these: one idea per sentence, and every formula only after its symbols are named.value + β·name + γ; the reassembly
Σᵢ hᵢ · (xⁿ)ⁱ) — and leave the rest to the code: never a clause-by-clause prose rendering
of the folds below ("left folds …, starting from …, multiplied by … each column").
Obligations read as plain words ("the running product must start at 1 and end at 0 or
1"); mechanisms in absorb/shed terms ("z multiplies in each column's factor under its own
name and divides out the same factor under the name σ assigns it"). A closed-form
theorem's docstring names the terms by role and lets the displayed statement carry the exact
list. Exemplar: Verifier/Expressions.lean's permChunkExpression.(value, name) pairs
are unchanged when every cell is renamed to the next one in its cycle" — not the displayed
multiset equation; the statements below carry the symbols). A module docstring longer than
~10 lines needs ## sections, each obeying the same budget; if a section still wants more,
the detail belongs on a declaration or in the book.assembleFinalMsm/ipaFold, checked by the fingerprint fixtures)").
Doc comments never cite issue numbers (#18, #14): state the fact ("binding the decode to the
witness is still open") and let the tracker own the numbering — issue refs rot and mean
nothing to a reader outside the repo's process.hFS, hquot, hgood, hencodes); on smaller theorems, naming each binder once in
the text is enough (short by default).Zcash.Snark.… paths shorten to the unambiguous tail in declaration
docstrings (module docstrings may keep full paths as cross-module links).native_decide, decide, simp,
Classical.choice): the reader wants the established fact and its scope, not how Lean checked
it — surface a mechanism only when it is the claim's content. Verbose mechanism-laden caveats
then collapse to one reader-facing clause — the fingerprint glossary entry reads "checked equal
to the Rust verifier's captured MSM, for the specific circuit under analysis", not "a
native_decide match on one selected fixture, an empirical anchor rather than a universal
equivalence, with the fixture's group bases opaque tags".Fiat–Shamir, backticked Lean anchors.Every pass is comments/prose only — zero proof-term changes. The last-notch polish sweep (above) is the pass's final editing step; only then verify before handing over:
Prose-only diff — strip comments (-- lines and nested /- … -/ blocks) from HEAD and
working versions; the code must be byte-identical. An unbalanced docstring terminator swallows
code and fails the check, so this also catches splice errors.
strip() { python3 -c '
import sys
s = sys.stdin.read(); out = []; i = 0; d = 0
while i < len(s):
if d == 0 and s.startswith("--", i): j = s.find("\n", i); i = len(s) if j < 0 else j
elif s.startswith("/-", i): d += 1; i += 2
elif d > 0 and s.startswith("-/", i): d -= 1; i += 2
elif d > 0: i += 1
else: out.append(s[i]); i += 1
print("\n".join(l.rstrip() for l in "".join(out).split("\n") if l.strip()))'; }
git diff --name-only -- '*.lean' | while IFS= read -r f; do
diff <(git show "HEAD:$f" | strip) <(strip < "$f") > /dev/null || echo "FAIL: $f"
done
typos <files> — the repo runs the typos checker (_typos.toml).
lake build Zcash — docstrings are syntax; the build is the parse gate.
To audit the whole tree for adherence (after a pass, before a docs PR, when new proof files
land), sweep every .lean file under Zcash/, skipping auto-generated files (header says "Do
not edit by hand"):
grep -rn '§[0-9]\|Step [0-9]' (allowed: § + a section title, and
public spec sections like §4.13);grep -rn 'will follow\|next phase\|the next step\|is the remaining\|filled in incrementally'
— for each hit, check whether the "pending" thing now exists in the tree;grep -rn -- '—[a-zA-Z\]|[a-zA-Z`]—'(unspaced em-dashes) andgrep -rn 'Fiat-Shamir'(hyphen; house style is the en dash,Fiat–Shamir`);grep -rn ' → .*kernel\| → .*bridge'.fixed (what) / compliant (why, per docstring group) /
flagged (needs author input).