Skip to content

docs: fix 12 broken guide anchors - #539

Merged
Taure merged 2 commits into
mainfrom
fix/broken-guide-anchors
Aug 21, 2026
Merged

Taure merged 2 commits into
mainfrom
fix/broken-guide-anchors

Conversation

@Taure

@Taure Taure commented Aug 21, 2026 •

Copy link
Copy Markdown
Contributor

All 151 anchor links across the 40 guides and the README now resolve, and a CI check keeps it that way. The docs audit (#537, P2-2) found 3 of the 16 breaks.

Two causes for the first 12

Renames without a link sweep. configuration.md gained ## The datagram gateway (was ...-role) and ## Instance capacity (was ## World capacity). Five inbound links still pointed at the old ids.

One systematic slip. Anchors for the wire frames dropped the dot instead of hyphenating it:

link said ex_doc generates
#binary-worldtick #binary-world-tick
#worldack-server-push #world-ack-server-push
#worldinput #world-input
#worldresync #world-resync
#worldphase_changed-server-push #world-phase_changed-server-push
#lua--docker #lua-docker

The last 4 were something else

I first read them as links to sections that no longer exist. That was wrong — they are real #### headings. ex_doc only emits ids for h2 and h3 in extras, so an h4 renders but cannot be linked:

heading sits under
#### Choosing a wire ### session.connect
#### Join context ### match.join
#### Batched input and the ack ### Client-side prediction
#### Refusing a join ### join(player_id, state)…

Promoting them to h3 was the obvious fix and the wrong one: each is genuinely part of the frame above it, and making "Join context" a sibling of match.input would misdescribe the protocol. They now point at the parent section, which lands the reader in the right place.

The check

scripts/check-doc-anchors.sh, wired into docs-drift.yml beside the three existing drift checks. No build required — the slugifier is validated against rebar3 ex_doc output and reproduces all 703 h2/h3 ids exactly, including two rules that are easy to get wrong:

  • a dot becomes a hyphen — world.tick is #world-tick, which is what six of these got wrong
  • repeats are counted, not occurrences: three ### Configuration give #configuration, #configuration-1, #configuration-2, and dedup is by slug across the whole page, so an h2 and an h3 sharing text collide

It names an h4 target with that explanation rather than calling it a typo, and offers a "did you mean" when a slug differs only by hyphenation.

Worth stating plainly: a broken anchor does not 404. It resolves to the page and drops the reader at the top of it, so nothing else was ever going to catch these — the configuration.md renames were two days old and the wire-frame ones had been wrong far longer.

Refs #537.

Two renames in configuration.md landed without sweeping inbound links:
`## The datagram gateway` was `...-role`, and `## Instance capacity` was
`## World capacity`. Five links still pointed at the old ids.

The larger group is one systematic mistake. Anchors for the wire frames dropped
the dot instead of hyphenating it - `#binary-worldtick` where ex_doc generates
`#binary-world-tick`, and the same for world.ack, world.input, world.resync and
world.phase_changed. Plus `#lua--docker` for `#lua-docker`.

Anchor ids were read from the generated HTML rather than guessed at, because
`### 5. Connect via WebSocket` keeps its number in the slug
(`#5-connect-via-websocket`) and there are two headings numbered 5 in that file.

Found by checking all 151 anchor links in the 40 guides and the README against
`rebar3 ex_doc` output; the docs audit had spotted 3 of them. Four targets are
left and are NOT typos - they name sections that do not exist:

  #join-context                 (cited by 4 guides)
  #batched-input-and-the-ack    (cited by 2)
  #choosing-a-wire              (self-link in websocket-protocol.md)
  lua-scripting.md#refusing-a-join (cited by 3)

Those need a decision about whether the section returns or the link is
repointed, so they are deliberately untouched here.

Refs #537 (P2-2).
Correcting the previous commit's claim. Those four targets are not missing
sections - they are real h4 headings. ex_doc only emits ids for h2 and h3 in
extras, so an h4 renders but cannot be linked:

  #### Choosing a wire            under ### `session.connect`
  #### Join context               under ### `match.join`
  #### Batched input and the ack  under ### Client-side prediction
  #### Refusing a join            under ### `join(player_id, state)` ...

Promoting them to h3 was the obvious fix and the wrong one: each is genuinely
part of the frame above it, and making "Join context" a sibling of `match.input`
would misdescribe the protocol. The links now point at the parent section, which
puts the reader on the right page in the right place.

scripts/check-doc-anchors.sh catches all of this, and runs in docs-drift.yml
next to the other three drift checks. It needs no build: the slugifier is
validated against `rebar3 ex_doc` output and reproduces all 703 h2/h3 ids
exactly, including two rules that are easy to get wrong -

  - a dot becomes a hyphen (`world.tick` -> #world-tick), which is what six of
    the broken links got wrong
  - repeats are counted, not occurrences: three `### Configuration` give
    #configuration, #configuration-1, #configuration-2, and dedup is by slug
    across the page, so an h2 and h3 sharing text collide

It reports an h4 target with that explanation rather than as a typo, and offers
a "did you mean" when a slug differs only by hyphenation.

All 151 anchor links across the 40 guides and the README now resolve.
Taure added a commit to widgrensit/asobi_site that referenced this pull request Aug 21, 2026
Twelve generated views were behind their source guides. The pipeline is fine -
this was a pending run, not a broken system.

The one with teeth: bot ids gained a random discriminator in #444, so the live
site taught `game.bots.add("Spark")` producing `bot_Spark`. The real roster id
is `bot_Spark_a3f91c`, and someone copying the old example and matching on the
name would find nothing.

This also carries 24 corrected anchor links through from asobi's guides.

DEPENDS ON widgrensit/asobi#539. Generated from that branch, because
regenerating from main would have carried the broken anchors onto the site -
the site's links currently resolve only because the generated
configuration_view.erl still holds the pre-rename heading id, and regenerating
alone would have broken them. Merge #539 first.

Refs widgrensit/asobi#537 (P2-1).
@github-actions

Copy link
Copy Markdown

🟡 Code Coverage — 76.4%

8702 of 11385 lines covered.


🟡 ELP Lint — 192 warnings

210 diagnostics found. See job logs for details.

@Taure
Taure merged commit 11b9ca1 into main Aug 21, 2026
18 checks passed
@Taure
Taure deleted the fix/broken-guide-anchors branch August 21, 2026 11:19
Taure added a commit to widgrensit/asobi_site that referenced this pull request Aug 21, 2026
Twelve generated views were behind their source guides. The pipeline is fine -
this was a pending run, not a broken system.

The one with teeth: bot ids gained a random discriminator in #444, so the live
site taught `game.bots.add("Spark")` producing `bot_Spark`. The real roster id
is `bot_Spark_a3f91c`, and someone copying the old example and matching on the
name would find nothing.

This also carries 24 corrected anchor links through from asobi's guides.

DEPENDS ON widgrensit/asobi#539. Generated from that branch, because
regenerating from main would have carried the broken anchors onto the site -
the site's links currently resolve only because the generated
configuration_view.erl still holds the pre-rename heading id, and regenerating
alone would have broken them. Merge #539 first.

Refs widgrensit/asobi#537 (P2-1).
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