Relationship Bridge Architecture V2
Status: Proposed v2 (2026-05-05)
Supersedes: the v1 primitive-first framing in this file from 2026-05-04
Scope: SECS runtime architecture, future deterministic kernel, host adapters
Does not change: .secs scripting language, secs-roslyn compiler identity, scope model, modding contract, or the rule that SECS is not replaced by Unity DOTS / Flecs / any other ECS
Purpose
The first draft correctly identified two real pressures:
- SECS needs richer relationship and query semantics than one host callback named
WalkScope. - Unity DOTS integration cannot put Unity packages into the engine or force a managed boundary through every hot path.
The first draft then centered the design on the wrong object: a public low-level native primitive layer modeled as RawHashMap, PairId, ReachableCache, a Flecs-like query VM, and one giant HostBridge*.
That is backwards. Those are implementation tools. The architecture SECS needs is a deterministic SECS semantic kernel: a host-agnostic runtime substrate that owns SECS concepts directly — scopes, relations, collections, modifier bindings, query plans, channel dependencies, snapshots, command journals, diagnostics, and deterministic iteration. Native collections may implement that kernel, but they are not the architecture.
This v2 document reframes the bridge around that semantic kernel.
Decision Summary
Build a host-agnostic deterministic SECS Kernel between the SECS runtime coordinator and host adapters.
The kernel owns the semantic graph and deterministic indexes the runtime needs:
- entity identity and lifetime tables
- relation definitions and relation storage
- scope-walk, reverse-walk, collection, ownership, and template
IsAindexes - query plans and ordered query result materialization
- modifier binding indexes and value-bucket preparation
- channel dependency edges, invalidation, and snapshots
- command journal recording and canonical apply order
- save/load state sections and content-manifest hooks
- host-agnostic diagnostics, tracing, and profiling markers
The kernel is pure netstandard2.1 C# with unsafe/blittable internals where needed. It has zero Unity package references. Unity DOTS is one adapter. The dev server is another adapter. Future hosts consume the same kernel.
The kernel may still live in an assembly named SECS.Native if that remains the product name, but the architectural concept is not "a raw native collection library." It is "the SECS semantic kernel."
Non-Negotiable Constraints
- SECS scripting remains the authoring surface. Never frame this work as replacing SECS with Flecs, Bevy, Unity DOTS, or a generic ECS.
- Engine and kernel assemblies have zero Unity package references.
- Unity packages appear only in the Unity adapter.
- Relationship storage is Bevy-style non-fragmenting: target is data, never archetype identity.
- Determinism is required at the semantic API level from day one.
- Hashmap iteration order and allocator free-list behavior must be deterministic from day one where those structures exist internally.
- The kernel must not truncate SECS identities. SECS declaration ids are 64-bit FNV-1a hashes; entity handles are 64-bit today. Flecs's packed 31-bit relation / 32-bit entity target encoding is not a valid SECS identity model.
- Instrumentation ABI slots must be host-agnostic. Do not put Unity
ProfilerMarkerfields in kernel structs. - The existing
ISecsHostReadssurface is a symptom of multiple responsibilities being collapsed into one interface. V2 splits the boundary by responsibility instead of reproducing the same shape as one giant function-pointer struct.
Corrected Layer Model
┌───────────────────────────────────────────────────────────┐
│ L1: SECS source (.secs) │
│ scopes, walks_to, modifiers, systems, events, │
│ saved scopes, mod operations │
└───────────────────────────────────────────────────────────┘
↓
┌───────────────────────────────────────────────────────────┐
│ L2: secs-roslyn output │
│ Generated behavior bodies + generated WorldSchema │
│ query plans, relation definitions, dependency metadata │
└───────────────────────────────────────────────────────────┘
↓
┌───────────────────────────────────────────────────────────┐
│ L3: SECS runtime coordinator │
│ registry, channel resolver, tick pipeline, events, │
│ activation, save/load, hot reload, diagnostics │
└───────────────────────────────────────────────────────────┘
↓
┌───────────────────────────────────────────────────────────┐
│ L4: SECS Kernel │
│ deterministic semantic graph and indexes │
│ relations, collections, query plans, modifier indexes,│
│ channel dependencies, snapshots, command journal │
└───────────────────────────────────────────────────────────┘
↓
┌──────────────────┬──────────────────┬─────────────────────┐
│ L5a: SECS.Unity │ L5b: SECS.Server │ L5c: future hosts │
│ DOTS/Burst │ managed server │ Godot, MonoGame, │
│ adapter only │ adapter │ custom engines │
└──────────────────┴──────────────────┴─────────────────────┘
↓
┌───────────────────────────────────────────────────────────┐
│ L6: Host runtime │
│ Unity DOTS / SignalR server / future host │
└───────────────────────────────────────────────────────────┘
What Changed From V1
V1 said "L4 is where Flecs's relationship semantics are reimplemented." V2 says: L4 is where SECS runtime semantics are represented in deterministic indexed form.
V1 exposed RawHashMap, PairId, and the query VM as the center of the public tier. V2 treats raw collections as internal kernel machinery unless an adapter use case proves a stable low-level API is necessary.
V1 put "one field per ISecsHostReads method" into a function-pointer bridge. V2 splits host integration into separate bridges because ISecsHostReads currently mixes unrelated jobs: host fields, scope walks, collections, template metadata, channel re-entry, template value resolution, generic scope queries, and prev-tick snapshots.
WorldSchema: The Compiler Output the Kernel Consumes
The compiler must eventually emit two kinds of output:
- Generated behavior bodies: formulas, triggers, systems, events, template methods, and contract callables.
- WorldSchema: a deterministic schema blob/table set describing the SECS world the kernel indexes.
WorldSchema is the missing architectural object from v1.
It contains:
- scopes and declared
walks_toedges - scope fields and their storage ids
- typed scoped collections and their field-path ids
- contracts, templates, tags, and template structural predicates
- relation definitions and relation metadata
- channel declarations, channel kinds, clamps, source fields, and
track_prev - modifier declarations, effects, stacking, propagation, and mod attribution ids
- query plans for generated query expressions
- declared formula/channel dependencies where known
- execution eligibility flags for generated bodies
- content manifest names and hashes for save/load compatibility
The kernel must be initialized from this schema. It must not infer core SECS semantics by looking at arbitrary raw pairs.
Concrete Schema Shape
WorldSchema is not a serialization format decision. It is the logical table set the compiler/runtime agree on. It can be materialized from today's SecsRegistry during migration, then emitted directly by secs-roslyn later.
public readonly struct WorldSchema
{
public ulong SchemaId { get; init; }
public int Version { get; init; }
public ReadOnlyMemory<ScopeRow> Scopes { get; init; }
public ReadOnlyMemory<ScopeFieldRow> ScopeFields { get; init; }
public ReadOnlyMemory<CollectionRow> Collections { get; init; }
public ReadOnlyMemory<RelationDefinition> Relations { get; init; }
public ReadOnlyMemory<ContractRow> Contracts { get; init; }
public ReadOnlyMemory<TemplateRow> Templates { get; init; }
public ReadOnlyMemory<TagRow> Tags { get; init; }
public ReadOnlyMemory<ChannelRow> Channels { get; init; }
public ReadOnlyMemory<ModifierRow> Modifiers { get; init; }
public ReadOnlyMemory<QueryPlanRow> QueryPlans { get; init; }
public ReadOnlyMemory<ExecutionBodyRow> ExecutionBodies { get; init; }
public ContentManifest Manifest { get; init; }
}
The important rule: every row order is deterministic compiler output order. The kernel can derive dense internal indices from this order, but ids remain the 64-bit SECS ids. Schema order is also the default order for declaration iteration, diagnostics, save sections, and diff output.
Schema Rows That Matter First
The first implementation pass does not need every row above. The minimum useful schema is:
| Row | Required fields | Purpose |
|---|---|---|
ScopeRow | ScopeId, Name, declared walk targets | Builds scope legality table and walk relation definitions |
ScopeFieldRow | ScopeId, FieldId, type, name | Validates host field bridge and channel source fields |
CollectionRow | parent scope, field id, kind, key type, element scope | Builds collection relation definitions and iteration semantics |
ContractRow | contract id, root scope, method ids | Builds contract entity sets and callable metadata |
TemplateRow | template id, contract id, root scope, tags | Builds structural predicates and template activation indexes |
ChannelRow | channel id, kind, scalar type, source field, clamps, track_prev | Builds channel dependency and snapshot policy |
ModifierRow | modifier id, effects, stacking, propagation, mod id | Builds modifier indexes and attribution |
ExecutionBodyRow | body id, body kind, execution lane, dependency declaration | Lets runtime route generated bodies safely |
Everything else can be added without changing the kernel concept.
Semantic Relation Model
The kernel stores relations, but relations are not anonymous Flecs pairs. Every relation is declared metadata.
public readonly struct RelationDefinition
{
public ulong RelationId { get; init; }
public ulong SourceScopeId { get; init; }
public ulong TargetScopeId { get; init; }
public RelationKind Kind { get; init; }
public RelationCardinality Cardinality { get; init; }
public RelationOrdering Ordering { get; init; }
public RelationLifecycle Lifecycle { get; init; }
public RelationMutationPolicy MutationPolicy { get; init; }
public RelationSavePolicy SavePolicy { get; init; }
public bool MaintainReverseIndex { get; init; }
public bool Acyclic { get; init; }
public bool HostBacked { get; init; }
}
Required relation kinds include:
| Kind | Purpose |
|---|---|
ScopeWalk | Declared walks_to edge used by @Scope / WalkScope semantics |
CollectionMembership | Parent field-path collection to child entity |
Ownership | Lifetime ownership for bindings and spawned children |
TemplateIsA | Template inheritance / structural IsA once semantics are committed |
ModifierBindingOwner | Binding owner to target linkage |
SavedScope | Dispatch-frame saved entity references and future saved lists |
HostReference | Host-exposed relation that is indexed by SECS but stored by the host |
The same physical storage may support multiple relation kinds, but the semantic metadata decides invalidation, traversal, save/load, diagnostics, and query planning.
Required Relation Enums
public enum RelationCardinality : byte
{
OneToOne,
OneToMany,
ManyToOne,
ManyToMany,
}
public enum RelationOrdering : byte
{
None,
AscendingTargetId,
SourceInsertionOrder,
ExplicitListOrder,
KeyOrder,
}
public enum RelationLifecycle : byte
{
None,
RemoveOnSourceDestroy,
RemoveOnTargetDestroy,
RemoveOnEitherDestroy,
CascadeDestroyTarget,
}
public enum RelationMutationPolicy : byte
{
RuntimeOwned,
HostMirrored,
HostAuthoritative,
SchemaOnly,
}
public enum RelationSavePolicy : byte
{
RuntimeState,
RebuildFromHost,
RebuildFromSchema,
Transient,
}
The exact enum names can change. The axes cannot. Cardinality, ordering, lifecycle, mutation, and save policy are semantic properties, so they belong in schema rather than in ad hoc storage code.
Initial Relation Definitions
| Relation | Cardinality | Ordering | Mutation | Save policy | Notes |
|---|---|---|---|---|---|
self ScopeWalk | one-to-one | none | schema/runtime-owned | rebuild from schema | Every entity can walk to itself for its root scope |
parent ScopeWalk | many-to-one | ascending target id | host mirrored or runtime owned | rebuild from host/runtime state | Scalar WalkScope requires at most one target for a scope id |
| collection membership | one-to-many from collection scope | explicit list or key order | runtime owned | runtime state | ScopedList and ScopedDictionary differ by ordering/key policy |
| ownership | one-to-many | ascending target id | runtime owned | runtime state | Drives lifetime cleanup and spawned-child teardown |
| modifier binding owner | one-to-many | source insertion order | runtime owned | runtime state | Drives remove-all-by-owner |
| saved scope | frame-local many-to-one | source insertion order | runtime owned | transient | Saved lists become ordered relation sets |
template IsA | many-to-many or DAG | schema order | schema only | rebuild from schema | Deferred until inheritance semantics are committed |
This table is deliberately semantic. It should exist before choosing any internal storage container.
Storage Rule
Relationship storage is non-fragmenting:
- No archetype-per-pair model.
- No unique
(Relation, Target)archetype identity. - A relation table stores targets as values and maintains forward/reverse indexes as required by
RelationDefinition.
This keeps the Bevy-style advantage from v1 while avoiding the mistake of importing Flecs's packed pair identity model.
Identity Model
V1's PairId packed a 31-bit relationship hash and 32-bit target index into one ulong. That is invalid for SECS.
SECS already uses 64-bit ids:
- declaration ids are FNV-1a-64
ulong TemplateIdwrapsulong- current
EntityHandlewrapslong
V2 therefore uses explicit composite keys:
public readonly struct EntityRef
{
public readonly long Value;
}
public readonly struct RelationKey
{
public readonly EntityRef Source;
public readonly ulong RelationId;
}
public readonly struct RelationEdge
{
public readonly EntityRef Source;
public readonly ulong RelationId;
public readonly EntityRef Target;
}
If a future backend wants packed keys for performance, it can build internal fingerprints or dense table indices after schema load. That optimization must never become the semantic identity contract.
Kernel API Surface
The kernel API should be narrow and semantic. A representative shape:
public interface ISecsKernel
{
KernelSchemaHandle LoadSchema(WorldSchema schema);
EntitySetView EntitiesByContract(ulong contractId);
EntitySetView EntitiesByScope(EntityRef scopeTarget);
bool TryWalkScope(EntityRef source, ulong scopeId, out EntityRef target);
RelationTargetView Targets(EntityRef source, ulong relationId);
RelationSourceView Sources(EntityRef target, ulong relationId);
void Record(CommandOp op);
ApplySummary ApplyRecordedCommands(KernelApplyPhase phase);
QueryResultView ExecuteQuery(QueryPlanId queryId, QueryArgs args, KernelScratch scratch);
ModifierView ActiveModifiers(EntityRef target);
ChannelDependencyToken BeginResolve(EntityRef target, ulong channelId);
void EndResolve(ChannelDependencyToken token);
void MarkFieldWritten(EntityRef target, ulong scopeId, ulong fieldId);
void MarkRelationChanged(RelationEdge edge);
bool TryReadPrevTick(EntityRef target, ulong channelId, out KernelScalar value);
void SnapshotTrackedChannels(IChannelValueReader reader);
}
This is not final API syntax. It states the boundary:
- callers ask for SECS concepts
- relation/query/channel operations go through semantic ids
- command application is explicit
- invalidation is semantic
- no Unity type appears
- no raw collection is required at the public layer
Views, Not Collections
Kernel methods return views such as EntitySetView, RelationTargetView, ModifierView, and QueryResultView. These views define:
- count
- indexed access
- deterministic iteration order
- lifetime/ownership rules
- whether the view survives mutation or only the current phase
They may be backed by arrays, raw lists, spans, slices, or adapter-native wrappers. The view contract is the API. The backing container is not.
Host Boundary Split
The old ISecsHostReads shape should not be converted one-to-one into function pointers. It currently combines too many responsibilities.
V2 splits the boundary:
| Boundary | Owns | Native eligibility |
|---|---|---|
HostFieldBridge | Read/write host scalar/entity fields by (entity, scopeId, fieldId) | Native/Burst eligible when implemented by adapter |
HostCommandSink | Apply host side effects and command buffers at canonical apply points | Adapter-specific |
HostCallableBridge | Declared scope methods / contract callables implemented by host code | Managed by default; native only when declared eligible |
HostEntityBridge | Entity creation, destruction, id allocation, and host entity mapping | Adapter-specific |
TraceBridge | diagnostics, walk trace, modifier trace, query trace | Host-agnostic callback ids |
InstrumentationBridge | profiling scopes/timers/counters | Opaque marker ids, not Unity types |
The runtime coordinator owns template metadata lookup, channel re-entry, template value resolution, saved-scope frames, and prev-tick snapshot reads. Those are SECS runtime services, not host services.
This split lets the Unity adapter provide Burst-safe function pointers for field reads and structural indexes without pretending every generated body is Burst-compatible.
Bridge Ownership Rules
Current ISecsHostReads member family | V2 owner |
|---|---|
ReadInt/Long/Float/Double/Bool/Entity | HostFieldBridge |
| host field writes | HostFieldBridge plus command apply phase |
WalkScope | kernel relation index; host may mirror authoritative edges |
GetChildren, GetChildByTemplate, WalkChildren | kernel collection relation index |
LookupTemplate | runtime coordinator / registry |
CallScopeQuery<TArgs,TResult> | HostCallableBridge when host-implemented; generated callable dispatch otherwise |
ResolveChannel* | runtime coordinator / channel resolver |
ResolveTemplateValue* | runtime coordinator / template-value resolver |
ReadPrevTick* | kernel snapshot service |
This table is the migration map. Anything on the right side that says runtime/kernel should not be added to a host function-pointer struct.
Execution Lanes
Generated behavior must declare its execution lane. Without this, the architecture cannot honestly support both Unity Burst and rich managed SECS behavior.
| Lane | Allowed | Examples |
|---|---|---|
NativeEligible | Blittable args, no managed allocation, no generic dispatch, no managed host callable, no unplanned channel re-entry | simple formulas, structural predicates, pure field reads |
KernelEligible | Uses kernel services such as query plans, relation walks, modifier indexes, and channel dependencies, but no host-managed callable | most future query/channel paths |
ManagedOnly | Uses managed callbacks, template metadata objects, generic scope queries, or behavior the compiler cannot prove native-safe | complex contract queries, structured feature-placement records, some validation paths |
A formula that calls ResolveChannelInt is not automatically invalid, but it is not automatically Burst-safe either. The compiler/runtime must classify it.
This replaces v1's ambiguous "function-pointer bridge means Burst-compatible" assumption.
Query Model
The query engine is a SECS query planner, not a generic Flecs query VM first.
The compiler lowers source constructs to query plans over kernel relations and indexes:
every X in Collectionordered X in Collection order_by Channel desc limit Nfirst/random/count- saved-scope iteration and future saved-scope lists
- multi-hop predicates through declared scope relations
- structural predicates:
has_tag,has_template,has_contract - future
descendants(Type)only after transitive traversal semantics are committed
The kernel decides whether a plan can execute through a simple indexed scan, ordered materialization, or a small backtracking join. A full Flecs-style backtracking VM is an implementation option, not the first architectural commitment.
All query result iteration order is part of the semantic contract. It cannot depend on hash bucket order.
Initial QueryPlan Shape
The first query IR can be small:
public readonly struct QueryPlanRow
{
public ulong QueryId { get; init; }
public QueryResultShape ResultShape { get; init; }
public QueryOrdering Ordering { get; init; }
public ReadOnlyMemory<QueryOp> Ops { get; init; }
}
public readonly struct QueryOp
{
public QueryOpCode OpCode { get; init; }
public int A { get; init; }
public int B { get; init; }
public ulong Id { get; init; }
}
Initial opcodes:
| Op | Meaning |
|---|---|
ScanContract | Start from entities registered under a contract |
ScanRelationTargets | Expand (source, relation) -> targets |
ScanRelationSources | Expand (target, relation) -> sources |
FilterHasTemplate | Structural template predicate |
FilterHasContract | Structural contract predicate |
FilterHasTag | Structural tag predicate |
FilterScalarCompare | Field/channel comparison via runtime reader |
SortByChannel | Ordered iteration by resolved channel |
Limit | Take first N after current ordering |
ProjectEntity | Emit entity result |
That covers the v1 pressure points without prematurely committing to a full variable-join VM. Add BindVariable / JoinVariable when there is a concrete lowering that needs them.
Channel, Modifier, and Dependency Integration
The six-phase channel pipeline remains the SECS value model:
Base -> Additive -> Multiplicative -> HardOverride -> Clamp -> Return
The kernel does not replace the channel resolver. It provides deterministic indexes and dependency edges the resolver needs:
- active modifier bindings by target
- active modifier bindings by owner
- bindings by affected channel/field
- propagation source to virtual binding mapping
- per-target prepared modifier buckets
- channel dependency edges discovered during resolution
- field-write, relation-change, membership-change, and binding-change invalidation
- prev-tick snapshot storage for tracked channels
ModifierEntry.ModId / mod attribution is reserved from day one as a host-agnostic integer id. The content manifest maps it to names and packages.
Determinism Contract
Determinism is not "the hashmap happens to iterate stably." Determinism is a semantic API guarantee.
Every kernel iterator must document its order:
- entity sets: ascending entity id unless a declaration says source order
- declaration tables: compiler output order
- collections: collection ordering semantics (
ScopedListorder,ScopedDictionarykey order, or explicit relation order) - query results: declared query order, explicit
order_by, or stable fallback order - command journal apply: tick step order, system registration order, command sequence number, then entity id where batching is required
- save/load sections: schema order, then stable key order
Internal hashmaps must still use deterministic hashing/iteration and allocators must use deterministic free-list behavior. Those are necessary implementation constraints. They are not sufficient by themselves.
Required Iterator Orders
| Iterator | Order |
|---|---|
| all entities | ascending entity id |
| entities by contract | activation order unless query explicitly requests id order |
| entities by scope | activation order within that scope unless query requests id order |
| relation targets | relation Ordering |
| relation sources | ascending source id unless relation declares insertion/list order |
ScopedList children | explicit list order |
ScopedDictionary children | ascending key order |
| active modifiers on target | binding application order, with prepared buckets preserving phase order |
| command journal | tick step, system registration order, sequence number |
| save sections | schema row order, then semantic key order |
This table can be changed only by explicit design decision. No implementation may expose hash bucket order through these iterators.
Observability and ABI Reservations
The v1 instinct to reserve observability from day one is correct. The Unity-specific shape is not.
Kernel structs reserve host-agnostic fields and callback slots:
uint ModIdon modifier binding / prepared modifier entriesTraceBridge.OnWalkTraceTraceBridge.OnQueryTraceTraceBridge.OnModifierTrace- opaque
PerfMarkerIdfields or marker ids in hot kernel components
The Unity adapter maps PerfMarkerId to Unity.Profiling.ProfilerMarker. The server adapter maps it to counters/log scopes. The kernel never references Unity profiling types.
Trace Payload Families
Trace payloads must be blittable or trivially serializable:
| Trace | Required fields |
|---|---|
| walk trace | source entity, scope id, result entity, relation id, success/failure code |
| query trace | query id, op index, input count, output count, elapsed marker id |
| modifier trace | target entity, modifier id, mod id, effect id, bucket, active/skipped reason |
| invalidation trace | invalidated entity/channel/relation, reason, generation before/after |
| diagnostic | code, severity, entity id, declaration id, optional payload token |
Strings are resolved by tools through the content manifest and registry name tables. Hot kernel paths emit ids, not strings.
Save/Load and Hot Reload
The kernel state is saveable because it is semantic:
- entity table
- relation tables
- modifier bindings
- channel cache entries that are save-worthy
- prev-tick snapshots
- command journal if saving mid-tick is supported
- content manifest: active content package, declaration names, ids, schema hash, mod attribution ids
Save/load format remains an open decision, but the content manifest is not optional. The manifest is the only way to survive modifier/template/channel renames across versions without silent loss.
Hot reload operates by comparing old and new WorldSchema instances and applying a controlled commit at a tick boundary. Pure data changes can patch declarations and invalidate affected caches. Structural changes rebuild affected relation/query/channel indexes.
Migration Strategy
Do not build a 15K LOC native primitive library in isolation and hope it matches SECS later.
V2 migration is contract-first:
- Define
WorldSchemafrom the current registry/declaration tables. - Define kernel semantic APIs and deterministic iteration contracts.
- Build a managed reference kernel for correctness tests if useful.
- Implement unsafe/native-backed kernel internals behind the same semantic APIs.
- Move scope walks and collection membership behind kernel relation indexes.
- Move
InstanceStoreentity/contract/scope indexes behind deterministic kernel tables. - Move modifier binding indexes and propagation mappings behind kernel tables.
- Move channel dependency invalidation and prev-tick snapshots behind kernel tables.
- Add query-plan execution for generated stand-ins.
- Split generated execution lanes and replace generated signatures in one planned compatibility break.
The ISecsHostReads signature flip is still a major event for generated code, but the runtime can prepare for it by introducing compatibility facades before the final generated-output switch.
Validation Gates
No kernel implementation should be considered architecture-complete without:
- differential tests against the current managed stores for
InstanceStore, modifier bindings, channel cache invalidation, and prev-tick snapshots - property tests for relation add/remove/destroy invalidation
- deterministic replay tests for command journal apply order
- save/load round-trip tests with renamed modifier/template ids through the content manifest
- query result order tests for every declared iterator order
- adapter boundary tests proving engine/kernel assemblies have no Unity package references
The managed reference kernel, if built, exists to make these tests precise before unsafe storage enters the picture.
What We Explicitly Do Not Build
V2 does not build:
- a general ECS replacement for SECS
- Flecs systems, observers, modules, timers, or script parser
- Unity DOTS as the canonical storage layer
- a public raw collection library as the primary product surface
- packed Flecs pair ids as the SECS identity model
- author-facing query syntax before the semantic kernel can execute it
Open Decisions Deferred to the Companion Doc
The companion document relationship-bridge-open-questions.md tracks the decisions still required under this v2 framing:
- exact kernel public API and assembly naming
- entity handle layout and generation policy
- relation metadata fields and lifecycle rules
- command journal apply semantics
- scope-walk cache invalidation model
- query-plan IR shape
- execution lane classification rules
- host bridge split details
- save/load format
- hot reload commit policy
- migration checkpoints
The key architectural decision in this document is already made: the bridge is a deterministic SECS semantic kernel, not a primitive-first Flecs clone.