Supported API contract — 1.3#
The 1.x authoring contract covers SimLOD.API, public provider/receipt/diagnostic types in SimLOD.Materialization, SimulationProviderDef, and the documented facade methods on SimLODWorldComponent. The 386-line metadata baseline inventories every exported framework type and public/protected declared member, including enum values, parameter names/defaults, inheritance and constraints. The build checks it automatically and preserves the 311-entry 1.2 contract. Deliberate additions require contract review and an explicit baseline update; changing the baseline is never an automatic build repair.
Verse lifecycle overrides, IThingHolder methods, debug actions and diagnostic window classes are engine integration surfaces. They remain in the binary inventory but are not consumer extension points. In particular, consumers must not edit the returned native ThingOwner or invoke the world tick/save callbacks. The Visitor Relay and example payload schemas are separate consumer/provider contracts, not generic framework population semantics.
Versions and compatibility#
| Version | Policy |
|---|---|
| Framework package | 1.3.0; additive opt-in provider commands and durable accepted receipts. |
Provider ApiMajor |
Defaults to 1. Explicit preview contract 0 remains accepted during 1.x because its signatures/semantics are compatible. Other values are refused. |
| Framework CLR assembly | Keep SimLOD, Version=0.1.0.0 through 1.x to preserve preview binary binding. This historical CLR identity is independent of package and API versions. |
| Consumer CLR assembly | Keep Visitor Relay 1.0.0.0; existing relay binaries remain compatible. |
| Saved data | Write abstract archive 4, native journal 3, SplitMix64-v1. Archives 1/2 default to unpaused; archives 1–3 default to empty command history. New writes require valid pause and command fields. |
| Provider schema/model | Provider-owned and independent. Schema upgrades require pure migration; a behavior-model mismatch suspends records. Locked native plans require their original schema/model. |
Within 1.x, existing documented signatures and meanings remain compatible. New capabilities must be opt-in. A breaking contract requires a new API major and migration plan. Forward loading of these retained older inputs is tested; loading newer saves into older framework/provider versions is not promised. The historical 0.6 consumer binary is an acceptance input, alongside actual pending/prepared 0.6 saves and 0.3/0.4/0.5 native saves. Version 1.1 adds an actual 1.0 survey checkpoint and an extracted starter compile against both public 1.0 and 1.1 DLLs.
Calls, failures and revisions#
Call on the game's main thread, starting with the first access, outside provider callbacks and native transition callbacks. Provider registration/archive restoration is lazy; a native call also attaches and validates the journal on first use. Receipt and entity fields are immutable snapshots; their exposed Pawn is a live, mutable native object. Do not cache a snapshot as authoritative across another mutation or game update.
Providers must supply deterministic, bounded, pure planning/validation/advance/migration callbacks. Persist authoritative state in payloads. Use StepContext.Random, not wall time or native global randomness, for abstract steps. Provider exceptions quarantine their records and preserve uncommitted payload/time/revision/RNG state. Framework rollback cannot undo forbidden external side effects from a provider.
Pass the revision from the current snapshot when admitting new work. Unknown entity/operation lookups throw KeyNotFoundException; invalid input is rejected with argument/invalid-operation exceptions. Stale revisions, missing/incompatible providers, overdue admission, forbidden reentrancy and unsafe native ownership refuse progress. Error text and diagnostic formatting are explanatory, not machine-readable contracts. Never parse a message to decide whether to retry. Use status, receipt and diagnostic fields.
Registration/archive failures preserve the original archive and prevent mutations. A successful native admission commits a saved plan and may reserve population; later native failures preserve that plan and its applied progress. Native effects are not transactional rollback: only normal completed Scribe boundaries are supported. Native reentrant saves and abrupt termination within a callback are outside the guarantee.
Abstract pause and resume#
Version 1.3 additionally provides the provider-command contract: opt-in pure planning, typed admission/domain refusals, atomic accepted payload/receipt persistence and exact replay. Command history is preserved through pause, provider absence, migration and native recovery. New commands require Ready/unlocked/caught-up state; existing accepted keys can be replayed without mutation. These calls validate the native journal. They do not provide item transactions or permission to change native member accounting.
Version 1.2 added Pause(id, expectedRevision), Resume(id, expectedRevision), EntitySnapshot.IsPaused and appended EntityStatus.Paused = 6. Its 311-line baseline added five metadata lines to the earlier 306-line surface. The current 1.3 baseline adds 75 further lines and preserves all 311 historical lines with declaring-type scope. Existing enum values and signatures are unchanged.
Both methods return whether the saved flag changed. A real change increments revision once; a current-revision same-state request returns false; stale requests are rejected. Pause removes scheduled work and preserves payload/RNG/logical time/deadlines. Resume requeues the unchanged deadline. It invokes no step; later normal ticks catch up under the existing quota. Missing/incompatible providers and quarantine take precedence over the Paused display status while IsPaused persists. Provider restoration or successful Retry does not resume a paused record.
These calls require compatible validated abstract providers with no Pawn-provider type, native members, operation history or transition lock, and a valid native journal. The guards apply to no-ops too. Native recovery remains governed by its receipts. Read the full time and persistence contract before using this API. Downgrading a new save into an older framework is unsupported; older versions preserve the unknown archive as blocked.
Replay, recovery and settlement#
Persist request keys in the consumer's own save root before allowing native progress. Keys are scoped to an entity, and settlement keys to an operation. Identical operation replays return the saved receipt; changed request fingerprints are rejected. Replays do not regenerate Pawns or reapply accounting. A known settlement key returns its original proposal; changed observations require an explicitly new key. Completed commit replay is idempotent. Revisions are admission guards, not substitutes for durable encounter keys.
Queued admission applies no native item effects. An unpaused world update attempts at most one member, with persisted fair ordering. This is a work-count quota, not a millisecond guarantee. Provider absence suspends queued work; compatible restoration permits pending work to continue. Faulted work needs explicit recovery. Recovery executes the original plan without replanning or inventing a missing native result.
Preparation records proposed dispositions and stops queue execution without changing committed provider accounting or moving Pawns. Commit rechecks identity and verified owners, applies accounting once and releases the lock. Only a claim whose generation provably never started can be cancelled. Ambiguous generation and unsupported holders remain blocked. Cancelled member IDs, operations and superseded settlements remain durable; no history is silently pruned and no old IDs/keys are reused.
The detailed contracts remain in abstract runtime, Pawn lifecycle, queued transitions and settlement. Capacity and compatibility claims are limited by the support policy.
Checking the freeze#
./tools/test-api.ps1 -NegativeControl
./tools/build.ps1
The checker uses .NET Framework reflection-only metadata loading and never executes game/provider code. The negative control changes a public parameter type in a temporary baseline and must be rejected by both exact and historical-compatibility checks. This catches binary surface changes; semantic behavior is verified by the model and native acceptance suites.