Antora migration polish: zero warnings + local mermaid + CI fix (#496)#497
Merged
michalharakal merged 4 commits intodevelopfrom Apr 13, 2026
Merged
Antora migration polish: zero warnings + local mermaid + CI fix (#496)#497michalharakal merged 4 commits intodevelopfrom
michalharakal merged 4 commits intodevelopfrom
Conversation
Adds an `asciidoc.attributes` block to `docs/antora.yml`
defining the four attributes `operator-design.adoc` references
but nobody declares:
framework_name = SKaiNET
ksp_version = 2.2.21-2.0.5
dokka_version = 2.1.0
asciidoctorj_version = 3.0.0
Antora treats component-level attributes as defaults for every
page in the component, so the seven `{FRAMEWORK_NAME}` /
`{KSP_VERSION}` / `{DOKKA_VERSION}` / `{ASCIIDOCTORJ_VERSION}`
references across lines 1, 8, 30, 78, 176, 177, 178, 215 of
`operator-design.adoc` now resolve to real values instead of
falling back to the literal attribute-name placeholder and
producing a warning.
Net warning count dropped from 13 to 7. The remaining 6 are
the pandoc section-level artifacts in `skainet-for-ai.adoc` and
`arduino-c-codegen.adoc` (commit 2) plus the kroki mermaid
400 on the large `hlo-getting-started.adoc` diagram (commit 3).
First step of the Antora migration polish pass. See #496.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Clears 6 section-title-out-of-sequence warnings across `skainet-for-ai.adoc` (5 occurrences) and `arduino-c-codegen.adoc` (1 occurrence) that were left over from the pandoc markdown -> asciidoc conversion in #494. Two interacting issues: 1. Pandoc generated 20 anchor lines of the form `[[1-tape-based-tracing]]`, `[[2-type-safe-tensor-creation-dsl]]` etc. These are standalone block anchors sitting ABOVE their section heading. In this position Asciidoctor treats them as bibliographic block markers that bind to the next block — which prevents the following `==` / `===` from registering as a section-opening heading, so the parser's section-level counter drifts and every subsequent nested heading trips the "expected level N, got level N+1" validator. The anchors are all auto-generated slug form of the heading text they precede. Asciidoctor auto-generates equivalent id-from-title anchors for every heading. Deleting these 20 anchors sacrifices nothing — the id format is the same, the #fragment URLs stay stable. 2. Pandoc converts markdown `#` to asciidoc `==` rather than the more idiomatic `=` (page title). That made every converted page "off by one" with no level-0 title. Demoting every heading by one step (remove one `=`) fixes this: the page now starts with `= Title` and section levels cascade naturally from there. Applied via `sed -E -i '' 's/^=(=+ )/\1/'` on the two affected files — matches `^=` followed by one-or-more additional `=` followed by a space, preserves block delimiters like a bare `====$` that aren't headings. Applied only to files that were flagged; the rest of the migration's converted files had clean hierarchies already. Net: warning count drops from 7 to 1. The remaining warning is the kroki mermaid 400 on the large diagram in `hlo-getting-started.adoc` which commit 3 will handle. Second step of the Antora migration polish pass. See #496. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
First run of the #494 docs.yml workflow on CI failed with: > Task :bundleDokkaIntoSite FAILED > Failed to create directory '/home/runner/work/SKaiNET/SKaiNET/docs/build/site/api' Root cause: the Antora step ran the node:20-alpine container as root (the default), so `docs/build/site/` and everything under it was owned by root. The subsequent Gradle `bundleDokkaIntoSite` step runs on the runner host as the `runner` user — which cannot create a subdirectory inside a root-owned tree. Two coupled fixes, both necessary: 1. `.github/workflows/docs.yml`: add `--user $(id -u):$(id -g)` to the `docker run` invocation. The container process now writes as the runner user and everything under `docs/build/site/` is owned correctly when Gradle takes over. 2. `docs/antora-playbook.yml`: add a `runtime.cache_dir: ./.cache/antora` setting. Without --user the default $HOME/.cache/antora resolution worked; with --user the container process has no matching passwd entry and $HOME falls back to `/`, so Antora would fail with `Failed to create content cache directory /.cache/antora; EACCES: permission denied`. Pointing cache_dir at a path under the mounted workspace makes it writable by the non-root user. The `.cache/` path is already gitignored via the pre-staged `## antora` section in the repo root .gitignore, so the cache never gets committed. Verified end-to-end locally with the CI flow: rm -rf docs/build/site docs/.cache docker run --rm --user "$(id -u):$(id -g)" \ -v "$PWD:/antora" -w /antora \ skainet-antora:local docs/antora-playbook.yml ./gradlew --no-daemon bundleDokkaIntoSite docs/build/site/ owned by $USER:$GROUP, api/ subtree populated with the Dokka aggregate. Third step of the Antora migration polish pass. This commit is independent of the earlier warning-clearance work — it unblocks CI regardless of what other polish happens next. See #496. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replaces the asciidoctor-kroki dependency with a small local
Asciidoctor block processor that invokes the @mermaid-js/mermaid-cli
binary baked into the Antora Docker image directly. Eliminates the
last build warning AND removes the build-time network dependency
on kroki.io entirely.
## Why
asciidoctor-kroki sends the diagram source to kroki.io (by default
via GET with the source encoded into the URL). The GET path has a
4 KB URL length limit, so larger diagrams come back with HTTP 400
and the block is silently dropped. Switching the extension to POST
did not help — kroki.io also rejected the content for a different
reason, with an empty response body and no diagnostic. Turning
around each mermaid block through a network round trip for every
build was already a sore point; finding that the only path to
reliable rendering was "give up on the external service entirely"
made the decision clear.
The new pipeline is purely local:
[mermaid] --> local-mermaid-extension.js
---- --> writes source to /tmp/skainet-mm-*/in.mmd
source --> exec mmdc -i in.mmd -o out.svg
---- --> reads out.svg
--> emits as a `pass` block (inline SVG)
mermaid-cli was already in the image from day one for the
asciidoctor-kroki "local fetch" path. Removing kroki and wiring
mermaid-cli directly via a 70-line extension is a strictly smaller
build dependency tree and strictly more reliable: no network, no
rate limits, no URL length caps, no flakes on CI, deterministic
outputs.
## Changes
1. `docs/.docker/Dockerfile`:
- Drop `asciidoctor-kroki@0.18` from the npm install list.
- `COPY local-mermaid-extension.js /opt/antora/` so the
playbook can reference it by absolute path without any
volume-mount gymnastics at run time.
- Update the image description label.
2. `docs/.docker/local-mermaid-extension.js` (new):
Asciidoctor.js block processor mirroring the shape used by
asciidoctor-kroki (same onContext / process / createBlock
pattern) but dispatching to /opt/antora/node_modules/.bin/mmdc
via child_process.execSync with the Puppeteer config the image
already writes at /opt/antora/puppeteer-config.json. Renders
to a temp dir, reads the SVG, returns it inline via a `pass`
block. Cleans the temp dir in a finally. On render failure
emits a literal block containing the original mermaid source
+ the stderr from mmdc and logs a warning, matching the
degradation style of the upstream kroki extension.
3. `docs/antora-playbook.yml`:
- Swap `asciidoctor-kroki` extension for
`/opt/antora/local-mermaid-extension.js`.
- Drop the `kroki-fetch-diagram` and `kroki-http-method`
attributes — both dead code now.
4. `docs/modules/ROOT/pages/tutorials/hlo-getting-started.adoc`:
The first render against real mermaid-cli surfaced a
previously-hidden authoring bug: one of the `sequenceDiagram`
participants was aliased as `Opt`, and `opt` is a mermaid
sequenceDiagram keyword (for optional blocks). Mermaid's
parser matches keywords case-insensitively and was treating
`Opt` as the start of an opt-block, producing:
Parse error on line 12: ...HLO->>Opt: Unoptimized IR
Expecting '+', '-', '()', 'ACTOR', got 'opt'
Rename the alias to `Optimizer` and drop the `as` clause.
Kroki had been silently rejecting this diagram for a
different reason the whole time; local rendering surfaced
the actual bug.
## Verification
docker build --no-cache -t skainet-antora:local docs/.docker
rm -rf docs/build/site docs/.cache
docker run --rm --user "$(id -u):$(id -g)" \
-v "$PWD:/antora" -w /antora \
skainet-antora:local docs/antora-playbook.yml
grep -c "<svg" docs/build/site/skainet/tutorials/hlo-getting-started.html
# => 3 (one inline SVG per [mermaid] block, all three diagrams)
./gradlew --no-daemon bundleDokkaIntoSite
ls docs/build/site/api # full Dokka aggregate present
Antora warnings + errors on the full build: 0 + 0. Down from the
13 warnings the Antora migration landed with in #494.
Fourth and final step of the Antora migration polish pass. See #496.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
📖 Documentation Preview The documentation has been built successfully for this PR. Generated Files:
Artifacts:
This comment will be updated automatically when the PR is updated. |
This was referenced Apr 13, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #496. Also unblocks the failing `bundleDokkaIntoSite` CI run on develop (see commit 3 below).
Summary
Clears every warning emitted by the Antora build, fixes a CI permission failure that was hiding behind the first post-merge `workflow_dispatch` of `docs.yml`, and replaces the asciidoctor-kroki dependency with a local mermaid renderer so builds no longer depend on kroki.io at all.
Warning count: 13 → 0. Errors: 0.
Four commits
1. `4a745624` — component attributes for operator-design
Adds `asciidoc.attributes` block to `docs/antora.yml` defining `framework_name`, `ksp_version`, `dokka_version`, `asciidoctorj_version` — the four attribute references in `operator-design.adoc` the original author never declared. Antora component-level attributes flow to every page, so seven `{FRAMEWORK_NAME}` / `{KSP_VERSION}` / `{DOKKA_VERSION}` / `{ASCIIDOCTORJ_VERSION}` placeholders now resolve to real values. 13 → 7 warnings.
2. `7a459bf3` — strip pandoc anchors + cascade-demote headings
The 6 "section title out of sequence" warnings in `skainet-for-ai.adoc` and `arduino-c-codegen.adoc` looked like they were about heading levels but turned out to be about 20 `[[...]]` anchor lines that pandoc generated above every heading. In that position Asciidoctor binds them to the next block as bibliographic markers, which blocks the `==` / `===` from registering as section-opening headings, which drifts the parser's level counter. Stripping the anchors fixes the hierarchy parse; Asciidoctor auto-generates id-from-title anchors anyway so URL fragments stay stable. Also cascade-demoted the two files' headings by one level (`sed -E 's/^=(=+ )/\\1/'`) so they start with the idiomatic `= Page Title`. 7 → 1 warning.
3. `ca06cf51` — CI permission fix on bundleDokkaIntoSite
First CI run of the post-migration `docs.yml` failed with `Failed to create directory docs/build/site/api` during the `bundleDokkaIntoSite` step. Root cause: the Antora container was running as root, so `docs/build/site/` was root-owned, and the subsequent Gradle task (running on the runner host as the `runner` user) couldn't `mkdir` inside it.
Two coupled fixes, both necessary:
Verified end-to-end locally with the full CI flow (clean site dir → non-root Antora run → writable cache dir → Gradle bundle succeeds → `docs/build/site/api/` populated with the Dokka aggregate).
4. `724f72bd` — drop kroki, render mermaid locally
The final warning was `asciidoctor-kroki: Skipping mermaid block` in `hlo-getting-started.adoc`. Kroki was returning HTTP 400 for one diagram; switching from GET to POST didn't help (kroki.io rejected the POST for a different reason with an empty response body). The fix is to stop using kroki at all and render mermaid locally via `@mermaid-js/mermaid-cli` which the Docker image already bakes in.
Pipeline change:
Changes:
Verification
Warning count: 0. Error count: 0. Rendered inline SVG count: 3.
Net effect
🤖 Generated with Claude Code