Skip to content

Turns on the Docs and Doc links gate stages - #168

Merged
johnnyt merged 1 commit into
mainfrom
sui-pk0h-docs-gate-stages
Sep 24, 2026
Merged

johnnyt merged 1 commit into
mainfrom
sui-pk0h-docs-gate-stages

Conversation

@johnnyt

@johnnyt johnnyt commented Sep 24, 2026

Copy link
Copy Markdown
Member

Bead: sui-pk0h

mix quality becomes the pre-publish check for this package's docs, locally and in CI: the Docs and Doc links stages of ex_quality are switched on.

What changes

  • Dependency requirement: the dev dependency moves from {:ex_quality, "~> 0.14", only: :dev, runtime: false} to {:ex_quality, "~> 0.15", only: :dev, runtime: false}, options unchanged. ex_quality 0.15.0 is the release that ships the Doc links stage; mix hex.info ex_quality lists it under recent releases as 0.15.0 (2026-09-24) (hex.pm's date).
  • mix.lock: updated with mix deps.update ex_quality only; the lock diff moves ex_quality alone (0.14.0 to 0.15.0), no other dependency.
  • .quality.exs: docs: [enabled: :auto] and doc_links: [enabled: :auto], with the reason at the setting (quoted below), and the file's header line listing what the full gate runs now names the two stages. No threshold moves.

No package version change and no changelog fragment: changelog.d/README.md excludes "quality gate, CI, or agent tooling changes".

The reason comment, quoted

# The two docs stages are opt-in in ex_quality, and both are on here so
# that this gate is the pre-publish check for the package's docs, locally
# and in CI. The Docs stage fails on any ExDoc warning. The Doc links stage
# fails on the link rules ExDoc accepts silently: a README relative link to
# a file not in the package files, a published relative link to a file that
# is not an extra, two extras sharing a basename, and a silent rewrite to a
# different extra. Each of those builds cleanly and breaks on HexDocs or
# hex.pm, so only a gate stage catches them before a publish.

Gate change justification

This repository treats gate settings as decisions, each carrying its reason at the setting (CLAUDE.md, Conventions), and holds moving a threshold for the operator (.claude/wurk/commit.md, "Gate thresholds are a human's call"). This change moves no number: it enables two stages, and the reason sits beside them. Enabling these two docs stages is authorized by the operator's standing consent for this work, relayed verbatim to the agent that made the change.

mix.lock and mix.exs diff

diff --git a/mix.exs b/mix.exs
index baf4ff5..88f1692 100644
--- a/mix.exs
+++ b/mix.exs
@@ -126,7 +126,7 @@ defmodule StatifierUI.MixProject do
       {:phoenix_live_view, "~> 1.0", optional: true},
 
       # Dev / test
-      {:ex_quality, "~> 0.14", only: :dev, runtime: false},
+      {:ex_quality, "~> 0.15", only: :dev, runtime: false},
       {:credo, "~> 1.7", only: [:dev, :test], runtime: false},
       {:dialyxir, "~> 1.4", only: [:dev, :test], runtime: false},
       {:excoveralls, "~> 0.18", only: :test},
diff --git a/mix.lock b/mix.lock
index 948ceac..674e2cb 100644
--- a/mix.lock
+++ b/mix.lock
@@ -7,7 +7,7 @@
   "earmark_parser": {:hex, :earmark_parser, "1.4.46", "67607a0532e810c6f630a515c548d0b24949643f168cc556303bee4cf96105c7", [:mix], [], "hexpm", "9c44636e8a1c68c62f526b2dcd85d941dbbcee7ab82cf64ba06ce28bef8e89f5"},
   "erlex": {:hex, :erlex, "0.2.9", "7debbbaa9f4f368b8cd648983e0f1d7963028508e9c59e9d4ed504e94ef52a55", [:mix], [], "hexpm", "8cfffc0ec7159e6d73de2ab28a588064de80f88b2798d5cbe4482cbbc200178b"},
   "ex_doc": {:hex, :ex_doc, "0.40.3", "4a972ffe64bc07dc605af487e98fc19b72a4185f55ca031b94c0552d6071c1d9", [:mix], [{:earmark_parser, "~> 1.4.44", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "2756e357742fecd9749b489b85d67c9ce99c465f2e75728d9e6dc8d704b973de"},
-  "ex_quality": {:hex, :ex_quality, "0.14.0", "702ed122c85c1d1f1dca2efab60871884e9ba6aefc492f334da51a8175543cc6", [:mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "ac8553e6b7a6a35ada03ef748530db2c5871d69427d74a634fd37afdeabf7e24"},
+  "ex_quality": {:hex, :ex_quality, "0.15.0", "e5af847cd6f78c8bde25f8cf8e96c8e3e92ed768affe3711dca05065887771b6", [:mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "b1d8943973be502fd5c5210f5f96e88b1262ce813b6d50092315a613573deb08"},
   "excoveralls": {:hex, :excoveralls, "0.18.5", "e229d0a65982613332ec30f07940038fe451a2e5b29bce2a5022165f0c9b157e", [:mix], [{:castore, "~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "523fe8a15603f86d64852aab2abe8ddbd78e68579c8525ae765facc5eae01562"},
   "file_system": {:hex, :file_system, "1.1.1", "31864f4685b0148f25bd3fbef2b1228457c0c89024ad67f7a81a3ffbc0bbad3a", [:mix], [], "hexpm", "7a15ff97dfe526aeefb090a7a9d3d03aa907e100e262a0f8f7746b78f8f87a5d"},
   "jason": {:hex, :jason, "1.4.5", "2e3a008590b0b8d7388c20293e9dcc9cf3e5d642fd2a114e4cbbb52e595d940a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "b0c823996102bcd0239b3c2444eb00409b72f6a140c1950bc8b457d836b30684"},

git diff --stat (against main at 7c51d40)

 .quality.exs | 20 ++++++++++++++++++--
 mix.exs      |  2 +-
 mix.lock     |  2 +-
 3 files changed, 20 insertions(+), 4 deletions(-)

Gate

Full mix quality on the committed tree, quoted whole (the dependency compile lines come first because the worktree was fresh). Docs and Doc links are both reported as run and passing, not skipped; the two skipped stages are the repo's two permanent ones (Gettext, Sobelow), declared in gate.not_applicable_skips.

==> earmark_parser
Compiling 2 files (.xrl)
Compiling 1 file (.yrl)
Compiling 3 files (.erl)
Compiling 32 files (.ex)
Generated earmark_parser app

20:15:37.027 [info] Compiling file system watcher for Mac...

20:15:37.508 [info] Done.
==> file_system
Compiling 7 files (.ex)
Generated file_system app
==> decimal
Compiling 4 files (.ex)
Generated decimal app
==> table
Compiling 5 files (.ex)
Generated table app
==> mime
Compiling 1 file (.ex)
Generated mime app
==> nimble_parsec
Compiling 4 files (.ex)
Generated nimble_parsec app
==> bunt
Compiling 2 files (.ex)
Generated bunt app
==> statifier_ui
===> Analyzing applications...
===> Compiling telemetry
==> jason
Compiling 10 files (.ex)
Generated jason app
==> doctor
Compiling 17 files (.ex)
Generated doctor app
==> phoenix_html
Compiling 6 files (.ex)
Generated phoenix_html app
==> phoenix_template
Compiling 4 files (.ex)
Generated phoenix_template app
==> phoenix_pubsub
Compiling 12 files (.ex)
Generated phoenix_pubsub app
==> plug_crypto
Compiling 5 files (.ex)
Generated plug_crypto app
==> statifier_datamodel
Compiling 7 files (.ex)
Generated statifier_datamodel app
==> credo
Compiling 257 files (.ex)
Generated credo app
==> plug
Compiling 1 file (.erl)
Compiling 42 files (.ex)
Generated plug app
==> kino
Compiling 50 files (.ex)
Generated kino app
==> makeup
Compiling 15 files (.ex)
Generated makeup app
==> makeup_elixir
Compiling 6 files (.ex)
Generated makeup_elixir app
==> makeup_erlang
Compiling 4 files (.ex)
Generated makeup_erlang app
==> ex_doc
Compiling 30 files (.ex)
Generated ex_doc app
==> erlex
Compiling 1 file (.xrl)
Compiling 1 file (.yrl)
Compiling 2 files (.erl)
Compiling 2 files (.ex)
Generated erlex app
==> dialyxir
Compiling 67 files (.ex)
Generated dialyxir app
==> predicator
Compiling 30 files (.ex)
Generated predicator app
==> ex_quality
Compiling 35 files (.ex)
Generated ex_quality app
==> websock
Compiling 1 file (.ex)
Generated websock app
==> websock_adapter
Compiling 4 files (.ex)
Generated websock_adapter app
==> phoenix
Compiling 74 files (.ex)
Generated phoenix app
==> phoenix_live_view
Compiling 55 files (.ex)
Generated phoenix_live_view app
==> saxy
Compiling 19 files (.ex)
Generated saxy app
==> statifier
Compiling 144 files (.ex)
Generated statifier app
==> statifier_ui
Running quality checks...

✓ Format: No changes needed (411ms)
✓ Compile: dev + test compiled (warnings as errors) (14.8s)

Running analysis stages in parallel...

○ Gettext: skipped (:gettext not installed)
○ Sobelow: skipped (:sobelow not installed)
✓ Doc links: 9 links checked (20ms)
✓ Dependencies: No unused dependencies (1.1s)
✓ Doctor: Passed (1.8s)
✓ Docs: No warnings (3.6s)
✓ Credo: No issues (3.9s)
✓ Tests: 1,208 of 1,208 passed, 93.6% coverage (6.9s)
⋯ Dialyzer: building PLT (this is a one-time cost)
✓ Dialyzer: No warnings (PLT built this run) (52.4s)

✓ All quality checks passed!

mix quality.verify then attested a second full run on the same tree: "Full gate green: scope all, no profile, 11 stages considered."

The Doc links stage reported no finding on main's docs, so no link fix was needed in this PR; the README and guide fixes landed earlier in 7c51d40.

Review (in-turn)

I re-read the diff against the bead and its notes. Each acceptance criterion: the requirement is ~> 0.15 with only: :dev, runtime: false unchanged (mix.exs deps list); mix.lock resolves ex_quality 0.15.0 and the lock diff above moves no other entry; .quality.exs carries both settings at enabled: :auto with the reason comment beside them; the full gate is green with Docs ("No warnings") and Doc links ("9 links checked") both run; no @version change and no changelog.d/ file; the diff stat touches only mix.exs, mix.lock and .quality.exs. The reason comment's link rules were checked against the stage table in ex_quality 0.15.0's README (Doc links: "fails on a relative link HexDocs or hex.pm would break") and match the bead's wording. test/packaging_test.exs stays green inside the Tests stage (1,208 of 1,208). .quality.exs is outside the formatter's inputs, and its existing blank lines between keyword entries are the file's house style, kept.

Provenance

  • The header comment at the top of .quality.exs lists what the full gate runs; it now names the docs build and doc links. This is a comment-only edit in a file the bead already names, so the diff stat is unchanged in file count.
  • The CLAUDE.md "Build & Test" line summarising the full gate does not name the two new stages; it is left as it is, since the bead's acceptance keeps the diff to mix.exs, mix.lock and .quality.exs.

mix quality becomes the pre-publish check for this package's docs,
locally and in CI. ex_quality 0.15 ships the Doc links stage; the dev
dependency requirement moves from ~> 0.14 to ~> 0.15 with its options
unchanged, and mix.lock moves ex_quality alone (0.14.0 to 0.15.0,
via mix deps.update ex_quality).

.quality.exs enables both stages at enabled: :auto, with the reason at
the setting: the Docs stage fails on any ExDoc warning, and the Doc
links stage fails on the link rules ExDoc accepts silently. No
threshold moves. The full gate is green with both stages run and
passing. No package version change; no changelog fragment
(changelog.d/README.md excludes quality gate changes).

Refs: sui-pk0h
@johnnyt
johnnyt merged commit 36c9f06 into main Sep 24, 2026
1 check passed
@johnnyt
johnnyt deleted the sui-pk0h-docs-gate-stages branch September 24, 2026 02:20
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