Skip to content

Correct the documentation where it disagreed with the library - #219

Merged
beaugunderson merged 1 commit into
mainfrom
bg-doc-accuracy
Aug 10, 2026
Merged

beaugunderson merged 1 commit into
mainfrom
bg-doc-accuracy

Conversation

@beaugunderson

@beaugunderson beaugunderson commented Aug 10, 2026 •

Copy link
Copy Markdown
Owner

An audit of every documented claim against the built library, prompted by GHSA-mxvh-v779-f36j (#218), where fromURL did not do what its docs promised. The question was whether anything else lied.

All 40 worked examples already passed — 18 assertions in the README example block, 22 JSDoc @example blocks. So did every range claim, throw claim, and classifier-delegation claim I could execute. The provenance statement is exact (10.2.1 onward carry SLSA attestations, 10.2.0 does not), all four published advisories do carry CVEs, there really are zero runtime dependencies, and ESM named imports genuinely work. The inaccuracies were in prose and in generated signatures.

Generated signatures

scripts/build-readme.ts rendered six signatures with required parameters that actually carry defaults:

static fromAddress4Nat64(address: string, prefix: string): Address6
toAddress4Nat64(prefix: string): Address4 | null
regularExpressionString(this: Address6, substringSearch: boolean): string
regularExpression(this: Address6, substringSearch: boolean): RegExp

Two of them contradicted their own prose in the same bullet — "The default prefix is the well-known prefix 64:ff9b::/96" sat directly beside a signature saying you must pass it. TypeDoc sets isOptional inconsistently for defaulted parameters (possibleSubnets.subnetSize gets isOptional=true default="128", regularExpression.substringSearch gets isOptional=false default="false"), so the generator now treats the presence of a default as optional too.

Separately, TypeScript this annotations were rendering as arguments, so isInSubnet: (this: Address4 | Address6, address: Address4 | Address6) => boolean read as a two-argument call when callers pass one. Those are filtered out, and function-valued properties now route through the same parameter rules as methods rather than raw type stringification.

Prose

Address4.reverseForm() was documented as returning ip6.arpa form. It returns in-addr.arpa — as the @param two lines below in the same comment block already said. Copy-paste from the IPv6 method.

The 6to4 terminology entry said the protocol "embeds an IPv4 address as the second 16 bits" of a 2002::/16 address. An IPv4 address is 32 bits and occupies bits 16–47, i.e. the second and third groups: 192.0.2.4 becomes 2002:c000:204::.

"Parses all standard IPv4 and IPv6 notations" claimed more than the library does, and contradicted SECURITY.md, which correctly notes that 2130706433, 0x7f000001 and 127.1 are all rejected. That rejection is deliberate and right; the Features bullet now says so instead of overstating.

group() and groupForV6() return HTML <span> markup and said nothing about it — group()'s entire description was "Groups an address". These are precisely the surfaces GHSA-v2v4-37r5-5v8g was about, so a reader who can't tell the output is markup can't reason about escaping it. Both now say what they return, and that the address content is escaped (verified: a hostile zone id comes back as &lt;img src=x onerror=alert(1)&gt;).

AddressError.parseMessage had no description whatsoever, rendering as a bare parseMessage: string. Meanwhile GHSA-v2v4-37r5-5v8g describes rendering it as HTML as "its documented purpose — it already contains <span class="parse-error"> markup". The behavior is real; the documentation the advisory appealed to was not. Now documented.

Address4's byte-array methods documented neither their throw conditions nor the fact that they reject the signed bytes Address6.fromByteArray folds. The 11.0.0 tripwire in test/common-test.ts already owns settling that split — in the direction of making v6 strict — so this only writes down where things stand and notes that the contracts converge.

isHostInSubnet pointed readers at {@link common.isHostInSubnet}, a module the API reference doesn't cover, so the pointer went nowhere. The substance is inlined instead.

The weekly download figures were stale: ~66M claimed against 85.7M actual, plus smaller drift on cacache (~44M → 40M) and socks-proxy-agent (~57M → 55M).

Badges and [src] links now point at main. There is no master branch on the remote; those 129 links resolved only through GitHub's renamed-branch redirect.

Tests

test/readme-test.ts guards the generator fix, since CI already checks the README is current but nothing checked it was correct: no signature may expose a this parameter, the six defaulted parameters must render optional, and the HTML-returning methods must mention HTML. All three assertions fail against the previous README (8 leaked this parameters, 3 required-but-defaulted signatures).

An audit of every documented claim against the built library. All 40
worked examples (18 in the README block, 22 JSDoc @example) already
passed; the inaccuracies were in prose and in generated signatures.

Generated signatures (scripts/build-readme.ts):

- Six signatures declared required parameters that carry defaults, two
  of them contradicting their own prose in the same bullet ("The default
  prefix is the well-known prefix 64:ff9b::/96" beside a signature
  saying you must pass it). TypeDoc sets isOptional inconsistently for
  defaulted parameters, so treat a default as optional too.
- TypeScript `this` annotations rendered as arguments, so
  `isInSubnet(address)` read as taking two. Filter them out, and route
  function-valued properties through the same parameter rules.

Prose:

- Address4.reverseForm() was documented as returning ip6.arpa form. It
  returns in-addr.arpa, as the @PARAM two lines below already said.
- 6to4 embeds a 32-bit IPv4 address in bits 16-47, not "the second 16
  bits".
- "Parses all standard IPv4 and IPv6 notations" claimed more than the
  library does: the inet_aton forms are rejected by design, which
  SECURITY.md already says.
- group() and groupForV6() return HTML and said nothing about it. These
  are the surfaces GHSA-v2v4-37r5-5v8g was about.
- AddressError.parseMessage had no description at all, though
  GHSA-v2v4-37r5-5v8g describes rendering it as HTML as "its documented
  purpose".
- Address4's byte-array methods documented neither their throw
  conditions nor that they reject the signed bytes Address6 folds. The
  11.0.0 tripwire in test/common-test.ts owns settling that split; this
  only writes down where it stands.
- isHostInSubnet pointed at {@link common.isHostInSubnet}, a module the
  reference doesn't cover. Inlined instead.
- Weekly download figures were stale (~66M against 85.7M actual).

Badges and source links now use main, which is the default branch, so
they no longer lean on GitHub's renamed-branch redirect.

test/readme-test.ts guards the generator fix: no signature may expose a
`this` parameter, defaulted parameters must render optional, and the
HTML-returning methods must say so. All three fail against the previous
README.
@beaugunderson
beaugunderson merged commit 9fd1110 into main Aug 10, 2026
6 checks passed
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