SECS — Current Status
Last updated: 2026-05-12
What's Built
Engine (SECS.Engine + SECS.Abstractions)
- Channel resolution — runtime implements the 6-phase pipeline (base → additive → multiplicative → HardOverride → clamp → return)
- Channel declarations — three kinds: Contributed, Base, Accumulative
- Channel value types — runtime supports
int,long,float,double, andboolchannel declarations, sources, formulas, and modifier effects - Dynamic formula channels — formula delegates evaluated at resolution time, with owner context
- Modifier system — bindings, triggers, duration, state machine (Active/Inactive/Removed)
- Modifier stacking policies — Single, Unique, Stackable with max_stacks and ReApplyMode (ignore, refresh, extend, replace)
- Dynamic modifier effects — formula-driven effect values that scale with game state
- Conditional modifiers —
when(guard-on-add) andwhile(continuous trigger) - Command processing — channel sources, modifier bindings, increment field
- Tick pipeline — ordered step execution with phase-based system sorting
- ITickSystem — systems with frequency gating and phase declarations
- Load distribution — per-entity tick spreading via AllByContractForTick (zero-alloc ref struct)
- Event system — pulse events, on_action hooks, player choices (PendingChoice)
- Scope walking — ISecsHostReads.WalkScope with host-defined hierarchy
- Instance store — entity tracking by contract, scope index for parent-child
- Template activation/deactivation — with command buffer pattern
- Cascading destruction — DestroyWithChildren for hierarchical entities
- Template upgrades — Upgrade method preserves entity handle
- Dirty tracking — DirtySet marks changed channels, SyncDirty writes back to host
- Identifier hashing — FNV-1a-64
ulongacross runtime registries, generatedHconstants, command payload ids, localization keys, host bridge signatures, Valenar, character-trainer, and benchmarks - Localization — YAML-based, ILocalizationProvider, FNV-1a-64 key hashing
- Rich text parsing — single-pass parser for scope references, colors, links, conditions
- Tooltip system — auto-generated from resolved channel breakdowns and ModifierDeclaration
- Typed identity record structs —
TemplateId,ModifierId,ChannelId,TagId,PhaseId,TickRateId,ScopeId,ContractId,SystemId,EventId,OnActionId,ActivityId,ActivityRunId,ActivityLaneId,PolicyId,DomainId,NeedId,SelectorId,RuleId,SlotKindId(allreadonly record struct (ulong Value)) - Scoped collections —
CollectionDeclaration(List + Dictionary),SecsRegistry.RegisterCollections/GetCollections/TryGetCollection,ISecsHostReads.WalkChildrenandGetChildByTemplate, host-side mutation hooks (OnAdded/OnRemovedmethod-id collision detection: SECS0840). Spec:docs/design/08-collections-and-propagation.mdPart 1. - Aggregate channels over collections —
AggregateChannelSourcewith all six ops (Sum / Min / Max / Average / Count / CountWhere), int / long / float / double resolvers, structural predicate (PropagationFilter), cache-DAG dependency tracking so child channel changes invalidate aggregates. Spec: 08 Part 1 § Aggregate channels. - Virtual binding propagation —
PropagationDispatcherwalkspropagates_to children [where ...]viaWalkChildren(collectionFieldHash), attaches/detaches virtual modifier bindings on children when source is added/removed, supports tag-filter predicates. Spec: 08 Part 2. - Structural tags —
TagIdtyped identity,template_tagsslot,has_tagpredicate evaluation in propagation filters and aggregatewhereclauses. Spec: 08 Part 3. - Prev-tick snapshots —
ChannelDeclaration.TrackPrev = trueopt-in,ISecsHostReads.ReadPrevTick{Int,Long,Float,Double,Bool}, end-of-tick snapshot, loud-fail on missing required snapshot. Spec: 08 Part 4. - System execution model — Pre / Main / Post stages with intra-stage
Order, frequency gating viaTickRate, per-tickEveryTickand one-shotOncesentinels. Spec: 08 Part 5. - Activity/policy startup mod finalization —
ModRegistryplusSecsRegistry.RegisterActivityMod,RegisterPolicyMod, andFinalizeModRegistration()merge activity/policy mod records once at host bring-up, with load-order last-writer-wins slots, conflict diagnostics, and replace-only architectural-slot errors.
Valenar Example Game
Granular per-wave status lives in examples/valenar/docs/roadmap.md. High-level summary:
- Phase 0 (pre-Wave-24) — shipped & committed: Region/Area/Province/Location scopes, settlement + MC entities, build queue, base building templates, three systems (TaxCollection, FoodConsumption, PopulationGrowth), three events (DemonRaid, PlagueSpreads, CelebrationBonus), formula channels, ASP.NET Core SignalR server, React/TypeScript client.
- Phase 1 (Waves 24-28) — shipped (uncommitted): Settlement-tier system. StageThresholds + StageTransitionSystem, SettlementRole + RoleAutoAssignSystem, OverEligibilitySystem + MaintenanceSystem, Province Markets scaffolding, TributeSystem with prev-tick snapshots.
- Phase 2 (Waves 29-34) — partial. Wave 29 (Resource templates + ResourceContract) and Wave 30 (Recipe + Production core: 5 recipes, Farm/Mine/Lumberyard, BuildingProductionSystem, OverflowDecaySystem, pre-spawn 9 Resources at founding) shipped uncommitted. Waves 31-34 planned (Pop food consumption / Storage buildings / Tools+Forge / Saturation throttle).
- Phase 3 (Waves 35-39) and Phase 4 (Waves 40+) — planned. See roadmap.
What's NOT Built
Engine
- SECS Compiler —
secs-roslyn/exists and builds as the unmodified Roslyn fork baseline; SECS syntax parsing/lowering has not started..secsfiles are specification only. AllGenerated/code is hand-written. Phase plan inSECS-Compiler-Plan.md. - Source-level generic Phase 3 mod merger — fully designed in
docs/design/06-overrides-and-modding.md(six operations:inject,replace,try inject,try replace,inject_or_create,replace_or_create; slot schema; canonical identity strings; AST-level merger), but the SECS compiler has not yet parsed source sets, extracted semantic slots, applied generic declaration operations, or emitted a merged game. The activity/policy runtime finalizer is built; the remaining generic source-set merger for templates, modifiers, systems, events, on-actions, scopes, contracts, and other non-activity/policy declarations is compiler-owned Phase 3 work. - Collections — SECS source surface —
ScopedList<T>/ScopedDictionary<TKey, T>field declarations and@Settlement.Resources[Iron].add_modifier Xindexer access need the SECS compiler. The runtime API (WalkChildren/GetChildByTemplate) is wired today; the source-level lowering is not. - SECS0822 diagnostic —
ScopedList<T> does not support indexed access; use .Where() / .First() / iteration— diagnostic id reserved, requires compiler. (Renumbered from SECS0820 in Wave 8 to free that code for the slot-restore runtime band; seeSECS-Compiler-Plan.md § Diagnostic Code Catalog.) - Template modifiers — template-scoped modifier declarations (designed in
docs/design/03-channels-and-modifiers.md, not implemented) - Scope stack runtime —
@prev,@rootduring foreach iteration (designed indocs/design/05-expressions.md, not implemented) - Compile-time scope validation — walk reachability checking (designed, requires compiler)
- Save/load — partial only.
ScopeSlotStore.Snapshot/Restoreand activity-run restore primitives exist, but there is no unified engine save payload and no committed persistence yet for modifier bindings, pending choices, policy-child links, or prev-tick snapshots. - Channel resolution caching — demand-driven caching exists (
ChannelCache, dirty invalidation, aggregate cache dependencies), but cache persistence across save/load and some broader optimization work remain open. - Priority on modifier effects — field reserved, not implemented
Valenar
See examples/valenar/docs/roadmap.md for per-wave plan. Major chunks still pending: Pop food consumption (Wave 31), Storage buildings + propagation (Wave 32), Tools + Forge + intermediate goods (Wave 33), Saturation throttle + edge events (Wave 34), Employment + Markets + Player levers (Phase 3, Waves 35-39), Frontend ledger + Project scheduling + 1M-pop optimization (Phase 4). Beyond waves: combat resolution, seasonal weather, named characters, save/load.
Open Decisions
- Namespaces — whether SECS definitions need namespacing for mod collision prevention. Currently global (Paradox-style). Decision deferred.
- secsc packaging — self-contained single binary vs dotnet tool; same code either way.
distribute false— opt-out syntax for load distribution on aggregation systems. Designed but not implemented.