Skip to content

M4 iteration 2: portable modules and the Mockingbird re-carve - #49

Merged
Dibujaron merged 10 commits into
mainfrom
feat/m4-iteration2
Jul 31, 2026
Merged

M4 iteration 2: portable modules and the Mockingbird re-carve#49
Dibujaron merged 10 commits into
mainfrom
feat/m4-iteration2

Conversation

@Dibujaron

Copy link
Copy Markdown
Owner

One module document can now serve many (hull, slot) placements, a module can claim several adjacent slots, and the Mockingbird is re-carved so her rooms are slots — five standard cabins served by a single rijay.cabin.standard document, a central payload bay, a crew commons, and a modular engine room.

Nothing about the authored-overlay bet changes. Every target is still drawn by hand against one specific hull's coordinates, which is what guarantees its doors line up. What changed is file organisation: one document per concept instead of one per placement. Free placement stays refused, and the validator still does no geometry.

This restores what docs/modules.md originally specified and that iteration 1 simplified away, so the Sparrow and Finch can be authored once, against final rules.

What landed

34be4ec 18d33fc a module document carries targets
5d46056 301373d a target may claim several adjacent slots
6f15216 the Mockingbird re-carved into ten slots
ecdec33 one rijay.cabin.standard serving all five cabins
b068b9f 0a49201 schema and docs
8164269 0f74346 review fixes

The ten slots

cockpit (4 tiles) · cabin_fore_a (2) · cabin_fore_b (2) · crew_commons (12) · cabin_mess (2) · payload (45) · cabin_engineer (2) · engineering (6) · cabin_aft_stbd (2) · hold (74)

Fixed hull: the cockpit passage, the x8 corridor, the aft junction, both stairwells, the whole Mezzanine with its Q ports, and the skin. Where a divider now has slot tiles on both sides — the aft passenger cabin partitions, the wall between the large common and those cabins — it left the hull and moved into the payload module. Those walls are movable now.

Verification

  • 337 Gleam tests, no failures; harness 29 passed / 2 deselected.
  • The Mockingbird's deck is unchanged, tile for tile. server/test/fixtures/mockingbird_authored.json and default_loadout_reproduces_the_authored_deck_test were the arbiter throughout and are untouched — zero deletions in mockingbird_test.gleam.
  • tools/slotmap.py renders the ten regions at exactly the planned tile counts, and the bare-hull render confirms the payload interior is genuinely open where the modules now own it.
  • The new module grids are byte-for-byte transcriptions of the deleted ones at the same origins, not re-drawings.

Two forced number changes

The plan's own module masses and tag figures required these; both were verified against the unchanged part documents.

  • Hull dry mass 96.0 → 73.0 — modules went 24.0 → 47.0, so the resolved total stays 128.0 and her flight numbers are unchanged.
  • Reactor power 10 → 18 — modules now draw 17 with the Consol patch, 18 with the stock engine, preserving the pre-M4 headroom of 1 and 0 respectively.

Known follow-up (not a blocker)

tag_deficit:power is unreachable through shipped content now: every slot has one candidate module except hold, whose two both draw 1. The rule is still enforced and unit-tested; what is missing is a shipped demonstration, which is why sim_test's refused-refit case retargeted to tag_deficit:engine. Iteration 3's refit catalog brings alternatives that can overdraw, at which point that test can go back to power. Worth noting she sits at exactly zero headroom with the stock engine, so the first catalog addition forces a reactor decision.

Vocabulary change

module_wrong_hull and module_wrong_slot are gone, replaced by module_not_drawn_for_slot. A typo in a module document's slots reports as target_slot_not_on_hull:<module id> — a content error naming the file at fault — kept distinct from the player-facing slot_not_on_hull:<slot id> refusal.

🤖 Generated with Claude Code

Dibujaron and others added 10 commits July 27, 2026 20:47
…not just the first (#M4)

every_shipped_module_resolves_in_its_slot_test picked one target per
module via list.find, so a module with several targets on this hull
(the upcoming multi-slot cabin) would have all but its first placement
silently unverified. Iterate every mockingbird target instead.
…(#M4)

`lookup_modules` only resolved the one slot id named in a loadout entry;
the rest of a multi-slot target's `slots` were never checked against the
hull, so `check_bounds`'s digit lookup silently dropped a bad id instead
of erroring. Resolve every id in the target's `slots` up front, reusing
the existing `slot_not_on_hull:<id>` reason string.
…lines (#M4)

Her five slots become ten, and they now name ROOMS rather than the shapes a
particular fit happened to draw: a cockpit, five identical 1x2 cabins, the crew
commons, the payload bay, engineering and the hold. Corridors, both stairwells,
the aft junction, the whole mezzanine and the hull skin stay fixed hull.

Two regions that were hard-coded interior — the mess cabin at (4, 10-11) and
engineering at (5-7, 18-19) — are stripped back to bare shell so their modules
supply what is in them. Everywhere a divider now has slot tiles on both sides
the hull hands the whole wall to the module (the Mockingbird already drew none
of those, so this is a rule the re-carve establishes rather than a diff).

`payload_passenger`, `commons_crew` and `engineering_stock` replace the four
modules whose regions no longer exist; `cockpit_stock` and both hold modules
keep their slot ids and their content.

Two hull numbers move so nothing downstream does. Her dry mass drops 96.0 ->
73.0 because the default modules grew 24.0 -> 47.0: the fit still totals 128.0,
so her flight numbers are untouched. Her reactor grows 10 -> 18 power because
the same interior is now billed as ten modules instead of five (17 with the
Consol patch fitted) — one spare, exactly the headroom she had before.

The cabin document that fills the five cabin slots lands in the next commit, so
the golden deck comparison is red at this commit by construction.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…s (#M4)

`rijay.cabin.standard` carries five targets on the Mockingbird — `cabin_fore_a`,
`cabin_fore_b`, `cabin_mess`, `cabin_engineer` and `cabin_aft_stbd` — and the
default loadout installs it in all five. One concept, one document, however
many places it fits; the id is namespaced `rijay.` rather than `mockingbird.`
because the Sparrow and the Finch add targets to this same file rather than
each growing a cabin file of their own.

Every target is still hand-drawn against its own origin: the three forward
cabins put the door and window on the same walls, the engineer's cabin flips
north-south, and the aft starboard cabin mirrors east-west. That is the point —
the doors line up because a human drew them lining up, not because anything
matched shapes at runtime.

`module.schema.json` learns the `targets` spelling, minimally, so the new
document validates; Task 5 owns the full schema and documentation pass.

Both suites green: 336 Gleam tests, harness 29 passed / 2 deselected, with
`default_loadout_reproduces_the_authored_deck_test` reproducing her frozen
pre-M4 deck tile for tile.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… (#M4)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Mirror branch A's exclusion onto branch B so hull+slot+targets is
genuinely rejected (the schema's typo-catching purpose otherwise misses
a half-finished migration to targets that leaves stale flat fields the
decoder silently ignores). Also fix docs/modules.md's Mockingbird slot
summary: the hold slot lives on the Lower deck, not a "Hold" deck.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… drop dead Slot (#M4)

A content bug (a module document's targets naming a slot id off the hull)
was reported through slot_not_on_hull, the player-refusal channel — give it
its own target_slot_not_on_hull:<module id> reason and update the three
vocabulary lists plus the covering test. Also: cover the schema's oneOf/not
construct with a live positive/negative test, close the targets+stray-slot
schema gap symmetric with hull, align docs/modules.md's both-spellings tone
with the schema's rejection, narrow lookup_modules's fitted tuple to
#(Module, Target) now that nothing reads the Slot element, and fix a stray
hyphenated "iteration-2a" in deckplan-format.md.
… (#M4)

The schema oneOf test proved `oneOf` was live but never `not`: its negative
case carried both `hull` and `slot`, so it matched BOTH branches and the
exactly-one rule refused it whether or not the `not` clauses did anything.
Adds `targets` beside a lone stray `slot` — the shape a half-finished
migration leaves behind — which matches branch 1 alone unless `not` is live.

Renames the test accordingly, and moves the both-spellings clause in
docs/modules.md next to the sentence it qualifies rather than after the
"neither" case.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@Dibujaron
Dibujaron merged commit b24d626 into main Jul 31, 2026
1 check passed
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.

1 participant