Architecture
One toolkit, used two ways: by the Publication Console's central steps, and by TC repositories that pin it by commit SHA.
1.Toolkit and consumers¶
flowchart TD
classDef toolkit fill:#15446c,stroke:#0d2c47,color:#ffffff,stroke-width:2px;
classDef consumer fill:#f7f9fb,stroke:#c8d2dd,color:#14202c,stroke-width:1.5px;
T["OASIS-Docs/publisher-toolkit
private
lib/: step_1, step_2, step_2_chrome
lint_html, robust_run, pa_pipeline
.github/workflows/: step_1 to step_6 (central)
templates/: workflow_step_1.yml, workflow_step_2.yml"]:::toolkit
C["Publication Console
steps 1.0 to 6.0
run the toolkit's own workflows
against any OASIS-Docs repo"]:::consumer
A["OASIS-Docs/tc-name
source + generated HTML / PDF / ZIP
(no workflow needed)"]:::consumer
P["OASIS-Docs/pinned-tc
.github/workflows/ step_1, step_2
actions/checkout ref: 40-char SHA"]:::consumer
T -->|workflow_dispatch
toolkit at main| C
C -->|checkout, build, commit back| A
T -->|actions/checkout
ref: pinned SHA| P
Central steps. The workflows step_1_md_to_html.yml to step_6_golive_to_prod.yml live in this repository. The Publication Console dispatches them on the toolkit's default branch. Each build step (1.0 to 4.0) checks out the target TC repository, builds, and commits the generated files back; steps 2.5 and 5.0 only read, and step 6.0 deploys, first committing manifests to the TC repository if the package has none. A TC repository needs no workflow of its own for this path, and it always gets the toolkit as it is on main at the time of the run.
Pinned consumers. A TC repository can instead carry its own step_1 and step_2 workflows, copied from templates/, which check the toolkit out at an explicit 40-character commit SHA. Toolkit upgrades are then a one-line ref: change in the consumer's workflow file. OASIS-Docs/dps and OASIS-Docs/niemopen work this way; scripts/verify_consumer_pin.sh lists the SHA each one pins.
2.Chain run sequence¶
For a pinned consumer, one chain is two workflow runs (step_1 then step_2), executed in the consumer TC repo. The central steps 1.0 and 2.0 do the same work inside the toolkit's own workflows.
sequenceDiagram
autonumber
actor Operator as Operator (TC Administration)
participant TC as OASIS-Docs/tc-name
participant Run as GitHub Actions runner
participant Tool as publisher-toolkit @ SHA
Operator->>TC: commit spec MD
Operator->>Run: gh workflow run step_1
Run->>TC: checkout @ HEAD
Run->>Tool: checkout @ pinned SHA
Run->>Run: pip install requirements
Run->>Run: apt install pandoc
Run->>Run: python -m lib.step_1_markdown_to_html_converter
(pandoc → HTML, strip D2/D3)
Run->>TC: commit generated .html
Operator->>Run: gh workflow run step_2
Run->>TC: checkout @ HEAD
Run->>Tool: checkout @ pinned SHA
Run->>Run: pip install + wkhtmltopdf
Run->>Run: python -m lib.lint_html
(D1..D7 checks)
Run->>Run: python -m lib.step_2_convert_html_to_pdf
(wkhtmltopdf → PDF)
Run->>Run: assert_pdf_quality
(A1 cover title, A2 no runner leak)
Run->>TC: commit generated .pdf
Since v0.4.0, step 2 prints with the OASIS PDF step vendored from OASIS-Docs/publication-assurance into lib/pa_pipeline/ (A4, the published footer, a numbered table of contents). lib/pa_pipeline/VENDORED.json records the upstream tag, commit and file hashes, and tests/test_pa_pipeline_vendored.py fails if a vendored file changes. Since v0.5.0, both renderers (lib/step_2_convert_html_to_pdf.py on wkhtmltopdf and lib/step_2_chrome.py on headless Chrome) run through lib/robust_run.py, which bounds the run and ends it with one STEP2 status line.
A pinned consumer's step_3 (ZIP bundle) and step_4 (latest-stage links) run after step_2 from its own workflows and do not use the toolkit. In the central chain, step 3.0 builds the ZIP and step 4.0 writes the manifests.
3.Responsibilities by repository¶
| Concern | Toolkit | Consumer TC repo |
|---|---|---|
| Pipeline code (md → html → pdf) | yes | |
| Pre-PDF checks (D1..D7) | yes | |
| Post-PDF assertions (A1, A2) | yes | |
The OASIS PDF step (lib/pa_pipeline/, vendored) |
yes | |
| Central workflows, steps 1.0 to 6.0 | yes | |
| Workflow templates | yes | yes (instantiated copy, pinned consumers only) |
| Spec source MD | yes | |
| Generated HTML / PDF / ZIP | yes | |
Spec-dir styles/*.css |
yes (downloaded once by step_1, then frozen) | |
.githooks/ |
yes | |
.file-metadata |
yes | |
| step_3 (zip) and step_4 (symlinks) workflows | yes (pinned consumers only) |
4.Reasons for a pinned SHA¶
For TC repositories that run the toolkit from their own workflows, three options were considered, and pinned SHA via actions/checkout was chosen.
| Option | Why rejected |
|---|---|
pip install from private GitHub URL |
Requires a token in every workflow. Harder to audit than a checkout step. No private package index available |
| Git submodule | Entangles toolkit version with the TC's commit graph. Toolkit upgrade becomes a two-step commit in every consumer |
actions/checkout with ref: <SHA> |
Immutable, reviewable in the consumer's PR, rollback is a one-line revert |
The pin must be the commit SHA, not the tag. Toolkit tags are annotated, so a tag has its own object SHA, which is not a commit; see upgrading the toolkit pin.
