Genesis Runtime Growth Pipeline — Stubs #1-#3
Source: docs/plugins/GENESIS.md § Stubs & Unimplemented Features (#1, #2, #3)
Blocks: Divine divinity generation, wallet-as-universal-counter pattern, entity awakening lifecycle
Related: #712 (Seed bond propagation), #713 (Seed batch growth events), #714 (external seed adoption)
Summary
Genesis has a fully implemented API surface (19 endpoints, 0 stubs) with templates, entity CRUD, bonds, capabilities, compression, and cleanup. But the runtime pipeline that connects currency wallet credits to seed growth to cognitive awakening is not implemented. Three tightly-coupled stubs form this pipeline and should be implemented as a single unit.
The Pipeline
Currency wallet receives credit (from game engine, quest reward, god-actor, autogain)
↓
Stub #2: ICurrencyTransactionListener (DI, L2 co-located)
Genesis checks in-memory wallet map (~microseconds)
Buffers matched credits in growth accumulator (ConcurrentDictionary)
↓
Stub #1: GenesisGrowthFlushWorkerService (BackgroundService)
Drains accumulator every GrowthFlushIntervalSeconds (default: 5s)
Batch-calls ISeedClient.RecordGrowthBatchAsync per entity
One Seed lock acquisition per entity per flush (not per credit)
↓
Stub #3: ISeedEvolutionListener implementation
Receives phase transition notifications from Seed
Dormant → Stirring: spawns Actor with ABML behavior from template
Stirring → Awakened: creates Character in system realm, binds Actor
Publishes genesis.entity.phase-changed event
Creates deferred bond Relationships at Awakened stage
What Each Stub Requires
Stub #2: ICurrencyTransactionListener
- New DI interface in
bannou-service/Providers/ICurrencyTransactionListener.cs:
ICurrencyTransactionListener
OnCurrencyCreditedAsync(walletId, currencyCode, amount, newBalance, ct)
OnCurrencyDebitedAsync(walletId, currencyCode, amount, newBalance, ct)
- Currency dispatch: lib-currency discovers
IEnumerable<ICurrencyTransactionListener> via DI, dispatches after wallet mutations (same pattern as ISeedEvolutionListener, ICollectionUnlockListener)
- Genesis implementation (
GenesisCurrencyTransactionListener): Singleton, checks in-memory ConcurrentDictionary<Guid, GenesisWalletMapping> for walletId, buffers matched credits in growth accumulator
- Wallet map population: Populated at startup from MySQL, invalidated via self-subscription to
genesis.entity.created/genesis.entity.deleted events (the event handlers in GenesisService.Events.cs are already registered as no-op placeholders for this)
Stub #1: GenesisGrowthFlushWorkerService
- BackgroundService following canonical polling loop pattern (T6)
- Drains growth accumulator, groups by entityId
- For each entity: loads template from cache, applies growth mappings (amount × ratio, filtered by direction), calls
ISeedClient.RecordGrowthBatchAsync
- Config properties
GrowthFlushIntervalSeconds and StartupDelaySeconds already exist in schema (unreferenced)
- Telemetry spans per cycle, per-item error isolation, worker error publishing
Stub #3: ISeedEvolutionListener
- Singleton implementation of
ISeedEvolutionListener (interface already exists in bannou-service/Providers/)
OnPhaseChangedAsync: loads entity by seedId (reverse lookup via entity query), loads template, checks awakening thresholds:
- Stirring phase: spawn Actor via
IActorClient with template's behavior document reference
- Awakened phase: create Character in system realm via
ICharacterClient, bind Actor via IActorClient.BindCharacterAsync, create deferred bond Relationships
- Updates entity model with
ActorId, CharacterId, CognitiveStage
- Publishes
genesis.entity.phase-changed event
Why These Are One Unit
Scale Considerations
At 100K+ entities with genesis-managed wallets:
- ICurrencyTransactionListener adds ~30ms of ConcurrentDictionary lookups per Currency autogain tick (vs ~9s with Redis)
- Batched flush reduces Seed lock acquisitions from one-per-wallet-credit to one-per-entity-per-flush-interval (10-20x reduction)
- 5-10 second delay between wallet credit and seed growth is invisible for entities whose phases span hours/days
Also Untracked (Lower Priority, Separate Issues)
Genesis Runtime Growth Pipeline — Stubs #1-#3
Source:
docs/plugins/GENESIS.md§ Stubs & Unimplemented Features (#1, #2, #3)Blocks: Divine divinity generation, wallet-as-universal-counter pattern, entity awakening lifecycle
Related: #712 (Seed bond propagation), #713 (Seed batch growth events), #714 (external seed adoption)
Summary
Genesis has a fully implemented API surface (19 endpoints, 0 stubs) with templates, entity CRUD, bonds, capabilities, compression, and cleanup. But the runtime pipeline that connects currency wallet credits to seed growth to cognitive awakening is not implemented. Three tightly-coupled stubs form this pipeline and should be implemented as a single unit.
The Pipeline
What Each Stub Requires
Stub #2: ICurrencyTransactionListener
bannou-service/Providers/ICurrencyTransactionListener.cs:IEnumerable<ICurrencyTransactionListener>via DI, dispatches after wallet mutations (same pattern as ISeedEvolutionListener, ICollectionUnlockListener)GenesisCurrencyTransactionListener): Singleton, checks in-memoryConcurrentDictionary<Guid, GenesisWalletMapping>for walletId, buffers matched credits in growth accumulatorgenesis.entity.created/genesis.entity.deletedevents (the event handlers in GenesisService.Events.cs are already registered as no-op placeholders for this)Stub #1: GenesisGrowthFlushWorkerService
ISeedClient.RecordGrowthBatchAsyncGrowthFlushIntervalSecondsandStartupDelaySecondsalready exist in schema (unreferenced)Stub #3: ISeedEvolutionListener
ISeedEvolutionListener(interface already exists inbannou-service/Providers/)OnPhaseChangedAsync: loads entity by seedId (reverse lookup via entity query), loads template, checks awakening thresholds:IActorClientwith template's behavior document referenceICharacterClient, bind Actor viaIActorClient.BindCharacterAsync, create deferred bond RelationshipsActorId,CharacterId,CognitiveStagegenesis.entity.phase-changedeventWhy These Are One Unit
Scale Considerations
At 100K+ entities with genesis-managed wallets:
Also Untracked (Lower Priority, Separate Issues)
GenesisVariableProviderFactory(${genesis.*}variables for Actor runtime)