Skip to content

Harden docslint: check stdlib doc completeness, signatures, and counts - #15

Merged
mitchellnemitz merged 9 commits into
mainfrom
impl-2026-07-24-docslint-hardening
Jul 24, 2026
Merged

mitchellnemitz merged 9 commits into
mainfrom
impl-2026-07-24-docslint-hardening

Conversation

@mitchellnemitz

Copy link
Copy Markdown
Owner

A recent manual audit of the stdlib docs found 14 inaccuracies that no check would have caught: wrong return types, missing members, stale counts, and bare spellings of builtins that have since moved into modules. This makes those classes of drift fail go test instead of surviving until someone reads the page.

What it adds

Four checks in internal/docslint, all driven off the compiler's own tables (no hand-maintained lists):

  • Completeness: every types.DocumentableMembers() entry must be documented in stdlib-index.md. No allowlist, no exemptions. A new builtin with no doc bullet fails the suite.
  • Signature drift: a documented member's return type and arity must match its source signature. Members with no static signature (delegates, custom-checked overloads) must carry the explicit no-static-signature marker instead.
  • Funcref-class counts: the four counts in guide/language.md (8 class labels, 71 monomorphic-generatable, 7 overloaded, 12 generic) must equal their source set sizes.
  • Stale bare spellings (widened): a moved builtin's bare call spelling (name() must not reappear in either stdlib doc. map/filter are excluded because the ERGO-6 carve-out in call.go keeps their bare 2-arg forms callable.

To make the first two mechanically checkable, stdlib-index.md is restructured so every catalog member is one bullet whose first backtick span is a parseable signature (or the no-static-signature marker). Section headings are untouched, so no anchors move.

Supporting changes

  • New read-only accessors in internal/types: DocumentableMembers() and FuncrefClassLabels(), both derived from existing catalog tables.
  • Doc fixes surfaced by the checks: added the missing array.contains, array.index_of, and set_stdin bullets; corrected six stale bare spellings (exp -> math.exp, run/run_env -> process.*, get -> dict.get, and dropped the parens on a reference to awk's own sqrt).

Every failure names the member, the expected value, the actual value, and file:line where one applies. Free-prose semantic claims are deliberately out of scope and documented as such in the package comment.

Scope and verification

Docs-and-tests-only: no compiler, codegen, runtime, or builtin-set change; stdlib-only Go. The checks run under the existing build-test CI job via go test ./.... Verified locally: gofmt/go vet clean, full suite green (22 packages), www builds with all internal links valid, and act -j build-test + act -j golden both pass.

mitchellnemitz and others added 9 commits July 24, 2026 16:16
Read-only accessors exposing per-member arity/return/no-static-sig facts
and the funcref-class label set, so the docs-completeness and
signature-drift checks (next) have a single source of truth instead of a
hand-maintained list.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…member

Split every packed "a / b" bullet into one bullet per catalog member, and
mark members with no static signature (delegate/custom-checked) with an
explicit "-- no static signature" marker instead of a synthesized arity/
return type. Preserves every previously-published fact; no section heading
changed. Prepares the doc for the completeness and signature-drift checks
added next.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
array.contains and array.index_of were only referenced in prose under
Strings; give them their own no-static-sig bullets under Arrays. Add
set_stdin, a flat builtin with no doc entry at all.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Every builtin/namespace member in the compiler's catalog must have a
bullet entry in stdlib-index.md, with no allowlist. Parses each checkbox
member bullet's first backtick span into a DocEntry; Completeness()
reports any catalog member ID absent from the parsed set, and
ParseViolations() fails on any malformed or duplicated member entry so
the machine-parseable format cannot be silently abandoned (FR-007/FR-009).

Extends the signature grammar to tolerate a generic type-param list
between the id and its params (assert_eq[T: comparable](...)), and adds
a keyword-pseudo-syntax skip so lines like "[x] throw <error>" (a
language keyword, not a catalog member) are ignored rather than
reported malformed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Compares every documented member's parsed arity/return type against
types.DocumentableMembers(). Members with no static signature are exempt
but must carry the explicit no-static-signature marker; a member that
does have a static signature is never silently skipped, matching FR-004/
FR-009's no-silent-exemption requirement.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extracts the four documented counts in guide/language.md (monomorphic-
generatable, the BuiltinFuncrefClass label set, overloaded, generic) and
asserts each against the real source-of-truth set size, so a drifted
prose number fails CI instead of rotting silently.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Scans every line (not just bullet heads before " -- ") of both
stdlib-index.md and guide/stdlib.md for a call-shaped bare reference to a
moved builtin. Excludes map/filter from the target set: call.go's ERGO-6
carve-out keeps their flat 2-arg Optional/Result form genuinely callable,
so RemovableBuiltins() over-counts them for this check's purposes. Fixes
the real hits this found: math.exp/process.run/process.run_env/dict.get
mentioned by their old bare spelling in prose.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Package doc comment now names all four checks and states explicitly that
free-prose semantic claims are not checked, so a future reader does not
mistake the check surface for full doc coverage (FR-012).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@mitchellnemitz
mitchellnemitz merged commit 48d04d7 into main Jul 24, 2026
8 checks passed
@mitchellnemitz
mitchellnemitz deleted the impl-2026-07-24-docslint-hardening branch July 24, 2026 21:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant