Imagination refreshed Cut 8 against Aetheria 59bc5753 and CultLib main, with
probe builds: 8a swaps Unity.Mathematics for CultMath on the legacy cache
(76 Unity conversion errors listed per file, MathFormatters kept), 8b cuts the
data model over. Operator rulings: CultMath gaps filled in CultMath 0.2.1
(f060536), which 8a pins; double overloads keep double precision; the
Temperature and SchematicShape drawers are ported into Aetheria's Studio
drawers.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Soul compiled step with dxc and found NaN gives 1, so the docs-based
change is reverted to the compiler's behaviour. The shader mirror test
only proved compilation and grows numeric comparison of every mirrored
function. The operator keeps the ref row indexer without an analyzer and
documents that writes through readonly, in, and property receivers land on
a copy.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Soul verified the Studio model rewrite and found a saveable partial edit
after a throwing drawer, edit decisions left in IMGUI, a comparer mismatch
on dictionary keys, and three model tests that do not pin their rules. The
operator chose: delete FlushAsync(soft) and edit Mimir's call, and retry a
lockless directory read on manifest mismatch. By-name reflection in CultNet
and CultMesh becomes a follow-up. The composite heuristic waits on the
operator.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
HLSL source did not yet compile as C#. Operator chose A throughout: generate the
full swizzle set and mixed constructors with a test over CultMath's own shader
bodies, fix cheap intrinsic semantics now and defer larger matrix features, add
Studio drawers for the new types after merge, and compile-check the shader
mirror with dxc.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Operator goal: CultUI, descended from Aetheria's PropertiesPanel, should be able
to recreate the CultCache Studio at runtime. The inspection logic moves into an
engine-free model in CultLib core and the editor Studio lowers it; the runtime
lowering is a follow-up.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Soul found foldouts dirtying records, fragile drawers, and type-only drawer
claims that cannot express Aetheria's inspector attributes. Operator decisions:
inspector attributes move into CultLib core, drawers claim by attribute or type
with a default fallback, opening a directory store creates no files, and game
data stores never live under a Unity Assets folder. Cut 8 lists CultMath in the
Unity manifest directly.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Operator decision: the manual Studio check runs in Aetheria against the tagged
package once Cuts 7 and 8 land. CultLib's demo Unity project, which has no
committed manifest and a UI assembly that does not compile, is recorded as a
follow-up outside the migration.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The parity audit showed CultMath is not a drop-in for Aetheria's
Unity.Mathematics use. Operator decisions: CultMath targets HLSL source
compatibility, so components and swizzles become writable; CultMath keeps its
own behavior where it differs from Unity.Mathematics; only what Aetheria uses is
added; the Unity bridge lives in CultMath's Unity package. Cut 8 swaps Aetheria.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Operator decision: Aetheria moves onto CultMath as the best workout GameCult's
math library can get, with gaps filled in CultMath itself. The map no longer
rejects the switch, and Cut 6's Studio drawers target CultMath types only.
Unity.Mathematics stays permitted for tooling supporting a Unity game; CultLib
uses CultMath.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The sibling runtimes now hold one home store per type, refuse moves and
non-home loads, validate before writing, and serialize mutations. TS
registration and attach methods became promise-returning and Rust attach
returns a Result, which consumers adopt when they re-pin. Cut 6 is in progress.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The AsyncLocalStorage guard refused ordinary write-backs from store change
handlers and still missed the real deadlock. The contract instead says a store
call must not wait for a write to its own cache to finish. Legacy global
retirement stays two-step and a crash leaving both records stays loud.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Operator decisions after Soul's check of the sibling locks: a legacy-key global
loads as a read-only compatibility shim that the first write replaces under
__global__ and removes; re-entrant mutation is forbidden in TS and Python; a
Rust store keeps receiving its full view and the default push_all fails closed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Soul found the TS and Python caches writing stores before validating, TS open
to async interleaving, Python accepting globals under any key, and Rust's
load_soa clearing before it could fail. Operator chose A throughout: a per-cache
TS queue for mutations, globals only under __global__, delete Rust's uncalled
load_envelope and make load_soa atomic, and leave error wording alone.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Cut 5 landed on the routing branch and the Python suite runs under unittest.
Soul found the sibling runtimes let a record's home move and loaded records from
the wrong store, and TS and Rust refused in-memory writes; those are being
brought to the C# reference.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Cut 4 ended at CultLib 5bd4e4e with the generator deleted and the registry
persisting exactly what MessagePack round-trips. The five Eve.Surface documents
change schema ids because constructor-filled get-only members now enter the
catalog; no store on disk holds them.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Soul's check of the generator deletion found the map's Q2 and Q4 evidence still
describing generated metadata and serializers as current. Those lines now say
the registry owns type names and all payloads go through MessagePackSerializer,
and Delvehold's re-pin follow-up names its generator references and its
preference for a stale CultLib worktree.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Deleting the generator exposed that its codec was the only writer for documents
without [MessagePackObject], and that it named nested member types with a dot
where reflection uses a plus. Operator decisions: the registry requires
[MessagePackObject] on every [CultDocument], and nested type names keep the
reflection form once a store scan shows no persisted record uses the dot form.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Operator decision: with .cc canonically MessagePack, the source generator only
duplicated the reflective registry. Nothing reads its output without a
reflection fallback, no consumer builds AOT, and nothing measured a benefit,
while the duplication caused every Cut 4 defect. The registry stays the single
descriptor authority with all rejection rules. Delvehold and EveUnity re-pin
follow-ups are recorded.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
MessagePack reads the base declaration's attributes, so the generator and
registry reject overrides whose Key or IgnoreMember differ from the base
instead of using the most-derived declaration. The typed serialize helpers are
deleted. Global-namespace type naming and generic document types in generator
assemblies are recorded as follow-ups.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Operator decisions: MessagePack's integer [Key] is the only slot authority and
the cache core references MessagePack.Annotations directly, since .cc is
canonically MessagePack; a generic document's resolvers come from its own
assembly. Also records the generator and registry disagreements Soul found with
old-versus-new consumer probes and the shape of the fixes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Operator chose option A on all three: a public cache read returns a document
with the current sequence, and consumers subscribe before reading; OnUpdate and
CultNet's derived streams stay unprotected and documented as such; schema-alias
handles and removals are documented as not stale-protected.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The CultNet subscription server and database watches keep latest values from
changes that carry no sequence, and the Mesh mirrors' refresh and observe paths
race with applied changes. None came from the sequence change; each is named so
it is not mistaken for covered.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Operator decision: the cache stamps each admitted change with a per-cache,
in-memory sequence and publishes on the caller's thread without scheduling
delivery. Latest-value consumers compare sequence numbers. Save-order delivery
with tickets is rejected: it turned the cache into a delivery scheduler,
deadlocked against the CultNet subscription server's lifecycle lock, and could
stall a cache on an interrupted wait.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Operator decision: changes reach observers in the order they were saved, across
threads, so latest-value consumers such as CultMesh's WatchRecord never apply a
stale record. Also records per-call publication on the caller's thread and that
only OnUpdate handler exceptions are rethrown to the caller.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Cut 3's second Soul pass found Watch observers and OnUpdate running while the
gate was held on re-pull and commit, which deadlocks a subscriber that waits on
a thread reading the cache, and a throwing handler that could leave a store
holding records the cache dropped. Observers now publish after the outermost
gate exit, and stores adopt their loaded view first. Also corrects the flush
wording, which described only single-file stores.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Operator chose option A: a flush or unconditional commit on a directory store
lands its changed pages onto the current manifest, so other writers' records
survive, while a single-file store stays last-writer-wins. Also records that an
attached store shares its cache's gate, which is how Cut 3 fixed the lock order.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Operator chose option A on all three questions Soul raised: one lock order
(cache, then store) with store I/O blocking that cache's readers; an
unconditional Commit is last-writer-wins like a flush; a store that fails to
hydrate on open throws and is never overwritten. Also records one key per
store, load-only OnUpdate, missing-file dirtiness, the late-route fixture,
TryGet kept for AquaSynth, the scoped SemaphoreSlim check, and the corrected
size target for CultCache.cs.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Operator chose option A. Opening hydrates; a consumer that wants a fresh store
removes the records it does not keep, upserts, and flushes, and the atomic
snapshot replace does the rest. No CultLib API is added and PullOnOpen goes in
Cut 3. The two AquaSynth single-document writers adopt that form; the
File.Exists-style setters in AquaSynth and Mimir just drop the property.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Cut 2 was not purely subtraction: load-time admission failures now propagate,
a store attached to a second cache replaces the first cache's callbacks, a
missing manifest empties the store on the next flush, and a v1 snapshot opened
as a directory store throws. The code still keeps atomic replace, manifest
ordering, content-addressed pages and both leases, but the tests for them left
with the stage probes. Cut 3 now restores them with real file locks, makes load
all-or-nothing, refuses shared stores, settles the legacy catalog resolver, and
keeps CultNet from publishing before a batch commits. The managed document is
recorded as parked with SoA.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
OpenAsync keeps pulling until attach hydrates in Cut 3. CultCache.FlushAsync
keeps its dead soft parameter for Studio's reflection until Cut 6. Loaded and
Unloaded are protected internal; PullSelected goes with the directory store;
a missing directory manifest is an empty store; doc comments go from all eight
files. PullOnOpen has AquaSynth and Mimir setters that mean overwrite without
loading, so Cut 3 must decide who owns replacing a store before deleting it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Cut 3 rewrites the Cut 1 fixture that attaches a second untyped store and
retires the reflective IsGlobal hack. Cut 4 makes the generator discover
inherited members like the reflective registry, so derived documents hash one
schema id in both builds, and requires [Key] on persisted document members.
Corrects sibling attach wording, the C# commit status, and a deleted doc target.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The two-process race probe (P7) spawned recursively and produced no trustworthy
result, so conditional commit's lock behavior is proven by Cut 3's tests, which
now require guarded child launches (explicit host, role chosen by environment,
fail if a child would spawn) or in-process concurrent file handles. The fork bomb
is recorded among the risks. Compare-exchange leaves the follow-ups.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Saved mid-pass after a workstation crash: per-entry Expect and ExpectUnchanged
on the one-store batch, TryCommit, a lock sidecar for the single-file store,
the last-writer-wins flush contract, the race tests and probe P7, and full
CultLib\packages paths for sibling runtimes. The Imagination pass is finishing
the rest.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Second and third Imagination passes, probe-backed. Globals get lifecycle owners
and the cache invents none; routing admits a record's home once and refuses
later routes over admitted types; mirrors go in every runtime; subtraction is
separated from behavior. SoA is parked at a tag with its intent recorded.
The MessagePack generator is contained in CultLib's own package reference.
Atomic multi-record commit stays as an explicit one-store batch replacing the
ambient transaction machinery. AetheriaEve is removed from all evidence.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
AetheriaEve is preserved as a specimen and constrains nothing. The consumers
that must survive the CultLib changes are the ones that build against it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The Imagination pass over cultcache-migration-target.md: answers to its eight
questions with evidence from CultLib and its canonical packages, the CultLib
store-routing authority map, the wire-parity plan, ten sequenced cuts with
failing-first tests, negative checks and build budgets, a subtraction ledger,
and rejected paths. Two corrections on review: Cut 0 is already done
(6bd3e176, 560779a4), and Cut 7 adds an LFS rule for .cc before committing
the catalog.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The neighboring cultcache-rs, cultcache-py, cultnet-rs and cultnet-ts
repositories are defunct. Wire parity is held against CultLib\packages
(cultcache, cultnet and cultmesh runtimes) with C# as the reference.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Aetheria moves onto modern CultCache from CultLib, cache only. States the end
state for Aetheria and CultLib, the wire-parity and foundation invariants, the
probe evidence, and the questions the Imagination pass must answer before any
cut. Points the parked perfect-machine map at it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Eight factions pointed at one boss hull GUID that no longer resolves,
shared wreckage from the database loss. PlaceFactionsMain gives a boss zone
to every faction carrying a BossHull, so each dangling link claimed a
chokepoint that could never spawn a boss.
AetherDb.Open no longer registers the name file store. CultCache subscribes
Add to a store EntryAdded, MultiFileBackingStore.PullAll re-emits what it
loads, and Add pushes to that type store, whose Push writes a file: opening
the cache rewrote all twelve name files, 4.4 MB, on every command. They were
byte identical, and it only surfaced as an error because Unity had one of
them memory mapped. Name files now load only on request, and the scope doc
records the underlying smell.
Adds commands: factions, clear-boss-hulls, save, loadout (runs the real
LoadoutGenerator against every hull), hardpoint-fit.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A design lists role names; a faction product is a manufacturer's branded
build of one, carrying its name, its flavor text, and a pseudo-gaussian
quality distribution per role whose mean is the technology put in and
whose deviation is their quality control. A PerformanceStat may name the
role whose quality it reads, unset reading the item own workmanship as
before, so old saves behave unchanged. Generation selects products rather
than designs, which makes what a faction makes the availability rule.
This is Njordr shape at one dimension: role names, per-role derivation
and per-product distributions carry over when quality widens into
dimensions. No parts exist yet; the product authors the role quality.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Aetheria authors roles, per-role stat derivation, continuous part quality
and per-faction role competence: the same shape one dimension wide, so
migration widens quality into dimensions rather than restructuring. No
second owner of item property derivation grows here.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Aetheria.Shared.csproj compiles ServerShared with MessagePack, UniRx
core, Ink and Unity.Mathematics from source against .NET Standard 2.1
(Unity's API level) with no Unity defines; a clean build checks that the
simulation stays engine-independent. tools/AetherDb opens AetherDB.msgpack
through the game's own CultCache for file-based C# scripts; station-fit
checks every station hull can take a docking bay.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>