Skip to content

Latest commit

 

History

History
157 lines (116 loc) · 16.7 KB

wiki-maintenance.md

File metadata and controls

157 lines (116 loc) · 16.7 KB

Maintaining the field manual

Astro prerenders the manual at /wiki/ alongside the game and debug pages. The static output is dist/wiki/index.html; /wiki and /wiki/ preserve query parameters and article fragments such as /wiki/#hauler. Ordinary document navigation needs no routing middleware, client router or prefetch. The manual never starts gameplay or opens a game WebSocket.

src/content.config.ts registers the custom loader in src/wiki/contentLoader.ts. It calls the same validated compiler, scripts/wiki-content.ts, used by the maintenance check. Astro does not apply a second Markdown renderer, and the collection does not use MDX. This loader is the build-time content entrypoint. Development refreshes article additions, edits and deletions; changes to generated reference inputs rebuild Astro's content module graph.

The static document contains the overview and every article with unique anchors. Without JavaScript, readers can follow links, read generated values and view illustration posters. src/components/wiki/WikiShell.svelte enhances that document with shadcn-svelte search controls and navigation, showing one overview, article, search or not-found panel. Search covers titles, summaries, headings and rules without changing the hash. Clearing search restores the route; following its current hash clears search and returns to the route's beginning. Unknown or malformed hashes show the manual's not-found panel. Charts and animated media mount only for active articles and are disposed on navigation or teardown. Svelte components in src/components/wiki/ render the overview, topic cards, article chrome and ship profiles as text; only each article's build-compiled body is inserted as HTML.

Content and coverage

Pages CMS reads the root .pages.yml on the selected branch. Open https://app.pagescms.org/jsolly/GeoRoids/main to find the Field manual collection. For edits, select a working branch containing that configuration, then save and ship through a PR. Saving uses GitHub's branch permissions; the CMS does not bypass the required PR and CI on main. Article filenames are stable URLs, so renaming and deletion are disabled in the editor. New articles still need developer review of coverage and source references. Upload PNG, JPEG, or WebP images through the media library; the editor writes /wiki/uploads/ URLs. Generated demonstrations and exact gameplay values remain maintained in their owning source files.

Edit content/wiki/*.md directly and ship the change through a PR. Each Markdown file contains title, category, summary, navigation order, related article paths, demonstration placements, and a rich-text body. Each placement selects a demonstration and its matching Heading 2, so the illustration stays beside the relevant text. Update the placement heading when renaming a section. Body images go in public/wiki/uploads/ as PNG, JPEG, or WebP and are referenced as /wiki/uploads/<name> with alternative text. Filenames are stable article IDs; title edits do not change URLs. Avoid renaming published articles because their filename is their URL. When a published topic is replaced, migrate every related link and source-reference key to the replacement article and remove the obsolete page; do not leave an alias that keeps the old ID alive. Validation prevents breaking internal links.

src/wiki/articleSources.json keeps developer source references separate from editorial content. src/wiki/gameReference.ts generates exact values from game definitions in a collapsed reference below the editable body. Keep each feature to two or three short sentences; explain its action, result, and essential limitation. Link to the owning topic instead of repeating its instructions. Use the existing demonstrations where motion explains the rule. Keep imported tuning values out of the narrative so balance changes do not leave stale copies. Some mechanics use private implementation literals, such as the touch flick threshold; those details remain in the editable prose and are checked during gameplay-source review. Do not create duplicate wiki constants for them. New articles need no TypeScript edits; gameplay changes still require developers to maintain coverage and source references. Explain player-visible behavior, including failure conditions and exceptions. Keep strategy separate from confirmed rules and avoid declaring a best tactic without gameplay evidence.

Use docs/wiki-coverage.md as the inventory. A new ship or player-facing mechanic needs an entry or a documented section within an existing entry, plus cross-links. New important interactions need the same treatment. Do not interpret a passing hash check as proof that editorial coverage is complete.

Back and Forward return to the scroll position of that visit, including after a reload. A new visit opens at the top.

Ship profiles

Each ship page pairs an Apache ECharts SVG radar with seven base-stat ratings and exact values. shipRatings() in src/wiki/shipScorecard.ts derives both displays from the current ship definitions, and src/components/wiki/ShipScorecard.svelte renders the values, bubbles and accessible labels. Each stat maps linearly from the fleet minimum to maximum onto 1–5 bubbles, rounded to a whole bubble. Size, shot interval, and ability cooldown reverse the scale so smaller or shorter scores higher. Equal fleet-wide values score 3. These compare base stats, not ability effectiveness or an overall ship ranking.

The Wiki imports only the radar chart and SVG renderer; the build-generated gameplay module graph rejects ECharts in gameplay bundles. Static rendering does not initialize charts. ShipScorecard.svelte owns a gated Svelte attachment that mounts the radar only after the shell initializes and only for the active article outside search. The attachment disposes the chart and its resize observer when the article leaves the page; revisiting the same hash keeps the existing chart. Navigation disposes the chart and its resize observer. The HTML values and accessible bubble labels remain the readable counterpart to the visual radar.

Ship hulls render as data-URI images from serializeKitHullSvg, as in the game's ship picker. The overview comparison uses the shadcn-svelte table primitive inside the focusable .table-scroll region, which stays its only scroll container. Markdown tables in article bodies use the same structure, data slots and utility classes as the committed shadcn-svelte table primitive. Their named, keyboard-focusable .table-scroll region is the only scroll container. Empty scorecard bubbles use a muted-foreground ring with at least 3:1 contrast against the page background; filled bubbles keep their brighter solid fill.

Demonstrations

src/wiki/media.ts describes each GIF and its static poster. Each demonstration has a title, descriptive alternative text, a caption explaining the controlled setup, and source files. Assets live in public/wiki/media/. Use actual simulation helpers and game geometry in the generator, with scripted inputs and a fixed clock. scripts/wiki-satellite-demo.ts records all six Earth-observation pickup hulls from the real SatellitePickupManager; keep that simulation separate from panel layout. A section with a demonstration renders its copy and animation in one card, without a repeated caption. Keep the Hauler demonstration on the real tow cable and furnace delivery path, show Scout scan sharing with a teammate radar, and show one environmental asteroid impact reducing health while the ship survives and continues flying. The HUD documentation must describe the local minimap separately from the full-screen universe map opened by M or the Map button, including the shared exploration state and discovered important assets. Keep reflective asteroid behavior in the reflection demonstration. Never invent a visual rule that the game does not implement.

Article demonstrations autoplay their GIF when an article opens; there are no playback controls to operate. When prefers-reduced-motion: reduce is active, articles use their static posters. Hiding the browser tab swaps active GIFs to posters, and returning to the tab resumes them when motion is allowed. Posters and descriptive text remain available without animation.

Generate or verify GIFs

The committed demonstration baseline belongs to linux-x64: Ubuntu 24.04 on x86-64, as on the GitHub ubuntu-24.04 runner and the Claude Code cloud container, which reproduce it byte for byte. Other platforms rasterize differently; arm64 Linux changes a few pixels and macOS differs more. The generator uses the repository's Node canvas package, Python with Pillow pinned in scripts/wiki-media-requirements.txt, and the Liberation Sans faces in scripts/wiki-media-fonts/. Liberation Sans is metric-compatible with Arial and answers every Arial request, and on Linux an empty fontconfig file hides the host's fonts. Set WIKI_MEDIA_PYTHON to the Pillow Python when it is not python3. On linux-x64, run from the checkout root:

npm run wiki:media
npm run wiki:media:check

Generation renders each controlled scene twice and compares frame and GIF hashes before writing GIFs, PNG posters, and public/wiki/media/manifest.json. Verification checks reproducibility and compares regenerated output with the committed assets. The manifest records the platform, fixed seed, dimensions, timing, encoder, and hashes. A generation or comparison failure exits unsuccessfully. Any other platform refuses to verify or to write public/wiki/media; npm run wiki:media -- --output <dir> still renders a local preview there.

The required wiki-media CI lane runs the check on ubuntu-24.04, so a change that moves generator output cannot merge with a stale baseline. When the check fails, the lane renders the current baseline outside the checkout and uploads it as the wiki-media-baseline-<run>-<attempt> artifact. Without linux-x64, download that artifact from the failed run, copy its files into public/wiki/media/, inspect them, and record the review below.

Source review gate

Run commands from /Users/johnsolly/code/GeoRoids or the root of its checkout.

npm run check:wiki validates frontmatter, stable article IDs, related and body links, image alternative text and local upload paths, source paths, demonstrations, and the accepted source digest. Markdown renders with HTML disabled; executable HTML is never inserted into the page. Gameplay source additions, removals, and changes invalidate the review, including files not cited in an existing article. The inventory also tracks Astro pages, Svelte components, styles, the content loader and frontend configuration, so adding or deleting an interface cannot bypass review. Changes to rendering, generated demonstrations, and generation scripts also invalidate it. package.json is tracked too, but its digest (scripts/wiki-source-digest.ts) ignores version strings inside dependencies, devDependencies, optionalDependencies, peerDependencies and overrides, so a dependency-only version bump and its lockfile change need no review. Adding, removing or moving a package, and any change to scripts, engines or other manifest fields, still invalidates it. Editorial Markdown and uploaded screenshots are validated on every build but do not invalidate the gameplay review. They cannot change the generated facts or accepted source digest. The build runs this check so stale documentation cannot quietly pass the normal release path.

When a check fails:

  1. Inspect changed source files and identify affected rules and illustrations.
  2. Update relevant articles and source references; regenerate affected demonstrations on linux-x64, or take the wiki-media lane's candidate artifact (Generate or verify GIFs).
  3. Inspect the resulting images and verify their behavior against the implementation. Run the media reproducibility check on linux-x64 when the generator changes; elsewhere CI's wiki-media lane runs it.
  4. Run lint, types, relevant gameplay tests, and desktop/mobile wiki checks.
  5. Record only the completed scope with npm run wiki:review: repeat --source for each reviewed changed path, --topic for every affected article, and --media for every affected demonstration, with a nonempty --note. Unmapped or deleted sources also need an explicit --owner source/path=topic-id using a selected real topic. Then run npm run test and npm run build, including the review-invalidation contract test. Commit the resulting docs/wiki-source-review.json with the change.

CI and builds never write or accept the committed baseline; the wiki-media lane only offers a candidate after its check fails. The digest detects review work; it cannot write or validate the explanation for you. Review notes should describe actual completed checks. Explicit acceptance formats the ledger with the pinned Biome installation before replacing it atomically; a formatter failure leaves the previous review intact.

Acceptance updates only the selected source hashes, adding or removing those keys as needed. It preserves unrelated pending hashes, the legacy review note and earlier review batches. A scoped acceptance can succeed while reporting other pending sources; the ordinary check still fails until those sources are reviewed. Unknown, duplicate or incomplete selectors fail before writing. Build and CI never accept a review automatically.

For a change confined to the Wiki checker, a review command from /Users/johnsolly/code/GeoRoids or its absolute worktree root is:

npm run wiki:review -- --source scripts/wiki-check.ts --topic field-manual --owner scripts/wiki-check.ts=field-manual --note "Reviewed scoped maintenance checks; player rules and demonstrations are unchanged."

Merging the ledger

Every branch appends to docs/wiki-source-review.json, so concurrent branches collide in it routinely. Resolve it with npm run wiki:merge during the conflicted merge; it reads the three conflict stages Git already holds, writes the resolution, and leaves staging to you.

Do not resolve it by hand, and do not resolve it with --accept. The obvious resolution is the union of both sides, and that is correct only while the two sides re-recorded disjoint sources. When both sides re-recorded the same source, the merged bytes match neither recorded digest, so a union writes a digest for content that does not exist — and npm run check:wiki still passes, because it compares digests against files and a union is self-consistent. The gate cannot catch that resolution; only the disjointness check can.

The resolver never emits a digest it cannot prove:

Case Result
Untouched by both sides the shared value, proven by all three agreeing
Re-recorded by one side that side's value, proven because only it moved
Re-recorded by both reset to the merge-base value, so the source reports pending
Added by both, digests differ omitted, so the source reports pending
Removed by either side omitted, correct whether or not the merged tree keeps the file

Review batches union by content rather than by index, because merging main interleaves other branches' batches and the arrays then agree on no index beyond the base. Dropping a batch the merge base holds is refused outright, as is a two-sided edit of the top-level note. Anything the resolver leaves pending is ordinary review work: inspect those sources and record them with npm run wiki:review before committing the merge.

To resolve it automatically instead, register the same script as a Git merge driver in your own checkout. The repository deliberately does not register it: scripts/repo-hooks.py installs executable hooks outside the worktree from reviewed origin/main only, so a branch can never change what Git runs, and a driver pointing into the worktree would reopen exactly that. Opt in locally if you accept that:

git config merge.wiki-ledger.name 'GeoRoids wiki review ledger'
git config merge.wiki-ledger.driver 'node scripts/merge-wiki-ledger.mjs %O %A %B'
printf 'docs/wiki-source-review.json merge=wiki-ledger\n' >> .git/info/exclude.gitattributes
git config core.attributesFile "$(git rev-parse --git-dir)/info/exclude.gitattributes"

scripts/merge-wiki-ledger.test.ts pins each rule above, including that a union of two-sided digests fails and that a real conflicted merge resolves.

Live CMS acceptance

Fixture checks prove collection validation and rendering, but do not verify an editor session. Select the feature branch in Pages CMS, save an editorial change and upload an image there. An agent may perform this check when John authorizes browser editing. Validate the resulting Git change, inspect the rendered article and image, then publish through /ship and verify the exact deployed release. Record that acceptance as unverified until the live editor save and published result have both been observed.