Interrupted-plan cancellation and settlement — API 0.5#
Settlement closes one unfinished native operation against observed native outcomes. It can release a member claim only when generation provably never started. Existing Pawns stay with their current verified native owners. The framework does not spawn, despawn, transfer, kill, resurrect or destroy anything during preparation or commit.
This is a separate, explicit provider opt-in. Existing synchronous and queued execution/recovery keep their behavior. An operation that can still finish normally can use ordinary recovery; settlement is useful when a death, permanent transfer, abandoned destination or partially completed return makes the original plan inappropriate.
Public flow#
// Keep both keys in the consuming mod's saved encounter state.
var prepared = sim.PrepareNativeSettlement(entity, sim.Get(entity).Revision,
"encounter-18/open", "encounter-18/settlement-1");
// Preparation suspends the original operation and persists a proposed resolution.
// Show prepared.Outcomes to the caller or save here before committing.
var inspection = sim.InspectNativeSettlement(entity,
prepared.OperationKey, prepared.SettlementKey);
if (inspection.CanCommit)
sim.CommitNativeSettlement(entity, prepared.OperationKey, prepared.SettlementKey);
Preparation requires the original entity lock, the expected current revision, a matching provider schema/model and AllowsNativeSettlement == true. It observes all items in the original operation, calls the provider's pure PlanNativeSettlement callback, validates its payload and rechecks the observations. Only then does it append the settlement, set the original operation to SettlementPending and remove its runnable queue entry. The abstract payload, revision, native Pawns, original plan, original request time and applied-item flags remain unchanged. Preparation may run while paused.
Commit rechecks the saved identity, disposition and owner tokens. A changed map, faction, death/corpse owner or holder blocks commit without changing the prepared journal or abstract payload. Moving within the same map does not invalidate an outcome. If the new outcome is legitimate, call preparation with a new settlement key. The old attempt becomes Superseded; its saved observations, payload and time remain in the journal. An old superseded key cannot commit.
The successful commit applies the saved provider payload, updates member states, clears the entity lock, increments the revision once and records Settled on the original operation and Completed on the settlement. There are no native calls after the provider/core validation in the commit section. A returned/captured Pawn that remains retained is identity-pinned. Death/transfer records relinquish the live binding only after verifying an external save owner; tombstones preserve member and Thing IDs. An unused cancelled claim keeps its monotonic member ID forever; a future claim receives a new ID.
Call GetNativeSettlements(entity, operationKey) for immutable receipts in preparation order. Keys are scoped to (entity, operationKey, settlementKey). Repeating preparation with the same key returns its original Prepared, Superseded or Completed receipt without replanning, even when the expected revision is now stale. Repeating a completed commit returns its receipt. RecoverNativeOperation replays a Settled receipt and cannot resume a prepared settlement. NativeOperationReceipt.IsTerminal covers both Completed and Settled; consumers must not assume Completed is the only terminal status. Original AppliedCount reports original native work, not the number of settled outcomes.
Observations and provider accounting#
| Observed condition | Result |
|---|---|
| New Reserved claim; no generation, action, disposal, binding or applied item | Cancelled; the provider may release this unused population claim. |
| Captured living individual in SimLOD's holder with unchanged faction | Retained; preserve the exact Pawn graph and pin it. |
| Living individual on a map or in WorldPawns, still a member | Materialized; leave native representation unchanged. |
| Living individual whose faction/membership changed, on a map or in WorldPawns | Transferred; preserve the external Pawn and account membership loss once. |
| Dead Pawn with a spawned corpse or verified WorldPawns owner | Dead; preserve the external native save graph and account death once. |
| An earlier explicitly permitted fixture disposal has its completion marker | Aggregated; settlement records that already completed effect. It performs no new disposal. |
| Generation started but no exact captured result | Blocked; no refund, replacement or regeneration. |
| Living carried/external-holder Pawn, transformed/discarded body, or changed faction still held by SimLOD | Blocked; requires a supported, verified native owner before settlement. |
The bounded external owner cases are map, corpse and WorldPawns. Arbitrary holder chains, including caravan-specific ownership, need a later adapter. A corpse may be destroyed or a Pawn moved between preparation and commit; the saved observation cannot silently become a different resolution.
Providers implement PlanNativeSettlement(EntitySnapshot state, IReadOnlyList<PawnSettlementOutcome> outcomes, NativeTransitionContext context). state.Payload is the locked payload currently held by the entity, not the abandoned operation's final payload. Each outcome contains the member ID, Thing ID, verified owner, AccountingState and ResultState. For materialization/rematerialization the accounting state is Materialized, because admission already reserved deployment. For reconciliation it is the member's preceding committed representation. The callback must be pure and perform no native/world/API mutations. Normal payload-size and provider validation apply. Settlement permission is independent of queued permission.
context.EffectiveTick is the settlement preparation tick. It stays fixed across saving and retries of that prepared key. An explicitly replaced preparation uses its own new tick. The original operation retains its own effective tick separately. The example expedition accounts its locked representation up to the settlement tick, then changes the affected buckets. Unused claims return to Uncreated; captured held individuals become Retained; losses enter Dead or Transferred once. It does not retroactively refund elapsed supply costs or pretend that a death occurred at the original deployment tick. Native food and inventory remain separate.
A long interruption may put the settlement's accounting cursor beyond several scheduler deadlines. The expedition skips deadlines already covered by that cursor, then resumes charging only for later time. The core preserves its original logical schedule and catches up normally. Other providers opting in must define an equally explicit policy.
Persistence and limits#
Native journal 3 adds prepared/superseded/completed settlements, observed owner tokens, proposed payloads and cancellation tombstones. It reads journals 1 and 2, preserves their synchronous/manual and queued recovery semantics, and upgrades after validation. Older readers reject journal 3. Abstract archive 2, RNG 1 and framework assembly identity 0.1.0.0 remain unchanged. A pending death reference now uses native saveDestroyedThings semantics: dead Pawns are marked Destroyed by RimWorld but can still be deep-saved by their corpse/WorldPawns. This prevents losing their binding during a prepared or pending death save. An already lost reference in an old save cannot be repaired by this change.
Missing/incompatible providers preserve the prepared plan but block commit and replacement. Restoring the matching provider enables explicit commit; settlements never execute automatically. Saves are supported after preparation, after failed preflight, after superseding a plan, and after commit. A failure before the commit leaves the prepared plan intact. The main-thread commit contains only the provider/core commit and framework record assignments; arbitrary reentrant saves inside callbacks and process failure mid-instruction are outside the supported contract.
The developer recovery window displays settlement outcomes and blockers and provides Prepare settlement and Commit settlement actions. Preparation is reviewable before commit. Retained Pawns remain unticked. No arbitrary existing-pawn ingestion, map deletion, automatic force-transfer, claim garbage collection, settlement-history compaction, Multiplayer or general rollback is added.
See implementation status for executed evidence and queued transitions for the original plan's timing and fairness rules.