The rulebook for token memory: what may change about a token after it is claimed, who may change it, and under what limits. A project-level resource, versioned, attached to many token definitions by batch, snapshot-copied at attach and locked when the token goes Live.
Only the variant machine ships in this step. General fields, apps and crafting are later steps of the same model — the endpoint and the policy shape do not change to accommodate them, which is why this can ship without anticipating them.
Frame 04 is extended and frames 09–11 are new. Attach, re-apply and detach are batch-only, at project level — the token's State tab is a read-only summary with no controls on it, because a policy is attached whole and never customised per token. Selecting one token in the batch tool is a valid batch of one.
01Policy library · project levelSits in the project library beside asset specs and attribute templates. Each policy is versioned; the list shows how many token definitions hold a snapshot of each version, and how many of those are locked because their token is Live.
Author once, attach to many token definitions. Editing a policy never changes a token that already holds a snapshot.
Policy
Version
Fields
Attached
State
Reveal only
variant transitions, nothing else writable
v2
variant
18 definitions · 12 locked
Published
Garden pet
variant + xp + hunger
v1
variant · xp · hunger
0 definitions
Draft
Showing 2 of 2 policiesA version with a locked attachment cannot be deleted
02Policy editor · fields and their write rulesEach field carries a type, default, visibility, mutable_by, write rules, transfer behaviour and marketplace display. Rolling limits are measured in hours — rolling N hours from each write, never calendar days, so there is no midnight reset and no timezone question. Cooldowns are per field only; there is no shared per-holding pool.
Maps and lists come later. No unlimited blobs, ever.
Measured from each write, not from midnight.
"Creator" means the project's administrative roles.
Field · xp · continued
Owner-scoped app grants always clear on transfer, whatever this is set to.
03The variant field · three things the author cannot changevariant is a system-defined enum, not a policy invention. The policy decides whether it is transitionable, its cooldown, its rolling limit, its mutable_by, and which per-instance fields a transition may write. It does not get to decide the three rules below, and topology is not here at all — from_variant indexes that token's own list, so it lives on the token.
Rarity & scorenever affected — both are definition-levelfixed
i
Declare which variant reaches which on the token's Variants tab. This page sets what is allowed to happen, not what does.
04Batch attach · the four outcomes, previewedExtendedBatch is the only authoring path — never one token at a time, and the token's State tab has no attach control on it. The diff lives here, and it reports all four outcomes at once: will attach · will re-apply · skipped because Live · blocked with a named reason. Live definitions are skipped, not failed — their snapshot is locked, and re-apply is Draft/Review only. A blocked token does not fail the batch: the compatible ones proceed and the blocked one is named (frame 09).
Attach Reveal only · v2
✕
Attaching to 7 selected token definitions in Paper Trail.
#014 Relicno policy → v2will attach
#022 Walletv1 → v2will re-apply
#031 Walletv2 alreadyno change
#042 SlabLive — snapshot lockedskipped
#051 SlabLive — snapshot lockedskipped
#077 Seedlingdeclares a return path · v2 sets variant one-wayblocked
#063 Relicno policy → v2will attach
!
Replacing v1 on #022 changes what holders may do once it goes Live. It has no minted copies yet, so nothing existing is affected.
✕
#077 Seedling is blocked. See what conflicts before attaching — the other six are unaffected.
05Snapshot and lock · the three states a token's policy can be inA snapshot is an independent copy. The policy in the library and the snapshot on the token are separate objects from the moment of attach, which is what makes a library edit structurally unable to reach an already-sold copy. Every control shown here lives in the batch tool — the token's State tab displays this, it does not operate it.
Token Draft · editable
SnapshotReveal only v2Draft
i
Re-apply and detach are available — from the project batch tool, with this token selected. A batch of one is still a batch.
Token Review · editable, reverts to Draft
SnapshotReveal only v2Review
i
Changing the policy here returns the token to Draft first.
Token Live · locked
SnapshotReveal only v2 — frozen at go-liveLive
!
Locked. Library edits cannot reach this token, and it cannot be re-applied or detached. Holders keep exactly the rules this copy was sold under.
06Go-Live gates · every failure is namedThree of the gates come from this system. None reports a generic invalid flag, and the authoring UI disables transition controls when the attached policy forbids variant writes rather than letting an author build something that cannot ship.
Token · go-Live readiness
✓
Policy attached
Reveal only v2 · snapshotted, ready to lock
✕
Variant writes permitted
Token #014 declares transitions, but its policy sets variant to not transitionable. Attach a policy that permits it, or clear the transitions
✕
Policy endpoints in range
A transition names variant index 7; this token has 4. Rejected at authoring, surfaced here as a reminder
✕
Declared outcome fields exist
Target opened declares reveal_seed, which is not defined on this token. Writing the variant without its payload is an invalid end state, not a partial success
✓
Listed holdings
None — a listed holding rejects all state writes
07One endpoint, six ordered checksNot a screen — the reference for the write path. Every state change goes through the same call, variant transitions included. Do not build a bespoke transition endpoint.
The update path · state-policy-design.md §5
update_token_state(
holding_id,
actor, // owner principal | app_id | system
changes: [ { field, op, value } ],
reason, // lands in the audit event
operation_id // idempotency key
)
1Actor allowed on every touched field
2Ops allowed for those fields
3Limits, cooldowns and rolling windows respected
4Holding eligible — owned, unlocked, not listed, Active — via the shared eligibility function
5Apply atomically
6Emit one audit event: copy identity, quantity, every field delta, actor, reason
actor is a static principal — the Internet Identity principal, or a wallet principal such as Oisy. Never a delegation principal, so a holding's owner stays stable across sessions. App authorisation reuses Canic delegated-signature auth: an approved app is a delegated token whose scopes name the project, definitions, fields, ops and limits it may write. Do not build a new ACL store.
08Outcome selection and build orderNot a screen — the two reference tables a developer needs beside this. Only the first selection mode is in scope, and only step 1 of the build order ships now.
Outcome selection · §6
Mode
Meaning
Status
Deterministic mapping
The target fixes the outcome; no choice, no roll
V1
Owner-selected path
The holder picks from a creator-declared set
Deferred
Rule-based selection
An automation rule resolves it from project state
Deferred
Oracle / randomness
Resolved server-side at execution
Deferred
Owner-selected is not owner-executed. Every V1 transition is executed by the holder, but the outcome is fixed by the policy. Whichever mode: the selection is recorded in state, the outcome is immutable after first success, and variant plus outcome plus audit event land atomically.
Build order · §12
Step
Scope
Status
1 · The variant machine
variant as an enum field, per-field cooldowns and rolling limits, policy presets and batch attach, owner-executed transitions, the shared endpoint and its audit events
This ship
2 · General fields
number · text · boolean · timestamp · enum, with write rules, transfer behaviours, marketplace visibility, freeze-while-listed
Burn-create recipes, cross-canister sagas, maps and lists, randomness
Later
Steps 2–4 only extend the field and action models. Neither the endpoint nor the policy shape changes for them, which is why step 1 ships without anticipating them. Progressive reveal is not a separate step — it is the narrowest policy step 1 can already express.
Attach · detach · empty states
09Attach blocked · incompatible with declared transitionsNewOpened from the blocked row in frame 04. The attach is rejected — nothing is stripped and nothing is partially applied. The message names both the conflicting policy rule and the specific transitions that violate it, because the creator's next move is either to edit those transitions or pick a different policy, and both need to know which. The same incompatibility is refused at every entry point: editing topology against an attached policy, attaching a policy against existing topology, and the go-Live gate.
Can't attach to #077 Seedling
✕
✕
Reveal only v2 sets variant to one-way.
This token declares a return path, which a one-way policy cannot permit.
The transitions that conflict
Sproutreached from Seedling
Seedlingreached from Sprout — the return path
Clear one direction, or attach a policy that leaves variant two-way. Nothing on this token has changed.
10Detach · pre-Live only, and blocked where transitions depend on itNewA policy detaches whole — there is no partial detach, because a policy is attached whole and never customised per token. Detaching beneath declared transitions would leave the token in exactly the state the go-Live gate exists to prevent, so it is refused on the same terms as an incompatible attach: report what depends on it, change nothing, and let the creator clear the transitions themselves if that is what they want. Live definitions are never detachable — the snapshot is frozen with everything else.
Detach Reveal only · v2
✕
Detaching from 4 selected token definitions in Paper Trail.
#031 Walletno transitions declaredwill detach
#063 Relicno transitions declaredwill detach
#014 Relic3 transitions depend on itblocked
#042 SlabLive — snapshot lockedskipped
!
#014 Relic keeps its policy.Forge, Awaken and Ascend all write variant, and with no policy attached none of them could run. Clear those transitions first if you want the policy gone.
i
A token with no policy attached is a valid state — it simply cannot transition. That is why detaching from a token with no transitions is unremarkable, and detaching from one with them is not.
11Nothing to attach yet · two different empty statesNewThese answer different questions and must not be merged. Left: the project has no state policies at all. Right: a policy exists but has never been published — a Draft template is never appliable, so "nothing here" would actively mislead someone who has just authored one and is looking for it. Both link to the project Templates library, which is also where the library's own empty state points back from.
Attach a state policy
✕
i
This project doesn't have any state policies.
A state policy decides what can change about a token after it is claimed — and a token needs one before any variant transition can run. You can author one in the project's Templates library.
Attach a state policy
✕
!
Garden pet hasn't been published yet.
Only published versions can be attached — a draft is still being edited, and a half-authored policy must never reach a token. Publish v1 in the Templates library and it will appear here.