Skip to the content.

Wiki synchronization

The Markdown files under docs/ are the canonical source for the project documentation. The GitHub Pages site and Sync Wiki workflows publish two views of that source. Neither published target is an independent source of truth.

Both publishers build one case-safe index of every canonical file before they write a destination. Relative page, image, and asset links are resolved from the linking source page. Missing files, directory escapes, malformed encoding, absolute local paths, case-only filename collisions, and duplicate flattened Wiki page names fail validation before a Wiki checkout can be mutated or a Pages artifact can be uploaded. Query strings, fragments, optional Markdown titles, and percent-encoded path components are retained.

The Pages workflow first creates an isolated Jekyll-ready staging tree. Nested source directories remain nested, local page links become .html routes, and asset paths remain relative to the linking page. The staging tree adds the source commit and page metadata used by Jekyll; it never changes canonical Markdown:

python scripts/prepare_pages_source.py \
  --source docs \
  --destination /path/to/pages-source \
  --source-sha "$(git rev-parse HEAD)"

The Sync Wiki workflow validates the canonical source and runs the same local command used by maintainers:

python scripts/sync_wiki_docs.py --source docs --destination /path/to/wiki-checkout

GitHub Wiki managed scope

Every regular *.md file below the source directory is copied to the top level of the wiki checkout using its basename. For example, docs/guides/CLI.md maps to CLI.md. Validation rejects symlinks and duplicate basenames before the destination changes, so this flattening is deterministic.

Repository-relative Markdown page links retain their .md suffix in the canonical source. The synchronizer resolves them before flattening, then maps them to the unique extensionless Wiki page name so GitHub routes navigation through the Wiki UI instead of serving raw Markdown. Local image and asset links are normalized to canonical source-root paths because the Wiki pages are flat. Every referenced local asset is copied to that path in the Wiki checkout. The synchronizer records only those copied paths in .ancestryllm-managed-assets.json; on a later run it removes assets that disappeared from the canonical links while preserving unrecorded Wiki files. Unsafe, malformed, or symlinked manifest paths fail before destination content changes. External links and code examples remain unchanged; queries, anchors, and Markdown link titles are preserved.

validate_wiki_docs.py also requires one nonempty, unique title and description in _data/page_metadata.json for every public Markdown page. Pages renders those fields as title, description, canonical, and Open Graph metadata. The generated-site validator checks that metadata, every rendered internal route and anchor, robots.txt, sitemap.xml, and the exact source-commit marker before upload. The deployment job checks representative production routes and the same marker after deployment.

External HTTP links are deliberately excluded from pull-request jobs. A scheduled or manually dispatched trusted workflow deduplicates them, rejects private or special-use destinations and unsafe redirects, rate-limits each host, and checks them with bounded concurrency and retries:

python scripts/check_external_doc_links.py \
  --source docs \
  --exceptions docs/_data/external_link_exceptions.json

An exception must identify the exact URL, an accountable owner, a nonempty reason, and an ISO expires date. Expired, duplicate, unsafe, or stale exceptions fail the workflow.

All top-level *.md files in the wiki checkout are managed. A managed page is removed when there is no source page with the same name. Referenced local assets and their hidden manifest are also managed. The .git directory and all unrecorded non-Markdown paths are outside the managed scope and remain untouched.

The synchronizer writes only pages whose bytes differ. Repeating the command with unchanged documentation therefore leaves the wiki checkout with an empty Git diff.

Bot commit and push

The workflow passes the synchronized checkout to commit_wiki_changes.py. The script stages the complete wiki worktree, exits successfully without a commit when the staged diff is empty, and commits additions, modifications, and deletions with the standard github-actions[bot] author and committer identity. Its commit message includes the source repository SHA as docs: synchronize from <source-sha>.

The commit step exposes only a committed workflow output. The separate push step runs only when that value is true. The job-scoped token is limited to the authenticated clone and push steps; it is never written to the wiki checkout or passed to the local commit script.