Skip to main content

Wiki Publishing

See also: Tooling and Scripts, CI CD and Deploys, Data Model

The wiki/ folder in the main repo is the wiki — there is no GitHub wiki (this repo's wiki was never readable without paying for seats; the old publish-wiki.yml mirror was removed 2026-07-19). Pushes to main that touch wiki/** fan out to the sibling fun-language/Stretched-wiki repo via .github/workflows/notify-wiki.yml, which fires a repository_dispatch (event_type=wiki-updated); that repo builds and serves the public site, see CI CD and Deploys and Secrets Management. Agents and contributors read the markdown directly; humans who want a browsable site serve it locally:

Serving the wiki​

bun run wiki:serve # http://localhost:4201 — pages render from wiki/*.md on EVERY request
bun run wiki:site # static export → dist/wiki (index.html = Home)

tools/wiki/render-site.ts (+ serve-wiki.ts) renders GitHub-flavored markdown with the wiki conventions intact: [[Page Title]] / [[Alias|Page Title]] cross-links, relative [text](../Page.md) links, _Sidebar.md as the nav, and ```mermaid fences rendered client-side with a vendored mermaid bundle (no CDN — the site works offline). Because wiki:serve renders per request, an edit or a wiki:build regeneration shows up on reload; there is no watcher or rebuild step.

Deployment: every PR gets a wiki preview alongside the app and Storybook — deploy-preview.yml builds dist/wiki and deploys it to a Firebase Hosting preview channel on the stretched-dev-wiki site (1-day expiry; the action comments the URL on the PR). Preview channels are unlisted-URL public — the wiki documents internals, and Harlo accepted that exposure for PR review (2026-08-02). On merge to main, notify-wiki.yml notifies the sibling fun-language/Stretched-wiki repo (repository_dispatch); that repo is the source of truth for the public, always-on wiki site. This repo does not host the public wiki itself — the dispatch is fire-and-forget at the workflow layer, so a dispatch failure does not corrupt wiki/; the next push re-triggers. Before firing, the workflow runs a real production build (bunx nx build stretched --configuration=production, same as ci.yml) — without it wiki:build SKIPS generated/Production-Bundle.md — then re-runs bun run wiki:build and requires an empty git status --porcelain over wiki/. Porcelain catches modified, deleted-then-recreated (untracked) AND the hybrid Data-Model.md (regenerated OUTSIDE wiki/generated/), all of which a plain git diff over wiki/generated/ would miss — so a direct or hookless push can never publish a snapshot this repo's own wiki gate rejects. The PAT that authorizes the dispatch (secrets.WIKI_DISPATCH_TOKEN) is a GitHub Actions secret — see Secrets Management for setup and rotation.

The generated section (wiki/generated/)​

Machine-written pages — never hand-edit them. Every page opens with a visible banner naming its generator, its data source, and the refresh command; all diagrams are mermaid fences, so the pages render on GitHub and in the local site alike. Generated Docs (wiki/generated/README.md — itself generated from the page registry in tools/build-wiki.ts) is the canonical index of the section and the guide for adding a new generated page — this page deliberately doesn't duplicate that table.

Data Model is the older hybrid pattern: a hand-written page whose ERD block is injected between ERD:START/ERD:END markers from the stretched-types README.

Commands and gates​

bun run wiki:build # regenerate every page whose inputs are available + link-check
bun run wiki:check # gate (pre-push + CI docs job): broken link ⇒ exit 1; drift ⇒ notice
bun run wiki:bundle:check # Production-Bundle.md ONLY — needs a fresh prod build
bun run wiki:test # unit tests for the generators (tools/build-wiki.spec.ts)

Generated pages are auto-accepted (2026-08-04). Machine pages carry no hand-authored content, so whatever the generators produce IS the wanted content: the pre-push hook runs wiki:build and auto-commits any refresh (chore(wiki): regenerate machine pages, same contract as the prettier step), and wiki:check reports drift as a notice (with a committed-vs-fresh diff of the differing lines) instead of failing — only broken links fail the gate. Drift can still reach CI from a hookless push or a PR behind main; it heals on the next hooked push.

Auto-accept makes determinism MORE load-bearing, not less: a nondeterministic generator wouldn't fail a gate anymore — it would make the hook commit a phantom "refresh" on every push, forever. Generators must obey Generator Determinism — the incident log there is why. Two timing details:

  • wiki:bundle:check runs right after the production build (after bundle:check) in both the pre-push hook and CI's test job — never in the build-less docs job, and wiki:check never diffs the bundle page. So the page is always checked against the build that just ran.
  • The coverage page merges, it doesn't demand. A project with a coverage-summary.json on disk gets fresh numbers; a project without one keeps its committed row. If a stale summary from another branch skews the page, rerun that suite with --coverage (or delete coverage/<project>) and wiki:build.

Editing the wiki (hand-written pages)​

  1. Edit or add a wiki/*.md page (in a PR).
  2. New page? Name it Your-Title.md (hyphens become spaces in the title), add it to wiki/_Sidebar.md and Home, and link it from related pages.
  3. Cross-link with [[Page Title]] (e.g. [[Data Model]]).
  4. Run bun run wiki:check locally before pushing (wiki:build to also refresh generated pages).

When to update a page​

Source files that a page documents carry a pointer of the form:

> 📖 **Wiki:** see [[Page Title]] for … Update that page when you change …

If you touch code behind a 📖 Wiki pointer, update the referenced page in the same change. Generated pages are the exception — they regenerate themselves; you only ever run bun run wiki:build (never hand-edit the output).