Skip to content

Ships the README-linked guides in the package and quiets the two JSON references - #230

Merged
johnnyt merged 1 commit into
mainfrom
px-i0dj-readme-guides-in-package
Sep 24, 2026
Merged

johnnyt merged 1 commit into
mainfrom
px-i0dj-readme-guides-in-package

Conversation

@johnnyt

@johnnyt johnnyt commented Sep 24, 2026

Copy link
Copy Markdown
Member

Bead: px-i0dj

What changes

  • README-linked guides ship in the package. hex.pm renders the package page from the README inside the package tarball, so a relative README link resolves to that path in the tarball and answers 404 unless the file ships. The README links relatively to ten docs files (listed under "README link targets" below), all already extras and none in package: [files: ...]. Each is now in files:, so one relative link works on GitHub, HexDocs and hex.pm alike.
  • The two mix.exs comments give that reason. package/0 said docs/ was deliberately excluded and docs/0 said extras need no entry in files:, both because HexDocs builds from disk; that missed the hex.pm README preview. Both now state it. The rest of docs/ (for example docs/reference/ast.md, an extra the README does not link) stays out of the tarball.
  • The two JSON references in the language reference no longer warn. docs/reference/language.md named predicator's own JSON.parse and JSON.stringify in Elixir's arity form, which ExDoc autolinks against Elixir's JSON module and reports undefined. They are now written in call form, JSON.parse(string) and JSON.stringify(value), matching the function table directly above them. No skip_code_autolink_to entry was added.
  • Unchanged: the conformance exclusions (exclude_patterns: [~r{\Alib/predicator/conformance/}], the lib/predicator* glob), @version (9.4.2), test/docs_adr_links_test.exs and test/predicator/conformance/package_boundary_test.exs (both green in the gate run below). No changelog fragment: changelog.d/README.md lists "documentation, ADRs, or plans" and "quality gate, CI, or agent tooling changes" under "Do not write a fragment for".

The warning set at the base this branch was cut from matched the bead exactly (the two JSON references, each printed for html and epub); nothing moved.

Acceptance evidence

mix docs --warnings-as-errors (branch head)

Generated predicator app
Generating docs...
View html docs at "doc/index.html"
View markdown docs at "doc/llms.txt"
View epub docs at "doc/predicator.epub"
exit=0

No warnings.

Relative links in published files (rules 1 and 6)

The check reads extras and package: [files: ...] from Mix.Project.config(), scans every extra and every lib/**/*.ex (moduledocs and docs) for inline markdown links that are not http(s):, mailto:, a fragment or an ExDoc e:/m:/c:/t: form, resolves each against the file it appears in, and reports any target that is not an extra; then it checks every README relative target against files: and extras.

check script (ruby, run from the repo root)
cfg = `mix run --no-start --no-compile -e 'IO.puts(Enum.join(Enum.map(Mix.Project.config()[:docs][:extras], fn {p, _} -> p; p -> p end), "\\n")); IO.puts("--"); IO.puts(Enum.join(Mix.Project.config()[:package][:files], "\\n"))' 2>/dev/null`
extras, files = cfg.split("--\n").map { |x| x.split("\n").reject(&:empty?) }
link_re = /\]\(([^)\s]+)\)/
def rel?(t) = !(t =~ /\A(https?:|mailto:|#|e:|m:|c:|t:)/) && !t.start_with?("`")
bad = []
check = lambda do |src, text, base_dir|
  text.each_line.with_index(1) do |line, n|
    line.scan(link_re).flatten.each do |t|
      next unless rel?(t)
      path = t.split("#").first
      next if path.nil? || path.empty?
      resolved = File.expand_path(path, base_dir).sub(Dir.pwd + "/", "")
      bad << "#{src}:#{n} #{t} -> #{resolved}" unless extras.include?(resolved)
    end
  end
end
extras.each { |e| check.(e, File.read(e), File.dirname(File.expand_path(e))) }
Dir["lib/**/*.ex"].each { |f| check.(f, File.read(f), File.dirname(File.expand_path(f))) }
# ... prints bad, basename duplicates among extras, and each README relative link with files=/extra=

Output:

relative links not targeting an extra: none
extras sharing a basename: none

Reference-style link definitions and raw href= attributes pointing at a relative path, checked separately with grep -rnE '^\s*\[[^]]+\]:\s' ... | grep -vE '\]:\s*(https?:|#)' and grep -rnoE 'href="[^"#:]+"' ... over the same files: both empty (grep exit 1).

README link targets against package: [files: ...] and extras

README relative links: 20 (distinct targets 11)
  README.md:19 docs/guides/nested-data-access.md files=true extra=true
  README.md:20 docs/reference/language.md files=true extra=true
  README.md:119 docs/guides/embedding.md files=true extra=true
  README.md:158 docs/reference/language.md files=true extra=true
  README.md:222 docs/guides/custom-functions.md files=true extra=true
  README.md:224 docs/guides/embedding.md files=true extra=true
  README.md:263 docs/guides/simple-subset.md files=true extra=true
  README.md:281 docs/reference/language.md files=true extra=true
  README.md:283 docs/isa.md files=true extra=true
  README.md:285 docs/guides/nested-data-access.md files=true extra=true
  README.md:287 docs/guides/custom-functions.md files=true extra=true
  README.md:289 docs/guides/location-expressions.md files=true extra=true
  README.md:291 docs/guides/embedding.md files=true extra=true
  README.md:293 docs/guides/porting.md files=true extra=true
  README.md:295 docs/architecture.md files=true extra=true
  README.md:318 docs/architecture.md files=true extra=true
  README.md:319 docs/isa.md files=true extra=true
  README.md:326 docs/guides/porting.md files=true extra=true
  README.md:332 docs/contributing.md files=true extra=true
  README.md:337 LICENSE files=true extra=true

The eleven distinct targets are the ten docs files this PR adds plus LICENSE, which was already in both.

mix hex.build (file list, tarball deleted afterwards)

Building predicator 9.4.2
  Files:
    lib/predicator
    ... (the lib/predicator tree, unchanged from main)
    lib/predicator/conformance
    lib/predicator.ex
    mix.exs
    README.md
    LICENSE
    CHANGELOG.md
    docs/reference/language.md
    docs/isa.md
    docs/guides/nested-data-access.md
    docs/guides/custom-functions.md
    docs/guides/location-expressions.md
    docs/guides/embedding.md
    docs/guides/simple-subset.md
    docs/guides/porting.md
    docs/architecture.md
    docs/contributing.md
  Version: 9.4.2
Package checksum: 2761ca5168c7d88fb0ec227a954cf5f923e61dbf7be7c3bd809863a549bb4e13
exit=0

lib/predicator/conformance appears as a bare directory entry with no files under it, exactly as on main: exclude_patterns still removes the generator modules.

Full gate, mix quality (quoted whole)

Running quality checks...

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

Running analysis stages in parallel...

○ Doctor: skipped (:doctor not installed)
○ Gettext: skipped (:gettext not installed)
○ Sobelow: skipped (:sobelow not installed)
✓ Dependencies: No unused dependencies (951ms)
✓ Credo: No issues (4.7s)
✓ Tests: 2,914 of 2,914 passed, 95.6% coverage (5.8s)
⋯ Dialyzer: building PLT (this is a one-time cost)
✓ Dialyzer: No warnings (PLT built this run) (49.9s)

✓ All quality checks passed!

The commit's tree is byte-identical (git write-tree before and after git commit) to the staged tree this gate ran green on, so the commit was made directly on that run.

git diff --stat origin/main

 docs/reference/language.md |  4 ++--
 mix.exs                    | 36 +++++++++++++++++++++++++++---------
 2 files changed, 29 insertions(+), 11 deletions(-)

Review (in-turn)

Tier: gate. The diff is 40 changed lines in mix.exs and one guide; it adds no public function, module, option or callback, changes no wire shape or corpus file, and moves no behaviour a record cites (the package file list is packaging, not an API a host codes against). I re-read the diff against the bead and its acceptance criteria. Each doc claim was checked against the code: the call forms JSON.parse(string) and JSON.stringify(value) are the ones the function table at the top of the section already uses; the new package/0 comment's claims (every README relative target ships; each is an extra; the rest of docs/ stays out) match the files: list, the extras list and the README scan above; the docs/0 comment's claim that extras are read off disk at publish time matches the unchanged extras list and the hex.build listing (which shows docs/reference/ast.md, an extra, absent from the package). The conformance paragraph of the package/0 comment kept its content; only its opening changed from "on the same principle" to a standalone "because", since the principle it referred to was the one being rewritten.

Provenance

  • Two lines of the conformance paragraph in package/0's comment were re-worded (see above); the bead named only the docs/ sentence, but that paragraph opened by pointing back to it.
  • The JSON references were fixed by writing them in call form rather than adding skip_code_autolink_to entries: both are predicator language functions, not Elixir functions, and the call form is how the rest of the section names them.

hex.pm renders the package page from the README inside the tarball, so a
relative README link resolves to that path in the tarball and answers 404
unless the file ships. The README links relatively to ten docs files, all
extras and none in package files; each is now in package: [files: ...],
so one relative link works on GitHub, HexDocs and hex.pm alike. The
comments in package/0 and docs/0 said docs/ was deliberately left out
because HexDocs builds from disk; that missed the hex.pm README preview,
and both now give the reason the guides ship. The conformance exclusions
(the files list's lib/predicator* glob with exclude_patterns) are
unchanged.

The language reference named predicator's own JSON.parse and
JSON.stringify in Elixir's arity form, which ExDoc autolinks against
Elixir's JSON module and reports undefined. They are now written in call
form, JSON.parse(string) and JSON.stringify(value), as the function
table above them already writes them, so nothing autolinks and no
skip_code_autolink_to entry is needed. mix docs --warnings-as-errors now
exits 0.

No version bump; no changelog fragment, since changelog.d/README.md
excludes documentation and quality gate changes.

Refs: px-i0dj
@codecov

codecov Bot commented Sep 24, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@johnnyt
johnnyt merged commit 53c51f6 into main Sep 24, 2026
2 checks passed
@johnnyt
johnnyt deleted the px-i0dj-readme-guides-in-package branch September 24, 2026 01:32
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