TessemblyDocs
0.3.x · RFC3 GitHub

STATE CONTRACTS

Bags, observation and hold

Keep actual supply, available information and currently usable pieces as different state dimensions.

Standard bags and custom sources

seven_bag() declares a uniform bag containing each standard kind once. With r kinds remaining, each has base next-draw probability 1/r. Initial leftovers can be declared separately as remainder("SZ", epoch=2).

tessembly
config {
    rule = seven_bag();
    start = remainder("SZ", epoch=2);
}

Do not infer physical bag boundaries from braces or pattern segments. Fixed queues and P3P3 are not silently edited to fit a standard bag. A host can validate actual bag legality against rule; validating the document alone does not prove game supply legality.

For multiplicities or weights, declare a custom bag/pool. Each positive integer weight corresponds to an individual listed token. bag draws from remaining tokens proportionally to their weights; pool draws with replacement. Omitted weights are one per token. Sampling and conditional probabilities belong to the consumer.

see-n is an explicit information contract

tessembly
config {
    see = view(active=true, next=5, hold=true,
               memory=history, reveal=supply, bag=known);
}
FieldMeaning / document-v1 default
activeReveal current piece / true
nextDirectly revealed next-piece count / 5
holdReveal hold content / true
memoryhistory or current / history
revealsupply, lock or host / supply
bagknown or hidden bag knowledge / known

supply advances observation when actual supply is consumed; lock updates it at post-lock decision boundaries; host uses consumer-defined reveal events. all() exposes actual supply within the declared horizon. An ambiguous see-7 label alone is not stored.

Independent hold-state dimensions

tessembly
config {
    hold = slot(initial=empty, used=false, allowed=true, deny=["T"]);
    active = token("I", origin=10);
    queue = [token("O", origin=11)];
    cursor = 0;
    tail = end;
}
ExpressionState
hold=none()No hold feature or slot
hold=slot(initial=empty)An available empty slot
initial=token("T",origin=9)A held T with explicit origin
used=trueHold already used this turn; re-hold locked
allowed=falseDefault hold-action policy denies use
deny=["T"]Deny hold while the pre-action active kind is T

deny exists only in advanced declarations. It is not a D/U shortcut or a proposed Clearra UI feature. The held kind does not trigger it, and it does not forbid moving or placing T. Equal kinds may still have different origins.

Swapping occupied hold consumes no future queue entry. Empty hold consumes one actual next piece. Both lock re-hold for the turn; host-confirmed lock and spawn unlock it. A failed swap leaves state unchanged.

Missing information and unsupported states

tail=pending means further supply information is needed; tail=end means supply has ended. Neither is a proof of zero solutions. Missing settings also do not become EMPTY or NONE implicitly.

If a dataset supports only occupied hold, EMPTY is UNSUPPORTED_STATE. Never invent a held piece for lookup. A consumer may provide a verified mapping preserving active/held, queue consumption, bag leftovers, revealed information and corresponding legal actions.