Skip to main content

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, and bool channel 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) and while (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 ulong across runtime registries, generated H constants, 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 (all readonly record struct (ulong Value))
  • Scoped collections — CollectionDeclaration (List + Dictionary), SecsRegistry.RegisterCollections / GetCollections / TryGetCollection, ISecsHostReads.WalkChildren and GetChildByTemplate, host-side mutation hooks (OnAdded / OnRemoved method-id collision detection: SECS0840). Spec: docs/design/08-collections-and-propagation.md Part 1.
  • Aggregate channels over collections — AggregateChannelSource with 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 — PropagationDispatcher walks propagates_to children [where ...] via WalkChildren(collectionFieldHash), attaches/detaches virtual modifier bindings on children when source is added/removed, supports tag-filter predicates. Spec: 08 Part 2.
  • Structural tags — TagId typed identity, template_tags slot, has_tag predicate evaluation in propagation filters and aggregate where clauses. Spec: 08 Part 3.
  • Prev-tick snapshots — ChannelDeclaration.TrackPrev = true opt-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 via TickRate, per-tick EveryTick and one-shot Once sentinels. Spec: 08 Part 5.
  • Activity/policy startup mod finalization — ModRegistry plus SecsRegistry.RegisterActivityMod, RegisterPolicyMod, and FinalizeModRegistration() 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 Compilersecs-roslyn/ exists and builds as the unmodified Roslyn fork baseline; SECS syntax parsing/lowering has not started. .secs files are specification only. All Generated/ code is hand-written. Phase plan in SECS-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 surfaceScopedList<T> / ScopedDictionary<TKey, T> field declarations and @Settlement.Resources[Iron].add_modifier X indexer access need the SECS compiler. The runtime API (WalkChildren / GetChildByTemplate) is wired today; the source-level lowering is not.
  • SECS0822 diagnosticScopedList<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; see SECS-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, @root during foreach iteration (designed in docs/design/05-expressions.md, not implemented)
  • Compile-time scope validation — walk reachability checking (designed, requires compiler)
  • Save/load — partial only. ScopeSlotStore.Snapshot/Restore and 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.