Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
7 changes: 2 additions & 5 deletions .github/workflows/docs-audit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ name: Docs Audit

on:
pull_request:
push:
branches: [main, master]

workflow_dispatch:

permissions:
Expand All @@ -18,9 +17,7 @@ jobs:
with:
node-version: '24'
cache: npm
- uses: actions/setup-python@v5
with:
python-version: '3.12'

- run: npm ci
- run: npx playwright install --with-deps chromium
- run: npm run check
Expand Down
13 changes: 10 additions & 3 deletions .github/workflows/pages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,20 @@ jobs:
with:
node-version: '24'
cache: npm
- uses: actions/setup-python@v5
with:
python-version: '3.12'

- run: npm ci
# Upstream ingestion is manual. Validate only the committed public sources.
- run: npx playwright install --with-deps chromium
- run: npm run check
- name: Verify source files remain unchanged
run: |
git diff --check
git diff --exit-code
- uses: actions/upload-artifact@v4
if: failure()
with:
name: browser-test-results
path: test-results/
- uses: actions/upload-pages-artifact@v3
with:
path: public
Expand Down
132 changes: 118 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ chapters, and documentation for Runtime, Silk, Virtnosis, Sage, and slg.

## Local development

Use Node 24 and Python 3.12. No sibling checkout is needed to build the site.
Use Node 24. Builds, ingestion tools, audits, and tests run in TypeScript on Node;
Python is not required. No sibling checkout is needed to build the site.

```sh
npm ci
Expand All @@ -21,39 +22,136 @@ are output files; do not commit `public/`.
- `src/**/page.html`: authored page fragments, with metadata in `page.vars.ts`.
- `src/**/page.md`: public documentation, including YAML frontmatter.
- `src/layouts/`: shared page chrome, navigation, and progressive browser clients.
- `src/globals/global.css`: Oro styles, based on `docs/branding/`.
`registry.ts` registers actual layout exports with DOMStack's type-only registry.
HTML `page.vars.ts` companions use `CheckedPageVars` from `#lib/page-vars.ts`
to validate supplied metadata against their layout chain and global vars during
`npm run typecheck`; this adds no runtime registry or subscriptions.
- `src/globals/global.css`: shared Oro styles, based on `docs/branding/`.
Homepage styles live in `src/style.css`; learn styles in `src/layouts/learn.layout.css`.
- `src/lib/`: rendering, URL, collection, and navigation helpers.
- `src/global.data.ts`: collection data derived from source pages.
- `src/artifacts.template.ts`: navigation/search JSON, raw Markdown, LLM packs,
and sitemap output.
- `src/globals/global.vars.ts`: shared site configuration.
- `src/globals/global.data.ts`: a watch-session index keyed by DOMStack `sourceId`,
caching validated document metadata, Markdown, and rendered search text. Navigation,
search, and LLM-export views are derived from those cached entries.
- `src/layouts/docs.layout.ts`: the shared documentation renderer, consuming one
lightweight navigation key for all collections.
- `src/{product}/llms.txt.template.ts`: product LLM packs; Silk includes its wiki.
- `src/{product}/docs/search.json.template.ts`: collection search indexes;
the wiki uses `src/silk/wiki/`.
- `src/lib/docs-page-outputs.ts`: shared `pageOutputs` hook exported by the `docs`
and `spec` layouts. Each page owns its raw Markdown export at its existing
collection `source/` URL, using its `sourcePath`.
- `src/llms.txt.template.ts`, `sitemap.xml.template.ts`, `CNAME.template.ts`,
and `nojekyll.template.ts`: site-wide artifacts.

Templates live beside their output locations. Single-file templates return strings
and use their filenames without `.template.ts` as output names. The root
`nojekyll.template.ts` explicitly names its hidden output `.nojekyll`.
Raw Markdown uses DOMStack page outputs instead of collection templates: body
edits update only that page's raw copy, and watch rebuilds retain unchanged copies
without rewriting them. Deleted pages and changed raw paths clean up owned files.
Navigation is rendered into HTML from global data; the legacy navigation
`index.json` endpoints are no longer generated.

Consult `docs/branding/` before changing visual design or copy tone. The approved
logo originals remain in `docs/branding/assets/`; their checked mirrors in `src/docs/branding/assets/` retain
the same public URLs. Update both when replacing an asset. Handlebars is disabled globally so literal `{{ ... }}` code
examples remain intact.

Each documentation page declares `title`, `description`, `docsCollection`,
`section`, `order`, `sourcePath`, `githubRepo`, and `githubRef`. Preserve
examples remain intact. The Markdown parser deliberately keeps the existing
plugin policy: tables, strikethrough, HTML, linkification, GitHub alerts, syntax
highlighting, and legacy heading IDs. DOMStack's other default extensions are
not implicitly enabled; review fragment and rendered-output compatibility before
adding plugins.

Each documentation page declares `description`, `docsCollection`, `section`,
`order`, `sourcePath`, `githubRepo`, and `githubRef`. Its first Markdown H1 is the
default title; do not repeat it in frontmatter. Preserve
`sourcePath`: it defines the stable raw Markdown endpoint and import identity.
The `start` document lives at its collection root; the specification lives at
`src/silk/spec/2026/page.md`. Order is explicit and does not depend on filenames.
New imported pages are appended; review their section and order after syncing.
DOMStack infers the first H1 as inline Markdown. `src/lib/titles.ts` converts that
value to plain text for document/social metadata, navigation, search titles, and
LLM-pack headings, while the article keeps its formatted heading and anchor.
An optional frontmatter `title` overrides the inferred title; use it only for an
intentional difference (inline Markdown is reduced to plain text there too).
An H1 edit changes navigation metadata, while a body edit below it does not.
Imports infer titles from H1s, retain explicit overrides, and use a filename
fallback only for new documents without an H1. Raw Markdown remains unchanged.

Use `layout: "docs"` for documentation pages in every collection (`spec` for the
specification). All docs share one lightweight navigation dependency: navigation
changes rebuild all docs, while body-only edits remain isolated to the changed
article, its raw output, and its collection's search and LLM exports. Search and
LLM artifacts retain separate, per-collection dependencies; raw outputs need none.

Use canonical directory links such as `/runtime/docs/guides/hello-world/`.
Collection roots redirect legacy `?p=` links while preserving fragments. Static
redirect pages retain Silk's old logger-guide and specification aliases. The
articles, sidebar, previous/next navigation, and ToC work without JavaScript;
search, tabs, copy controls, and Ask AI progressively enhance them.

### Incremental global data

DOMStack beta.7 supplies private `previousState`, reset/delta `changes`, and
`setState()` to the data callback. Initial builds and resets process all documents;
watch deltas replace only `changes.upserted` entries and delete `changes.removed`
IDs. Pages leaving a docs collection retain only their route/redirect metadata.
The cache contains plain data, never page instances or renderers, and DOMStack
commits its snapshot only after a successful build. It does not persist across
watch sessions or change the clean-build/ingestion workflow.

Collection views are still rebuilt from cached document references, and existing
DOMStack fingerprints plus `dataDeps` remain the only downstream invalidation
system. There are no extra application hashes or changed-key declarations.
Source initialization, projection, state cloning, and fingerprinting still have
collection-wide costs; a body edit no longer rereads/renders the whole corpus for
search. The standalone watcher test measures these reads/renders directly.

Beta.7's dependency tracking is conservative and incomplete for package import
aliases and static re-exports. Restart the watcher after changing shared helpers
reached through `#lib/*` or re-exports, or inputs read outside tracked imports.
Editing `global.data.ts` itself resets the index; ordinary page edits are tracked.

### Redirects from old URLs

Follow the [DOMStack redirect-pages recipe](https://domstack.net/docs/cookbook/redirect-pages/):
keep old paths on the **destination page**, rather than in a separate route map.
For Markdown, add frontmatter:

```yaml
redirectFrom:
- /old-guide/
- /old-guide.html
```

HTML pages can declare the same array in their `page.vars.ts` object. Global data
validates and collects these aliases; `src/redirects.pages.ts` subscribes only to
`redirects` and renders each old URL through the existing `redirect` layout. The
target comes from the destination page's actual URL, so retained aliases follow
it when it moves. Removing an alias or destination removes its generated redirect
in watch mode. Body edits do not change the redirect collection.

Use same-origin paths beginning with `/`, with trailing `/` for directory URLs.
Queries, fragments, unsafe paths, duplicate aliases, and aliases colliding with
source pages are rejected. Choose paths that do not overlap assets or other
generated outputs. Redirect pages have a canonical target and a no-JavaScript
meta-refresh/fallback link; with JavaScript they preserve the incoming query and
fragment. These are static client-side redirects, not HTTP 301 responses.

Legacy `?p=` document IDs still use the separate client resolver; do not put them
in `redirectFrom`. Manual content imports preserve existing page metadata,
including aliases. The logger guide and specification now declare their old
paths this way without changing their Markdown bodies or raw exports.

## Refreshing upstream content

Ingestion is separate from building and CI. These commands read explicit upstream
checkouts, preserve the established curated/website-owned content, and write
committed DOMStack Markdown pages. Review and commit their changes before deploying.

```sh
python3 silk/tools/sync-from-silk-docs.py --silk-repo /path/to/silk
python3 runtime/tools/generate-js-api-reference.py --runtime-repo /path/to/runtime
node silk/tools/sync-from-silk-docs.ts --silk-repo /path/to/silk
node runtime/tools/generate-js-api-reference.ts --runtime-repo /path/to/runtime
npm run build
npm run audit
npm run audit:content
Expand All @@ -69,8 +167,11 @@ linked API headings become plain-text titles when a page changes. The reference
catalog includes new pages in the same import batch. Runtime's generated
reference markers retain surrounding prose.

The Python index and LLM exporters have been replaced by DOMStack templates.
Content audits inspect `public/` by default; set `ORO_SITE_OUTPUT` to inspect
The generators call the TypeScript importer directly; they never run during a
DOMStack build. Search indexes and LLM exports are DOMStack templates, not ingestion
outputs. Content audits derive document IDs and expected raw filenames from committed
Markdown frontmatter, then inspect the generated files in `public/` by default.
They do not depend on public navigation JSON. Set `ORO_SITE_OUTPUT` to inspect
another output directory. Set `ORO_RUNTIME_REPO` explicitly to additionally audit
against a particular upstream Runtime checkout; ordinary checks are independent
of whatever happens to be checked out next door.
Expand Down Expand Up @@ -117,7 +218,10 @@ update the relevant assertions and redirects together.

## Deployment and dependency updates

GitHub Actions builds and uploads `public/` and deploys with the Pages environment.
Pull requests run the Docs Audit workflow. Production-branch pushes run the
Pages workflow, which validates once, uploads that checked `public/` artifact,
and deploys with the Pages environment. Both workflows use Node only and retain
browser failure artifacts.
The repository's **Settings → Pages → Source** must be **GitHub Actions**. Merging
these changes does not itself change that repository setting. The output contains
`CNAME`, `.nojekyll`, branding assets, raw Markdown, and `llms.txt` packs.
Expand Down
71 changes: 67 additions & 4 deletions docs/migration.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# DOMStack migration status

The repository implementation now builds the entire Oro website with
`@domstack/static@beta`. The lockfile records the resolved beta so `npm ci`
`@domstack/static@12.0.0-beta.7`. The lockfile records the pinned beta so `npm ci`
remains reproducible. Production cutover is complete; deployment evidence is recorded below.

## Implemented
Expand All @@ -13,16 +13,79 @@ remains reproducible. Production cutover is complete; deployment evidence is rec
| Compatibility | Original collection roots, all valid legacy document IDs, aliases, fragments, and raw Markdown endpoints are retained. |
| Page chrome | Headers, footers, metadata, product navigation, learn chapter bars, documentation sidebars, breadcrumbs, previous/next links, and heading lists render at build time. |
| Progressive features | Search, keyboard tabs, copy controls, Ask AI, mobile sidebar controls, active headings, and tab fragments work with browser JavaScript. |
| Artifacts | One build emits HTML, indexes, search data, raw Markdown, LLM packs, the sitemap, CNAME, and `.nojekyll`. |
| Ingestion | Silk and Runtime retain their upstream/editorial ownership rules and accept explicit upstream checkout paths. Unchanged public pages retain exact Markdown and metadata. |
| Artifacts | One build emits HTML, search indexes, raw Markdown, LLM packs, the sitemap, CNAME, and `.nojekyll`. Legacy navigation JSON exports are retired. |
| Ingestion | Native TypeScript tools retain Silk and Runtime upstream/editorial ownership rules and explicit checkout paths. Unchanged public pages retain exact Markdown and metadata. |
| Cleanup | The browser Markdown renderers, vendored rendering libraries, old HTML shells, duplicate Python exporters, generated source-tree indexes, and Jekyll configuration are retired. |
| CI | Audit and deployment workflows use Node 24, Python 3.12, and the same `npm run check` gate. |
| CI | Node 24 runs ingestion, audits, browser serving, and the `npm run check` gate without Python. Pull requests validate in Docs Audit; production pushes validate and deploy the same artifact in Pages, without a duplicate push audit. |

All six documentation collections use the single `docs` layout; the Silk
specification retains `spec`. The `docs` layout subscribes to one shared,
lightweight navigation key covering all collections. Navigation changes rebuild
all docs. Body-only edits update the changed article and its page-owned raw copy,
plus its collection's search and LLM templates, which retain per-collection
dependencies. DOMStack 12.0.0-beta.6 supplies the `pageOutputs` hook shared by
`docs` and `spec`; no collection subscription is needed for raw exports. Watch
rebuilds skip unchanged raw writes and clean up removed or renamed outputs.
Global data now uses beta.7's optional stateful API to cache processed documents
by `sourceId`. Initial/reset builds index all docs; deltas reread and render only
upserted docs and remove deleted entries. Lightweight route/redirect records also
cover non-doc pages. Collection views reference cached entries, while existing
fingerprints and `dataDeps` alone decide downstream invalidation. State is saved
only after successful validation and committed by DOMStack after a successful
build. Source initialization, state transfer, projections, and fingerprinting
still have whole-site costs. Ingestion remains separate from building.

The actual watcher regression measured 585 initial Markdown reads/search renders,
then one of each for a body edit, title override, or raw-path change, and zero
for deletion. All 1,238 clean outputs matched the pre-index beta.7 build byte for
byte. Restart watch mode for aliased/re-exported helper changes that beta.7 does
not track; no framework patch or duplicate invalidation system is introduced.
Shared article transforms remain page-local rather than storing rendered articles
in global data. Markdown keeps the existing alerts, highlighting, and legacy
heading-ID policy; enabling
additional DOMStack Markdown plugins is an explicit compatibility decision.
Homepage and learn styles are scoped to their consumers, and progressive clients
are TypeScript modules rather than unchecked global initializers.

Artifact templates are co-located with their output directories: product
`llms.txt.template.ts` files and collection `search.json.template.ts` files.
The former six `source/sources.template.ts` exporters are replaced by the shared
`src/lib/docs-page-outputs.ts` hook, with each source page owning its raw output.
The wiki uses `src/silk/wiki/`; other collections use `src/{product}/docs/`.
Navigation remains in global data for HTML rendering, not as public `index.json`
exports. Content audits read committed Markdown metadata for document IDs and
expected raw exports. Single-file outputs use the template filename without `.template.ts`;
raw page outputs use destination-root paths derived from collection metadata and
`sourcePath`, preserving public URLs and Markdown bytes with frontmatter stripped. Site-wide `llms.txt`, sitemap, CNAME, and `.nojekyll` templates
remain at the source root, with an explicit hidden-output name for `.nojekyll`.

The route inventory is in `tools/migration/baseline.json`; original Markdown
links and heading text are in `tools/migration/link-inventory.json`. The migration
utility can reconstruct the initial conversion from a legacy checkout. It is
not part of ordinary builds or content refreshes.

HTML page companions now validate their supplied vars with DOMStack's type-only
layout registry and `ValidatePageVars`, via `CheckedPageVars`. The registry
references actual renderer, parent, and default exports for all seven layouts;
it does not alter runtime discovery, rendering, or subscriptions. Markdown
frontmatter continues to use runtime metadata validation rather than per-page
TypeScript companions.

Path redirects follow the DOMStack `redirectFrom` cookbook pattern: old paths
live in destination-page metadata, global data validates a separate redirects
projection, and a typed pages factory uses the existing redirect layout. The
logger-guide and specification aliases now use this path; legacy `?p=` links
retain their query-aware client resolver. Alias changes and destination moves
update generated pages, while body-only edits leave redirects untouched.

All 585 documentation pages now use their Markdown H1 as the default title,
removing redundant frontmatter titles without changing article bodies. Because
DOMStack beta.6 infers raw inline Markdown, shared title helpers reduce it to
plain text at metadata consumers and in ingestion. Formatted H1s and anchors
remain unchanged; intentional frontmatter overrides remain supported. This also
removes stale link syntax from 31 metadata titles. Imports no longer regenerate
redundant title fields and preserve explicit overrides during upstream refreshes.

## Acceptance checks

`npm run check` runs:
Expand Down
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading