Documentation Site Operations
Purpose
This page is the operating guide for the hosted ViewCompose documentation system. Content rules remain authoritative in Documentation Governance, while platform selection and trade-offs are recorded in ADR-0001.
Build pipeline
The production artifact is assembled in seven explicit stages:
verifyDocumentLanguageschecks that canonical and localized titles and narrative use the language of their directory and that every active public page has a required locale mirror.verifyDocumentationStructurevalidates source placement, catalog parity, reachability, and repository links.verify:translationsvalidates required Chinese coverage, canonical source fingerprints, explicit stale status, and stale-warning markers.verifyCompleteViewComposeApiDocsgroups immutable releases by source revision and verifies the exact entry set plus every generated file's size and SHA-256. A valid group is reused; any stale, malformed, incomplete, extra, symlinked, or digest-mismatched group is rebuilt in a temporary workspace before route, alias, manifest, and pinned-source verification. Missing revisions are fetched only by full SHA. Historical workspaces receive only their group's release records and non-published compatibility shims when their source predates current build contracts.- the website generators read publishing metadata, the immutable release registry, and
docs/modules/README.md. They generate the catalog plus one module-manual snapshot per released artifact/version from the same frozen Git revision; they do not maintain a second registry. Every unique frozen revision is resolved by exact full SHA before any snapshot read, independent of whether immutable API output was restored or rebuilt. - Docusaurus type-checks and builds the handwritten documents, site presentation, generated API
output, localized search indexes, and compatibility redirects for both
enandzh-CNintowebsite/build/, with broken links and anchors treated as errors. After Docusaurus resolves presentation fields such asslug, remark transforms remove Governance V2 ownership fields and translation-review fingerprints from browser page chunks, and rewrite verified links to repository files outsidedocs/as GitHub source URLs. Source Markdown remains repository- relative and authoritative, while production and test sources are not duplicated in the site artifact; the generated Capability Reference remains the public relationship model. - the build wrapper verifies shared site-shell behavior across locales, audits Docusaurus-owned HTML accessibility, and enforces build-time, total output, JavaScript, CSS, and per-locale search-index budgets. Dokka-generated HTML remains under the API generator's independent integrity gate rather than the site-template accessibility gate.
Run the complete local verification from the repository root:
./gradlew verifyDocumentationStructure verifyCompleteViewComposeApiDocs
cd website
npm ci
npm run test:scripts
npm run verify:languages
npm run verify:translations
npm run typecheck
npm run build
npm run build includes the accessibility and budget gates. Run npm run verify:site to recheck an
existing website/build/ artifact without rebuilding it.
The quality report lives at build/reports/documentation/site-quality-report.json, outside the
deployed/budgeted tree, so rechecking website/build/ reproduces the build result.
During local iteration, -PviewComposeDocsModules=artifact-a,artifact-b limits Dokka assembly to an
explicit subset. A production build never uses this shortcut.
build/versioned-api-cache/integrity-manifest.json is generated cache state, not a second release
registry or a deployable API resource.
Its complete key is derived from per-revision fingerprints; each revision fingerprint covers its
immutable artifact/version/source triple set and the current generator implementation. Aliases and
unpublished working-tree current output are deliberately outside immutable reuse and are rebuilt
for every assembly. VIEWCOMPOSE_API_DOCS_MAX_PARALLEL_REVISIONS accepts only 1 or 2; CI keeps
it at 1 until an accepted hosted-runner process-tree memory measurement justifies two concurrent
2 GiB Gradle/Dokka processes.
Governance V2 assets are repository inputs, not another site registry: schemas and deterministic
discovery feed the compiled zero-exception strict gate, where every issue blocks. The committed
website/src/data/capability-reference.json dataset is intentionally rewritten with
./gradlew updateDocumentationCapabilityReference; verification independently derives and
byte-compares the expected model. The localized /reference/ page consumes that one tree, while
/api/ remains the exhaustive per-artifact, per-version Dokka output.
Run npm run write-translations when React, navbar, footer, or sidebar messages gain new keys. It
adds missing JSON messages without overwriting reviewed Chinese translations. Markdown mirror
layout, source fingerprints, required-page tiers, and stale recovery are defined in the
localization workflow.
Search, redirects, and quality budgets
Each locale builds a credential-free local search index from rendered documents. It keeps page
summaries, headings, public contracts, and command guidance. Exhaustive evidence tables and dated
ledgers may use search-partition-detail when an adjacent searchable heading and summary remain;
API contracts, command references, and reader-facing guides may not use that partition. Search UI
messages remain reviewed in the standard zh-CN catalog.
Search output is structurally segmented by the public top-level routes: documentation overview, AI integration, tutorials, guides, architecture, migration, modules, tooling, and project maintenance. The navbar loads the current route's segment, and the results page provides a localized segment selector. Every public document therefore remains searchable without requiring one monolithic locale index. The budget gate applies the unchanged per-file ceiling to every segment and requires the complete locale-by-segment matrix, so a missing translation segment or an accidental return to a single index fails CI.
Exceptionally large temporary execution plans remain repository-only production drafts when the
active-plan index retains a searchable purpose and scope summary and every durable public contract
and command remains in its searchable owning documentation. Canonical indexes keep repository-
relative source links so the documentation graph remains complete; the strict Markdown-link hook
rewrites only a verified draft: true target to its exact GitHub source URL during the site build.
The target is therefore reviewable from the public index without adding temporary execution state
to rendered output, localized fallbacks, search, or the sitemap. A missing target, a non-draft
broken link, or any other unresolved route still fails the build.
The per-segment, per-locale search budget is 6.25 MiB. Reviewed bilingual architecture and contract additions moved it from 4 through 6 MiB; the lazy-collection branch then partitioned exhaustive plan and benchmark detail before the final 6.25 MiB ceiling. Exact transition evidence is consolidated below. Reaching this ceiling again requires structural index segmentation rather than another content-only partition or threshold increase; API and command guidance remains searchable.
Rendered code blocks remain complete on their owning pages and keep their compiled-source links, but local full-text search indexes the surrounding explanation instead of duplicating every code token. Exact public symbols remain discoverable through module API inventories and the generated Reference. This boundary reduces repeated bilingual index material without hiding a page, sample, command contract, or migration route; if a command or symbol exists only inside a fence, add its name to the owning prose rather than returning all code bodies to the index.
Compatibility redirects preserve /docs, /getting-started, /compose-migration,
/migrate-from-compose, and previously published active-plan routes after those plans move to the
archive, including their locale-prefixed forms. Add a redirect only for an intentional historical
or campaign route; canonical document paths remain the source of truth.
The global sidebar links to the Architecture Decisions and Published Module catalogs without repeating every entry on every rendered page. Each bilingual catalog remains complete and ordered; every decision and current module manual remains directly routable, searchable, and linked from its catalog. Module links stay within the selected locale on local builds and the hosted site. The repository-file link transform recognizes both canonical and localized Markdown roots, leaving manual links for Docusaurus to resolve while source-only files retain their repository URLs. This prevents catalog additions from multiplying navigation labels across the entire site artifact.
On 2026-09-08, the integrated framework-contract candidate with the same bilingual corpus, Node 24.19.0, Docusaurus 3.10.2, and six immutable API source revisions produced 50,585,643 non-API bytes before this catalog/link correction and 49,275,384 after it: -1,310,259 bytes (-2.59%). The conclusion is improved artifact size and localized navigation. All 84 site-script tests, 39 current module routes in both locales, 133 immutable API versions and their bilingual manuals, accessibility, shell, and unchanged 47.8 MiB/120-second budgets pass. This measures deployed bytes, not browser interaction latency; retain the full bilingual route and size gates for future catalog growth.
The versioned thresholds live in website/site-budgets.json. Immutable Dokka output is canonical
at /api/**; the supported build removes locale-prefixed API copies and the redundant locale social
card because localized pages use the canonical API tree and one absolute social-card URL.
Immutable module-manual snapshots retain localized routes, server-rendered content, styles, links, and color-mode bootstrap as read-only static HTML, but not redundant hydration scripts or route chunks. Current manuals remain hydrated. The gate enforces full-page navigation, the static marker, and script removal. Post-build Dokka compaction removes generated indentation while preserving literal element bodies byte for byte; immutable source manifests and cache integrity remain upstream.
The budget model separates expected release-history growth from regressions. Current ceilings are 47.8 MiB for non-API output, 4.5 MiB average and 24 MiB maximum per API tree, 1 MiB for API routing overhead, 8 MiB total and 768 KiB largest-file JavaScript, 128 KiB CSS, 6.25 MiB per locale search segment, and 120 seconds for the Docusaurus build. Locale-prefixed API copies remain forbidden.
The ceiling moved from 41 MiB to 46.9 MiB only after paired attribution and consolidation. A reviewed 2026-08-30 exception moved it to 47.1 MiB after the required top-level bilingual AI Integration chapter was consolidated from two routes to one and still exceeded the prior ceiling. The search-segmentation acceptance moves the ceiling to 47.8 MiB. The ratchet resumes there: recover capacity structurally before adding another route, remove redundant deployed representations, and never remove current contracts or valid release history. Existing guarded transforms remove unused locale copies, machine-only governance/translation front matter, immutable-manual hydration, and generated indentation without changing routes or readable content. Historical same-corpus measurements and limitations remain in source below rather than being repeated in the public operating contract.
The accessibility audit covers the site-owned English and localized pages and checks document language, title and main landmarks, heading order, accessible names, image alternatives, table headers, iframe titles, and duplicate IDs. It deliberately excludes redirect stubs and Dokka-generated implementation pages. Changes to the Dokka template require a separate generated API accessibility review rather than weakening this gate.
The site-shell verifier requires both locale homepages to use one explicit browser-storage
namespace, so switching languages preserves the reader's light or dark color-mode choice. It also
rejects the removed standalone Maven-coordinate banner on either homepage. The same gate inspects
the final bundled stylesheets and rejects filters, transforms, containment, or related properties
on the .navbar root because they would confine Docusaurus's fixed mobile sidebar and backdrop to
the navbar height. The same restriction applies to navbar pseudo-elements: browser-specific
compositing can paint a positioned filter layer above the in-flow menu toggle and brand while
leaving the positioned search input visible. The navbar therefore uses its ordinary background
without a blur layer.
Released versions and aliases
Immutable API trees use /api/<artifact>/<version>/. The mutable current alias follows the
version currently registered by the repository. Before an artifact's first release, its current
route contains Dokka generated from the working source and no versioned route exists. The latest
alias is generated only for stable versions; alpha, beta, release-candidate, snapshot, preview,
development, and EAP versions must not silently become latest.
Immutable module-manual snapshots use /modules/<artifact>/<version>; the unversioned
/modules/<artifact> page remains the maintained current guide. Historical manuals are generated
as canonical English snapshots, including at the equivalent zh-CN route, so the locale path never
pretends that an unreviewed historical translation exists.
Relative links from a historical manual to another released module are rewritten to that module's versioned route. Links to temporary execution plans are instead pinned to the manual source revision on GitHub, so completing or archiving a plan cannot break an immutable manual snapshot.
The append-only release registry pairs every version with a full immutable source SHA; missing or movable links fail. Freeze source and manuals first, then append registry/version metadata in a second commit. The frozen SHA must stay reachable and cannot be replaced by a squash commit.
release.retiredModules preserves superseded history outside the active catalog.
release.unpublishedModules permits only pre-release working-tree current output and must remove
an artifact when its first immutable entry is appended.
verifyAssembledViewComposeApiDocs accepts an explicit local subset; deployment uses the complete
verifier and checks every API/manual route in both locales. Current prereleases emit no latest.
Generated output is never committed. A clean checkout restores history from registered revisions and fetches only an otherwise-missing exact SHA, independent of temporary branches.
For each module release:
- freeze the releasable source, source comments, compiled samples, and module manual in a commit;
- append an immutable registry record and update the module's publishing version and
sourceRevisionin a metadata-only commit; - run the publishing configuration gate, complete API verifier, and production site build before publishing. The configuration gate rejects current metadata without an exact registry match.
Continuous integration and deployment
.github/workflows/documentation.yml remains present for every pull request. Its standalone impact
job configures only tools/viewcompose-quality-build, publishes the source-owned classification in
the job summary, and selects the expensive documentation child only for documentation, website,
published-production, or conservative full-fallback inputs. The stable Build documentation
context is an always() result facade: an intentional skip succeeds only after a successful
unselected plan, while a planning or selected-child failure remains fatal. A push to main, or a
manual run on main, always selects the complete child; only its verified Pages artifact can deploy
through the protected github-pages environment.
The selected child computes the immutable generator and complete-history fingerprints before
restoring website/generated/api. Pull requests use restore-only access; only a successful main
child may save a cache. The primary key is unique per run so a verified recovery can supersede a
corrupt archive, while ordered restore prefixes first select the same complete fingerprint and then
the most recent cache produced by the same generator. Because the generator fingerprint includes
the actual Java and Node runtimes, the workflow pins their complete distribution versions instead
of floating major selectors; changing either version is an explicit cache migration. A restore is
never trusted by key alone: the
assembler verifies every revision group and publishes hit, partial, miss, recovery, generated-group,
invalid-group, parallelism, and duration telemetry in the job summary. The source/language/
translation gate runs once, the catalog is generated once, and CI then uses prepared type-check and
site-build entry points so npm lifecycle hooks do not repeat the same prebuild work. Cache-service
restore or save failures degrade to full generation or a skipped write rather than bypassing the
verifier or blocking an otherwise valid Pages artifact.
Deployment succeeds only after production smoke tests fetch both catalogs and every current manual in both locales, including representative no-trailing-slash routes. HTTP, rendered not-found, wrong-plugin, or missing-catalog failures remain fatal after bounded CDN retries.
GitHub repository settings must use GitHub Actions as the Pages source. The checked-in CNAME
declares docs.viewcompose.com; DNS should point the docs CNAME to viewcompose.github.io and
HTTPS enforcement is enabled only after GitHub validates the domain.
No Maven Central credentials, signing material, domain registrar credentials, analytics keys, or search administration keys belong in the repository. Deployment uses GitHub's short-lived Pages identity token.
Failure recovery
- If source verification fails, fix the canonical document or catalog rather than weakening the gate.
- If release-history verification fails, append the missing immutable record or correct unpublished metadata. Never rewrite an already released artifact/version entry.
- If Dokka fails, reproduce with a selected module and correct its source/API configuration.
- If an API cache group fails integrity, keep the automatic group-level regeneration. Do not edit
the manifest, accept a key-only hit, save caches from pull requests, or bypass the complete API
verifier. A recovered
mainrun writes a newer unique key for the same fingerprint. - If Docusaurus reports a broken link or anchor, preserve strict checking; generated static API links are the only links explicitly exempted from its route graph.
- If the accessibility gate fails, fix the rendered page or theme component. Do not suppress a rule because a minifier formats otherwise valid HTML differently.
- If a site budget fails, inspect whether the regression is non-API output, API-tree average, one immutable or unpublished-current API tree, routing overhead, or a locale-prefixed duplicate. Remove the regression or document and review an intentional threshold change; do not restore a fixed total-output ceiling that fails merely because valid immutable release entries were appended.
- If translation verification reports source drift, review and update the Chinese meaning before recording the new fingerprint. A tracked page may be explicitly marked stale; a required page may not.
- If language verification fails, correct the misplaced narrative or missing required mirror; format a genuine foreign-language UI literal as code instead of weakening the classifier.
- If deployment fails after a successful build, keep the last Pages deployment live and rerun only
after checking repository Pages settings and the
github-pagesenvironment. - If the custom domain fails while the Pages artifact is healthy, diagnose DNS and domain verification separately from the documentation build.
Last verified
The current production contract serves 133 immutable API versions, module manuals, and Chinese
fallback routes. The coordinated-release closeout audited 522 pages at 468.9 MiB total and
46.7/46.9 MiB non-API; two exact-cache-hit runs reused 6/6 groups and took 47.3 s and 43.0 s.
Cache correctness and latency are no material change, while added history and narrower headroom
are mixed. A later same-corpus consolidation reduced non-API output from 49,208,553 to
49,086,492 bytes (-122,061, -0.248%), an improved representation with 524 accessible
pages. These heterogeneous local/hosted observations are not a steady-state benchmark; the local
cache also lacked six groups. Full-cache CI remains the version-route acceptance gate. Detailed
evidence remains in the pull-request gate plan
and Governance V2 archive.
On 2026-08-29, a dedicated bilingual XML-migration route produced 49,373,569 non-API bytes,
195,354.6 bytes above the unchanged ceiling. Removing that duplicate of the linked local tooling
contract and consolidating this operating page reduced the same corpus to 49,171,339 bytes:
-202,230 bytes (-0.4096%) from the rejected candidate and -24,110 bytes (-0.0490%) from the
49,195,449-byte route-free attempt. An accepted run left 6,875.4 bytes headroom and audited 526
pages; accepted warm retries completed in 34.2–59.8 s. The representation is improved
with no material change to routes, search contracts, or tooling behavior. This is local warm
build evidence; a future dedicated route must recover its measured capacity first.
On 2026-08-30, the required top-level bilingual AI Integration chapter produced 49,238,608 non-API
bytes after its overview and setup were consolidated into one route. The last accepted full-site
output was 49,042,390 bytes, so the chapter adds 196,218 bytes (+0.4001%) and is regressed for
output size; functional, version-history, accessibility, language, translation, and route checks
all remained successful. The ceiling is therefore reviewed at 47.1 MiB, leaving 149,321.6 bytes of
headroom. This is one local production build and measures uncompressed output rather than transfer
size, runtime, or query latency; it makes no performance-improvement claim. The next action is to
hold this ceiling, reuse the single AI route, and reclaim measured capacity before adding another
AI documentation page.
On 2026-09-07, the same-corpus monolithic build produced 49,280,799 non-API bytes and search
indexes of 6,014,297 English bytes and 6,618,181 Chinese bytes; the Chinese index exceeded the
unchanged 6.25 MiB ceiling by 64,581 bytes. Segmenting all nine public top-level routes produced a
largest index of 2,048,055 bytes, reducing the maximum reader download by 4,570,126 bytes
(69.0541%). The split indexes added 776,685 bytes (6.1483%) of index metadata and moved total
non-API output to 50,060,856 bytes, an increase of 780,057 bytes (1.5829%). The result is
mixed: bounded on-demand search payload and future per-area capacity improved, while total
uncompressed output regressed. The reviewed 47.8 MiB non-API ceiling accepts only this measured
segmentation overhead; all public routes and search content remain present. These local builds do
not measure transfer compression, query latency, or hosted-runner variance. The next action is the
hosted pull-request build with the required locale-by-segment matrix still enforced.