Stale sweep identified generated anchors by collection membership and role, so an author's hull-collider in
Generated was deleted. Generated anchors now carry aetheria.generated; the sweep removes only those. New smoke
pass package_asymmetric_pass: an L-shaped render hull pins tractor X and shield centre to the bounds centre,
a Source-only ship pins that generation never reads the Source fallback, and a collider placed in Generated
survives Package. All commits build.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Hand mutants (floor dropped; recentre before generation) survived the first Package pass; both now fail.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
AetherDb ship-authoring centre prints Shape.CenterOfMass; Package asks it and moves Ship Root so that point sits
at the world origin, after regenerating the unowned map icon, shield and tractor from the render meshes (Keep
leaves one alone). Package never makes a hull collider (ruling package-frame-defer-collider). smoke_package's
bound-collection rollback cases now rebind to a different path so a rollback that restores keys but not values fails.
C# not yet built when committed; the Blender smokes and Python unit tests pass.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
_bind_collection restores every aetheria.* key if the ID-property store
refuses a value, so a bad ship id or pending leaves the collection as it
was. smoke_package.py gains default-run cases: relpath raising ValueError
(the cross-drive signal) must store the absolute path and finish; a refused
id or pending must leave bound and unbound collections unchanged.
All commits build (Python only).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The two Lows from Soul s1 (follow-up catalog-merge-replay-order). The thermal constants are placeholders
(-1) in this commit: it builds and fails by design, the next commit pins the measured values.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Master's catalog blob (f5645e0a, grammar global and seven verbs), then `consumables-first-set apply`.
Dry run on that tree, verbatim:
Vent radius Min 33.03 (Djinni 14x17 cells at 2 units: half diagonal 22.02, x1.5), Max 49.55
New designs:
Thruster Overdrive 1x1 mass 10 price 18000 stackable False duration 6 roles [propellant, regulator]
ThrottleLockData
Multiplier ThrusterData.Thrust 3-4.5 (propellant)
Multiplier VelocityLimitData.TopSpeed 2-3 (propellant)
Multiplier ThrusterData.Heat 5-3 (regulator)
Multiplier ThrusterData.Visibility 5-3 (regulator)
"Opens every drive wide and holds it there. The ship is thrown forward on a bright, hot plume while the pilot keeps the wheel."
Coolant Vent 1x1 mass 15 price 12000 stackable False duration 15 roles [nozzle, coolant]
VapourDump radius 33.03-49.55 (nozzle), opacity 0.9-0.98 (nozzle), lifetime 14-20 (coolant)
Multiplier RadiatorData.Emissivity 0.3-0.5 (coolant)
"Dumps the coolant loop into space as a spreading bank of vapour. Sensors lose whoever is inside it, and the radiators pay for the loss."
New products:
Thruster Overdrive -> "send it" by DME, every role mean 0.55 dev 0.2: no brakes/ no regrets/ one good burn
Thruster Overdrive -> "Updraft" by Finch, every role mean 0.65 dev 0.2: Light as a feather and, for six seconds, about as fast as one in a gale.
Coolant Vent -> "Smoke Machine" by NiteLife, every role mean 0.55 dev 0.12: Fills the room. Nobody can say who came in with you.
Coolant Vent -> "Morning Fog" by Lightsail, every role mean 0.55 dev 0.1: Rolls in thick, lifts slowly, and leaves the bills with the other fellow.
Dry run. Pass "apply" to author 2 designs and 4 products.
A second run answers "already authored; nothing to do". This commit builds.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GameData/Aetheria.cc is master's blob, not this branch's; the consumables-first-set
apply is replayed in the next commit. The AetherDb command list takes both new
commands. This merge commit does not build until the apply and test seeding follow.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The command mutated the cache's own VerseGrammar before the batch upsert, so the upsert was redundant and two Soul
mutants (update branch dropped; Same ignoring description or render path) survived: the replace test judged the result
with the same Same() the command uses. The test now reads the fields. Unrun until the full job.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ValidateAll (one owner, called by AetheriaStores.Open) refuses duplicate verb names; Validate refuses the reserved role
name actor. Tests pin the name-class edges (a z 0 9 _), a null role element, the starter verb replaced when only its
description or render path differs, the grammar global updated in place, and the fixture's second allegiance and zero-role
speak. The test's scoped registry is TestCatalog.Registry(). Builds; unverified until the full run.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Catalog sha256 193a4d25... (origin/master) -> f5645e0a... Output of 'dotnet run --project tools/AetherDb -- verse-grammar' (the dry run, before this apply), CultLib git-45c2f40:
Grammar: new, revision 1.
Verbs a Ghostlight-simulated Aetheria world may use: ship actions the game films in-engine, and speech rendered as Aetheria conversation.
Starter verbs (7):
mine(site: Place, ore: Cargo) [ShipAction] new
The actor works an ore body at a place and takes the ore into its hold.
haul(cargo: Cargo, destination: Place) [ShipAction] new
The actor carries cargo to a destination place.
tow(target: Faction) [ShipAction] new
The actor tows a station or hull belonging to the target faction.
defend(protected: Faction, at: Place) [ShipAction] new
The actor guards a protected faction's ships and holdings at a place.
attack(target: Faction) [ShipAction] new
The actor attacks the target faction's ships and holdings.
explore(region: Place) [ShipAction] new
The actor surveys a region and charts what is there.
speak() [Conversation] new
The actor says something to whoever is in earshot. Shown as Aetheria dialogue: face to face when docked, by radio with the speaker's portrait over their ship when undocked.
Dry run. Pass "apply" to land the grammar global and 7 verb(s).
A second dry run printed 'Nothing to do.' Data only; does not itself pass the suite until the validation commit's tests are in (builds: yes, the code is unchanged by this commit).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Takes master's catalog pointer (GameData/Aetheria.cc) and its TestCatalog.Registry fixture path;
VerseGrammar is the global scratch catalogs author (TestCatalogGlobal stays deleted: the shipped
registry now has a real global, so a test-only second one would have to be authored beside it).
StatResolverTests, TestCatalogTests and AetheriaStoresTests author VerseGrammar.
Does not pass the suite: the catalog is master's and holds no grammar until the verse-grammar apply commit follows.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Imagination passes (session self-2026-10-10-ag): the Duel oscillation was a
probe artifact (orbits unplaced before the zone's first tick); wiring and
envelope specs refreshed at 08d064c8; the ship-owned incoming-lock warning.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
New Ship places each mesh by the matrix an object can hold (_held: location, rotation, scale), so a sheared parent no
longer makes the drafted cells differ from the cells Rasterise reads from the hull left behind. smoke_frame pins a failed
Save of a saved ship (write failure and stale revision) leaving its ship.cc, New Ship refusing a vertical wall before
anything changes (twice), the sheared-parent equality, and Ctrl+Z past a first Save: the refusals name the way forward
(Bind Ship Collection, Load Layout) and the route works. All commits build.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
New Ship baked rotation and scale into the mesh data after checking the cells on the evaluated mesh, so a Mirror
modifier acted in a changed frame (a half hull, length 10, got 3x5 cells). The meshes now keep their data and carry the
placement as their own matrix; the cells and grid_origin are the ones computed before the bind and are placed by the one
_place_grid writer, which Rasterise shares; no call that can refuse follows the bind. The single-user refusal, which
protected the baking, is deleted. One _triangles_xy reads the evaluated meshes for both New Ship and Rasterise.
smoke_frame: a Mirror half hull gets the cells of the hand-mirrored solid, and the drafted cells equal Rasterise's of the
hull left behind. Every commit builds (Python only).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Package refuses loose meshes and a pending ship; Package reads the .cc rows cut to the seven known members and only
compares a buffer that belongs to the bound ship; Flip Nose turns the hull back when its Rasterise fails; New Ship
refuses meshes in child collections; the Grid is not drawn from a buffer short of cells; Rasterise refuses a ship with
no Ship Root. Eight hand mutants, all caught. Every commit builds (Python only).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
One frame predicate: _loose_meshes no longer exempts Source, so a mesh Rasterise reads is a mesh Flip Nose turns (it
turns Ship Root's descendants) or the operator refuses and selects it. Package: the glTF exporter's RuntimeError is
printed to the console and reported as fixed text; the validator's verdict goes to the console and the panel reports
accepted or refused with the anchor count only (no ship ID, no anchor ID). smoke_frame and smoke_package pin each, five
hand mutants caught. Every commit builds (Python only).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Pass 7: a pending Save over an existing ship.cc is refused and leaves it; a failed Save keeps the files that were in
the ship folder; New Ship takes no hardpoints from the ship before it; a buffer that belongs to another ship is neither
saved nor rasterised. Pass 8: operators called with undo=True push a native step in background Blender only when they
carry UNDO, so Rasterise, Flip Nose and New Ship undo as one step and Save does not. Nine hand mutants, all caught.
Closes no finding; every commit builds (Python only).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sixteen gear picks drawn with replacement fill a shipped station hold, so a station whose roll hit
usually stored nothing (29 of 400 held one against the ruled quarter). The consumable step now runs
before the gear fill; with no consumable on offer it still draws nothing, so generation is unchanged.
Ships keep their step after OutfitEntity.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Station and ship rates are measured per hull on two station hulls and two ship hulls with holds that
sixteen gear picks fill, on a station whose first bay refuses, and on the shipped catalog's own hulls.
The ship band is 3000 seeds so chances of .12, .15 and .05 fall outside it. These tests fail on the
generator as it stands (consumable stocked after the gear); the next commit fixes the generator.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Builds: yes. The previous commit's pin test failed on '.' (a dot last is refused by its own rule).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Regex form could not be mutated on the verification path (the mutant runner collapsed its backslashes), and a
character loop with named length constants states the same rule without the dependency. Adds refusals for a capital
inside a name, a hyphen, and a direct empty-name case. Builds (not yet run when committed).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
One chooser (_ship_collection) and one predicate (_is_ship). _save_layout is the only
replace_layout caller and creates a pending ship's file, removing what it made on failure.
Rasterise writes the layout buffer and aetheria.grid_origin = [x, y, width, height]; Flip Nose
and Package refuse meshes outside Ship Root. New Ship checks first and writes nothing to disk.
Operator reports are fixed text; AetherDb output goes to the system console. smoke_frame covers
undo, hardpoints, Save, cleanup, loose meshes and an empty Game folder preference.
Builds: yes (needs the previous commit's ship_cc).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
layout_revision(shape, hardpoints) is the revision rule replace_layout and Package share.
SHIP_ID_CHARS and RESERVED_SHIP_IDS mirror ShipAuthoringStore.RequireShipId; ShipSchemaPinTests
sweeps every character and every candidate stem against the C# rule. ship_cc errors no longer
carry the path, mount id, anchor id or object name. C# tests: create judges the ID not the
display name, FindRoot answers the working directory itself, short trailing-dot IDs.
Builds: yes (C# test edits and Python only).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The previous commit (8bfce189) does not build: CS0104 ambiguous Random in ThrustAllocatorTests.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Nothing asked, nothing fired is a fact about the intent: when all three clamped intents are exactly zero Allocate returns the zeroed buffer before the solve, so a warm solve that stops at the iteration cap can no longer fire thrusters. The output flush is gone. The warm start is left at the last solved point. Tests: the two 40-thruster hulls Soul found, and a small intent still answered at any column scale. Builds untested locally; verified on Yggdrasil.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Off-centre joint limits (20..50, -10..50, -50..0) so Max-Min is distinguishable from |Min|+|Max| and 2*max/2*Max; Bind walking past tagged
nodes that are not joints; Rigs and the lead mount follow hull order where it differs from name order. Tests only; builds.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Flushing an empty cache writes no file, so the previous fixture still hit the new missing-file refusal.
Builds.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>