Skip to content

Publish starship play on the site - #27

Merged
christopherfowers merged 1 commit into
mainfrom
feat/starship-content
Aug 31, 2026
Merged

Publish starship play on the site#27
christopherfowers merged 1 commit into
mainfrom
feat/starship-content

Conversation

@christopherfowers

@christopherfowers christopherfowers commented Aug 31, 2026

Copy link
Copy Markdown
Owner

The site published none of Starships of the Galaxy — half of SW5e, and the
gap the owner called out by name. sw5e-database now carries all 453 items
(christopherfowers/sw5e-database#16) and the API serves them
(christopherfowers/sw5e-api#28); this is the half a reader can actually see.

Route Items
/starship-base-sizes 6
/starship-deployments 6
/starship-equipment 104
/starship-modifications 257
/starship-ventures 67
/starship-rules 13

Built against the real content set, the site prerenders 2,273 routes, which
is the count react-router.config.ts and the container job independently
arrive at.

Mapping

These are the only canonical documents that were never a flat row, so this is
the only place canonical.mjs shapes rather than renames:

  • Base sizes render two tables — the six-row tier progression and the six
    roles with their armour, shields, reactor, coupling, speed and turning. The
    tier table's third column is named by the document, because every hull calls
    its signature die something different (a Tiny ship rolls Swarm Tactics, a
    Gargantuan one Superior Firepower). The shields column is dropped for the
    three sizes whose roles are launched without any, rather than printed as six
    dashes.
  • Deployments render their rank table and their features.
  • Equipment carries one stat block per category, so a hyperdrive has a
    class and no damage roll, and ammunition shows both damage scales and the
    launchers that fire it.
  • Rule chapters are titled rather than named, so they go through common
    with the title, and the body's duplicate opening chapter heading is stripped
    because the page already prints it as the h1.

Lists that survive their own size

Nobody scrolls 257 rows, so the two large types get real filters rather than a
longer table:

  • Modifications — facets on type, grade and ship size. The hull
    requirement is lifted out of the prerequisite prose into a column and a facet
    of its own: 35 of the 257 are gated on it, the clause is buried in a sentence,
    and "what can my Small ship fit?" is unanswerable without it. Selecting
    Medium or larger takes the table from 257 rows to 14. Four of the five
    columns sort.
  • Ventures — facets on the two real gates: the deployment whose rank is
    required and the character class whose levels are.

Why the archive path does not carry these

normalize.mjs records the six types with no archive file. The archive has
their files, but three of them lost their structured columns to the 2022
scrape — every numeric field on all six base sizes is zero, and every piece of
ammunition carries a name and a price and nothing else. The canonical documents
have hull dice, tier tables, roles and ammunition damage only because the import
read them back out of the rules chapters. Mapping the flat records here would
publish a starship section that cannot say how much hull a Small ship has. The
committed fixture is built from the archive, so the six indexes are empty in it
and render as maneuvers used to.

Tests

  • scripts/lib/canonical.test.mjs — twelve cases on the crossings that
    silently break: the tier table's data-named column, the dropped shields
    column, both ammunition damage scales, the per-category stat blocks, the
    hull requirement being lifted out of the prerequisite and not repeated in
    it, and a chapter's stripped heading.
  • e2e/starships.spec.ts — all six routes prerendered with their own markup
    rather than the SPA shell (the failure mode that still returns 200 and still
    type-checks), every one reachable from the header, and the nav strip's fade
    still present now that nineteen destinations overflow every viewport.
  • CI's container job compares each of the six indexes against the content image
    it was built from, with an absolute floor as well as the derived count.

Sequencing

The image job builds from ghcr.io/christopherfowers/sw5e-database:latest,
so this job stays red until sw5e-database#16 has merged and published its
content image
. That is observed rather than predicted: on the current run
every other check passes, the site builds and prerenders six empty starship
indexes without complaint, and the single failing step is the one asserting the
floors — the assertion refusing a starship-free catalogue, working as intended.

Everything else is green: verify (typecheck, lint, 329 unit tests, the build,
92 end-to-end tests), the API contract job, and CodeQL.

Merge order: sw5e-database → wait for its release → sw5e-api → this.

The site carried none of Starships of the Galaxy, which is half of SW5e, and
the six types it needs are now in sw5e-database. This maps them, gives them
navigation, and gives each one a list that can actually be used.

The mapping is where the work is. These are the only canonical documents that
were never a flat row, so this is the only place canonical.mjs shapes rather
than renames: a base size arrives with a six-row tier table, six roles and two
dice pools, a deployment with a rank table, and both are rendered as tables
rather than flattened into prose. The tier table's third column is named by the
document, because every hull calls its signature die something different. A
rule chapter is titled rather than named, so it goes through `common` with its
title and has its duplicate opening chapter heading stripped, since the page
already prints that as its h1.

Two lists needed more than columns. Modifications are 257 rows and nobody
scrolls 257 rows, so grade and type become facets and the hull requirement is
lifted out of the prerequisite prose into a column and a facet of its own: 35
of them are gated on ship size, and "what can my Small ship fit?" is otherwise
unanswerable. Ventures get the same treatment for their two real gates, the
deployment whose rank is required and the class whose levels are.

The starship types are canonical-only. The archive has their files, but three
of them lost their structured columns in the 2022 scrape, and the canonical
documents only have hull dice, tier tables, roles and ammunition damage because
the import read them back out of the rules chapters. Mapping the flat records
here would publish a starship section that cannot say how much hull a Small
ship has, so normalize.mjs records them with no archive file instead.

The container job compares every one of the six indexes against the content
image it was built from, with an absolute floor as well as the derived count:
two numbers agreeing on zero would pass against an image with no starships in
it at all, which is the state this work exists to end.
@christopherfowers
christopherfowers merged commit accc72c into main Aug 31, 2026
7 of 8 checks passed
@christopherfowers
christopherfowers deleted the feat/starship-content branch August 31, 2026 01:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants