Skip to main content

Act 2 Gate Spec: First People to First Outpost

Context

This doc authors the gate predicate that authorizes the ActState.CurrentAct: 2 -> 3 transition (the Act 2 First Outpost act finishing and Act 3 Settlement beginning) per ../lore/adr/ad-0010-act-progression-actstate-scope.md. The transition is driven by the ActProgression system, which reads this predicate against committed scopes and fires OnActCompleted(2) followed by OnActStarted(3) when the predicate becomes true.

The source act doc is ./gd-act-2-first-outpost.md. The "Boundaries Into Act 3" section at lines 61-69 names the act's end state: a functioning Outpost foothold whose next question becomes settlement-scale growth. The binding rule from ad-0010 lines 93-99 applies: named state on committed scopes only.

Gate Predicate

Act 2 is complete when the first Outpost-tier Settlement has been founded, is alive under pressure, and is structurally distinct from the Core/Camp layer. Expressed as named state on committed scopes:

ActState.CurrentAct == 2
&& Realm.CoveredSettlements.Count >= 1
&& Realm.CoveredSettlements.Any(s => s.IsFirstOutpost == true)
&& Realm.CoveredSettlements.Single(s => s.IsFirstOutpost).FoundingState == Founded
&& Realm.CoveredSettlements.Single(s => s.IsFirstOutpost).ClaimedTerritories.Count >= Config.Act2.MinClaimedTerritories
&& Realm.CoveredSettlements.Single(s => s.IsFirstOutpost).CoreBuilding.ConstructionState == Functioning

Named-state sources:

  • ActState.CurrentAct is the saga-scoped Act ladder index per ad-0010 line 53.
  • Realm.CoveredSettlements is the per-Realm collection of Settlement scope rows under this Realm; the Realm scope is committed at ad-0009 lines 49-55.
  • Settlement.IsFirstOutpost is the per-Settlement flag identifying the first-founded Outpost-tier Settlement of the campaign, matching the gd-act-2-first-outpost.md lines 13-15 commitment that the first Outpost is the first population-bearing rung of the Settlement ladder.
  • Settlement.FoundingState derives from the Settlement scope's lifecycle (per gd-settlements-and-outposts.md "Footprint Rule") and reaches Founded when the Outpost is no longer provisional.
  • Settlement.ClaimedTerritories is the connected-footprint claim list per gd-settlements-and-outposts.md lines 26-37.
  • Settlement.CoreBuilding.ConstructionState is the Outpost's central building production state (settlement layer infrastructure per gd-act-2-first-outpost.md lines 50-58).
  • Config.Act2.MinClaimedTerritories is a UI-exposed Config field with world-size-parameterized defaults; concrete values live in Config, not in this predicate.

The predicate does not require Realm.PolityRank to have advanced; the Realm remains at PolityRank.Outpost through Act 2 and Act 3 per ad-0009 lines 75-80. PolityRank promotion to BannerNetwork is the Act 3 -> Act 4 transition, not this one.

Triggered Events

When the predicate transitions to true, the ActProgression system fires:

  • OnActCompleted(ActProgressionArgs { PreviousAct = 2, NewAct = 3, TransitionDay = <current day> }).
  • OnActStarted(ActProgressionArgs { PreviousAct = 2, NewAct = 3, TransitionDay = <current day> }).

Both events carry trigger on_action per ad-0010 lines 81-84 and the on_action allowlist in .claude/rules/behavior-vocabulary.md.

Capability Unlocks

The Act 3 unlock surface is broad settlement-scale play, as committed at gd-act-3-settlement.md lines 24-33. Concretely, on the Act 2 -> Act 3 transition:

  • District grouping and designation logic become structurally legible per gd-act-3-settlement.md lines 26-27.
  • Settlement-buildings and local economic chains become recurring priorities (gd-act-3-settlement.md lines 28-29).
  • Training, recovery, and specialized production compete for labor and space (gd-act-3-settlement.md lines 30-31).

This gate authorizes only that Act 3 begins; the broad consolidation work and the Banner Network-ready state are Act 3 outcomes resolved by the next gate.

Runtime Backing Status

Status at this doc's acceptance time: contract-only.

  • Host/runtime owner: the predicate is read by legacy/v1/examples/valenar/Host/Systems/ActProgressionSystem.cs (proposed; authored in Wave 5a per ad-0010 lines 155-158).
  • Source/generated owner: the predicate body lives in Content/acts/systems.secs and the matching Generated stand-in.
  • Read-model/UI owner: the React client's saga-position surface reads ActState.CurrentAct; the Settlement screen separately surfaces founding state per ../ux/gd-settlement-screen.md.
  • Tests: <deferred-to-wave-5a> runtime-backing wave.
  • Illegal fallback behavior: if any named-state input cannot resolve through the 6-phase channel pipeline, the system throws IllegalTransitionException rather than advancing or holding. No calendar-elapsed fallback, no time-since-founding fallback, no "first Settlement exists for a fixed tick window" heuristic.
  • Next closure wave: Wave 5a runtime-backing wave (per ad-0010 line 185).

Cross-References