The spec polled /generated/licensing.html, which the server can only answer with 404. Every unmatched path goes through _version() at server.py:124, where the first segment is checked against library.versions(), and that list is [latest, *release_tags, deployed] and nothing else. The word generated is a directory inside a version tree, never a version, so the poll could not succeed whatever the build did. It then held the full resolveTimeout(5_300_000) budget before giving up.
Sphinx writes the page one level down: commands.py:37 sets generated = src / "generated" and line 112 writes generated/licensing.rst into it, so the address is /deployed/generated/licensing.html. The sibling spec had it right all along, test-yaml-page.js:5 being /deployed/compose.html, and this spec is a copy of it that lost the segment while keeping the comment about the deployed working tree on line 25.
Nine jobs of run 39530674125 fail on this one line. The rescue bundles settle it in a single pair of counters from one container in one window: 222 requests for /generated/licensing.html answered 404 beside 2 for /deployed/compose.html answered 200, with the container running and healthy throughout.
It is not the ModuleNotFoundError that 6f7dda1a9f guards. That one is real and belongs to the latest and v16.2.1 builds, which answer 500, and no spec in the run requests /latest/ anything. Both changes are needed and neither substitutes for the other.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Documentation
Description
This role publishes the Infinito.Nexus documentation for the latest commit and for every release tag. It builds the repository's Markdown, reStructuredText and role READMEs into an HTML site with Sphinx and the Awesome Sphinx Theme. There is no database.
Overview
One python:<version>-slim container runs the service in files/python/infinito_docs/:
- It keeps a git mirror of
services.docs.source_repositoryin thedocs_sitesvolume and fetches it everyservices.docs.fetch_intervalseconds, or later when a build is still running. latestis the last commit of the default branch. It is built at start and rebuilt whenever a fetch finds a new commit; the previous build stays online until the new one replaces it.- A release tag (
vX.Y.Z) is built the first time someone opens it. The browser shows a progress bar and reloads once the build is done. Tags never change, so each tag is built only once. - Up to
services.docs.build.parallelbuilds run at once, each withservices.docs.build.jobsparallel Sphinx processes.jobsdefaults to half the host's CPUs,parallelto the same number capped at 2. A free slot claims a translated site only once its version is current, so a version and its first language run in sequence. - Every replica serves from the shared
docs_sitesvolume. The replica holdingbuilder.lockin that volume fetches and builds; the queue (queue/) and the build states (states/) are files beside the sites, so a new lock holder resumes the queue when the builder dies. Cross-node locking relies on NFSv4, the default ofsvc-storage-nfs-client.
| Path | Content |
|---|---|
/ |
Redirect to /latest/ |
/<version>/... |
The built site, or its build progress |
/versions/ |
Every version with its build status and progress |
/api/versions |
The same as JSON |
Every page carries a version switcher in its sidebar. Switching keeps the current page and falls back to the start page of a version that lacks it.
Features
- Every release: The latest commit is the default, each release tag is selectable and built on demand.
- Generated reference: API pages via
sphinx-apidoc, one page per role from itsmeta/main.ymland README, and an index of every YAML file. - Folder navigation: The sidebar mirrors the repository tree and highlights the current page and heading.
Configuration
Override these keys of services.docs in the inventory:
| Key | Purpose |
|---|---|
source_repository |
Repository to document, e.g. a fork |
fetch_interval |
Seconds between two fetches of new commits and tags |
build.jobs |
Parallel Sphinx processes per build; defaults to half the host's CPUs, raise cpus and mem_limit with it |
build.parallel |
Builds running at once; defaults to half the host's CPUs capped at 2, and each one costs another scratch tree on disk |
cpus |
Container CPU cap; also takes a percentage of the host, e.g. 50%, see sys-svc-container |
applications:
web-app-docs:
services:
docs:
source_repository: https://git.example.com/your-org/core.git
build:
jobs: 4
parallel: 2
cpus: "4"
mem_limit: 8g
Delete sites/<version> inside the docs_sites volume to rebuild a version on its next visit.
Further Resources
- Sphinx Official Website
- Awesome Sphinx Theme
- Corporate design review: the documentation site in light, dark, desktop and mobile
Persona contract opt-outs
The role publishes a public documentation site. meta/services.yml pins sso.enabled and sso.shared to false, and the role ships no meta/users.yml and no account provisioning; templates/env.j2 only configures the build service. tasks/main.yml only wires the container and proxy stack and stages the Sphinx tooling into the build context.
There is no account and no auth chain for the biber or administrator persona, so templates/playwright.env.j2 declares PERSONA_BIBER_BLOCKED=true and PERSONA_ADMINISTRATOR_BLOCKED=true. The guest persona and the baseline reachability and CSP assertions run unconditionally.