Skip to content

feat(data): value-partitioned archetypes (shared components)#143

Open
krisnye wants to merge 4 commits into
mainfrom
krisnye/allocation-components
Open

feat(data): value-partitioned archetypes (shared components)#143
krisnye wants to merge 4 commits into
mainfrom
krisnye/allocation-components

Conversation

@krisnye

@krisnye krisnye commented Jul 14, 2026

Copy link
Copy Markdown
Collaborator

Description

Adds value-partitioned archetypes (the "shared components" pattern) to the ECS. A component declared partition: true stores every distinct runtime value in its own archetype, whose partition column is a zero-per-row ConstTypedBuffer — so entities sharing a value are contiguous in memory (a storage-level coarse spatial broad phase).

Public surface

  • partition: true schema marker (primitive components).
  • ensureArchetype(keys, values?) — discriminated return: a Router (write-only) when the key set includes a partition component without a value; a concrete Archetype when a value is supplied or no partition key is present.
  • Router — routes each insert by the row's partition value to the concrete child (created on first use).
  • queryArchetypes(include, { where }) — partition-value filter, decided at archetype granularity (O(archetypes), no row scan).
  • store.archetypes.<Name> and the transaction context t discriminate partitioned vs concrete per declared archetype.
  • update migrates an entity between value-children when its partition value changes.

Internals

  • Single resolveArchetype(keys, partitionValues?) primitive backs ensureArchetype, routing, migration, and restore.
  • Index maintenance is wired via in-place insert decoration at archetype creation (onArchetypeCreated hook) — no Proxy, no forwarding wrapper. This also removes the pre-existing Proxy that wrapped concrete archetypes.
  • Partition detection reads the live schema, so dynamically extending a store/database with partition components works.
  • toData/fromData round-trips partition children (values + rows).

Type-perf

Flat, sub-quadratic scaling preserved — no TS7056 cliff (verified via scripts/typeperf). ~4% flat instantiation overhead when unused, from carrying PK through the composition types.

Also

Removes the unused, orphaned observeDependentValue helper (no internal, cross-package, or firefly-platform consumers) — which also removes a runtime Proxy.

Tests

Red/green compile-time type tests (positive + negative @ts-expect-error) at the isolated-helper, store, and transaction-context levels, plus runtime tests at the core, store, and database/transaction layers — including dynamic extend, N-distinct-values → N-archetypes with const columns, unique-index enforcement across value-children, and migration.

🤖 Generated with Claude Code

krisnye and others added 4 commits July 14, 2026 01:13
Components declared `partition: true` store each distinct runtime value in
its own archetype, whose partition column is a zero-per-row const buffer —
entities sharing a value are contiguous (a storage-level spatial broad
phase). Adds a discriminated `ensureArchetype` (Archetype | Router),
routing insert, partition-value migration on update, a partition `where`
on queryArchetypes, and full discrimination through the store/database/
transaction-context types. Index maintenance is wired via in-place insert
decoration (no Proxy). Also removes the unused `observeDependentValue`.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… code

Fixes the root type issues the casts were hiding rather than casting:
- align ArchetypeQueryOptions.exclude domain (drops `options.exclude as any`
  in selectEntities)
- thread IX through createStore's return type
- fix Store.extend to resolve component/resource schemas (C & FromSchemas<XC>)
Partition tests are now fully typed and cast-free (no `as number`/`as any`);
also drops an identity cast in the core router.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
When the leading run of order keys are partition components, each archetype
holds a constant value for them, so the archetypes already bucket the rows on
that leading key: sort the buckets by value, sort only the remaining keys
within each bucket, and concatenate in bucket order. Turns the O(N log N) sort
into O(N log(N/K)), and O(N) when a partition key is the sole order key. Falls
back to the full sort when no leading order key is a partition component, with
identical output. Tests compare against a naive full sort across leading,
compound, descending, where-filtered, fallback, large-K, and tie cases.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Router was too general a name to sit peer to Archetype and forced an extra
import at every use site. Move it under the Archetype namespace via declaration
merging so it reads Archetype.Router and rides the existing Archetype import.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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