Skip to content

Promote the AsciiDoc conversion, five-language localisation and publishing pipeline to main - #23

Open
736-c41-2c1-e464fc974 wants to merge 2 commits into
mainfrom
develop
Open

736-c41-2c1-e464fc974 wants to merge 2 commits into
mainfrom
develop

Conversation

@736-c41-2c1-e464fc974

@736-c41-2c1-e464fc974 736-c41-2c1-e464fc974 commented Oct 20, 2026 •

Copy link
Copy Markdown
Collaborator

Promotes to main the work that has been running on develop: the guidelines become a single localised AsciiDoc source tree that renders and publishes itself.

main holds English-only Markdown and ODT files and publishes nothing. After this it holds 15 documents that each carry all five languages in one file, rendered to PDF by open-govpress and published with a language chooser, a per-language index, and an archive of every past build.

Most of this arrived as #21, squashed. Its reasoning — section by section, including the content defects found along the way — is that commit's message.

What changes

Documents. 13 AsciiDoc files replace 10 Markdown files and 4 ODT checklists. The four checklists become AsciiDoc with [%interactive] form fields, so the PDF keeps working checkboxes rather than shipping a separate ODT. 21 PNGs are gone: diagrams are now Mermaid blocks in the source, and the two picture sets that contain words are generated per language by tools/make-four-cs-svg.sh.

Languages. Every document carries English, German, French, Italian and Romansh in one file, guarded by ifeval:: blocks — not five files per document, which drift apart the first time someone fixes a typo in only one. 20 shared fragments in docs/partials/ hold the abbreviation list, glossary, references and document map, one file per language, sliced by tag so each document includes only what it cites.

The German, French, Italian and Romansh texts are unreviewed machine translation. The binding versions remain the ones published in the official languages on the Federal Chancellery website. A FCh translation review is required before the non-English versions here are treated as anything more than drafts. TRANSLATING.adoc states this and documents the conventions.

Rendering and publishing. .github/workflows/render-docs.yml renders the five languages as a matrix, merges them into one site, and deploys to Pages; lint.yml runs 13 pre-commit hooks including a repository-local check-asciidoc that renders every document once per language and checks every cited reference key against the entries actually emitted. Eight scripts in tools/ hold the shell, so shellcheck and editorconfig-checker can see it.

Local builds. devenv.nix and .envrc give render-docs, which produces the same output as CI using the same scripts. DEVENV-SETUP.adoc covers the setup.

Action required after merging: move the publishing branch

The PAGES_PUBLISH_BRANCH repository variable currently reads develop, and the workflow reads it to decide which branch owns the site root. It has to be changed once this merges, or the site will go on tracking develop while main carries the same content.

Settings → Secrets and variables → Actions → Variables — set PAGES_PUBLISH_BRANCH to main, or delete it: unset means main, so removing the variable restores the documented default rather than leaving a second place to keep in sync.

Two things about the timing:

  • The merge's own workflow run will not publish. It is triggered before the variable changes, so its gate still resolves to develop and the publish and deploy steps skip. After changing the variable, re-run Render docs on main — or push to it — to publish from main for the first time.
  • Nothing else needs touching. main is already in the workflow's trigger list and in the github-pages environment's deployment branch policy, both of which were set up to make exactly this switch a one-variable change.

Until the variable moves, pushes to main render and lint — catching breakage — but do not publish, and develop stays the published branch.

v* release tags are exempt and archive themselves under tags/<tag>/ whichever branch is current.

Verified

The pipeline has run green on develop: all five render jobs, the collect job, and the deploy. The site is live:

open-govpress is pinned at 0.0.19 with a SHA-256, in devenv.nix and in the workflow, and the pin was checked by re-rendering rather than by reading a changelog.

Known follow-ups

  • The renderer is re-hosted on a contributor's fork. GOVPRESS_URL and govpressUrl point at a GitHub Release on the fork the conversion was done in, because the 112 MiB binary cannot be committed and Git LFS is blocked on forks. Once swiss/open-govpress publishes a release asset, both should point there — a pipeline on this repository should not depend on a personal fork staying public.
  • No branch protection on main or develop yet. The check names now exist (render (en)…render (rm), collect, deploy, git-hooks), so required status checks can be configured precisely. Any rule must target the two branches specifically rather than a ** pattern, which would block the site-history force-push the publish job depends on.
  • docs/index.adoc does not yet link to the published site; the README now does.

…govpress rendering and publishing pipeline (#21)

## Summary

This turns the guidelines into a single localised AsciiDoc source tree
that renders itself. Today the repository holds English-only Markdown
and ODT files and publishes nothing; after this it holds 15 documents
that each carry all five languages in one file (en, de, fr, it, rm),
renders them to 75 PDFs through
[open-govpress](https://github.com/swiss/open-govpress) — the Swiss
federal AsciiDoc rendering tool — and publishes them to GitHub Pages
with a language chooser, a per-language index, and an archive of every
past build.

Live preview of the result, built from this branch by the same workflow
being proposed here:
[736-c41-2c1-e464fc974.github.io/opensource-guidelines](https://736-c41-2c1-e464fc974.github.io/opensource-guidelines/)

**This needs open-govpress 0.0.19**, which is what the build pins.
Sections 5 to 7 record what each release from 0.0.12 to 0.0.15
contributed, and why — those are the ones this work drove. 0.0.16 to
0.0.19 are upstream releases it did not; the pin was moved to 0.0.19 and
checked by re-rendering, not by reading their changelog.

**How to read the counts and the complaints.** The base of this branch
is 38 files: eight English Markdown documents, four ODT checklists, 21
bitmaps and three config files. Nothing else. So de, fr, it and rm are
new here, and so is every AsciiDoc construct in the diff — the attribute
headers, the `image::` and `link:` macros, the tables, `tools/`, the
workflows and every rendered PDF. Two consequences, applied throughout
below: a number given for the whole set is a per-language figure
multiplied by five, and that multiplication is this branch's doing, not
a quantity the repository already had; and where a defect was created
*and* repaired inside this branch, it says so rather than being filed as
inherited debt. Sections 5, 6 and 8 each contain one of those.

The work, in eight parts — 1 to 4 are the conversion itself, 5 to 8 the
cleanups that followed:

## 1. Markdown/ODT → AsciiDoc

- Every `.md` and `.odt` document converted to `.adoc` and the originals
removed. `git ls-files '*.md'` now returns nothing — the contributor
guides went too, so every tracked document in the repository is linted
by the same gate. `docs/en/` is flattened to `docs/`, since a
per-language directory has nothing left to name once each file carries
five languages.
- The four OSS checklists become `[%interactive]` AsciiDoc checklists —
87 static `☐` glyphs in the ODT source (25/14/9/39) turned into real
fillable PDF AcroForm widgets, not just squares that look clickable.
- Intra-repo `link:` targets point at `.pdf`, because they are followed
inside the rendered PDFs next to their siblings; `README.adoc` keeps
`.adoc` targets, being read on GitHub.
- pandoc left its own litter, cleaned up in the same pass: a stray `\–`
escaping a character AsciiDoc does not treat as markup, and a handful of
alt texts and captions written during conversion that did not match the
picture (see section 3).

## 2. All five languages, in one file per document

- A document is `:lang:` on line 1, a conditional doctitle, a shared
attribute header (pared back in section 8 to only what a renderer
actually reads), and five whole-body `ifeval::` blocks in the order `en,
de, fr, it, rm`. `open-govpress render --lang` pins `{lang}` as a locked
attribute, which drives the guards.
- **`TRANSLATING.adoc` is the entry point for reviewers** — it documents
the file shape, the rules, the Kennzeichnung table and what a translator
can silently destroy. **`DEVENV-SETUP.adoc`** is the companion: Nix,
devenv, direnv, the helper scripts, the hooks, and seven troubleshooting
entries for the failures this setup actually produces. Both carry
`:l10n-languages: en` and render in English only — contributor
documentation has no translated body, and without the attribute each
would take a row on all five index pages. README links to both from all
five language blocks.
- Deliberately one file, not five copies: five copies drift apart the
first time someone fixes a typo in only one of them.
- The title-page Kennzeichnung is per-language and names the DTI sector
per the Federal Chancellery's own pages (the abbreviation differs:
**DTI** de/en, **TNI** fr, **TDT** it and rm). `TRANSLATING.adoc`
settles on TDT, which is what the corpus overwhelmingly uses — 45
against 5 — but **the documents are not yet consistent**: five `TDI`
stragglers remain in the Italian and Romansh blocks, and
`docs/partials/glossary.it.adoc` still defines a `TDI::` entry whose own
expansion spells out TDT. Worth an FCh ruling before this is published.
- `publiccode.yml` gains `rm-CH`.

## 3. Diagrams that are text

The 21 diagram bitmaps — 19 distinct images, two of them used twice —
cannot carry translated labels, so one set of pixels would have had to
serve all five languages. Six already carried text in the wrong language
in the English-only source: four in German (the ZenDiS goals diagram,
and the sovereignty pediment, scale and matrix in Em002-7) and two in
Italian (the publication-measures diagram in Em002-2 and the licence
tree in Em002-3). They are now:

- `[mermaid]` blocks with translated labels — they diff, spell-check and
are reviewable in a pull request. Authored bare, so open-govpress
supplies the project palette.
- Three pictures that were tables all along → real AsciiDoc tables. They
translate, and are announced as tables by a screen reader.
- The four-Cs gears → a generated SVG per language
(`tools/make-four-cs-svg.sh`), so the labels are real text. The PNGs it
replaces had no editable source in the repo at all — the base tree
contains no `.svg`, `.drawio` or `.pptx` of any kind.
- The document map was drawn five times across four documents in the
English source and had already diverged into two disagreeing copies —
they disagree on the key ("Checklists DTI (.odt)" against "Checklists
(.docx)") and on the entire right-hand column. It now lives once per
language in `docs/partials/` and is included at all 25 points.

Two figure captions were casualties of this branch rather than the
source, and are noted here rather than in the pre-existing list:
Em002-5's picture had no caption at all in the Markdown, and the one
written during conversion described the Art. 9 EMOTA process while the
picture shows the four Cs; and Em002-4's Figure 1 was the morphological
box, so converting it to a table left Figure 2 as the only figure, since
renumbered.

`docs/en/assets/` held 1.72 MB of bitmaps across 21 files.
`docs/assets/` is 233 kB, and all but the 154 kB `publiccode.yml`
screenshot is now text.

## 4. Build, CI and publishing

- `devenv.nix` / `.envrc` for local work: `render-docs` (all languages,
or `render-docs de rm`) produces byte-identical output to CI, including
the index pages — an index reimplemented in the workflow is an index
that stops matching what you see before you push.
- `.github/workflows/render-docs.yml`: renders the five languages as a
matrix, merges them into one site, uploads PDFs as an artifact on every
push and PR, and deploys to Pages from whichever branch the
`PAGES_PUBLISH_BRANCH` repository variable names (`develop` here).
- Every build is kept: pushes to the publishing branch land under
`commits/<sha>/` (newest 10) and own the site root, `v*` release tags
land permanently under `tags/<tag>/`. Backed by a `site-history` branch,
since a Pages deployment replaces the whole site and cannot read back
what is published.
- `.github/workflows/lint.yml` runs 13 pre-commit hooks —
whitespace/EOF/symlink/executable checks, `editorconfig-checker`,
`nixfmt`, `yamllint`, `ripsecrets`, `shellcheck -x -o all`, and a
repository-local `check-asciidoc` that renders every document once per
language (a conditional left unterminated in the Romansh block is
invisible while parsing as English) and checks every cited reference key
against the entries actually emitted — see section 6. `typos` and `vale`
are deliberately excluded: they are English-language tools and four of
five languages here are not English.
- The shell that does the work lives in `tools/*.sh` rather than inside
Nix strings, where shellcheck and editorconfig-checker cannot see it.
Two remnants are not yet covered: about twenty lines of
document-selection bash inline in `render-docs.yml`, which also
duplicates the `:l10n-languages:` logic in `tools/render-docs.sh`, and
the short `enterShell`/`scripts` bodies in `devenv.nix`.

## 5. Tables that were never tables

The English source drew 101 Markdown tables — 57 pipe blocks and 44
`<table>` elements — plus four ODT checklists built out of tables
throughout. Converted, that is 114 AsciiDoc tables per language, and
only ten of them per language hold tabular data. The rest are FAQ
question-and-answer pairs, glossaries, reference lists, project
fact-sheets, single-cell callouts, empty write-in boxes, and tables
whose only job was to indent something. They are tables because the
source came out of Word, not because the content has columns.

That matters once these render. open-govpress sets `tr { break-inside:
avoid }` and deliberately keeps it: a row that breaks mid-cell is the
one fragment shape its repair logic refuses to handle, and Paged.js then
abandons the rest of the document. Converted verbatim, a page-tall FAQ
answer becomes an atomic block the layout cannot place — so the remedy
is the construct, not a stylesheet.

Each family moved to the construct that already described it:

- **The Em002-6 FAQ** — 48 tables per language whose first column held
nothing but a localised literal `Q`/`F`/`D` and `A`/`R` — became
`[qanda.unnumbered]`. The bolding convention was applied inconsistently
in the English source and reproduced faithfully across the translations;
the construct supplies the emphasis, so the inconsistency went with it,
along with the legend table that documented the convention.
- **Glossaries, references and the ten Annex D project fact-sheets**
became description lists. Em002-6's glossary came out of the conversion
as a description list already — it was hand-built `<div style="display:
flex">` pairs in the Markdown, not a table — so this finishes what the
first commit started.
- **The chapter-opening definition of digital sovereignty** in Em002-7
became a sidebar, and a source attribution in Em002 became a `NOTE:`,
which also deleted the hand-maintained "Source note:" prefix — one in
the English source, five once translated.
- **The four checklists** lost their wrapper tables. Em002-2.3's third
column was empty in every row in the ODT; the first column was emptied
earlier in this branch by the checkbox conversion, which moved the `☐`
into the list item where it belongs. Neither was doing anything but
indenting.

**The 15 write-in boxes per language were the worst of it — and briefly,
a defect this branch created for itself.** The conversion turned each
empty ODT box into a `[cols="1"]` table holding one empty cell, and such
a table is an *implicit* header row: asciidoctor emits a `<thead>` with
a single empty `<th>` and no body, and the theme paints `th` black.
Every box in all five languages printed as a solid black rectangle —
three of them on page 2 of the English Em002-2.1 — until they became
`field::[]`, a real `/Tx` widget you can type into and save. Together
with the checkboxes, the checklists are fillable rather than
half-fillable.

The same implicit-header trap bit Em002 from the other direction. In the
Markdown all nine measures sat in one `<table>` with `Measure 1:` as an
ordinary bold cell, and HTML has no implicit header, so nothing
repeated. Split into AsciiDoc tables and then rendered by 0.0.12 — which
this PR commissioned, and which repeats a table's header on every
continuation page — "Measure 1: Implement the Practical Guidelines…"
printed as a heading above Measures 3, 6 and 8. Both are gone with the
tables.

Ten tables per language stay, 50 in all, and each earns it: Em002-5's
ten-column target-group matrix, Em002-4's morphological box, Em002-7's
self-assessment grid, use-case classification and WTO-threshold case
distinction, Em002-3's two licence comparisons, Em002-2's document and
platform tables, and Em002-1's constellation/impact pairs. Em002-7 cites
"Table 1" by number in running prose, and Em002-3 numbers its two
licence tables in hand-written captions, so converting either would have
stranded the reference.

Almost no prose changed. Four of the eight commits leave the
per-language word census byte-identical, and three of the other four
differ only by markup that was deliberately removed, `{empty}` guards
that render as nothing, or the `field` and `rows` tokens of the new
macro. The exception is Em002, where ten lead-in sentences named the
construct being removed — "the following table" became the following
overview / Übersicht / liste / elenco / glista — and the "Source note:"
prefix gave way to the localised NOTE label.

**open-govpress 0.0.12 was released for this part**:
`[qanda.unnumbered]`, page-break protection for terms, questions and
bordered blocks, the `field::[]` `/Tx` widget, and tables that repeat
their header and hold their column widths across a page break. One item
was asked for and did not ship — the Romansh admonition terminology in
`attributes-rm.adoc` still needs TERMDAT or a native speaker before a
published document relies on it.

## 6. Lists kept in two places each, and a gate that did not reach
conversion

Three lists — abbreviations, glossary, references — were each maintained
by hand in two documents, spread across Em002, Em002-6 and Em002-7, and
all three had drifted. They now live once, in
`docs/partials/{abbreviations,glossary,references}.<lang>.adoc`, and
each document includes the subset it needs by tag.

The drift is the reason it was worth doing, and it was in the English
source before anything here touched it:

- The **abbreviation** lists (Em002 and Em002-6) differed on four
entries: `AO` read "aApplication owner" in one and "Application owner"
in the other, `HERMES` was italicised in one only, `OSSD` disagreed on
capitalisation, and an organisational unit was "usually an office"
against "usually a federal office".
- The **glossary** (Em002-6 and Em002-7) disagreed on five entries, two
of them rewritten outright, and split the term itself as "Product stand-
ardisation" in one copy.
- Of the **seven** reference keys appearing in both Em002 and Em002-7's
Annex A, five differed in title, in link form, or in both. Annex A had
lost `[DigiV]`'s URL entirely and the head noun from `[BBL-CL]`, which
began mid-phrase, "for Art. 9 EMOTA Blanket Exception". The remaining
two were identical in the Markdown and only diverged here, the
conversion rendering one as `link:url[text]` and the other as `+url+`,
which prints as inert text — drift this branch added, worth closing with
the rest.

**The parse gate this branch added did not reach conversion** — and the
comment explaining why was wrong. `tools/check-asciidoc.sh` went in a
day and ten commits earlier with `--out-file /dev/null`; asciidoctor
special-cases that path and returns *before conversion*, so no
conversion-stage diagnostic could reach it at any `--failure-level`. The
comment I had written blamed the log level instead, which is the kind of
wrong that stops the next person retrying. It now converts for real, and
a companion check compares cited keys against defined ones per document
per language, flattening the corpus with `asciidoctor-reducer` so it
applies the same tag selection that could silently drop an entry.

**Twenty footnotes were being truncated, and that one is this branch's
too.** Asciidoctor ends a `footnote:[…]` at the first unescaped `]`;
Markdown's `[^n]:` has no such rule, so footnotes that cite their source
as `[St2024]`, `[Gu2024]`, `[BBL-WL]` or `[A029]` — four per language in
Em002-1 and Em002-7 — were cut off at the citation and spilled the
remainder into the surrounding paragraph. In one case that was an entire
definition. The closing bracket is escaped now. The checker had been
reading that backslash as part of the key and finding no entry for it,
so it was passing over footnotes in silence; taught the escape, it
checks the keys inside them like any other.

That surfaced references that were already broken in the English source,
and would have been carried into four more languages unchecked:

- Em002-7 defined `[KKB-MB]` while citing `[KBB-MB]` six times without
defining it — six bracketed labels pointing at nothing. One information
sheet, one URL, one letter apart; KBB is Kompetenzzentrum
Beschaffungswesen Bund and the sibling keys are already `[KBB-KV]` and
`[KBB-Perimap]`.
- `BIT-KOM2023`, `BITCOM2024`, `PE1999`, `DigiO`, `OSI2019` and `OSI`
were each cited with no entry anywhere. `[OSI]` deliberately became
`[Pe1999]`, not `[OSI2024]`: the sentence introduces the Open Source
Definition's criteria, and `[OSI2024]` is an alphabetical licence index.

**Em002-7's self-assessment grid is now fillable.** It asks the reader
to place a technology on a five-by-five grid of sovereignty perspectives
against maturity levels, and the source gave them a picture of one — a
bitmap carrying the row and column names and nothing to mark. Section 3
made it a real table; every cell is now an interactive checkbox, 25
`/Btn` widgets per language, filled and read back through pdf.js. Its
two reference tables became description lists.

Every citation in the document set now resolves, and the gate proves it:
exit 0 over the whole corpus with an empty allow-list.

**open-govpress 0.0.13 to 0.0.15 followed.** 0.0.13 implements
`include::[tags=…]`, which the partials depend on — 0.0.12 accepted the
attribute and silently ignored it, the dangerous direction, since stock
asciidoctor honours it and a gate would go green while the PDF shipped
every entry in the file. 0.0.14 adds the three fixes in section 7, and
0.0.15 corrects a paint defect it introduced with them: on a turned page
the app's own viewport backdrop reached the paper, because the print
stylesheet's reset was a less specific selector than the rule it meant
to override and `@media` adds no specificity. Here that was a grey band
down the right third of all four turned pages of Em002-5, in every
language; the exposure was exactly one release wide, since the landscape
role had landed in the commit before. Both defects were specified from
this repo, with measurements, and both were fixed upstream rather than
worked around here.

## 7. Links that went nowhere, and a table that ran off the paper

Two defects in every PDF this renders, invisible to any check in the
repository, both fixed by the renderer rather than by editing the
documents.

**Every inter-document link was dead.** Up to 0.0.13 the renderer
resolved a relative `link:em002-2.pdf[…]` against its own internal
origin and baked the result into the annotation, so the target led
nowhere in any PDF reader. 285 annotations per language, 1,425 across
the set. 0.0.14 rewrites each annotation back to the authored string
after printing, so a relative target passes through *verbatim* — meaning
the 1,080 relative targets authored here (of 1,100 `.pdf` link macros;
the other 20 are absolute URLs) were already correct input. They were
deliberately never rewritten into absolute URLs, which would have had to
be undone. Not one source line changed and all of them now resolve —
`/URI (em002-1.pdf)`.

**Em002-5's target-group matrix ran off the sheet.** Ten columns against
a 453.5 pt measure: with `cols="3,1,1,1,1,1,1,1,1,1"` a narrow column
gets 37.8 pt, and `Geschäftsleitung` — in the German this branch adds —
renders at 81.1 pt, so the surplus was simply painted past the paper
edge: nine words, including `X` and `(X)` data cells, not merely a
clipped heading. A reader could not tell those columns were there. The
Markdown had dodged the width by rotating all nine group headings 90°,
which the conversion to a real table does not carry over.

The renderer now lets cell content break, and says when it had to.
Em002-5 takes the `[.landscape]` role instead, which turns the page that
one table sits on without changing the document type: a matrix whose
headings are broken mid-syllable is legible only in the sense that the
glyphs are on the sheet. It costs two to three pages — 8 to 11 in
English, 8 to 10 in the others; landscape buys width and spends height —
and the attribute sits on the table, not the document, because
`:govpress-style: base-form-landscape` would turn all eight pages of a
prose factsheet sideways *and* declare it a Basisformular, which it is
not.

Both fixes were specified from this repo, with measurements, in
`ai-prompt-wide-tables.md` upstream.

## 8. Headers this branch wrote, then pared back

Two cleanups to the document header — and unlike sections 5 to 7, there
is no inherited defect here at all. The header did not exist before this
branch; both items are its own first draft, corrected once the tool's
real behaviour was known. They are worth a section only because the
reasoning generalises.

**Seven of the nineteen header attributes never reach a reader.** The
conversion gave every document the full open-govpress front-block set,
on the assumption the CLI reads them all. It does not: `:govpress-style:
report` makes open-govpress apply two attribute files of its own
*before* the document's header — `styles/common.adoc` and
`styles/report.adoc`, bundled in the app — and between them they already
set `govpress-front-block`, `title-page`, `pdf-theme`, `title-logo`,
`toc`, `sectnums`, `toclevels`, `sectnumlevels` and `experimental`. They
are applied softly, so a document's own header still outranks them; ours
restated values already in force, byte-identically, fifteen times over.
Dropped.

`:toc:`, `:toclevels:`, `:sectnums:` and `:sectnumlevels:` deliberately
stay, with a comment saying why they look redundant and are not: GitHub
and GitLab render every `.adoc` in the repository with plain
Asciidoctor, which applies none of open-govpress's style files, so
without them the web view of the source loses its contents list and its
section numbering. The rule applied was *drop what no renderer reads*,
not *drop what the PDF does not need*. `:classification:` stays too,
empty and commented, so a document answers the question rather than
leaving it unasked.

**`:url-repo:` was added to all 15 documents and then referenced by none
of them.** Meanwhile the address was written out literally — 14
occurrences in the English source, in four different forms (`/releases`,
the bare root, `/tree/main`, `/tree/main/docs/en`), which this branch
multiplied by five before adding fifteen unused attribute definitions on
top, for 70 in all. All 55 body occurrences now derive from the
attribute, and its value is the repository root rather than `/tree/main`
— the only value all four forms can be built from, and the form
open-govpress's own showcase uses. The repository being a fork makes the
owner segment the part most likely to move, which is now written once
per document instead of spelled out in every link.

The four checklists, `index.adoc` and the README template *lose* the
attribute rather than gaining a reference: none of them links to the
repository at all, so defining it there would have kept the
unused-attribute problem alive in six files.

## Pre-existing content bugs fixed along the way

These were all in the English Markdown, ODT or bitmaps at the base of
this branch, and they were found by converting the source and then
reading it closely enough to translate it.

- **`em002-1.md` had a large duplicated content block** — roughly the
first third of the document repeated, in two differently truncated
forms; four top-level headings appear twice. De-duplicated.
- **Broken `.odt` checklist links** across several documents: a trailing
space before `.odt` in three places, a doubled space and a missing word
in `Em002-4.1 OSS Community.odt`, and a bad root path in the index.
- **Footnotes embedded in heading text** in three places, unsupported
per the AsciiDoc docs. Relocated to the first natural mention of the
same term in the body. (The duplicate element IDs and the stray `[N]` in
the table of contents are how that surfaces once rendered, so the
symptom is this branch's; the malformed headings are not.)
- **Orphaned footnotes** defined but never referenced — in seven of the
eight documents, 43 in total — dropped rather than force-inserted.
- **Footnotes that were nothing but "See: " and a bare URL** — thirteen
in the English source, 65 once translated. The prefix carried no
information and the address stood where a title belonged. The prefix is
gone and each link now has the text it should have had, following the
style Em002-7 already used for its Wikipedia references.
- **Defects baked into the diagram bitmaps**, unfixable without an image
editor: a box in Italian inside the English licence tree ("GPL o licenza
permissiva"); "Verb sements must flow back?", a mangling of
"Verbesserungen müssen zurückfliessen"; an Italian footnote column in
the security-grounds diagram; a decision node with two branches both
labelled "No", which cannot be followed; "Trnsparenz" and
"Altrnativoptionen" in the sovereignty scale; and the morphological box
screenshotted from PowerPoint with an object still selected, grab
handles visible.
- **ODT-conversion artefacts in the English text**, repaired per
document as each was translated — `Fehler! Verweisquelle konnte nicht
gefunden werden.`, an empty `in Section )` cross-reference,
"aApplication owner", "the roject is Free", "must be uthorised",
"Outcomes are feedback continuously", "thus subject to the legal
requirements of a?", "(at noted in Poledna/…", a doubled "in principle",
the misspelt `opdencode.de`, an `eoperation.ch` link contradicting
`eoperations.ch` in the same document, and a fedlex link whose display
text pointed at `/de` while the target was `/en`.
- **`publiccode.yml`'s screenshot** pointed at a bitmap through a
`/blob/` URL, which serves an HTML page rather than an image.

**Left for FCh to decide, as content rather than conversion:** Em002-3
annex D.5 attributes the ASTRA.EMSG road-asset application to
MeteoSwiss, though both its repository and its description point to the
Federal Roads Office. Two more are translation judgements rather than
conversion defects, and are flagged rather than fixed:
`docs/em002-6.adoc` renders ISBO and DSBO as CSI and CPD in the French
block, against the rule in `TRANSLATING.adoc` that role abbreviations
stay as written; and the TDI/TDT split in section 2.

## Repository settings this needs (one-time, by an admin)

Nothing here can be set from a pull request — these are repository
settings, and the publish job stays red until they are in place. Merging
without them is safe: the render job and the PDF artifact work
regardless, only the Pages deploy fails.

**All five are now in place on `swiss/opensource-guidelines`**, checked
against the API rather than read off the UI. The list stays here as the
record of what the pipeline depends on, and of what to redo if the
repository is ever recreated.

**1. Turn Pages on, sourced from Actions.** — *done*
*Settings → Pages → Build and deployment → Source:* **GitHub Actions**
(not "Deploy from a branch"). This is what creates the `github-pages`
environment the deploy job targets. Currently `build_type: workflow`,
serving <https://swiss.github.io/opensource-guidelines/>.

**2. Choose the branch that publishes — `PAGES_PUBLISH_BRANCH`.** —
*done, set to `develop`*
*Settings → Secrets and variables → Actions → Variables.* The workflow
reads this to decide which branch owns the site root and the `commits/`
archive. **Unset means `main`**, which is the behaviour this repository
had before this branch; it is set to `develop` here, so `develop`
publishes and `main` does not.

`on:` is the one block GitHub Actions allows no expressions in, so the
trigger list in `render-docs.yml` stays literal — `branches: [main,
develop]`. The variable picks among the branches listed there rather
than replacing the list, so pointing it at some third branch means
adding that branch to the trigger as well.

The decision is made once, in a `gate` step whose output every
publishing step and the deploy job read back, and
`tools/site-publish.sh` re-checks the same variable before it will touch
the site root. Tags are exempt: a `v*` release archives itself under
`tags/<tag>/` whatever the variable says.

> **`main` does not publish, and never did.** These are the first
workflows the repository has ever had — neither `main` nor `develop`
carries one today, and no Actions run has happened here — so `develop`
becomes the only branch that renders and publishes. `main` is kept in
the trigger list and in the environment's branch policy anyway, so that
moving `PAGES_PUBLISH_BRANCH` back to it later needs no further setup.

**3. Let `develop` and release tags deploy, not just the default
branch.** — *done*
*Settings → Environments → `github-pages` → Deployment branches and
tags.* GitHub creates this environment restricted to the default branch,
so runs from any other ref are rejected with a protection-rule error —
the archive reaches the `site-history` branch but never the site. Both
the publishing branch and the release tags need a rule, so the list
reads:

| Type | Pattern |
|---|---|
| Branch | `develop` |
| Branch | `main` |
| Tag | `v*` |

`main` is deliberately kept: moving `PAGES_PUBLISH_BRANCH` back to it
then needs no environment change.

**4. Leave the default `GITHUB_TOKEN` permissions alone — no change
needed.** — *done (nothing to do)*
*Settings → Actions → General → Workflow permissions* works on either
setting. Both workflows declare `permissions: contents: read` at the top
and raise only what a specific job needs (`contents: write` on `collect`
to push the `site-history` branch, `pages: write` + `id-token: write` on
`deploy`). An explicit block in the workflow overrides the repository
default, so there is nothing to loosen globally.

**5. Check that no ruleset covers `site-history`.** — *done*
The publish job force-pushes a single parentless commit to a
`site-history` branch (created on first run — no need to make it by
hand). An organisation ruleset matching `**` or requiring pull requests
on all branches will block that push. No ruleset currently matches the
branch. It is pure derived output, re-renderable from source at any
time, so exempting it costs nothing.

Nothing needs to be done for pull requests: PR runs never deploy and
never push — they only upload the `site` artifact.

## Notes for reviewers

- **The `open-govpress` binary is re-hosted, and should be repointed.**
open-govpress itself lives at https://github.com/swiss/open-govpress.
Since this repository is on GitHub and needs the binary available to
Actions, the devenv and CI builds fetch the 0.0.19 Linux tarball
re-hosted as a GitHub Release on the contributor's fork
(`open-govpress-v0.0.19`), verified against a pinned SHA-256 —
committing it is not an option (112 MiB, over GitHub's 100 MB limit) and
Git LFS is blocked on forks by GitHub policy. The pin lives in two
places that have to stay in sync:
`govpressVersion`/`govpressUrl`/`govpressSha256` in `devenv.nix`, where
the URL interpolates the version, and
`GOVPRESS_VERSION`/`GOVPRESS_URL`/`GOVPRESS_SHA256` in
`.github/workflows/render-docs.yml`, where it is literal. Once
`swiss/open-govpress` publishes a release asset of its own, both should
point there — a pipeline on this repository should not depend on a
personal fork staying public.
- The document revision is bumped to 2.0, tagged `v2.0`.
- Suggested reading order: `TRANSLATING.adoc`, then one document
(`docs/em002-5.adoc` is the smallest and was the proof of the
mechanism), then `tools/`. `DEVENV-SETUP.adoc` if you want to build it
yourself first.
The pipeline publishes every document, in all five languages, and
nothing in the repository said where. Adds one line per language block,
after the line that names the document index.

The address is a shared `:url-site:` attribute beside `:url-repo:`
rather than five literals: the site carries all five languages behind
one chooser, so there is nothing to localise in the address, and
TRANSLATING.adoc already states the rule that an attribute reference is
not text to be translated. That rule enumerated the shared attributes,
so it is updated to name this one too.

Link display text is the bare address. Everything around it is
translated, but the label needs no review in four languages it would
otherwise have to be read in.

Rendered in all five languages and checked: the attribute expands, and
each PDF carries an annotation to the published site, not just the text.

This branch was successfully deployed

1 active deployment
github-pages — fa56f477 Deployed Oct 20, 2026 by 736-c41-2c1-e464fc974 via deploy #3
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