@storylet-studio/runtime 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +55 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +18 -8
- package/dist/index.d.ts +18 -8
- package/dist/index.js +55 -18
- package/dist/index.js.map +1 -1
- package/package.json +8 -3
- package/dist/storyletengine.min.js +0 -2
- package/dist/storyletengine.min.js.map +0 -1
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../../../../expr/packages/expr/src/ast.ts","../../../../expr/packages/expr/src/evaluate.ts","../../../../expr/packages/expr/src/prng.ts","../../../../expr/packages/expr-specificity/src/index.ts","../../dialect/src/index.ts","../../model/src/index.ts","../../../../expr/packages/scoperegistry/src/index.ts","../src/engine.ts","../src/describe.ts"],"sourcesContent":["export { Engine, Flow } from \"./engine.js\";\nexport type {\n BagMount, BoxView, DealtCard, EngineLogEntry, EngineOptions, EngineTraceHandler, LogEntry, OpenFlowOptions,\n OutcomeView, PlayOptions, RankedList, PropertyView, TraceEvent, TraceHandler, TraceVerdict,\n} from \"./engine.js\";\nexport { describeBundle } from \"./describe.js\";\nexport type {\n BoxSummary, BundleDescription, BundleIdentity, HandSummary, MapSummary, PropertyScopeKind,\n PropertyScopeSummary, PropertySummary, TagGroupSummary,\n} from \"./describe.js\";\nexport { makePrng, shuffleInPlace } from \"./prng.js\";\nexport type { Prng } from \"./prng.js\";\n","// ---------------------------------------------------------------------------\n// AST - the in-memory expression tree and its serialised tagged-tuple form.\n//\n// The in-memory `ExprNode` is a discriminated union (kind field). The published\n// `AstNode` is the compact tagged-tuple form that goes into a compiled bundle's\n// { src, ast } envelope - what a runtime walks, never parses.\n//\n// This module is dialect-agnostic: scope tokens and function names are plain\n// strings here; meaning is supplied by a Dialect (see dialect.ts).\n// ---------------------------------------------------------------------------\n\nexport type ScalarValue = boolean | number | string | string[];\n\nexport type BinaryOp =\n | \"==\" | \"!=\" | \">\" | \">=\" | \"<\" | \"<=\"\n | \"+\" | \"-\" | \"*\" | \"/\"\n | \"and\" | \"or\";\n\nexport type UnaryOp = \"not\" | \"neg\";\n\nexport type ExprNode =\n | { kind: \"bool\"; value: boolean }\n | { kind: \"number\"; value: number }\n | { kind: \"string\"; value: string }\n // All property references are scoped: bare `@name` is canonicalised to\n // `@<defaultScope>.name` at parse time. Names are lowercased at parse time.\n | { kind: \"scopedvar\"; scope: string; name: string }\n | { kind: \"call\"; name: string; args: ExprNode[] }\n | { kind: \"unary\"; op: UnaryOp; operand: ExprNode }\n | { kind: \"binary\"; op: BinaryOp; left: ExprNode; right: ExprNode }\n // Produced only by flag-delta function argument parsing (see Dialect\n // `flagDeltaArgs`) - not valid elsewhere.\n | { kind: \"flagdelta\"; sign: \"+\" | \"-\"; name: string };\n\n/**\n * Path into an ExprNode tree. Each segment names the field on the parent node,\n * with numeric indices for array elements (call args).\n * binary.left -> [\"left\"]\n * binary.right.args[0] -> [\"right\", \"args\", 0]\n * top-level node -> []\n */\nexport type AstPath = readonly (string | number)[];\n\n// ---------------------------------------------------------------------------\n// Published tagged-tuple form (JSON arrays, opcode at index 0).\n// ---------------------------------------------------------------------------\n\nexport type AstNode =\n | [\"b\", boolean]\n | [\"n\", number]\n | [\"s\", string]\n | [\"sv\", string, string]\n | [\"u\", UnaryOp, AstNode]\n | [\"bin\", BinaryOp, AstNode, AstNode]\n | [\"call\", string, ...AstNode[]]\n | [\"fd\", \"+\" | \"-\", string];\n\n/** In-memory ExprNode -> published tagged-tuple AstNode. */\nexport function serialiseAst(node: ExprNode): AstNode {\n switch (node.kind) {\n case \"bool\": return [\"b\", node.value];\n case \"number\": return [\"n\", node.value];\n case \"string\": return [\"s\", node.value];\n case \"scopedvar\": return [\"sv\", node.scope, node.name];\n case \"unary\": return [\"u\", node.op, serialiseAst(node.operand)];\n case \"binary\": return [\"bin\", node.op, serialiseAst(node.left), serialiseAst(node.right)];\n case \"call\": return [\"call\", node.name, ...node.args.map(serialiseAst)];\n case \"flagdelta\": return [\"fd\", node.sign, node.name];\n }\n}\n\n/** Published tagged-tuple AstNode -> in-memory ExprNode. */\nexport function deserialiseAst(node: AstNode): ExprNode {\n switch (node[0]) {\n case \"b\": return { kind: \"bool\", value: node[1] };\n case \"n\": return { kind: \"number\", value: node[1] };\n case \"s\": return { kind: \"string\", value: node[1] };\n case \"sv\": return { kind: \"scopedvar\", scope: node[1], name: node[2] };\n case \"u\": return { kind: \"unary\", op: node[1], operand: deserialiseAst(node[2]) };\n case \"bin\": return { kind: \"binary\", op: node[1], left: deserialiseAst(node[2]), right: deserialiseAst(node[3]) };\n case \"call\": {\n const args = (node.slice(2) as AstNode[]).map(deserialiseAst);\n return { kind: \"call\", name: node[1], args };\n }\n case \"fd\": return { kind: \"flagdelta\", sign: node[1], name: node[2] };\n }\n}\n","// ---------------------------------------------------------------------------\n// Evaluator - walk an ExprNode against an EvalContext, parameterised by Dialect.\n//\n// Operators (binary/unary), short-circuiting, and type-checking are generic.\n// Scope resolution uses the context's scope maps + the Dialect's per-scope\n// missing-property policy. Function calls dispatch to the Dialect's functions.\n//\n// Ported from @storylets/engine (storylets/packages/engine/src/expression.ts),\n// generalised by injecting scopes + functions from the Dialect.\n// ---------------------------------------------------------------------------\n\nimport type { ExprNode, ScalarValue } from \"./ast.js\";\nimport type { Dialect, EvalContext, ScopeResolver } from \"./dialect.js\";\n\nexport class EvalError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"EvalError\";\n }\n}\n\nexport function evaluate(node: ExprNode, ctx: EvalContext, dialect: Dialect): ScalarValue {\n // Per-scope missing-property policy, precomputed once per top-level evaluate.\n const missingPolicy = new Map<string, \"false\" | \"throw\">(\n dialect.scopes.map((s) => [s.token, s.missing ?? \"false\"])\n );\n\n const rec = (n: ExprNode): ScalarValue => {\n switch (n.kind) {\n case \"bool\": return n.value;\n case \"number\": return n.value;\n case \"string\": return n.value;\n\n case \"scopedvar\": {\n const scope = ctx.scopes[n.scope];\n if (scope === undefined) {\n // Scope context absent -> graceful false. (A scope the dialect knows\n // about but the context didn't populate, or an unknown scope.)\n return false;\n }\n // A scope is either a static bag or a host resolver ({ get }). Bag values\n // are always ScalarValue (never functions), so a `get` function reliably\n // distinguishes a resolver.\n const val = typeof (scope as ScopeResolver).get === \"function\"\n ? (scope as ScopeResolver).get(n.name)\n : (scope as Record<string, ScalarValue>)[n.name];\n if (val === undefined) {\n // Property not declared on the present scope. Policy decides: \"false\"\n // for back-compat scopes, \"throw\" for scopes where a missing key is a\n // bug publish-time validation should have caught.\n if (missingPolicy.get(n.scope) === \"throw\") {\n throw new EvalError(`@${n.scope}.${n.name} is not declared on the current ${n.scope}.`);\n }\n return false;\n }\n return val;\n }\n\n case \"call\": {\n // `advance` is the language's own, the first core built-in: the next\n // stage in the argument's ladder, saturating at the last. Core rather\n // than dialect because it IS the quality design's insertion mechanism\n // (an outcome that never names its destination routes through an\n // inserted stage automatically), and every dialect should say it the\n // same way. A dialect that defines its own `advance` wins, for\n // back-compat with any dialect that already had one.\n if (n.name === \"advance\" && !dialect.functions[n.name]) {\n const arg = n.args[0];\n if (n.args.length !== 1 || arg === undefined) {\n throw new EvalError(`advance() takes exactly 1 argument, got ${n.args.length}`);\n }\n const ladder = ladderOf(arg, ctx);\n if (ladder === undefined) {\n throw new EvalError(\"advance() needs a quality reference (@scope.name of a quality property)\");\n }\n const current = stageIndex(rec(arg), ladder, \"advance\");\n return ladder[Math.min(current + 1, ladder.length - 1)]!;\n }\n const def = dialect.functions[n.name];\n if (!def) throw new EvalError(`unknown function '${n.name}'`);\n return def.eval(n.args, { evaluate: rec, ctx });\n }\n\n case \"flagdelta\":\n throw new EvalError(\"flagdelta node is only valid as an argument to a flag-delta function\");\n\n case \"unary\": {\n if (n.op === \"not\") {\n const val = rec(n.operand);\n if (typeof val !== \"boolean\") throw new EvalError(`'not' requires a boolean operand, got ${typeof val}`);\n return !val;\n }\n // neg\n const val = rec(n.operand);\n if (typeof val !== \"number\") throw new EvalError(`unary '-' requires a numeric operand, got ${typeof val}`);\n return -val;\n }\n\n case \"binary\": {\n // Short-circuit operators first\n if (n.op === \"and\") {\n const l = rec(n.left);\n if (typeof l !== \"boolean\") throw new EvalError(`'and' requires boolean operands, left is ${typeof l}`);\n if (!l) return false;\n const r = rec(n.right);\n if (typeof r !== \"boolean\") throw new EvalError(`'and' requires boolean operands, right is ${typeof r}`);\n return r;\n }\n if (n.op === \"or\") {\n const l = rec(n.left);\n if (typeof l !== \"boolean\") throw new EvalError(`'or' requires boolean operands, left is ${typeof l}`);\n if (l) return true;\n const r = rec(n.right);\n if (typeof r !== \"boolean\") throw new EvalError(`'or' requires boolean operands, right is ${typeof r}`);\n return r;\n }\n\n const left = rec(n.left);\n const right = rec(n.right);\n\n // Quality: when either operand REFERENCES a quality (the node carries\n // the scope+name the channel resolves), ordering compares by ladder\n // position and arithmetic is refused. Everything else is untouched,\n // so a context with no channel behaves exactly as before.\n const lLadder = ladderOf(n.left, ctx);\n const rLadder = ladderOf(n.right, ctx);\n const ladder = lLadder ?? rLadder;\n if (ladder !== undefined) {\n if (lLadder && rLadder && !sameLadder(lLadder, rLadder)) {\n if (n.op === \">\" || n.op === \">=\" || n.op === \"<\" || n.op === \"<=\") {\n throw new EvalError(`'${n.op}' compares two different qualities, whose stage orders are unrelated`);\n }\n }\n switch (n.op) {\n case \">\": return stageIndex(left, ladder, \">\") > stageIndex(right, ladder, \">\");\n case \">=\": return stageIndex(left, ladder, \">=\") >= stageIndex(right, ladder, \">=\");\n case \"<\": return stageIndex(left, ladder, \"<\") < stageIndex(right, ladder, \"<\");\n case \"<=\": return stageIndex(left, ladder, \"<=\") <= stageIndex(right, ladder, \"<=\");\n case \"+\": case \"-\": case \"*\": case \"/\":\n throw new EvalError(`'${n.op}' cannot be applied to a quality - a stage is a position, not a number; use advance() to move it`);\n default: break; // == and != fall through to plain value equality\n }\n }\n\n switch (n.op) {\n case \"==\": return valueEquals(left, right);\n case \"!=\": return !valueEquals(left, right);\n case \">\": assertNumbers(left, right, \">\"); return (left as number) > (right as number);\n case \">=\": assertNumbers(left, right, \">=\"); return (left as number) >= (right as number);\n case \"<\": assertNumbers(left, right, \"<\"); return (left as number) < (right as number);\n case \"<=\": assertNumbers(left, right, \"<=\"); return (left as number) <= (right as number);\n case \"+\":\n if (typeof left === \"number\" && typeof right === \"number\") return left + right;\n if (typeof left === \"string\" && typeof right === \"string\") return left + right;\n throw new EvalError(`'+' requires two numbers or two strings, got ${typeof left} and ${typeof right}`);\n case \"-\": assertNumbers(left, right, \"-\"); return (left as number) - (right as number);\n case \"*\": assertNumbers(left, right, \"*\"); return (left as number) * (right as number);\n case \"/\":\n assertNumbers(left, right, \"/\");\n if ((right as number) === 0) throw new EvalError(\"division by zero\");\n return (left as number) / (right as number);\n }\n }\n }\n };\n\n return rec(node);\n}\n\n/**\n * Equality for `==` / `!=`. Primitives compare by value (JS `===`); arrays\n * (the flags value type) compare as SETS: same members, ORDER IRRELEVANT.\n *\n * Plain `===` on arrays would be reference equality - two distinct arrays with\n * the same contents would never be equal, and a fresh array (from a scope read\n * or a function result) would never equal another. Mixed array/non-array\n * operands are unequal, and never an error.\n *\n * Order was significant until 2026-09-01, and that was wrong: a flags value IS\n * a set, and its stored order is an artefact of the order somebody happened to\n * add things in. `set_flags(@f, +a)` then `+b` compared UNEQUAL to the same two\n * flags added the other way round, which is a difference no author can see and\n * none intends. The Storylet Engine papered over it by sorting in `set_flags`,\n * which only holds while every producer sorts: a bundle's declared default, or\n * a host handing a list in, does not.\n *\n * Compared as MULTISETS (sorted copies), so a duplicated flag still counts. A\n * well-formed flags value has no duplicates, but equality should not be the\n * thing that decides what happens if one appears.\n */\nfunction valueEquals(a: ScalarValue, b: ScalarValue): boolean {\n if (Array.isArray(a) || Array.isArray(b)) {\n if (!Array.isArray(a) || !Array.isArray(b)) return false;\n if (a.length !== b.length) return false;\n const x = [...a].sort();\n const y = [...b].sort();\n for (let i = 0; i < x.length; i++) if (x[i] !== y[i]) return false;\n return true;\n }\n return a === b;\n}\n\nfunction assertNumbers(l: ScalarValue, r: ScalarValue, op: string): void {\n if (typeof l !== \"number\" || typeof r !== \"number\") {\n throw new EvalError(`'${op}' requires numeric operands, got ${typeof l} and ${typeof r}`);\n }\n}\n\n// --- quality (design: storylets-new/design/quality.md) -----------------------\n\n/** The ladder behind an operand NODE, when the context's quality channel says\n * it references a quality. Values are plain strings; the node is what carries\n * the (scope, name) the channel needs. */\nfunction ladderOf(node: ExprNode, ctx: EvalContext): readonly string[] | undefined {\n if (node.kind !== \"scopedvar\" || ctx.qualities === undefined) return undefined;\n return ctx.qualities(node.scope, node.name);\n}\n\n/** Index of a stage in a ladder; an unknown stage is an error naming the\n * value, never a silent pass (a drifted save is exactly what lands here). */\nfunction stageIndex(value: ScalarValue, ladder: readonly string[], op: string): number {\n if (typeof value !== \"string\") {\n throw new EvalError(`'${op}' on a quality compares stages, got ${typeof value}`);\n }\n const i = ladder.indexOf(value);\n if (i < 0) throw new EvalError(`\"${value}\" is not a stage of this quality (stages: ${ladder.join(\", \")})`);\n return i;\n}\n\nconst sameLadder = (a: readonly string[], b: readonly string[]): boolean =>\n a.length === b.length && a.every((x, i) => x === b[i]);\n","// ---------------------------------------------------------------------------\n// mulberry32 - the contractual PRNG.\n//\n// A fixed, published algorithm that both product families need and neither\n// owns. It lived in `@storylet-studio/runtime` as prng.ts and inline in\n// `@patterkit/runtime`'s engine.ts, plus separately in three of Patterplay's\n// harnesses, plus a hand port in each of six native runtimes: thirteen copies\n// of forty lines. It belongs here, in the package both families already depend\n// on, for the same reason the evaluator does.\n//\n// All arithmetic is unsigned 32-bit, matching JavaScript's `>>> 0` and\n// Math.imul.\n// ---------------------------------------------------------------------------\n\nexport interface Prng {\n /** One draw in [0, 1); advances the state. */\n next(): number;\n /** The persisted state (a uint32; feed back into makePrng to restore). */\n state(): number;\n}\n\n/**\n * ECMA-262 7.1.6 ToUint32, which is what `seed >>> 0` means.\n *\n * Written out rather than spelled `seed >>> 0` because THIS is the obligation a\n * port in a language without JavaScript's shift semantics has to reproduce, and\n * the shorthand hides it. Patterplay's C++ port cast the seed straight to an\n * integer type, which is undefined behaviour outside that type's range and gave\n * two wrong answers before the parity corpus pinned them.\n */\nexport function toUint32(seed: number): number {\n if (Number.isNaN(seed) || !Number.isFinite(seed)) return 0;\n const modded = Math.trunc(seed) % 4294967296;\n return modded < 0 ? modded + 4294967296 : modded;\n}\n\n/**\n * Seed a generator. The state is UNSIGNED throughout (`>>> 0`, never `| 0`):\n * the two produce identical draws and differ only in the sign of the number a\n * save persists, and Patterplay shipped `| 0` for long enough that over half of\n * all its saves carried a negative state its own native ports could not read\n * back.\n */\nexport function makePrng(seed: number): Prng {\n let s = toUint32(seed);\n return {\n next(): number {\n s = (s + 0x6d2b79f5) >>> 0;\n let t = Math.imul(s ^ (s >>> 15), 1 | s);\n t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n },\n state(): number {\n return s;\n },\n };\n}\n\n/** The contractual shuffle: Fisher-Yates, descending. Runs of one element\n * consume no draws (the loop never executes for length < 2). */\nexport function shuffleInPlace<T>(arr: T[], prng: Prng): void {\n for (let i = arr.length - 1; i > 0; i--) {\n const j = Math.floor(prng.next() * (i + 1));\n [arr[i], arr[j]] = [arr[j]!, arr[i]!];\n }\n}\n","// ---------------------------------------------------------------------------\n// @wildwinter/expr-specificity - public surface.\n//\n// Matched-constraint specificity: score how many atomic constraints in an\n// expression are actively holding it true against the current state. An\n// evaluation-aware walk (unlike a static clause count, an `or`'s score depends\n// on which branch is currently matching). Shared by Storylet Studio (storylet\n// draw priority) and Patter (dialogue best-match), which had independently\n// grown the same algorithm.\n//\n// Built on @wildwinter/expr's `ExprNode`. The host supplies truthiness via an\n// `evalTruthy` closure, so this package stays ignorant of the eval context,\n// the dialect, and the host's truthiness rule - each host keeps its own\n// behaviour while sharing one definition of the walk.\n// ---------------------------------------------------------------------------\n\nimport type { ExprNode } from \"@wildwinter/expr\";\n\n/** A call node, narrowed from the ExprNode union. */\ntype CallNode = Extract<ExprNode, { kind: \"call\" }>;\n\n/**\n * Evaluate an expression subtree to a boolean. Host-bound: the host closes over\n * its own evaluate + eval context + dialect and applies its own truthiness\n * coercion (Storylets' `conditionPasses`, Patter's `truthy`, etc.).\n */\nexport type EvalTruthy = (node: ExprNode) => boolean;\n\n/**\n * A call treated as a conjunction of constraints rather than a single atom, so\n * it contributes its operand count instead of 1. `check_flags` is the built-in\n * example (see {@link CHECK_FLAGS_COUNTING_CALL}).\n */\nexport interface CountingCall {\n /** The function name this rule applies to. */\n name: string;\n /** How many constraints the call contributes when it holds (at least 1). */\n count: (node: CallNode) => number;\n}\n\nexport interface MatchedSpecificityOptions {\n /**\n * Root polarity - the truth value the whole condition must have. Production\n * only ever scores conditions already known eligible, so this defaults to\n * `true` and rarely needs setting.\n */\n want?: boolean;\n /**\n * Calls scored by operand count rather than as a single atom. Defaults to\n * `[CHECK_FLAGS_COUNTING_CALL]`. Supply your own to add or replace rules.\n */\n countingCalls?: readonly CountingCall[];\n}\n\n/**\n * `check_flags(v, f1..fN)` counts as N constraints - an N-ary AND over the flag\n * operands - never fewer than 1. `args[0]` is the flags source, so the operand\n * count is `args.length - 1`.\n */\nexport const CHECK_FLAGS_COUNTING_CALL: CountingCall = {\n name: \"check_flags\",\n count: (node) => Math.max(1, node.args.length - 1),\n};\n\nconst DEFAULT_COUNTING_CALLS: readonly CountingCall[] = [CHECK_FLAGS_COUNTING_CALL];\n\n/**\n * Score how many atomic constraints in `node` are actively holding it true\n * against current state, via `evalTruthy`.\n *\n * The walk carries a polarity flag `want` (\"the truth value this subtree must\n * have for the whole to hold\"), applying De Morgan as it descends:\n * - atom: 1 if its truth matches `want`, else 0\n * - and: under `want`, both must hold -> sum; under `!want`, behaves as or\n * - or: under `want`, strongest branch -> max; under `!want`, behaves as and\n * - not: recurse with `want` flipped\n * - counting call (e.g. check_flags): its operand count when it must hold and\n * does, else the negated rules apply\n *\n * @example\n * // `@x == 5 and @y > 3` with both holding -> 2\n * matchedSpecificity(ast, node => conditionPasses(evaluate(node, ctx)))\n */\nexport function matchedSpecificity(\n node: ExprNode,\n evalTruthy: EvalTruthy,\n opts?: MatchedSpecificityOptions,\n): number {\n const countingCalls = opts?.countingCalls ?? DEFAULT_COUNTING_CALLS;\n return walk(node, opts?.want ?? true, evalTruthy, countingCalls);\n}\n\nfunction walk(\n node: ExprNode,\n want: boolean,\n evalTruthy: EvalTruthy,\n countingCalls: readonly CountingCall[],\n): number {\n if (node.kind === \"binary\" && (node.op === \"and\" || node.op === \"or\")) {\n const l = walk(node.left, want, evalTruthy, countingCalls);\n const r = walk(node.right, want, evalTruthy, countingCalls);\n // De Morgan: an `and` under negation behaves like an `or`, and vice versa.\n const behaveAsAnd = (node.op === \"and\") === want;\n if (behaveAsAnd) return l > 0 && r > 0 ? l + r : 0; // both must hold -> sum\n return Math.max(l, r); // either holds -> strongest branch\n }\n if (node.kind === \"unary\" && node.op === \"not\") {\n return walk(node.operand, !want, evalTruthy, countingCalls);\n }\n if (node.kind === \"call\") {\n const rule = countingCalls.find((c) => c.name === node.name);\n if (rule) {\n const operands = rule.count(node);\n const holds = evalTruthy(node);\n if (want) return holds ? operands : 0;\n return holds ? 0 : 1; // negated: De Morgan -> at least one operand fails -> 1\n }\n }\n // Any other node is an atom worth one constraint when its truth matches want.\n return evalTruthy(node) === want ? 1 : 0;\n}\n","// ---------------------------------------------------------------------------\n// @storylet-studio/dialect - the storylets expression dialect.\n//\n// One dialect drives runtime eval AND publish-time validation (schema 6.1).\n// Five scopes, fixed (Reboot 3); bare `@name` is `@story.name` (schema 6.2,\n// resolved 2026-07-19). Function eval semantics carry from the old engine's\n// storylets-dialect.ts where the function survives (random, check_flags,\n// set_flags); the play-history functions are the new set pinned in schema 6.3.\n// ---------------------------------------------------------------------------\n\nimport { EvalError } from \"@wildwinter/expr\";\nimport type { Dialect, EvalHelpers, ExprNode, ScalarValue } from \"@wildwinter/expr\";\n\n/** turns_since_played / _in when the card / value has never been played. */\nexport const NEVER_PLAYED = 9999;\n\n/**\n * Host callbacks the dialect's functions read from `EvalContext.host`. The\n * runtime supplies these (its PRNG, its play log); the compiler validates\n * without them.\n */\nexport interface StoryletsHost {\n /** One PRNG draw in [0, 1) - the session mulberry32 (schema 3.3). */\n nextRandom(): number;\n /** Plays of the card (gameId) from the play log. */\n countPlayed(card: string): number;\n /** Turns since the card (gameId) last played; NEVER_PLAYED when never. */\n turnsSincePlayed(card: string): number;\n /** Plays of cards belonging to the dimension value (both by gameId). */\n countPlayedIn(dimension: string, value: string): number;\n /** As above; NEVER_PLAYED when never. */\n turnsSincePlayedIn(dimension: string, value: string): number;\n}\n\nconst host = (h: EvalHelpers): Partial<StoryletsHost> =>\n (h.ctx.host ?? {}) as Partial<StoryletsHost>;\n\nconst stringArg = (fn: string, args: ExprNode[], h: EvalHelpers, i: number): string => {\n const v = h.evaluate(args[i]!);\n if (typeof v !== \"string\" || v === \"\") {\n throw new EvalError(`${fn}() argument ${i + 1} must be a non-empty string`);\n }\n return v;\n};\n\n/** Resolve the first argument of check_flags / set_flags to a flag set. */\nconst flagsArg = (fn: string, args: ExprNode[], h: EvalHelpers): string[] => {\n if (args.length === 0) {\n throw new EvalError(`${fn}() requires at least one argument (the flags property)`);\n }\n const v = h.evaluate(args[0]!);\n if (Array.isArray(v)) return v as string[];\n // An unset flags property may surface as false; treat as the empty set\n // (carried from the old dialect). Anything else is a type error.\n if (v === false) return [];\n throw new EvalError(`${fn}() first argument must be a flags property`);\n};\n\nexport const storyletsDialect: Dialect = {\n // A missing property in a PRESENT scope is always an error: every property\n // is declared with a default, so absence means a publish bug, a drifted\n // save, or a foreign scope the host never fed (schema 6.2).\n scopes: [\n { token: \"story\", missing: \"throw\" },\n { token: \"world\", missing: \"throw\" },\n { token: \"box\", missing: \"throw\" },\n { token: \"deck\", missing: \"throw\" },\n { token: \"hand\", missing: \"throw\" },\n ],\n defaultScope: \"story\",\n functions: {\n random: {\n minArgs: 2, maxArgs: 2, returnType: \"number\",\n eval(args: ExprNode[], h: EvalHelpers): ScalarValue {\n if (args.length !== 2) throw new EvalError(\"random(a, b) requires exactly 2 arguments\");\n const nextRandom = host(h).nextRandom;\n if (!nextRandom) throw new EvalError(\"random() called without a PRNG in context\");\n const a = h.evaluate(args[0]!);\n const b = h.evaluate(args[1]!);\n if (typeof a !== \"number\" || typeof b !== \"number\") {\n throw new EvalError(\"random(a, b) arguments must be numbers\");\n }\n if (!Number.isInteger(a) || !Number.isInteger(b)) {\n throw new EvalError(\"random(a, b) arguments must be integers\");\n }\n const lo = Math.min(a, b);\n const hi = Math.max(a, b);\n return Math.floor(nextRandom() * (hi - lo + 1)) + lo;\n },\n },\n check_flags: {\n minArgs: 1, returnType: \"boolean\", flagDeltaArgs: true,\n eval(args: ExprNode[], h: EvalHelpers): ScalarValue {\n const flags = flagsArg(\"check_flags\", args, h);\n for (let i = 1; i < args.length; i++) {\n const arg = args[i]!;\n if (arg.kind !== \"flagdelta\") {\n throw new EvalError(\"check_flags() flag args must be +flagName or -flagName\");\n }\n if (arg.sign === \"+\" ? !flags.includes(arg.name) : flags.includes(arg.name)) {\n return false;\n }\n }\n return true;\n },\n },\n set_flags: {\n minArgs: 1, returnType: \"flags\", flagDeltaArgs: true,\n eval(args: ExprNode[], h: EvalHelpers): ScalarValue {\n const result = [...flagsArg(\"set_flags\", args, h)];\n for (let i = 1; i < args.length; i++) {\n const arg = args[i]!;\n if (arg.kind !== \"flagdelta\") {\n throw new EvalError(\"set_flags() flag args must be +flagName or -flagName\");\n }\n if (arg.sign === \"+\") {\n if (!result.includes(arg.name)) result.push(arg.name);\n } else {\n const idx = result.indexOf(arg.name);\n if (idx >= 0) result.splice(idx, 1);\n }\n }\n // Sorted so a SAVE is deterministic: the same flags reached by different routes\n // serialise to the same bytes, which keeps save diffs and cross-runtime byte\n // comparisons stable. It is no longer what makes equality work - flags compare\n // as a SET since 2026-09-01 - so this is now about the stored form only, and\n // Patterplay not sorting is a difference that costs nothing.\n return result.sort();\n },\n },\n count_played: {\n minArgs: 1, maxArgs: 1, returnType: \"number\",\n eval(args: ExprNode[], h: EvalHelpers): ScalarValue {\n const card = stringArg(\"count_played\", args, h, 0);\n const fn = host(h).countPlayed;\n if (!fn) throw new EvalError(\"count_played() called without a play log in context\");\n return fn(card);\n },\n },\n turns_since_played: {\n minArgs: 1, maxArgs: 1, returnType: \"number\",\n eval(args: ExprNode[], h: EvalHelpers): ScalarValue {\n const card = stringArg(\"turns_since_played\", args, h, 0);\n const fn = host(h).turnsSincePlayed;\n if (!fn) throw new EvalError(\"turns_since_played() called without a play log in context\");\n return fn(card);\n },\n },\n count_played_in: {\n minArgs: 2, maxArgs: 2, returnType: \"number\",\n eval(args: ExprNode[], h: EvalHelpers): ScalarValue {\n const dimension = stringArg(\"count_played_in\", args, h, 0);\n const value = stringArg(\"count_played_in\", args, h, 1);\n const fn = host(h).countPlayedIn;\n if (!fn) throw new EvalError(\"count_played_in() called without a play log in context\");\n return fn(dimension, value);\n },\n },\n turns_since_played_in: {\n minArgs: 2, maxArgs: 2, returnType: \"number\",\n eval(args: ExprNode[], h: EvalHelpers): ScalarValue {\n const dimension = stringArg(\"turns_since_played_in\", args, h, 0);\n const value = stringArg(\"turns_since_played_in\", args, h, 1);\n const fn = host(h).turnsSincePlayedIn;\n if (!fn) throw new EvalError(\"turns_since_played_in() called without a play log in context\");\n return fn(dimension, value);\n },\n },\n },\n};\n","// ---------------------------------------------------------------------------\n// @storylet-studio/model - the shape source-of-truth.\n//\n// Transcribes design/storylets-schema.md (bundle, save) and\n// design/storylets-source.md (shards). Entity shapes are generic over their\n// expression representation E: source shards use plain `src` strings\n// (Card<string>), the compiled bundle uses { src, ast } envelopes\n// (Card<Expression>). No behaviour lives here.\n// ---------------------------------------------------------------------------\n\nimport type { Expression, ScalarValue } from \"@wildwinter/expr\";\n\nexport type { Expression, ScalarValue, AstNode } from \"@wildwinter/expr\";\n\n// --- shared declarations -----------------------------------------------------\n\nexport type PropertyType = \"boolean\" | \"number\" | \"string\" | \"enum\" | \"flags\" | \"quality\";\n\n/** A property declaration: @world / @story / @box / @deck / tag / hand\n * state. A declared property always has a value (`default` is required);\n * referencing an undeclared property is a publish-time error. */\nexport interface PropertyDecl {\n name: string;\n type: PropertyType;\n default: ScalarValue;\n values?: string[];\n /**\n * A quality's ordered ladder of stage names (design/quality.md). Order IS\n * the meaning: `>=` compares by position here, and `advance()` steps along\n * it. The one order-semantic list in the format, accepted as such: it is a\n * declaration, and inserting a stage mid-ladder is the design's whole point.\n */\n stages?: string[];\n /**\n * The sharing axis (design/flows.md, Patter's flag adopted): is this\n * property's value one world value across all flows, or a copy per flow?\n * It does NOT change reference syntax - sharing is set here, on the\n * declaration, not by a different scope token. Absent = the scope\n * default: `@story` shared; box, deck, hand and tag properties per-flow.\n * On a `@world` declaration the flag is a validation error - `@world` is\n * the game's own state, always engine-level, never per-flow.\n */\n shared?: boolean;\n purpose?: string;\n}\n\n/** A card-template field (box-defined). Data for the host; the engine never\n * interprets fields and they are not addressable from expressions. */\nexport interface FieldDecl {\n name: string;\n type: PropertyType;\n default: ScalarValue;\n values?: string[];\n purpose?: string;\n}\n\n/** Cooldown policy, in turns (schema 3.4). */\nexport type RedrawPolicy = \"always\" | \"never\" | number;\n\n// --- gameId derivation (Patter's effectiveGameId, adopted 2026-07-20) --------\n//\n// gameId is the renameable host-facing address; it is OPTIONAL in source and\n// derived from the entity's title until the author pins one, so a rename of\n// the title carries the address with it (no \"new-deck\" stuck placeholder).\n// The compiler fills a concrete gameId into every bundle entity.\n\n/** Slugify a human label into a filename- / address-safe gameId. */\nexport function gameIdify(text: string): string {\n return text.toLowerCase().replace(/['’]/g, \"\")\n .replace(/[^a-z0-9-]+/g, \"-\").replace(/-+/g, \"-\").replace(/^-+|-+$/g, \"\");\n}\n\nexport function isValidGameId(gameId: string): boolean {\n return /^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/.test(gameId);\n}\n\n// --- property names (adopted 2026-08-18, with Patter, from one rule) ---------\n//\n// Design and argument: `@wildwinter/app-shell` src/property-names.ts. Not house\n// style: the rule is what `@wildwinter/expr` can parse. Its lexer takes an\n// identifier as /[a-zA-Z_][a-zA-Z0-9_]*/ and folds it to lower case, so\n// `@story.isNight` reaches a property called `isnight`, `@story.9lives` and\n// `@story.not` are parse errors, and `@story.is-night` is not an error at all: it\n// compiles to `@story.is` MINUS the string \"night\". That last one is why the rule\n// is enforced rather than trusted - it is the only violation that silently means\n// something else.\n//\n// Here rather than behind an import of the UI kit because the compiler, the CLI\n// and the embedded runtime resolve state by these. `property-name-parity.test.ts`\n// holds them to the shell's, and `property-name-grammar.test.ts` holds them to the\n// parser they came from.\n\n/** The words `@wildwinter/expr` lexes as keywords, so no property may be called one. */\n// A legal property NAME is a fact about the expression language, not about this\n// model: `not` is reserved because the tokeniser reads it as an operator. Both\n// families kept their own copy of the rule AND of the keyword list, a list\n// neither owned. @wildwinter/expr derives the list from its own tokeniser, so a\n// keyword added there cannot leave a stale copy here.\n//\n// Re-exported so nothing that imports them has to move.\nexport {\n propertyNameify, isValidPropertyName, isCaseOnlyPropertyName, RESERVED_PROPERTY_NAMES,\n} from \"@wildwinter/expr\";\n/** The effective address: a pinned gameId, else derived from the title, else\n * the immutable id (so there is always something addressable). */\nexport function effectiveGameId(entity: { gameId?: string; title?: string; id: string }): string {\n const pinned = entity.gameId?.trim();\n if (pinned) return pinned;\n const fromTitle = entity.title ? gameIdify(entity.title) : \"\";\n return fromTitle || entity.id;\n}\n\n/**\n * The first free gameId of the form `base`, `base-2`, `base-3`, ... not already\n * in `taken`.\n *\n * A gameId is API - `deal()` and the play log speak it - so a name minted for a\n * new or duplicated entity must not collide with an existing one. This lived in\n * two copies, one in the editor and one in the CLI's kit scaffolder, character\n * for character the same; two copies of an addressing rule can drift, and a\n * drift here means the same act produces different addresses depending on which\n * program did it. It is here, beside `gameIdify`, because both programs need it\n * and no UI touches it.\n */\nexport function freeGameId(base: string, taken: ReadonlySet<string>): string {\n let gameId = base;\n for (let n = 2; taken.has(gameId); n++) gameId = `${base}-${n}`;\n return gameId;\n}\n\n/**\n * The first free TITLE of the form `base`, `base 2`, `base 3`, ... whose\n * derived gameId is not already in `taken`.\n *\n * The sibling of `freeGameId` for the \"New box\", \"New deck\" case, where the\n * author is given a title and the address follows from it. The dedupe is on the\n * DERIVED gameId rather than the title, because two titles that slug to one\n * address are the collision that matters.\n */\n/**\n * An id-sorted collection in the order a person should SEE it.\n *\n * Storage is sorted by immutable id (source rule 5) so that two authors adding\n * one item each never touch the same line. That makes array position useless as\n * display order, so the order the author arranged rides in a sparse `order`\n * field, with position as the fallback and id to break a tie.\n *\n * One definition, because this rule has to give the same answer in four places\n * that a reader compares side by side: the compiler (what the bundle carries),\n * the editor (what the card document lists), the exports, and Find. When they\n * disagree, the editor shows one order and the game plays another.\n */\nexport function byDisplayOrder<T extends { id?: string; order?: number }>(items: readonly T[]): T[] {\n return items\n .map((x, i) => ({ x, key: x.order ?? i, i }))\n .sort((a, b) => a.key - b.key || ((a.x.id ?? \"\") < (b.x.id ?? \"\") ? -1 : (a.x.id ?? \"\") > (b.x.id ?? \"\") ? 1 : a.i - b.i))\n .map((e) => e.x);\n}\n\nexport function freeTitle(base: string, taken: ReadonlySet<string>): string {\n let title = base;\n for (let n = 2; taken.has(gameIdify(title)); n++) title = `${base} ${n}`;\n return title;\n}\n\n// --- entities (generic over expression representation E) ---------------------\n\nexport interface Outcome<E> {\n id: string;\n gameId?: string;\n title?: string;\n purpose?: string;\n /** Authored display order (sparse; one without it falls back to its id\n * position). Unlike `Card.order` this one IS compiled into the bundle:\n * which option is offered first is authorial, and a host reading a dealt\n * card's outcomes is building the player's menu. */\n order?: number;\n /** Gating; availability is always evaluated against current state. */\n condition?: E;\n /** Target (\"@scope.name\") -> expression; all right-hand sides evaluate\n * against pre-play state (schema 3.7). */\n changes: Record<string, E>;\n}\n\nexport interface Card<E> {\n id: string;\n gameId?: string;\n title?: string;\n purpose?: string;\n /** Authored display order within the deck (sparse; a card without one falls\n * back to its id position). Merges as a per-card value, so id-sorted storage\n * stays merge-clean (Reboot 7.4); dropped from the compiled bundle. */\n order?: number;\n condition?: E;\n /** Default 0; an expression must evaluate to a number. */\n priority: number | E;\n redraw: RedrawPolicy;\n /** Tags: tag group id -> tag ids. An absent group is a wildcard (matches\n * any binding of it), except the reserved home group, whose default\n * inverts (schema 2.4). Editors and fixtures speak gameIds; stored\n * references are ids. */\n tags?: Record<string, string[]>;\n /** How many hands may hold this card at once (schema 3.5): integer >= 1,\n * default 1. One copy is the exclusivity rule; copies: N is the\n * deliberate opt-out for interchangeable filler. Always counted WITHIN a\n * flow, whether or not the card is shared. */\n copies?: number;\n /** Scarcity across flows (design/shared-scarcity.md). Absent takes the\n * deck's flag; set here it overrides the deck, so a single unique card can\n * stay in the content it belongs to. A shared card's claims count every\n * flow's board, and a shared `redraw: \"never\"` is spent for everyone the\n * first time anyone plays it.\n *\n * A finite `redraw` stays PER FLOW even when shared: a cooldown is an\n * absolute turn of the card's box clock and clocks are per flow, so\n * \"3 turns of whose clock?\" has no answer. A world-wide timer is a @world\n * question, not an engine one (shared-scarcity 9.3.3). */\n shared?: boolean;\n /** The world cap: how many hands ACROSS EVERY FLOW may hold this at once.\n * Read only when the card is shared, and defaults to `copies`, so the\n * common case writes one number and \"five in the world, one to a customer\"\n * is `copies: 1, sharedCopies: 5`. */\n sharedCopies?: number;\n /** Card-template data: field name -> value, validated at publish. */\n fields?: Record<string, ScalarValue>;\n outcomes: Outcome<E>[];\n}\n\nexport interface Deck<E> {\n id: string;\n gameId?: string;\n title?: string;\n purpose?: string;\n /** The deck gate, evaluated once per draw in the draw's environment. */\n condition?: E;\n /** This pile is scarce across flows (design/shared-scarcity.md): every card\n * in it is shared unless the card says otherwise. The container is where\n * Patter puts its own shared-memory flag, and the deck is our container. */\n shared?: boolean;\n properties: PropertyDecl[];\n cards: Card<E>[];\n}\n\nexport interface Tag {\n id: string;\n gameId?: string;\n /**\n * This tag's own starting values for properties its GROUP declares\n * (design/hand-typing.md). The group says what the property IS; a tag says\n * only where it starts, so \"every zone has a haunting level\" is written once\n * and \"the cave starts at 2\" is written where it belongs.\n *\n * A name here that the group does not declare is an error: it would be a\n * value for nothing.\n */\n values?: Record<string, ScalarValue>;\n /** Authored display order (sparse; one without it falls back to its id\n * position). Merges as a per-item value, so id-sorted storage stays\n * merge-clean (Reboot 7.4). */\n order?: number;\n properties?: PropertyDecl[];\n /** Template-of-play extras (e.g. spatial geometry). Source only: preserved\n * in shards, never compiled into the bundle. */\n templates?: Record<string, unknown>;\n}\n\n/** A named axis for cross-cutting cards (schema 2.4, renamed from\n * Dimension). Tags are declared, not freeform. */\nexport interface TagGroup {\n id: string;\n gameId?: string;\n purpose?: string;\n /**\n * A property reference (`\"@story.act\"`) whose value names a tag in this group\n * by gameId. The engine reads it at every ask and binds the group, exactly as\n * if the asking hand had chosen that tag; a hand's own binding wins.\n *\n * For an axis driven by STATE rather than by place: acts, chapters, a\n * difficulty band. Without it, only a hand can bind a group, so such an axis\n * had nowhere to gate and every card needed its own condition.\n *\n * A reference rather than an expression on purpose (design/where-and-\n * selectors.md Part B): a computed binding belongs in a property the outcomes\n * maintain, and an expression here would make this type generic for no gain.\n */\n boundBy?: string;\n /**\n * What omitting this group means for a card. Default false: omission is a\n * wildcard, so the card matches whatever the group is bound to. True inverts\n * it, so a card that names no tag here is unavailable wherever the group IS\n * bound (and unaffected where it is not).\n *\n * `place` is the built-in instance of this pair: bound to the asking hand,\n * and inverted per card rather than per group.\n */\n required?: boolean;\n /** Authored display order (sparse; one without it falls back to its id\n * position). Merges as a per-item value, so id-sorted storage stays\n * merge-clean (Reboot 7.4). */\n order?: number;\n /**\n * Properties EVERY tag in this group has (design/hand-typing.md). The\n * declaration lives here and each tag carries only its own starting value in\n * `Tag.values`, which is the separation the format was missing: a tag's own\n * `properties` entry has to restate the type on every tag purely in order to\n * say the value, and a tag added later silently arrives without it.\n *\n * Compiled by FLATTENING onto each tag, so the bundle keeps its per-tag\n * shape and no runtime, port or bundle schema changes: source is where the\n * author works and where merges happen, the bundle is a compiled artefact\n * that can afford to be explicit.\n *\n * A tag may still declare its own `properties` for a group whose tags\n * genuinely differ. Declaring the same NAME both ways is an error.\n */\n properties?: PropertyDecl[];\n tags: Tag[];\n /** Template-of-play extras for the GROUP, the same bag its tags carry: this is\n * where a group is marked spatial and where that template keeps its own\n * group-level configuration. Source only, preserved but never compiled.\n *\n * A bag rather than a `spatial: true` flag because the marker and the\n * configuration are one thing (see model/spatial.ts), and because core is not\n * meant to grow a field per template of play. */\n templates?: Record<string, unknown>;\n}\n\n/** The reserved tag group (schema 2.4): present in every box without\n * declaration, its tags the box's hand ids. Every hand implicitly binds it to\n * itself; a card that names a place is available only at that place.\n *\n * Called `place` rather than `home` since 2026-08-21: one word for one thing\n * across the format, the editor and the exports. \"Where\" is the QUESTION a\n * card answers (at a place, or anywhere in a region); \"place\" is the direct\n * half of that answer. `home` was a metaphor an author had to learn, and it\n * leaked into hand-edited shards and the docs. */\nexport const PLACE_GROUP = \"place\";\n\n/** A declared kind of hand (schema 2.6): live-inherited, author-side only,\n * never called from game code. One condition governs every instance. */\nexport interface HandTemplate<E> {\n id: string;\n gameId?: string;\n title?: string;\n purpose?: string;\n /** Authored display order (sparse; one without it falls back to its id\n * position). Merges as a per-item value, so id-sorted storage stays\n * merge-clean (Reboot 7.4). */\n order?: number;\n\n /** Fixed tag bindings: tag group id -> tag id. */\n bindings?: Record<string, string>;\n /** The holes: tag group ids each instance fills (one tag each). */\n chooses?: string[];\n /** Shared availability condition, ANDed in (schema 3.1); evaluated per\n * instance against that instance's composed @hand. */\n condition?: E;\n /** Default slot cap. */\n slots: number | \"unbounded\";\n /** Declared @hand state every instance carries. */\n properties: PropertyDecl[];\n}\n\n/** A standalone hand's inline rule (schema 2.6): owned by the hand. */\nexport interface HandRule<E> {\n bindings?: Record<string, string>;\n condition?: E;\n slots: number | \"unbounded\";\n}\n\n/** A hand (schema 2.6): a template instance (template + chosen) or a\n * standalone hand (rule). Exactly one of template / rule. Fully concrete:\n * deal is name-only. */\nexport interface Hand<E> {\n id: string;\n /** The name deal() is called with; a rename is a breaking change\n * (Reboot 7.4). */\n gameId?: string;\n title?: string;\n purpose?: string;\n /** Hand template id (not gameId). */\n template?: string;\n /** Template instances: tag group id -> tag id, one per `chooses` hole. */\n chosen?: Record<string, string>;\n /** Standalone hands: the inline rule. */\n rule?: HandRule<E>;\n /** Override; defaults to the template's / rule's slots. The ONLY template\n * field an instance may override (schema 2.6). */\n slots?: number;\n /** Standalone hands' own @hand state (template instances inherit the\n * template's declarations). */\n properties?: PropertyDecl[];\n /** Authored display order within the box (sparse; authoring-only, never\n * compiled into the bundle - the compiler's explicit field list drops it). */\n order?: number;\n /** Template-of-play extras (e.g. a spatial pin). Source only. */\n templates?: Record<string, unknown>;\n}\n\nexport interface Box<E> {\n id: string;\n gameId?: string;\n title?: string;\n purpose?: string;\n /** The only per-box ranking policy (Reboot 2.2). */\n ranking: { specificity: boolean };\n /** The card template: what every card in this box carries. */\n fields: FieldDecl[];\n properties: PropertyDecl[];\n tagGroups: TagGroup[];\n decks: Deck<E>[];\n handTemplates: HandTemplate<E>[];\n hands: Hand<E>[];\n}\n\n// --- the compiled bundle (.storyletsc) ---------------------------------------\n\nexport const BUNDLE_SCHEMA = \"storylets/bundle@0\";\n\n/** Binds bundles to shards (staleness gate) and saves to bundles. */\nexport interface BundleContent {\n project: string;\n version: string;\n /** hash32 over the canonical source shards (schema 2.8). */\n hash: string;\n}\n\nexport interface BundleSettings {\n playAdvancesTurns: number;\n}\n\n/**\n * A map that a bundle was asked to carry: one spatial tag group's geometry,\n * flattened for a host to draw (design/graphical-views.md 2, \"The map MAY ship\").\n *\n * INERT PAYLOAD. Nothing in the engine reads this and nothing ever will: the\n * runtime deals in tag names. It is here so a host that wants an in-game map does\n * not have to invent its own export, and it is absent unless the project asked\n * for it (`export.map`), so a build that does not want a map carries no bytes.\n *\n * GAME IDS throughout, never internal ids. Internal ids are authoring identity\n * and mean nothing outside the project; a host matches these against the same\n * names it passes to `peek`. There is nothing here to strip either, which is why\n * `metadata: \"stripped\"` needs no special case: no titles, no purposes.\n *\n * Sites are deliberately NOT here. A site is where an author parked a hand while\n * working, held in the view sidecar precisely because it is not content, and a\n * host that wants to place a hand already has its zone from the compiled binding.\n */\nexport interface BundleMap {\n /** The owning box, by gameId (tag groups are box-scoped). */\n box: string;\n /** The tag group this is a map of, by gameId. */\n group: string;\n /** One entry per zone that has been drawn; a tag with no polygon is not a\n * place yet and is left out rather than shipped as an empty shape. */\n zones: { tag: string; polygon: ViewPoint[] }[];\n /** Background pictures, back to front, as bundle-relative paths. Hidden ones\n * do not ship: what an author put away is not something to spring on a host. */\n backgrounds?: BundleBackground[];\n}\n\n/** One shipped picture. `locked` and `hidden` are authoring state and do not\n * travel; the draw order is the array order. */\nexport interface BundleBackground {\n /** Where the file sits relative to the bundle (\"assets/<box>/<file>\"). */\n file: string;\n x: number;\n y: number;\n width: number;\n height: number;\n opacity?: number;\n}\n\nexport interface Bundle {\n schema: typeof BUNDLE_SCHEMA;\n content: BundleContent;\n metadata: \"full\" | \"stripped\";\n settings: BundleSettings;\n world: {\n properties: PropertyDecl[];\n /** ScopeRegistrySpec (@wildwinter/scoperegistry): the owned/foreign\n * split. Absent = engine-owned @world (standalone play). */\n registry?: unknown;\n };\n story: {\n properties: PropertyDecl[];\n };\n boxes: Box<Expression>[];\n /** Maps, when the project asked for them. Absent is the normal state. */\n maps?: BundleMap[];\n}\n\n// --- the save envelope --------------------------------------------------------\n\nexport const SAVE_SCHEMA = \"storylets/save@1\";\n\nexport interface PlayRecord {\n /** Card and outcome by gameId (feeds the play-history functions). */\n card: string;\n outcome: string;\n turn: number;\n}\n\n/** A property bag: name -> value. */\nexport type PropertyBag = Record<string, ScalarValue>;\n\n/** The per-scope property partitions one side of the sharing flag holds:\n * a save carries one of these for the shared values and one per flow\n * (design/flows.md). NO world key, in either: @world is the game's own\n * state, resolved through the world resolver and saved by whoever owns\n * it - \"host saves its container once, each engine saves its own\n * envelope\" (engine-runtimes.md 3.1). */\nexport interface PropsPartition {\n story: PropertyBag;\n box: Record<string, PropertyBag>;\n deck: Record<string, PropertyBag>;\n hand: Record<string, PropertyBag>;\n /** Tag state, keyed by tag id. */\n value: Record<string, PropertyBag>;\n}\n\n/** One flow's snapshot inside the envelope (schema 4). */\nexport interface FlowSave {\n /** The per-flow property partitions. */\n props: PropsPartition;\n /** Per-box turn counters, keyed by box id (schema 3.4) - per flow: there\n * is deliberately no global turn. */\n turns: Record<string, number>;\n /** mulberry32 state, uint32 (schema 3.3), per flow. */\n prng: number;\n /** Absolute next-eligible turn (of the card's box's clock) per card id;\n * MAX_SAFE_INTEGER = never (deliberately not Infinity, which\n * JSON-serialises to null). */\n cooldowns: Record<string, number>;\n /** Hand contents (card ids, in dealt order), keyed by hand id. The claims\n * ledger is derived from this (schema 3.5). */\n board: Record<string, string[]>;\n playLog: PlayRecord[];\n}\n\n/** The whole engine, one envelope: the shared partitions once, then every\n * live flow keyed by its id - Patter's shape (one shared blob + N flow\n * blobs; multi-flow and save/load are the same feature). */\n/** The engine's half of a save: what every flow shares. Properties, and the\n * cards a shared `redraw: \"never\"` has taken out of the world for good\n * (design/shared-scarcity.md). Claims are NOT here: they are derived from the\n * live boards, and each flow's board rides its own blob. */\nexport interface SharedSave {\n props: PropsPartition;\n /** Card ids, sorted, so a save is byte-stable for a diff. */\n spent: string[];\n}\n\nexport interface SaveEnvelope {\n schema: typeof SAVE_SCHEMA;\n content: BundleContent;\n shared: SharedSave;\n flows: Record<string, FlowSave>;\n}\n\n/** The .storyletsave FILE: the HOST's file, not the engine's - the engine's\n * envelope plus, when the host keeps one, its @world container. This is\n * \"host saves its container once, each engine saves its own envelope\"\n * folded into one file for the single-host case; the ENGINE never reads or\n * writes `world` (loadGame takes the envelope alone). */\nexport const SAVEFILE_SCHEMA = \"storylets/savefile@1\";\n\nexport interface SaveFile {\n schema: typeof SAVEFILE_SCHEMA;\n engine: SaveEnvelope;\n /** The host's @world values, saved and restored by the host. */\n world?: PropertyBag;\n}\n\n// --- source shards (design/storylets-source.md) --------------------------------\n\n/** The project folder: a macOS package, a plain folder elsewhere. */\nexport const PROJECT_FOLDER_EXTENSION = \".storylets\";\n/** The compiled bundle (strict JSON; generated, never hand-edited). */\nexport const BUNDLE_EXTENSION = \".storyletsc\";\n\n/**\n * Where a shipped background sits, relative to the bundle file.\n *\n * One function so the compiler (which writes the name into the bundle) and the\n * export op (which writes the bytes) cannot drift apart: a path agreed in two\n * places is a path that eventually disagrees. Per BOX, because two boxes may\n * each have their own `plan.png` and a build must not silently keep one of them.\n */\nexport const bundleAssetPath = (boxGameId: string, file: string): string =>\n `assets/${boxGameId}/${file}`;\n/** Per-type shard extensions, JSON5 inside (source doc section 2). */\nexport const SHARD_EXTENSIONS = {\n project: \".storyletproj\",\n box: \".storyletbox\",\n tags: \".storylettags\",\n hands: \".storylethands\",\n deck: \".storyletdeck\",\n /** The arrangement layer: where things SIT, never what they are. Its own shard\n * because positions churn (an afternoon of tidying a canvas touches every\n * card) and content does not, so a designer arranging and a writer editing\n * never collide on one file (design/graphical-views.md section 1.2). */\n view: \".storyletview\",\n /** Threaded comments: content-ADJACENT, so neither in a content shard (a\n * writer's deck edit must not conflict with a reviewer's comment) nor in the\n * arrangement sidecar (this is not where anything sits). One per box,\n * id-keyed (design/annotation.md). Documentation NOTES used to share this\n * file and were retired: `purpose` already says why a thing exists, and\n * Patterpad's typed routing has no destination here. */\n notes: \".storyletnotes\",\n} as const;\n\nexport const PROJECT_SCHEMA = \"storylets/project@0\";\nexport const BOX_SCHEMA = \"storylets/box@0\";\nexport const TAGS_SCHEMA = \"storylets/tags@0\";\nexport const HANDS_SCHEMA = \"storylets/hands@0\";\nexport const DECK_SCHEMA = \"storylets/deck@0\";\nexport const VIEW_SCHEMA = \"storylets/view@0\";\n/** The comment sidecar's schema. Still called \"notes\" on disk: the file already\n * held both, and renaming it would break every project for no gain. */\nexport const NOTES_SCHEMA = \"storylets/notes@0\";\n\n/** A point in a canvas's own coordinates. */\nexport interface ViewPoint {\n x: number;\n y: number;\n}\n\n/**\n * Canvas furniture: what an author draws AROUND the content to make sense of it\n * (design/graphical-views.md 3, \"Frames and sites\").\n *\n * Both canvases carry the same thing, which is why they share a type: a node\n * canvas and a map are different views of different material, but \"put a box\n * round this lot and call it act two\" is the same thought on either.\n *\n * It lives in the view sidecar because it is ARRANGEMENT. Nothing here is\n * content: no runtime reads it, no bundle carries it, and deleting the sidecar\n * loses only the drawing. Threaded comments are the\n * other thing entirely - they attach to entities and they travel - but a canvas\n * DRAWS their markers, while owning none of them.\n */\nexport interface CanvasFurniture {\n /** Titled areas behind the content, back to front (see `stacked`).\n *\n * There was a second kind, a `stickies` list, retired on 2026-08-10\n * (design/annotation.md): a dropped comment marker does the same job in a\n * fraction of the space, and an annotation that takes as much room as the\n * thing it is about is a bad trade on a canvas. */\n frames?: Frame[];\n}\n\n/**\n * A titled area behind a group of things: Unreal's comment box.\n *\n * Deliberately dumb about what is inside it. It has no membership list and\n * computes none: a frame is a thing an author DREW, and the cards under it are\n * whatever happens to be under it now. That is what keeps it honest when content\n * moves, and it is the same reasoning that keeps a zone's sites out of the map's\n * sidecar.\n */\nexport interface Frame extends ViewPoint {\n id: string;\n w: number;\n h: number;\n /** Shown in the frame's bar, and the handle it is dragged by. */\n title?: string;\n /** One of the furniture palette's names (see `FURNITURE_COLOURS`); the theme\n * decides what that looks like, so a frame does not carry a hex value that\n * would fight the palette on the day somebody switches theme. */\n colour?: string;\n /** Place in the frame band (sparse, `stacked`). Frames can nest. */\n z?: number;\n}\n\n/** The furniture palette: names, not colours. The theme maps them, so the same\n * shard reads correctly on linen and on baize. */\nexport const FURNITURE_COLOURS = [\"paper\", \"amber\", \"sage\", \"sky\", \"rose\", \"slate\"] as const;\nexport type FurnitureColour = typeof FURNITURE_COLOURS[number];\n\n/** One deck's node canvas: where its cards sit, and the furniture around them.\n * Sparse throughout. A card with no entry lays out by default, and an entry for\n * a card that no longer exists is inert, so there is no referential integrity to\n * maintain against content that moves underneath. */\nexport interface DeckCanvas extends CanvasFurniture {\n /** Keyed by CARD id. */\n cards?: Record<string, ViewPoint>;\n}\n\n/** The box's map: where its hands sit in space, and the furniture around them. */\nexport interface BoxMap extends CanvasFurniture {\n /** Keyed by HAND id. WHERE a site is, and nothing else.\n *\n * Which zone it is IN is not recorded here, and deliberately (2026-08-06,\n * with the rebinding drag): a hand that binds a zone already says so in its\n * own shard, as `chosen` or as a rule binding, and that is the truth the\n * runtime deals from. A copy here could only ever go on to disagree with it,\n * and a site whose recorded zone contradicts the hand it stands for would be\n * the most misleading thing on the map.\n *\n * Called `pins` until 2026-08-10 (design/annotation.md). No compatibility\n * branch: the only projects that exist are the examples in this repo, and they\n * were edited. */\n sites?: Record<string, ViewPoint>;\n}\n\n/** The arrangement layer for one box: where things SIT, never what they are.\n *\n * Its own shard on purpose (design/graphical-views.md section 1.2). Positions\n * churn, content does not: an afternoon of tidying a canvas touches every card,\n * and if that lived in the deck shard then a designer arranging and a writer\n * editing card text would collide on one file all day, while a content review\n * would be full of coordinates. Keyed by id throughout so the existing merge\n * engine handles two designers rearranging different things without a conflict.\n *\n * Source-only. It never reaches the compiled bundle, exactly as `order` does\n * not: the compiler reads the fields it names and this is not among them. */\nexport interface ViewShard {\n schema: typeof VIEW_SCHEMA;\n /** Keyed by DECK id: one node canvas each. */\n canvases?: Record<string, DeckCanvas>;\n map?: BoxMap;\n}\n\n/** A coverage input driver: during a coverage run the harness feeds a\n * host-seam property (`@world.x`) values from `values`, so content gated on\n * external state gets exercised (Patter's coverageDrivers, carried whole). */\nexport interface CoverageDriver {\n /** \"initial\": set once as each playthrough starts. \"recurring\": re-rolled\n * per turn at the cadence, so one run passes through several states. */\n kind: \"initial\" | \"recurring\";\n /** For recurring drivers: how often to re-roll per turn (default \"sometimes\"). */\n cadence?: \"rarely\" | \"sometimes\" | \"often\";\n /** The pool the harness picks from (uniform). Empty = inert. */\n values: ScalarValue[];\n}\n\n/** Authoring-side coverage configuration (never compiled into the bundle). */\nexport interface CoverageConfig {\n /** Property drivers, keyed by ref (\"@world.danger\"). */\n drivers?: Record<string, CoverageDriver>;\n\n}\n\nexport interface ProjectShard {\n schema: typeof PROJECT_SCHEMA;\n project: {\n id: string;\n name: string;\n version: string;\n };\n settings: BundleSettings;\n /** Coverage drivers + argument domains (authoring/testing config; stays\n * out of the compiled bundle). */\n coverage?: CoverageConfig;\n /** Validation switches (authoring config; never compiled). Off is written\n * as ABSENT, like `export.map`: a shard says what an author chose. */\n validation?: {\n /** Also warn when state is WRITTEN but nothing reads it. Off by default:\n * cards are routinely written ahead of the content that will read them,\n * so mid-development this warning is mostly noise. The read side (a gate\n * on state nothing writes) always warns, because that kills cards now. */\n warnUnreadWrites?: boolean;\n };\n world: {\n properties: PropertyDecl[];\n registry?: unknown;\n };\n story: {\n properties: PropertyDecl[];\n };\n /** Templates of play: configuration bags keyed by template name. Core\n * validates only what it knows. */\n templates: Record<string, unknown>;\n export: {\n bundle: string;\n metadata: \"full\" | \"stripped\";\n /**\n * Does a `.storyletpack` carry the boxes' binary assets (background images)?\n *\n * Default false, and a project-level DEFAULT rather than a rule: a pack is a\n * delivery, so the caller can override it per pack (2026-08-07). Some\n * projects would benefit from sending their pictures in certain\n * circumstances and others never would, which is why neither \"always\" nor\n * \"never\" is the answer.\n *\n * Nothing to do with the compiled bundle, which has its own switch: `map`.\n */\n packAssets?: boolean;\n /**\n * Does the compiled bundle carry the maps (zone shapes and background\n * pictures)?\n *\n * Default false, and the default matters: geometry is authoring data, the\n * runtime deals in tag names, and a shipping build should carry nothing it\n * does not use. But a host that wants an in-game map should not have to\n * invent its own export, and it is most useful early - a prototype with a\n * real map beats a prototype with a list of zone names.\n *\n * It sits beside `metadata` on purpose: that is already the switch for\n * \"authoring data that may or may not ship\", and this is its sibling rather\n * than a new concept. With it on, `export` also writes the background files\n * next to the bundle, and `describeBundle` says what is in there.\n */\n map?: boolean;\n };\n}\n\nexport interface BoxShard {\n schema: typeof BOX_SCHEMA;\n box: {\n id: string;\n gameId?: string;\n title?: string;\n purpose?: string;\n /** Authored display order among boxes (sparse; absent falls back to the\n * folder-name position). Authoring-only, like a card's (never compiled\n * into the bundle); merges as a per-field value. */\n order?: number;\n ranking: { specificity: boolean };\n fields: FieldDecl[];\n properties: PropertyDecl[];\n };\n}\n\n/** The box's tag groups: how its cards are filed. */\nexport interface TagsShard {\n schema: typeof TAGS_SCHEMA;\n groups: TagGroup[];\n}\n\n/** The box's hand templates + hands (the writer/programmer contract). */\nexport interface HandsShard {\n schema: typeof HANDS_SCHEMA;\n templates: HandTemplate<string>[];\n hands: Hand<string>[];\n}\n\nexport interface DeckShard {\n schema: typeof DECK_SCHEMA;\n deck: {\n id: string;\n gameId?: string;\n title?: string;\n purpose?: string;\n condition?: string;\n /** Scarce across flows: see Deck.shared. */\n shared?: boolean;\n /** Authored display order within the box (sparse; see BoxShard). */\n order?: number;\n properties: PropertyDecl[];\n };\n cards: Card<string>[];\n}\n\n// --- templates of play --------------------------------------------------------\n// The spatial template's types, field access and geometry. Re-exported here so the\n// package has one entry point, and kept in its own module because core schema and\n// a template of play are different things (Reboot 6).\nexport * from \"./spatial.js\";\n\n// How a hand reaches a tag group, and whether that binding is the hand's own to\n// change. Core schema rather than a template of play, but the map is what needed\n// it said out loud.\nexport * from \"./hands.js\";\n\n// Frames: what an author draws around the content. Arrangement,\n// so it lives in the sidecar and reads forgivingly (furniture.ts says why).\nexport * from \"./furniture.js\";\n\n// Threaded comments: the conversation about a thing, in its own sidecar.\nexport * from \"./comments.js\";\n\n// Guessing a property's type from what an outcome writes: the quick fix's input.\nexport * from \"./infer.js\";\n","// ---------------------------------------------------------------------------\n// @wildwinter/scoperegistry - the scope registry / runtime state container that\n// sits on top of @wildwinter/expr.\n//\n// expr is a stateless calculator: given an AST, an EvalContext (the state), and\n// a Dialect, it computes. This package is the *state* layer: it owns the world\n// state as a set of named scopes - each either an **owned** scope (a property\n// bag this registry stores and saves) or a **foreign** scope (host- or\n// other-engine-resolved at runtime, never stored here) - and produces the\n// `EvalContext` (for evaluation) and `ExpressionSchema` (for validation) that\n// expr consumes. Plus the `scopeRegistrySpec` interop format for importing a\n// foreign owner's scope declarations.\n//\n// Design: design/scope-registry.md (in the patter repo). expr never depends on\n// this; this depends one-way on expr.\n// ---------------------------------------------------------------------------\n\nimport type {\n EvalContext, ExpressionSchema, PropertyType, ScalarValue, ScopeResolver,\n} from \"@wildwinter/expr\";\n\nexport type { EvalContext, ExpressionSchema, PropertyType, ScalarValue, ScopeResolver } from \"@wildwinter/expr\";\n\n// ---------------------------------------------------------------------------\n// Declarations + the scopeRegistrySpec interop format\n// ---------------------------------------------------------------------------\n\n/**\n * A property declaration. `default` is used by an *owned* scope to seed its bag\n * (foreign scopes ignore it - the host owns the value). `writable: false` makes\n * a property read-only; default is read/write. (`type`/`values` feed validation.)\n */\nexport interface ScopeDeclaration {\n name: string;\n type: PropertyType;\n values?: string[]; // for enum / flags\n /** A quality's ordered ladder of stage names (quality.md). */\n stages?: string[];\n default?: ScalarValue; // owned scopes: seed value\n writable?: boolean; // default true\n}\n\n/** One scope in a `scopeRegistrySpec`: a token + (optional) declarations. */\nexport interface ScopeSpec {\n token: string;\n /** Scope-level read/write default for its declarations (default true). */\n writable?: boolean;\n /** Property declarations; omit for an opaque scope (any name, unchecked). */\n declarations?: ScopeDeclaration[];\n}\n\n/**\n * The interop format an owner (Storylet Studio, a host game) exports so another\n * engine can validate references into its scopes. Carried under the well-known\n * `scopeRegistrySpec` JSON key (inside a `.storyworld`, or a standalone file).\n */\nexport interface ScopeRegistrySpec {\n version: number;\n scopes: ScopeSpec[];\n}\n\n/** The spec versions this build understands. */\nexport const SUPPORTED_SPEC_VERSIONS = [1] as const;\n\n/**\n * Extract + validate a `scopeRegistrySpec` from any JSON value (a parsed\n * `.storyworld` bundle, or a vanilla `{ scopeRegistrySpec: ... }` manifest).\n * Returns null when the key is absent (so callers can probe arbitrary files);\n * throws on a malformed or unsupported-version spec.\n */\nexport function readScopeRegistrySpec(source: unknown): ScopeRegistrySpec | null {\n if (!source || typeof source !== \"object\") return null;\n const raw = (source as Record<string, unknown>).scopeRegistrySpec;\n if (raw === undefined) return null;\n if (typeof raw !== \"object\" || raw === null) throw new Error(\"scopeRegistrySpec must be an object\");\n const spec = raw as Record<string, unknown>;\n if (typeof spec.version !== \"number\") throw new Error(\"scopeRegistrySpec.version must be a number\");\n if (!(SUPPORTED_SPEC_VERSIONS as readonly number[]).includes(spec.version)) {\n throw new Error(`unsupported scopeRegistrySpec version ${spec.version} (supported: ${SUPPORTED_SPEC_VERSIONS.join(\", \")})`);\n }\n if (!Array.isArray(spec.scopes)) throw new Error(\"scopeRegistrySpec.scopes must be an array\");\n for (const s of spec.scopes) {\n if (!s || typeof s !== \"object\" || typeof (s as ScopeSpec).token !== \"string\") {\n throw new Error(\"each scopeRegistrySpec scope needs a string token\");\n }\n }\n return spec as unknown as ScopeRegistrySpec;\n}\n\n// ---------------------------------------------------------------------------\n// PropertyBag - the state kernel's unit of state (added 0.2.0; design:\n// storylets-new/design/engine-runtimes.md 3.1). A typed, declared property\n// bag with defaults, the firing rule (engine writes notify subscribers;\n// host writes are silent but always auditable), examiner rows, one\n// sanctioned clone door, and bare-value save/load. Owned registry scopes\n// are bags; products may also hold bag families of their own (per-box,\n// per-scene) and mount the shared ones.\n// ---------------------------------------------------------------------------\n\n/** One property change. `silent` marks a host write (the firing rule: it\n * reaches the audit hook but not subscribers); `reason` is the host's own\n * note for its log. */\nexport interface BagChange {\n name: string;\n prev?: ScalarValue;\n next: ScalarValue;\n silent: boolean;\n reason?: string;\n}\n\n/** One examiner row: what a property examiner/editor needs to render and\n * edit a declared property. */\nexport interface PropertyRow {\n name: string;\n type: PropertyType;\n value: ScalarValue | undefined;\n default: ScalarValue;\n values?: string[];\n writable: boolean;\n}\n\nexport class PropertyBag {\n /** The live values record (stable identity across reseed, so an\n * EvalContext built over it stays valid). Read-path for evaluation;\n * writes go through `set` so the firing rule applies. */\n readonly values: Record<string, ScalarValue> = {};\n private decls = new Map<string, ScopeDeclaration>();\n private readonly subscribers = new Set<(change: BagChange) => void>();\n private readonly auditors = new Set<(change: BagChange) => void>();\n /** Name normalisation policy: lowercase by default (the registry's\n * long-standing contract); a product whose names are case-significant\n * passes identity. */\n private readonly norm: (name: string) => string;\n\n constructor(declarations: ScopeDeclaration[] = [], opts?: { normalise?: (name: string) => string }) {\n this.norm = opts?.normalise ?? ((n) => n.toLowerCase());\n this.seed(declarations);\n }\n\n private seed(declarations: ScopeDeclaration[]): void {\n for (const d of declarations) {\n const name = this.norm(d.name);\n this.decls.set(name, d);\n // Cloned so bags seeded from one declaration set never share a\n // mutable default (flags arrays).\n this.values[name] = structuredClone(d.default ?? defaultFor(d));\n }\n }\n\n get(name: string): ScalarValue | undefined {\n return this.values[this.norm(name)];\n }\n\n /** Write a property. Engine writes (the default) notify subscribers;\n * pass `silent: true` for a host write, which reaches only the audit\n * hook. Throws on a read-only property. Returns the change. */\n set(name: string, value: ScalarValue, opts?: { silent?: boolean; reason?: string }): BagChange {\n const n = this.norm(name);\n if (this.decls.get(n)?.writable === false) throw new Error(`'${name}' is read-only`);\n const change: BagChange = {\n name: n,\n prev: this.values[n],\n next: value,\n silent: opts?.silent ?? false,\n reason: opts?.reason,\n };\n this.values[n] = value;\n for (const audit of this.auditors) audit(change);\n if (!change.silent) for (const fn of this.subscribers) fn(change);\n return change;\n }\n\n /** Notified of engine (non-silent) writes. Returns the unsubscribe. */\n subscribe(fn: (change: BagChange) => void): () => void {\n this.subscribers.add(fn);\n return () => this.subscribers.delete(fn);\n }\n\n /** Notified of EVERY write, silent or not. Returns the unsubscribe. */\n onAudit(fn: (change: BagChange) => void): () => void {\n this.auditors.add(fn);\n return () => this.auditors.delete(fn);\n }\n\n /** Examiner rows: the declared surface only (stray values are storage,\n * not surface). */\n rows(): PropertyRow[] {\n return [...this.decls.entries()].map(([name, d]) => rowFor(d, this.get(name), undefined, name));\n }\n\n declarations(): ScopeDeclaration[] {\n return [...this.decls.values()];\n }\n\n /** The one sanctioned copy door: values deep-copied, declarations\n * duplicated, the normalisation policy carried, subscriptions NOT\n * carried. */\n clone(): PropertyBag {\n const c = new PropertyBag([], { normalise: this.norm });\n c.decls = new Map(this.decls);\n Object.assign(c.values, structuredClone(this.values));\n return c;\n }\n\n /** Clear and re-seed from new declarations, in place (the values record\n * keeps its identity, so contexts built over it stay valid). */\n reseed(declarations: ScopeDeclaration[]): void {\n for (const k of Object.keys(this.values)) delete this.values[k];\n this.decls.clear();\n this.seed(declarations);\n }\n\n /** Bare values, ready to embed in a product's save. */\n save(): Record<string, ScalarValue> {\n return structuredClone(this.values);\n }\n\n /** Lay saved values over the current ones (call after a fresh seed:\n * orphans land as strays, new declarations keep their defaults; the\n * product decides whether to prune). Does not fire events. */\n load(values: Record<string, ScalarValue>): void {\n for (const [k, v] of Object.entries(values)) this.values[this.norm(k)] = v;\n }\n}\n\nfunction rowFor(d: ScopeDeclaration, value: ScalarValue | undefined, writable?: boolean, name?: string): PropertyRow {\n return {\n name: name ?? d.name.toLowerCase(),\n type: d.type,\n value,\n default: d.default ?? defaultFor(d),\n ...(d.values !== undefined ? { values: d.values } : {}),\n writable: writable ?? d.writable ?? true,\n };\n}\n\n// ---------------------------------------------------------------------------\n// The registry / state container\n// ---------------------------------------------------------------------------\n\ninterface OwnedScope {\n kind: \"owned\";\n bag: PropertyBag;\n}\ninterface ForeignScope {\n kind: \"foreign\";\n resolver: ScopeResolver;\n decls: Map<string, ScopeDeclaration>;\n scopeWritable: boolean;\n}\ntype Entry = OwnedScope | ForeignScope;\n\n/** The versioned owned-state fragment both product save envelopes embed\n * (design/engine-runtimes.md 3.1: one serialisation shape for bags). */\nexport interface OwnedStateFragment {\n version: number;\n scopes: Record<string, Record<string, ScalarValue>>;\n}\n\nexport const SAVE_FRAGMENT_VERSION = 1;\n\nexport class ScopeRegistry {\n private readonly scopes = new Map<string, Entry>();\n\n /**\n * Register a scope this registry **owns and stores**. Its bag is seeded from\n * each declaration's `default` (or a type default). Owned scopes are\n * type-checked (declarations) and serialized by `save`/`load`.\n */\n defineOwned(token: string, declarations: ScopeDeclaration[]): this {\n return this.mountOwned(token, new PropertyBag(declarations));\n }\n\n /**\n * Attach an EXISTING bag as an owned scope - the shared-container move: a\n * host (or the other product) holds the bag; this registry reads, writes\n * and lists it like its own, but the holder saves it.\n */\n mountOwned(token: string, bag: PropertyBag): this {\n this.assertFree(token);\n this.scopes.set(token, { kind: \"owned\", bag });\n return this;\n }\n\n /** An owned scope's bag (subscribe, audit, rows live there). */\n ownedBag(token: string): PropertyBag {\n const e = this.scopes.get(token);\n if (!e || e.kind !== \"owned\") throw new Error(`'@${token}' is not an owned scope`);\n return e.bag;\n }\n\n /**\n * Re-initialise an existing **owned** scope's bag from new declarations,\n * clearing its current values. For scope-local state that resets on a context\n * change (e.g. entering a new scene / site / deck) without disturbing other\n * scopes. Mutates the bag in place, so an `EvalContext` already built from this\n * registry stays valid.\n */\n reseedOwned(token: string, declarations: ScopeDeclaration[]): this {\n this.ownedBag(token).reseed(declarations);\n return this;\n }\n\n /**\n * Register a **foreign** scope backed by a host `{ get, set? }` resolver. The\n * values live in the host/other engine and are never stored or saved here.\n * `declarations` (optional, e.g. imported from a `scopeRegistrySpec`) are used\n * only for validation; omit them for an opaque scope.\n */\n defineForeign(\n token: string,\n resolver: ScopeResolver,\n declarations: ScopeDeclaration[] = [],\n scopeWritable = true,\n ): this {\n this.assertFree(token);\n const decls = new Map<string, ScopeDeclaration>();\n for (const d of declarations) decls.set(d.name.toLowerCase(), d);\n this.scopes.set(token, { kind: \"foreign\", resolver, decls, scopeWritable });\n return this;\n }\n\n has(token: string): boolean {\n return this.scopes.has(token);\n }\n\n /** Read a property; undefined if the scope or property is not present. */\n get(scope: string, name: string): ScalarValue | undefined {\n const e = this.scopes.get(scope);\n if (!e) return undefined;\n return e.kind === \"owned\" ? e.bag.get(name) : e.resolver.get(name.toLowerCase());\n }\n\n /** Write a property (an ENGINE write: the bag's subscribers fire; use\n * the bag directly for silent host writes). Throws on an unknown or\n * read-only scope/property. */\n set(scope: string, name: string, value: ScalarValue): void {\n const e = this.scopes.get(scope);\n if (!e) throw new Error(`unknown scope '@${scope}'`);\n if (e.kind === \"owned\") {\n try {\n e.bag.set(name, value);\n } catch {\n throw new Error(`'@${scope}.${name}' is read-only`);\n }\n return;\n }\n const n = name.toLowerCase();\n if (!this.foreignWritable(e, n)) throw new Error(`'@${scope}.${name}' is read-only`);\n e.resolver.set!(n, value);\n }\n\n private foreignWritable(e: ForeignScope, name: string): boolean {\n if (!e.resolver.set) return false; // no setter => read-only scope\n return e.decls.get(name)?.writable ?? e.scopeWritable;\n }\n\n /** Examiner rows across every scope with a declared surface: owned bags\n * first, then declared foreign scopes (values read through, writability\n * reflecting the resolver). Opaque foreign scopes are not listed. */\n listProperties(): ({ scope: string } & PropertyRow)[] {\n const out: ({ scope: string } & PropertyRow)[] = [];\n for (const [token, e] of this.scopes) {\n if (e.kind === \"owned\") {\n for (const row of e.bag.rows()) out.push({ scope: token, ...row });\n } else {\n for (const d of e.decls.values()) {\n out.push({\n scope: token,\n ...rowFor(d, e.resolver.get(d.name.toLowerCase()), this.foreignWritable(e, d.name.toLowerCase())),\n });\n }\n }\n }\n return out;\n }\n\n /**\n * Build the `EvalContext` expr's `evaluate` consumes: owned scopes as static\n * bags, foreign scopes as their resolvers. `host` carries dialect-function\n * callbacks (PRNG, tag lookups) and is passed through untouched.\n */\n toEvalContext(host?: Record<string, unknown>): EvalContext {\n const scopes: EvalContext[\"scopes\"] = {};\n for (const [token, e] of this.scopes) {\n scopes[token] = e.kind === \"owned\" ? e.bag.values : e.resolver;\n }\n // The quality channel (quality.md): declared here once, so a host that\n // registers a quality gets ordering comparisons and advance() with no\n // further wiring. Only added when a quality exists, so contexts stay\n // byte-identical for products that declare none.\n const qualities = this.qualityLadders();\n return qualities.size === 0 ? { scopes, host } : {\n scopes, host,\n qualities: (scope, name) => qualities.get(scope)?.get(name.toLowerCase()),\n };\n }\n\n /** Every quality declaration's ladder, keyed scope token then name. */\n private qualityLadders(): Map<string, Map<string, readonly string[]>> {\n const out = new Map<string, Map<string, readonly string[]>>();\n for (const [token, e] of this.scopes) {\n const decls = e.kind === \"owned\" ? e.bag.declarations() : [...e.decls.values()];\n for (const d of decls) {\n if (d.type !== \"quality\" || d.stages === undefined) continue;\n let m = out.get(token);\n if (!m) { m = new Map(); out.set(token, m); }\n m.set(d.name.toLowerCase(), d.stages);\n }\n }\n return out;\n }\n\n /**\n * Build the `ExpressionSchema` expr's validator consumes. Scopes with no\n * declarations are **omitted** (opaque - references into them are not flagged);\n * declared scopes contribute their property types for validation.\n */\n toSchema(): ExpressionSchema {\n const properties = new Map<string, Map<string, { type: PropertyType; enumValues?: string[]; stages?: string[] }>>();\n for (const [token, e] of this.scopes) {\n const decls = e.kind === \"owned\" ? e.bag.declarations() : [...e.decls.values()];\n if (decls.length === 0) continue;\n const m = new Map<string, { type: PropertyType; enumValues?: string[]; stages?: string[] }>();\n for (const d of decls) m.set(d.name.toLowerCase(), {\n type: d.type, enumValues: d.values,\n ...(d.stages !== undefined ? { stages: d.stages } : {}),\n });\n properties.set(token, m);\n }\n return { properties };\n }\n\n /** Serialize **owned** scopes only (foreign scopes are host-owned,\n * host-saved), as bare bags - the 0.1.x shape, kept stable so existing\n * consumers' save formats are untouched. A product embedding the\n * versioned cross-product shape uses `saveFragment`. */\n save(): Record<string, Record<string, ScalarValue>> {\n const out: Record<string, Record<string, ScalarValue>> = {};\n for (const [token, e] of this.scopes) if (e.kind === \"owned\") out[token] = e.bag.save();\n return out;\n }\n\n /** Restore owned-scope values from a `save` blob. Unknown/foreign scopes\n * are ignored. */\n load(blob: Record<string, Record<string, ScalarValue>>): void {\n for (const [token, vals] of Object.entries(blob)) {\n const e = this.scopes.get(token);\n if (e?.kind === \"owned\") e.bag.load(vals);\n }\n }\n\n /** The versioned owned-state fragment (the one serialisation shape both\n * product families' save envelopes embed when they adopt the kernel;\n * design/engine-runtimes.md 3.1). `save()` wrapped with a version stamp. */\n saveFragment(): OwnedStateFragment {\n return { version: SAVE_FRAGMENT_VERSION, scopes: this.save() };\n }\n\n /** Restore from a versioned fragment; an unsupported version throws. */\n loadFragment(fragment: OwnedStateFragment): void {\n if (fragment.version !== SAVE_FRAGMENT_VERSION) {\n throw new Error(`unsupported owned-state fragment version ${fragment.version} (supported: ${SAVE_FRAGMENT_VERSION})`);\n }\n this.load(fragment.scopes);\n }\n\n private assertFree(token: string): void {\n if (this.scopes.has(token)) throw new Error(`scope '@${token}' is already registered`);\n }\n}\n\nfunction defaultFor(d: ScopeDeclaration): ScalarValue {\n if (d.default !== undefined) return d.default;\n switch (d.type) {\n case \"boolean\": return false;\n case \"number\": return 0;\n case \"string\": return \"\";\n case \"enum\": return d.values?.[0] ?? \"\";\n case \"flags\": return [];\n // A quality starts at the first rung of its ladder.\n case \"quality\": return d.stages?.[0] ?? \"\";\n }\n}\n","// ---------------------------------------------------------------------------\n// The reference runtime: an Engine is the world + flow manager, and ALL play\n// happens on a Flow handle (design/flows.md; the shape is Patter's, adopted\n// deliberately so a host driving both engines holds two objects with the\n// same grammar). The dealing semantics of design/storylets-schema.md\n// section 3 run per flow, implemented exactly and held to the conformance\n// corpus.\n//\n// The flow model, in one place:\n// - an Engine owns the bundle, every lookup built from it, the SHARED\n// property partitions and the @world resolver; a Flow owns its own\n// PRNG, per-box clocks, cooldowns, board, claims, play history and the\n// per-flow property partitions. Flows meet only through shared state.\n// - sharing is a per-property `shared` flag on the declaration (never a\n// scope token): @story defaults shared; box, deck, hand and tag\n// properties default per-flow. Every name is shared XOR per-flow, so a\n// read is a union of two bags and a write routes by name.\n// - @world is the game's own state: always engine-level, resolved through\n// the host's resolver (EngineOptions.world) or a self-backed bag, and\n// NEVER in saveGame() - the host saves its container, each engine saves\n// its own envelope (engine-runtimes.md 3.1).\n// - there is no default flow and no ambient current flow: openFlow(id) is\n// the only way in, an existing id is REPLACED (the old flow closes),\n// and a closed flow's handle is INERT - every verb throws (Patter's\n// stale-handle rule).\n// - engine.getProperty serves world.* and shared refs only; a ref that\n// resolves per-flow throws, naming the fix (Patter's teaching rule).\n//\n// Key dealing contracts, unchanged from round 2 (all per flow now):\n// - two verbs: deal(hand) claims, peek(box, criteria) just looks; you can\n// never play a card you only peeked (3.1, look/use rule)\n// - availability order: deck gate -> cooldown -> tags -> hand condition ->\n// card condition -> claims (3.1)\n// - claims are physical WITHIN a flow: a card sits in at most `copies`\n// hands of that flow's board at once, at most once in any one hand; the\n// ledger is derived from the board contents (3.5)\n// - a SHARED card (its deck's flag, or its own overriding it) is scarce\n// across flows too: at most `sharedCopies` hands anywhere, counted over\n// every live flow's board, and a shared `redraw: \"never\"` is spent for\n// everyone the first time anyone plays it. A finite redraw deliberately\n// stays per flow - a cooldown is an absolute turn of a per-flow clock, so\n// there is nothing shared to compare it against (design/shared-scarcity.md)\n// - the reserved home group inverts the wildcard: a homed card is\n// available only to an ask binding its home (2.4)\n// - ranking: priority desc -> specificity desc (box toggle) -> seeded\n// shuffle of each maximal tie run (3.2)\n// - one PRNG per flow: expression random(), tie shuffles and the batch\n// deal's hand-order shuffle all advance it; state lives in the save (3.3)\n// - each box has its own turn counter PER FLOW; cooldowns are absolute\n// next-eligible turns of the card's box's clock, set at play time from\n// the post-advance turn; \"never\" is MAX_SAFE_INTEGER, not Infinity (3.4)\n// - @hand composes bound-tag props -> hand props -> chosen tags/criteria\n// (by group name), later shadowing earlier; writes route back to their\n// source; criteria names cannot be written (3.6)\n// - outcome availability is never snapshotted: outcomes() and play()\n// evaluate gates against current state (3.1, 3.7)\n// - a trace event fires after the state it reports has landed, so a\n// handler reading the flow inside it sees the effect (the Live Link's\n// board snapshot depends on this; the shared fixture pins it)\n// ---------------------------------------------------------------------------\n\nimport { deserialiseAst, evaluate } from \"@wildwinter/expr\";\nimport type { EvalContext, ExprNode, ScalarValue, ScopeResolver } from \"@wildwinter/expr\";\nimport { matchedSpecificity } from \"@wildwinter/expr-specificity\";\nimport { storyletsDialect, NEVER_PLAYED } from \"@storylet-studio/dialect\";\n\n/** The play-history indexes' key for one (group, tag) pair.\n *\n * A UNIT SEPARATOR (U+001F) joins them: ids are letters, digits and\n * underscores, so a control character cannot occur in one and two different\n * pairs can never collide into one key the way a \".\" or \":\" join could. NUL\n * would say the same thing and was the first choice, but GDScript will not\n * carry one in a string - it substitutes U+FFFD and warns on every parse - and\n * the four runtimes keep the same spelling. */\nconst tagKey = (groupId: string, tagId: string): string => `${groupId}\\u001f${tagId}`;\n\nimport type { StoryletsHost } from \"@storylet-studio/dialect\";\nimport { PLACE_GROUP, effectiveGameId } from \"@storylet-studio/model\";\nimport type {\n Box, Bundle, Card, Deck, Expression, FlowSave, Hand, HandTemplate,\n PlayRecord, PropertyBag, PropertyDecl, PropsPartition, SaveEnvelope, Tag, TagGroup,\n} from \"@storylet-studio/model\";\nimport { PropertyBag as StateBag } from \"@wildwinter/scoperegistry\";\nimport type { PropertyRow } from \"@wildwinter/scoperegistry\";\nimport { makePrng, shuffleInPlace } from \"./prng.js\";\nimport type { Prng } from \"./prng.js\";\n\nexport interface EngineOptions {\n /** Default seed for each flow's PRNG; override per flow in openFlow\n * (cross-runtime determinism, schema 3.3). Default 0. */\n seed?: number;\n /** Retain each flow's event log for introspection - the game-engine seam\n * (schema 5): every trace event, sequence-stamped and turn-stamped where\n * the event has a box context. `true` keeps the default 1000 entries\n * (oldest dropped first). Off by default; subscribeTrace stays the\n * zero-retention stream. */\n log?: boolean | { cap?: number };\n /**\n * The host's resolver for @world - the values the game owns and the\n * story reads (and, where `set` is offered, writes). Omit it and the\n * engine self-backs @world from the declared defaults. Engine-level,\n * shared by all flows, never in saveGame(): the host saves its container\n * once, each engine saves its own envelope (design/flows.md).\n */\n world?: ScopeResolver;\n}\n\nexport interface OpenFlowOptions {\n /** Seed for this flow's PRNG (defaults to the engine's `seed`). */\n seed?: number;\n}\n\n/** A card view in a dealt hand or a peeked list. Carries NO outcome\n * availability - ask `outcomes()` for current truth (schema 5). */\nexport interface DealtCard {\n id: string;\n gameId: string;\n title?: string;\n purpose?: string;\n fields?: Record<string, ScalarValue>;\n}\n\nexport interface OutcomeView {\n id: string;\n gameId: string;\n title?: string;\n purpose?: string;\n /** Evaluated against CURRENT state at the moment of the ask. */\n available: boolean;\n}\n\n/** What a peek returns: the top of the stock, looked at and put back.\n * The engine has no pick policy (Reboot 2.1). */\nexport interface RankedList {\n box: string;\n cards: DealtCard[];\n}\n\nexport interface PlayOptions {\n /** Turn advance override; default settings.playAdvancesTurns. */\n advanceTurns?: number;\n}\n\n// --- the trace (schema 5): the deal/play log for tooling ----------------------\n\n/** Why a card did or did not make an ask, in availability order (schema 3.1). */\nexport type TraceVerdict =\n | \"dealt\" // in the hand / the returned list\n | \"capped\" // eligible, ranked below the size cap\n | \"cooldown\" // schema 3.1 step 1\n | \"deck-gate\" // step 2\n | \"tags\" // step 3 (incl. the home group's inverted default)\n | \"condition\" // steps 4-5 (a failing or erroring condition)\n | \"priority\" // a priority expression errored or was not a number\n | \"claimed\" // step 6: no free copy on YOUR board\n | \"claimed-elsewhere\" // step 6: another flow holds the world's copies\n | \"taken\"; // a shared redraw:never was spent, by anyone, for everyone\n\n/** One event on the deal/play log - \"why did Ambush at the ford get dealt\n * here?\" is answered by the ask event's per-card verdicts and keys. The\n * verb is the event type, so a peek is distinguishable from a deal when\n * reading a run back. */\nexport type TraceEvent =\n | {\n type: \"deal\";\n /** Hand gameId. */\n hand: string;\n cards: { id: string; verdict: TraceVerdict; priority?: number; specificity?: number }[];\n }\n | {\n type: \"peek\";\n /** Box gameId. */\n box: string;\n criteria: Record<string, string>;\n cards: { id: string; verdict: TraceVerdict; priority?: number; specificity?: number }[];\n }\n | { type: \"evict\"; hand: string; card: string; reason: TraceVerdict | \"hand-condition\" | \"vanished\" }\n | { type: \"play\"; card: string; outcome: string; turn: number }\n /** One landed outcome change; `path` is the resolved store location (a\n * routed @hand write shows where it actually went, schema 3.6). `prev`\n * is the value it replaced, so a log can read \"0 -> 1\". */\n | { type: \"write\"; target: string; path: string; value: ScalarValue; prev?: ScalarValue }\n /** An explicit clock advance via advanceTurns (schema 3.4); `turn` is the\n * box's new value. Plays stamp their own turn on the play event. */\n | { type: \"turns\"; box: string; turn: number }\n /** An expression eval error: never a silent pass (schema 3.1), always a\n * visible diagnostic. */\n | { type: \"diagnostic\"; where: string; message: string };\n\nexport type TraceHandler = (event: TraceEvent) => void;\n/** The engine-level tap: every flow's events, tagged with the flow id -\n * the tools' one stream. */\nexport type EngineTraceHandler = (flow: string, event: TraceEvent) => void;\n\n/** A retained log entry: the trace event plus its place in flow time.\n * `seq` orders the whole flow (monotonic; survives clearLog). `turn` is\n * the clock of the box the event happened in when it fired (peek: the box;\n * deal/evict: the hand's box; play and its writes: the played card's box,\n * stamped together with the play's own turn). Diagnostics carry no turn. */\nexport type LogEntry = TraceEvent & { seq: number; turn?: number };\n\n/** One entry on the ENGINE's log: the same event, plus the flow it happened\n * in. A run is several flows over shared state, so \"what happened in this\n * run\" is only answerable in one ordered stream, and only if each line says\n * who. The flow's own log stays flow-local and unchanged. */\nexport type EngineLogEntry = LogEntry & { flow: string };\n\n// --- internals ---------------------------------------------------------------\n\ninterface CardEntry {\n card: Card<Expression>;\n deck: Deck<Expression>;\n box: Box<Expression>;\n}\n\n/** Is this card scarce across flows (design/shared-scarcity.md)? The deck says\n * what the pile is for and the card may override it, the same inheritance a\n * property has with its scope default. Hoist the deck's flag out of a card\n * loop and pass the answer down: the ask runs this per card per deal. */\nconst cardIsShared = (card: Card<Expression>, deckShared: boolean): boolean =>\n card.shared ?? deckShared;\n\n/** How many hands ACROSS EVERY FLOW may hold this at once. Defaults to\n * `copies`, so the common case writes one number and only \"five in the world,\n * one to a customer\" needs both. Meaningless on an unshared card, and the\n * compiler warns when one sets it. */\nconst sharedCap = (card: Card<Expression>): number => card.sharedCopies ?? card.copies ?? 1;\n\ntype HandSource = { kind: \"value\"; id: string } | { kind: \"hand\"; id: string } | { kind: \"criteria\" };\n\n/** The composed @hand for one ask: the read bag, plus where each name\n * routes on write (schema 3.6). */\ninterface HandEnv {\n bag: PropertyBag;\n sources: Map<string, HandSource>;\n /** tag group id -> bound tag id (home included, its \"tag\" a hand id). */\n boundTags: Map<string, string>;\n}\n\n/** One ask, resolved: a deal (hand present, condition from its template or\n * rule) or a peek (criteria only, no condition - schema 3.1). */\ninterface AskDescriptor {\n box: Box<Expression>;\n hand?: Hand<Expression>;\n condition?: Expression;\n /** tag group id -> tag id, everything the ask binds (fixed + chosen +\n * criteria; for deals also home -> the hand's own id). */\n boundTags: Map<string, string>;\n /** Chosen tags / criteria surfaced into @hand by group gameId, the tag's\n * gameId as the value (schema 3.6). */\n askNames: Record<string, string>;\n}\n\n// Stores are shared-kernel bags (@wildwinter/scoperegistry, the properties\n// implementer Patter shares): identity normalisation because storylets\n// property names are case-significant as authored.\nconst bagFromDecls = (decls: PropertyDecl[]): StateBag =>\n new StateBag(decls, { normalise: (n) => n });\n\n// Truthiness for a bare condition. Booleans and numbers as you would expect;\n// a string passes when non-empty and a flag list when non-empty, matching\n// JavaScript's own coercion for those two.\n//\n// Until 2026-09-01 this admitted ONLY booleans and numbers, and Patterplay's\n// `truthy` admitted strings and lists as well. That was drift from writing the\n// two engines at different times, not a considered difference: the two share a\n// property registry, so the same value read from the same registry answered a\n// condition differently depending on which engine asked. expr-specificity calls\n// truthiness host-bound, and it is, but \"host-bound\" is licence for a host to\n// choose, not licence for two hosts in one family to disagree by accident.\nfunction conditionPasses(v: ScalarValue): boolean {\n if (typeof v === \"boolean\") return v;\n if (typeof v === \"number\") return v !== 0;\n if (typeof v === \"string\") return v !== \"\";\n return v.length > 0; // string[] (flags)\n}\n\n/** One examiner row, addressed by the property-path grammar\n * (getProperty / setProperty take the same `path`). */\nexport interface PropertyView extends PropertyRow {\n path: string;\n}\n\n/** One kernel bag with its store path prefix (story / box.<id> / deck.<id>\n * / hand.<id> / value.<id>): the state logger's mount surface\n * (design/engine-runtimes.md 3.4 - the logger builds on the PropertyBag\n * audit hook, so it needs the bags themselves, not just their rows).\n * The Engine lists the shared bags, a Flow its own; the @world container\n * is the host's bag and the host mounts it itself. loadGame() replaces\n * every bag, so re-enumerate after a load. */\nexport interface BagMount {\n prefix: string;\n bag: StateBag;\n}\n\n/** One box on the enumeration surface (examiners, hosts): identity plus\n * its clock (per flow). */\nexport interface BoxView {\n id: string;\n gameId: string;\n title?: string;\n turn: number;\n}\n\n/** The sharing default per scope (design/flows.md, the old system's rule):\n * @story is the playthrough family's globals, shared; the narrower scopes\n * are geographic, per-flow, so \"this flow's danger in the docks\" stays\n * expressible. A declaration's `shared` flag overrides. */\nconst SCOPE_DEFAULT_SHARED = { story: true, box: false, deck: false, hand: false, value: false } as const;\ntype FlaggedScope = keyof typeof SCOPE_DEFAULT_SHARED;\n\nconst isShared = (scope: FlaggedScope, d: PropertyDecl): boolean => d.shared ?? SCOPE_DEFAULT_SHARED[scope];\nconst sharedHalf = (scope: FlaggedScope, decls: PropertyDecl[]): PropertyDecl[] =>\n decls.filter((d) => isShared(scope, d));\nconst flowHalf = (scope: FlaggedScope, decls: PropertyDecl[]): PropertyDecl[] =>\n decls.filter((d) => !isShared(scope, d));\n\n/** One side's five stores (shared on the engine, per-flow on each flow). */\ninterface Partition {\n story: StateBag;\n box: Map<string, StateBag>;\n deck: Map<string, StateBag>;\n hand: Map<string, StateBag>;\n value: Map<string, StateBag>;\n}\n\ntype PartitionKind = keyof Partition;\n\n/** Everything a Flow shares with its Engine: the bundle-derived lookups\n * (immutable), the shared stores (replaced wholesale by loadGame/reset),\n * and the seams. One object, held by both classes - the two are one\n * machine in two lifetimes. */\ninterface Internals {\n bundle: Bundle;\n logCap?: number;\n cardsById: Map<string, CardEntry>;\n cardsByGameId: Map<string, CardEntry>;\n boxesByGameId: Map<string, Box<Expression>>;\n boxesById: Map<string, Box<Expression>>;\n handsById: Map<string, { hand: Hand<Expression>; box: Box<Expression> }>;\n handsByGameId: Map<string, { hand: Hand<Expression>; box: Box<Expression> }>;\n templatesById: Map<string, HandTemplate<Expression>>;\n groupsById: Map<string, { group: TagGroup; box: Box<Expression> }>;\n requiredGroups: Set<string>;\n nodeCache: WeakMap<Expression, ExprNode>;\n ladders: {\n world: Map<string, readonly string[]>;\n story: Map<string, readonly string[]>;\n box: Map<string, Map<string, readonly string[]>>;\n deck: Map<string, Map<string, readonly string[]>>;\n value: Map<string, Map<string, readonly string[]>>;\n hand: Map<string, Map<string, readonly string[]>>;\n };\n hasQualities: boolean;\n /** Does ANY deck or card in the bundle opt into shared scarcity? False for\n * the overwhelming majority of projects, and when it is false the two\n * claim-ledger walks in dealing are skipped entirely. Same idea as\n * `hasQualities` above: a bundle that does not use a feature must not pay\n * for it. */\n hasShared: boolean;\n /** The per-flow halves of every declaration list, precomputed once: each\n * new flow builds its bags from these. */\n flowDecls: { story: PropertyDecl[]; box: Map<string, PropertyDecl[]>; deck: Map<string, PropertyDecl[]>; hand: Map<string, PropertyDecl[]>; value: Map<string, PropertyDecl[]> };\n /** The shared stores. Reassigned wholesale by loadGame/reset. */\n shared: Partition;\n /** @world: the host's resolver, or the self-backed bag's. */\n worldResolver: ScopeResolver;\n /** `turn` is the box clock the event happened on, where the caller knows it\n * - the same stamp the flow's own log carries. Unity and Unreal passed it\n * from the start; JS and Godot dropped it, so their examiners printed \"[-]\"\n * on every deal, peek, evict and write line while the other two printed the\n * real turn. Four runtimes, two different run logs (2026-08-29). */\n emitEngine: (flow: string, event: TraceEvent, turn?: number) => void;\n engineTracing: () => boolean;\n}\n\nconst handDeclsOf = (internals: Internals, hand: Hand<Expression>): PropertyDecl[] => {\n if (hand.template !== undefined) {\n return internals.templatesById.get(hand.template)?.properties\n ?? internals.bundle.boxes.flatMap((b) => b.handTemplates).find((t) => t.id === hand.template)?.properties\n ?? [];\n }\n return hand.properties ?? [];\n};\n\n/** Build one side of the partition from the bundle. */\nconst buildPartition = (internals: Internals, half: (scope: FlaggedScope, decls: PropertyDecl[]) => PropertyDecl[]): Partition => {\n const b = internals.bundle;\n return {\n story: bagFromDecls(half(\"story\", b.story.properties)),\n box: new Map(b.boxes.map((box) => [box.id, bagFromDecls(half(\"box\", box.properties))])),\n deck: new Map(b.boxes.flatMap((box) => box.decks.map(\n (deck): [string, StateBag] => [deck.id, bagFromDecls(half(\"deck\", deck.properties))]))),\n // A template instance inherits the template's property declarations;\n // a standalone hand declares its own (schema 2.6).\n hand: new Map(b.boxes.flatMap((box) => box.hands.map(\n (hand): [string, StateBag] => [hand.id, bagFromDecls(half(\"hand\", handDeclsOf(internals, hand)))]))),\n value: new Map(b.boxes.flatMap((box) => box.tagGroups.flatMap((group) => group.tags.map(\n (tag): [string, StateBag] => [tag.id, bagFromDecls(half(\"value\", tag.properties ?? []))])))),\n };\n};\n\nconst partitionValues = (p: Partition): PropsPartition => ({\n story: p.story.values,\n box: Object.fromEntries([...p.box].map(([id, bag]) => [id, bag.values])),\n deck: Object.fromEntries([...p.deck].map(([id, bag]) => [id, bag.values])),\n hand: Object.fromEntries([...p.hand].map(([id, bag]) => [id, bag.values])),\n value: Object.fromEntries([...p.value].map(([id, bag]) => [id, bag.values])),\n});\n\nconst loadPartition = (p: Partition, values: PropsPartition | undefined): void => {\n // Fresh defaults are already in the bags; the saved values land over\n // them: orphaned keys (deleted entities, re-flagged properties) drop;\n // newly declared properties keep defaults.\n p.story.load(values?.story ?? {});\n for (const kind of [\"box\", \"deck\", \"hand\", \"value\"] as const) {\n for (const [id, bag] of Object.entries(values?.[kind] ?? {})) {\n p[kind].get(id)?.load(bag);\n }\n }\n};\n\n// --- the Engine ---------------------------------------------------------------\n\nexport class Engine {\n private readonly internals: Internals;\n private readonly seed: number;\n private readonly flowsById = new Map<string, Flow>();\n private readonly engineTraceHandlers = new Set<EngineTraceHandler>();\n /** The host's @world binding, if the engine was built with one: it\n * outlives reset/loadGame (the host's container is the host's). The\n * self-backed resolver is rebuilt instead. */\n private readonly hostWorld?: ScopeResolver;\n\n constructor(bundle: Bundle, opts: EngineOptions = {}) {\n this.seed = opts.seed ?? 0;\n if (opts.world !== undefined) this.hostWorld = opts.world;\n const internals: Internals = {\n bundle,\n ...(opts.log ? { logCap: typeof opts.log === \"object\" ? (opts.log.cap ?? 1000) : 1000 } : {}),\n cardsById: new Map(), cardsByGameId: new Map(),\n boxesByGameId: new Map(), boxesById: new Map(),\n handsById: new Map(), handsByGameId: new Map(),\n templatesById: new Map(), groupsById: new Map(),\n requiredGroups: new Set(),\n nodeCache: new WeakMap(),\n ladders: { world: new Map(), story: new Map(), box: new Map(), deck: new Map(), value: new Map(), hand: new Map() },\n hasQualities: false,\n hasShared: false,\n flowDecls: { story: [], box: new Map(), deck: new Map(), hand: new Map(), value: new Map() },\n shared: undefined as unknown as Partition,\n worldResolver: undefined as unknown as ScopeResolver,\n emitEngine: (flow, event, turn) => {\n if (this.internals.logCap !== undefined) {\n this.engineLog.push({ ...event, flow, seq: this.engineSeq++, ...(turn !== undefined ? { turn } : {}) });\n if (this.engineLog.length > this.internals.logCap) {\n this.engineLog.splice(0, this.engineLog.length - this.internals.logCap);\n }\n }\n for (const h of this.engineTraceHandlers) h(flow, event);\n },\n engineTracing: () => this.engineTraceHandlers.size > 0,\n };\n this.internals = internals;\n\n for (const box of bundle.boxes) {\n internals.boxesById.set(box.id, box);\n internals.boxesByGameId.set(effectiveGameId(box), box);\n for (const group of box.tagGroups) {\n internals.groupsById.set(group.id, { group, box });\n if (group.required === true) internals.requiredGroups.add(group.id);\n }\n for (const deck of box.decks) {\n if (deck.shared === true) internals.hasShared = true;\n for (const card of deck.cards) {\n const entry = { card, deck, box };\n internals.cardsById.set(card.id, entry);\n internals.cardsByGameId.set(effectiveGameId(card), entry);\n if (card.shared === true) internals.hasShared = true;\n }\n }\n for (const template of box.handTemplates) {\n internals.templatesById.set(template.id, template);\n }\n for (const hand of box.hands) {\n internals.handsById.set(hand.id, { hand, box });\n internals.handsByGameId.set(effectiveGameId(hand), { hand, box });\n }\n }\n this.initLadders();\n\n // The per-flow halves, precomputed once (a bundle's declarations never\n // change): each openFlow builds its bags from these.\n internals.flowDecls = {\n story: flowHalf(\"story\", bundle.story.properties),\n box: new Map(bundle.boxes.map((box) => [box.id, flowHalf(\"box\", box.properties)])),\n deck: new Map(bundle.boxes.flatMap((box) => box.decks.map(\n (deck): [string, PropertyDecl[]] => [deck.id, flowHalf(\"deck\", deck.properties)]))),\n hand: new Map(bundle.boxes.flatMap((box) => box.hands.map(\n (hand): [string, PropertyDecl[]] => [hand.id, flowHalf(\"hand\", handDeclsOf(internals, hand))]))),\n value: new Map(bundle.boxes.flatMap((box) => box.tagGroups.flatMap((group) => group.tags.map(\n (tag): [string, PropertyDecl[]] => [tag.id, flowHalf(\"value\", tag.properties ?? [])])))),\n };\n\n this.initShared(this.hostWorld);\n }\n\n /** Build the shared stores and the @world seam. `hostWorld` sticks for the\n * engine's lifetime; reset/loadGame rebuild the shared bags around it. */\n private initShared(hostWorld?: ScopeResolver): void {\n const internals = this.internals;\n internals.shared = buildPartition(internals, sharedHalf);\n if (hostWorld !== undefined) {\n internals.worldResolver = hostWorld;\n } else {\n // Standalone: self-backed from the declared defaults. Still FOREIGN\n // in spirit - never in saveGame(); a host that wants @world to\n // persist saves the container itself (play-helpers ships one).\n const bag = bagFromDecls(internals.bundle.world.properties);\n internals.worldResolver = {\n get: (n) => bag.get(n),\n set: (n, v) => { bag.set(n, v); },\n };\n }\n }\n\n /** Quality ladders by scope for the eval channel (design/quality.md):\n * world/story keyed by name; box/deck/value keyed by owner id then name.\n * Built once - a bundle's declarations never change. Ladders are\n * declaration-level, so the sharing flag does not touch them. */\n private initLadders(): void {\n const internals = this.internals;\n const grab = (decls: PropertyDecl[] | undefined): Map<string, readonly string[]> => {\n const m = new Map<string, readonly string[]>();\n for (const d of decls ?? []) if (d.type === \"quality\" && d.stages !== undefined) m.set(d.name, d.stages);\n return m;\n };\n const b = internals.bundle;\n internals.ladders.world = grab(b.world.properties);\n internals.ladders.story = grab(b.story.properties);\n for (const box of b.boxes) {\n internals.ladders.box.set(box.id, grab(box.properties));\n for (const deck of box.decks) internals.ladders.deck.set(deck.id, grab(deck.properties));\n for (const group of box.tagGroups) {\n for (const tag of group.tags) internals.ladders.value.set(tag.id, grab(tag.properties));\n }\n for (const hand of box.hands) internals.ladders.hand.set(hand.id, grab(handDeclsOf(internals, hand)));\n }\n const any = (m: Map<string, Map<string, readonly string[]>>): boolean =>\n [...m.values()].some((x) => x.size > 0);\n internals.hasQualities = internals.ladders.world.size > 0 || internals.ladders.story.size > 0\n || any(internals.ladders.box) || any(internals.ladders.deck)\n || any(internals.ladders.value) || any(internals.ladders.hand);\n }\n\n // --- flow management (Patter's surface, name for name) ----------------------\n\n /** Open (or REPLACE) the named flow. An existing id's flow is closed\n * first - re-opening a name is a reset of that name's whole per-flow\n * state; shared state is untouched. There is no default flow: \"main\" is\n * a caller convention, not an engine rule. */\n openFlow(id: string, opts: OpenFlowOptions = {}): Flow {\n // Replacing an existing id KEEPS its place in the order. `close()` would\n // drop the key, and a JS Map re-inserts a deleted key at the END, so\n // openFlow(\"a\"); openFlow(\"b\"); openFlow(\"a\") listed [b, a] here and\n // [a, b] on all three ports - a different `flows()` order and, since\n // `saveGame` keys its flows in that order, a different `.storyletsave`\n // byte stream for the same run (2026-08-29). markClosed without dropFlow\n // is the difference: the old handle goes inert, the slot stays put.\n this.flowsById.get(id)?.markClosed();\n const flow = new Flow(this, this.internals, id, opts.seed ?? this.seed);\n this.flowsById.set(id, flow);\n return flow;\n }\n\n getFlow(id: string): Flow | undefined {\n return this.flowsById.get(id);\n }\n\n /** Every live flow, open order. */\n flows(): Flow[] {\n return [...this.flowsById.values()];\n }\n\n /** Close the named flow: its handle goes INERT (every verb throws). A\n * dropped-but-held flow must not keep writing shared state (Patter's\n * stale-handle lesson). Unknown ids are a quiet no-op, like closing a\n * closed door. */\n closeFlow(id: string): void {\n const flow = this.flowsById.get(id);\n if (!flow) return;\n this.flowsById.delete(id);\n flow.markClosed();\n }\n\n /** @internal - Flow.close() routes here so both doors agree. */\n dropFlow(id: string, flow: Flow): void {\n if (this.flowsById.get(id) === flow) this.flowsById.delete(id);\n }\n\n /** Close every flow and reseed the shared state to its defaults (the\n * self-backed @world included; a host-bound @world is the host's and is\n * not touched). */\n reset(): void {\n // The log is a run-lifetime utility and is not saved; a reset is a new run.\n // All three ports cleared it here and the reference did not, so `reset()`\n // (and `loadGame`, which calls it) left the previous run's entries in place\n // with `seq` continuing across the boundary - while the same call on Godot,\n // Unity or Unreal returned an empty log (2026-08-29).\n this.engineLog = [];\n for (const flow of this.flowsById.values()) flow.markClosed();\n this.flowsById.clear();\n this.spent.clear();\n this.initShared(this.hostWorld);\n }\n\n // --- shared scarcity (design/shared-scarcity.md) -----------------------------\n\n /** Cards a shared `redraw: \"never\"` has taken out of the world, by card id.\n * The claim ledger is DERIVED from live boards and so needs no storage;\n * this one is durable, so it rides the save's shared half. */\n private spent = new Set<string>();\n\n /** @internal */\n isTaken(cardId: string): boolean {\n return this.spent.has(cardId);\n }\n\n /** @internal */\n markTaken(cardId: string): void {\n this.spent.add(cardId);\n }\n\n // --- the run's log (design/shared-scarcity.md 8.2) ---------------------------\n\n /** Every flow's events in one ordered stream, each tagged with its flow.\n * Opt in with the same `log` option the flow logs use; capped the same way.\n *\n * This exists because a flow's own log cannot answer the question a run\n * raises: when a story action in ANOTHER flow moves shared state, your\n * flow's log says nothing and your value simply changes. Reading a run\n * needs one stream that says who did what, and merging the per-flow logs by\n * hand is a thing every host would otherwise have to write. */\n private engineLog: EngineLogEntry[] = [];\n private engineSeq = 0;\n\n log(): readonly EngineLogEntry[] {\n return this.engineLog;\n }\n\n clearLog(): void {\n this.engineLog = [];\n }\n\n /** @internal - shared claims across every LIVE flow, card id -> holders.\n * Derived, which is what makes closeFlow and the openFlow replace release\n * what a flow was holding: its board leaves the map with it. */\n sharedClaims(): Map<string, number> {\n const counts = new Map<string, number>();\n for (const flow of this.flowsById.values()) {\n for (const id of flow.heldCardIds()) counts.set(id, (counts.get(id) ?? 0) + 1);\n }\n return counts;\n }\n\n // --- engine-level state access ----------------------------------------------\n\n /**\n * Read shared state by path: \"world.x\", \"story.gold\" (when shared),\n * \"box.b_x.heat\" (when shared). A ref that resolves PER-FLOW throws,\n * naming the fix - silently answering with some flow's copy (or a junk\n * default) was the bug Patter's engine.getProperty guard exists to stop.\n */\n getProperty(path: string): ScalarValue {\n const found = this.resolveShared(path);\n const value = found.kind === \"world\" ? this.internals.worldResolver.get(found.name) : found.bag.get(found.name);\n if (value === undefined) throw new Error(`no property at \"${path}\"`);\n return value;\n }\n\n setProperty(path: string, value: ScalarValue): void {\n const found = this.resolveShared(path);\n if (found.kind === \"world\") {\n if (!this.internals.worldResolver.set) {\n throw new Error(`@world is read-only here: the host bound no write`);\n }\n this.internals.worldResolver.set(found.name, value);\n return;\n }\n // A host write: silent under the firing rule (no subscriber feedback\n // loop), but visible to the bag's audit hook.\n found.bag.set(found.name, value, { silent: true, reason: \"host setProperty\" });\n }\n\n private resolveShared(path: string): { kind: \"world\"; name: string } | { kind: \"bag\"; bag: StateBag; name: string } {\n const parts = path.split(\".\");\n const perFlow = (): never => {\n throw new Error(`\"${path}\" is per-flow state - read it on a Flow, not the Engine`);\n };\n if (parts.length === 2 && parts[0] === \"world\") return { kind: \"world\", name: parts[1]! };\n if (parts.length === 2 && parts[0] === \"story\") {\n const name = parts[1]!;\n if (this.internals.shared.story.get(name) !== undefined) return { kind: \"bag\", bag: this.internals.shared.story, name };\n if (this.internals.flowDecls.story.some((d) => d.name === name)) perFlow();\n throw new Error(`no property at \"${path}\"`);\n }\n if (parts.length === 3 && (parts[0] === \"box\" || parts[0] === \"deck\" || parts[0] === \"hand\" || parts[0] === \"value\")) {\n const kind = parts[0] as Exclude<PartitionKind, \"story\">;\n const [, id, name] = parts as unknown as [string, string, string];\n const bag = this.internals.shared[kind].get(id);\n if (bag !== undefined && bag.get(name) !== undefined) return { kind: \"bag\", bag, name };\n if (this.internals.flowDecls[kind].get(id)?.some((d) => d.name === name)) perFlow();\n if (bag === undefined && !this.internals.flowDecls[kind].has(id)) throw new Error(`no ${kind} store \"${id}\"`);\n throw new Error(`no property at \"${path}\"`);\n }\n throw new Error(`bad property path \"${path}\"`);\n }\n\n /** The shared surface as examiner rows: @world (read through the\n * resolver) then the shared partitions. Per-flow rows live on each Flow. */\n listProperties(): PropertyView[] {\n const out: PropertyView[] = [];\n for (const d of this.internals.bundle.world.properties) {\n const value = this.internals.worldResolver.get(d.name);\n out.push({\n path: `world.${d.name}`, name: d.name, type: d.type,\n value: value ?? d.default, default: d.default,\n ...(d.values !== undefined ? { values: d.values } : {}),\n ...(d.stages !== undefined ? { stages: d.stages } : {}),\n } as PropertyView);\n }\n const add = (prefix: string, bag: StateBag): void => {\n for (const row of bag.rows()) out.push({ path: `${prefix}.${row.name}`, ...row });\n };\n add(\"story\", this.internals.shared.story);\n for (const [id, bag] of this.internals.shared.box) add(`box.${id}`, bag);\n for (const [id, bag] of this.internals.shared.deck) add(`deck.${id}`, bag);\n for (const [id, bag] of this.internals.shared.hand) add(`hand.${id}`, bag);\n for (const [id, bag] of this.internals.shared.value) add(`value.${id}`, bag);\n return out;\n }\n\n /** The SHARED kernel bags with their store path prefixes (the state\n * logger's mount surface). The @world container is the host's own bag -\n * the host mounts it itself. */\n listBags(): BagMount[] {\n const mounts: BagMount[] = [{ prefix: \"story\", bag: this.internals.shared.story }];\n for (const kind of [\"box\", \"deck\", \"hand\", \"value\"] as const) {\n for (const [id, bag] of this.internals.shared[kind]) mounts.push({ prefix: `${kind}.${id}`, bag });\n }\n return mounts;\n }\n\n /** Every flow's trace, one stream, each event tagged with its flow id. */\n subscribeTrace(handler: EngineTraceHandler): () => void {\n this.engineTraceHandlers.add(handler);\n return () => this.engineTraceHandlers.delete(handler);\n }\n\n // --- persistence (schema 4) -------------------------------------------------\n\n /** The whole engine, one envelope: the shared partitions once, then\n * every live flow keyed by its id. @world is NEVER here - the host\n * saves its container, each engine saves its own envelope. */\n saveGame(): SaveEnvelope {\n return structuredClone({\n schema: \"storylets/save@1\" as const,\n content: this.internals.bundle.content,\n shared: { props: partitionValues(this.internals.shared), spent: [...this.spent].sort() },\n flows: Object.fromEntries([...this.flowsById].map(([id, flow]) => [id, flow.snapshot()])),\n });\n }\n\n /** Restore: shared state once, then every flow REBUILT from its blob.\n * Handles held from before the load are closed and inert (Patter's\n * rule); take fresh ones from getFlow()/flows(). */\n loadGame(envelope: SaveEnvelope): void {\n if (envelope.content.project !== this.internals.bundle.content.project) {\n throw new Error(`save is for project \"${envelope.content.project}\", bundle is \"${this.internals.bundle.content.project}\"`);\n }\n const env = structuredClone(envelope);\n this.reset();\n loadPartition(this.internals.shared, env.shared.props);\n for (const id of env.shared.spent ?? []) this.spent.add(id);\n for (const [id, saved] of Object.entries(env.flows ?? {})) {\n this.openFlow(id).restore(saved);\n }\n }\n}\n\n// --- the Flow -----------------------------------------------------------------\n\nexport class Flow {\n readonly id: string;\n private readonly engine: Engine;\n private readonly internals: Internals;\n private closed = false;\n\n private prng: Prng;\n /** Per-box turn counters, keyed by box id (schema 3.4) - per flow. */\n private turnCounts = new Map<string, number>();\n private cooldowns: Record<string, number> = {};\n /** The board: hand contents (card ids, dealt order), keyed by hand id. */\n private boardContents = new Map<string, string[]>();\n private playLog: PlayRecord[] = [];\n // --- play-history indexes -------------------------------------------------\n // The four play-history host functions used to SCAN playLog on every call,\n // and they are called once per candidate card per ask, so dealing was\n // O(candidates x playLog): a shipped game got measurably slower the longer\n // somebody played it, which is the failure mode nobody meets in testing.\n // Measured before the change, 2000 cards: a box with no history condition\n // held flat at 0.3ms while `count_played` went 0.8ms -> 27.9ms as the log\n // reached 4000 plays.\n //\n // These are a pure summary of `playLog`, maintained where it is appended and\n // rebuilt where it is replaced, so they cannot drift from it. They are NOT\n // saved: `playLog` is the record, this is a derivation, and rebuilding on\n // load keeps the save format untouched.\n //\n // The tag keys are the played card's OWN (groupId, tagId) pairs, which is\n // what makes the box-local rule survive: a group name resolves inside the\n // ASKING box, so a card in another box carries different ids and cannot\n // match, exactly as the per-record `inTag` check used to decide.\n private playCount = new Map<string, number>();\n private lastPlayOf = new Map<string, PlayRecord>();\n private tagPlayCount = new Map<string, number>();\n private lastPlayInTag = new Map<string, PlayRecord>();\n /** The per-flow property partitions (the not-shared halves). */\n private stores: Partition;\n\n private traceHandlers = new Set<TraceHandler>();\n private logEntries: LogEntry[] = [];\n private logSeq = 0;\n\n /** Merged read view per scope, built once (bags are stable for the\n * flow's life): the flow's own bag first, the shared bag behind it.\n * Names are disjoint (shared XOR per-flow by declaration), so \"first\"\n * is routing, not shadowing. */\n private readonly storyReader: ScopeResolver;\n private readonly boxReaders = new Map<string, ScopeResolver>();\n private readonly deckReaders = new Map<string, ScopeResolver>();\n\n /** @internal - built by Engine.openFlow / Engine.loadGame only. */\n constructor(engine: Engine, internals: Internals, id: string, seed: number) {\n this.engine = engine;\n this.internals = internals;\n this.id = id;\n this.prng = makePrng(seed);\n this.stores = buildPartition(internals, flowHalf);\n for (const box of internals.bundle.boxes) {\n this.turnCounts.set(box.id, 0);\n for (const hand of box.hands) this.boardContents.set(hand.id, []);\n }\n const pair = (own: StateBag | undefined, shared: StateBag | undefined): ScopeResolver => ({\n get: (n) => own?.get(n) ?? shared?.get(n),\n });\n // `internals.shared` is reassigned wholesale by loadGame/reset, but a\n // load rebuilds every Flow too, so a live flow's readers and the\n // shared partition are always the same generation.\n this.storyReader = pair(this.stores.story, internals.shared.story);\n for (const box of internals.bundle.boxes) {\n this.boxReaders.set(box.id, pair(this.stores.box.get(box.id), internals.shared.box.get(box.id)));\n for (const deck of box.decks) {\n this.deckReaders.set(deck.id, pair(this.stores.deck.get(deck.id), internals.shared.deck.get(deck.id)));\n }\n }\n }\n\n // --- lifetime ----------------------------------------------------------------\n\n get isClosed(): boolean {\n return this.closed;\n }\n\n /** Close this flow: the handle goes inert, every verb throws. */\n close(): void {\n if (this.closed) return;\n this.engine.dropFlow(this.id, this);\n this.markClosed();\n }\n\n /** @internal */\n markClosed(): void {\n this.closed = true;\n }\n\n private assertOpen(): void {\n if (this.closed) throw new Error(`flow \"${this.id}\" is closed`);\n }\n\n /** A box's current turn (schema 3.4), on THIS flow's clock. */\n turn(boxRef: string): number {\n this.assertOpen();\n const box = this.internals.boxesByGameId.get(boxRef) ?? this.internals.boxesById.get(boxRef);\n if (!box) throw new Error(`unknown box \"${boxRef}\"`);\n return this.turnCounts.get(box.id) ?? 0;\n }\n\n /** Subscribe to this flow's deal/play trace (schema 5). Returns the\n * unsubscribe. With no subscribers anywhere the flow does no trace work. */\n subscribeTrace(handler: TraceHandler): () => void {\n this.traceHandlers.add(handler);\n return () => this.traceHandlers.delete(handler);\n }\n\n private get tracing(): boolean {\n return this.traceHandlers.size > 0 || this.internals.logCap !== undefined || this.internals.engineTracing();\n }\n\n private emit(event: TraceEvent, turn?: number): void {\n if (this.internals.logCap !== undefined) {\n this.logEntries.push({ ...event, seq: this.logSeq++, ...(turn !== undefined ? { turn } : {}) });\n if (this.logEntries.length > this.internals.logCap) this.logEntries.splice(0, this.logEntries.length - this.internals.logCap);\n }\n for (const handler of this.traceHandlers) handler(event);\n this.internals.emitEngine(this.id, event, turn);\n }\n\n /** The retained flow log (opt-in via the Engine's `log`), oldest first,\n * capped. The introspection seam for hosts and tools; the durable play\n * history in a save stays `playLog` (schema 4) - the log is a\n * flow-lifetime utility and is NOT saved. */\n log(): readonly LogEntry[] {\n return this.logEntries;\n }\n\n /** Empty the retained log; `seq` keeps counting, so ordering across a\n * clear stays meaningful. */\n clearLog(): void {\n this.logEntries = [];\n }\n\n // --- expression plumbing ----------------------------------------------------\n\n private node(expr: Expression): ExprNode {\n let node = this.internals.nodeCache.get(expr);\n if (!node) {\n node = deserialiseAst(expr.ast);\n this.internals.nodeCache.set(expr, node);\n }\n return node;\n }\n\n /** Tag group names are box-scoped: two boxes may name a group the same way\n * (schema 1 - boxes namespace their groups), so a name is only ever\n * resolved inside the box being asked, never bundle-wide. Ids are\n * project-unique and accepted here too, still confined to the box. */\n private groupInBox(box: Box<Expression>, ref: string): TagGroup | undefined {\n return box.tagGroups.find((g) => effectiveGameId(g) === ref)\n ?? box.tagGroups.find((g) => g.id === ref);\n }\n\n /** Fold one play into the indexes. O(the card's tags), not O(the log). */\n private indexPlay(record: PlayRecord): void {\n this.playCount.set(record.card, (this.playCount.get(record.card) ?? 0) + 1);\n this.lastPlayOf.set(record.card, record);\n const entry = this.internals.cardsByGameId.get(record.card);\n if (!entry) return;\n for (const [groupId, tagIds] of Object.entries(entry.card.tags ?? {})) {\n for (const tagId of tagIds) {\n const key = tagKey(groupId, tagId);\n this.tagPlayCount.set(key, (this.tagPlayCount.get(key) ?? 0) + 1);\n this.lastPlayInTag.set(key, record);\n }\n }\n }\n\n /** Rebuild the indexes from the log. Called wherever `playLog` is REPLACED\n * rather than appended to, which is `restore` alone. */\n private rebuildPlayIndex(): void {\n this.playCount.clear();\n this.lastPlayOf.clear();\n this.tagPlayCount.clear();\n this.lastPlayInTag.clear();\n for (const record of this.playLog) this.indexPlay(record);\n }\n\n /** `box` is the box whose ask is being evaluated: the play-history\n * functions take a bare group name, so it resolves there (a card's tags\n * reference its own box's group, which keeps the counts box-local).\n * History is THIS flow's: countPlayed answers \"have I done this\". */\n /** One host per box, built once.\n *\n * The closures below read `this.playCount`, `this.turnCounts` and the rest\n * LIVE, so a cached host answers with current state - which is what makes\n * caching safe rather than a snapshot bug. Unreal did this from the start\n * (`hostsByBox_`, built at flow construction) and the other three rebuilt a\n * host, and its closures, on every `evalCtx` call: once per deck per ask,\n * and once per surviving card in the eviction pass. Structural divergence\n * in one port AND the allocation the audit flagged, so the other three\n * copied it (2026-08-29). Lazy rather than eager, so a bundle's unvisited\n * boxes cost nothing. */\n private hostsByBox = new Map<string, StoryletsHost>();\n\n private host(box: Box<Expression>): StoryletsHost {\n const cached = this.hostsByBox.get(box.id);\n if (cached !== undefined) return cached;\n const made = this.makeHost(box);\n this.hostsByBox.set(box.id, made);\n return made;\n }\n\n private makeHost(box: Box<Expression>): StoryletsHost {\n /** A group NAME and tag name resolved in THIS box, as the index's key.\n * Resolved once per call now, where `inTag` used to resolve it again for\n * every record in the log. Undefined when either name is unknown here,\n * which is the old per-record `false` and answers \"never\". */\n const keyOf = (group: string, tag: string): string | undefined => {\n const found = this.groupInBox(box, group);\n const t = found?.tags.find((v) => v.gameId === tag);\n return found && t ? tagKey(found.id, t.id) : undefined;\n };\n /** Turns-since is measured on the played card's box's clock (3.4). */\n const since = (record: PlayRecord): number => {\n const entry = this.internals.cardsByGameId.get(record.card);\n if (!entry) return NEVER_PLAYED;\n return (this.turnCounts.get(entry.box.id) ?? 0) - record.turn;\n };\n return {\n nextRandom: () => this.prng.next(),\n countPlayed: (card) => this.playCount.get(card) ?? 0,\n turnsSincePlayed: (card) => {\n const last = this.lastPlayOf.get(card);\n return last ? since(last) : NEVER_PLAYED;\n },\n countPlayedIn: (group, tag) => {\n const key = keyOf(group, tag);\n return key === undefined ? 0 : this.tagPlayCount.get(key) ?? 0;\n },\n turnsSincePlayedIn: (group, tag) => {\n const key = keyOf(group, tag);\n const last = key === undefined ? undefined : this.lastPlayInTag.get(key);\n return last ? since(last) : NEVER_PLAYED;\n },\n };\n }\n\n /** The evaluation environment (schema 3.1/6.2): @box/@deck resolve to the\n * card under evaluation; in hand-condition contexts @deck is an empty bag,\n * so any reference is an eval error (missing-policy throw). Every scope\n * is the flow's MERGED view - its own copies over the shared values,\n * names disjoint - and @world reads through the engine's resolver. */\n private evalCtx(box: Box<Expression>, deck: Deck<Expression> | undefined, handEnv: HandEnv): EvalContext {\n return {\n scopes: {\n world: this.internals.worldResolver,\n story: this.storyReader,\n box: this.boxReaders.get(box.id) ?? {},\n deck: deck ? this.deckReaders.get(deck.id) ?? {} : {},\n hand: handEnv.bag,\n },\n host: this.host(box) as unknown as Record<string, unknown>,\n // The quality channel, answering for THIS ask's box and deck. Only wired\n // when a quality exists, so a bundle without one evaluates byte-\n // identically to before the feature.\n ...(this.internals.hasQualities ? {\n qualities: (scope: string, name: string): readonly string[] | undefined =>\n scope === \"world\" ? this.internals.ladders.world.get(name)\n : scope === \"story\" ? this.internals.ladders.story.get(name)\n : scope === \"box\" ? this.internals.ladders.box.get(box.id)?.get(name)\n : scope === \"deck\" && deck ? this.internals.ladders.deck.get(deck.id)?.get(name)\n // @hand is composed, so the ladder belongs to whatever supplied the\n // value THIS ask: the bound tag, or the asking hand. `sources` is\n // already the map that answers that, because write-back needs it.\n : scope === \"hand\" ? this.handLadder(handEnv, name)\n : undefined,\n } : {}),\n };\n }\n\n /** The ladder behind one composed @hand name, or undefined when the name is\n * not a quality (or came from criteria, which are tag NAMES, never state). */\n private handLadder(handEnv: HandEnv, name: string): readonly string[] | undefined {\n const source = handEnv.sources.get(name);\n if (!source) return undefined;\n return source.kind === \"value\" ? this.internals.ladders.value.get(source.id)?.get(name)\n : source.kind === \"hand\" ? this.internals.ladders.hand.get(source.id)?.get(name)\n : undefined;\n }\n\n private eval(expr: Expression, ctx: EvalContext): ScalarValue {\n return evaluate(this.node(expr), ctx, storyletsDialect);\n }\n\n private passes(expr: Expression | undefined, ctx: EvalContext, where?: string): boolean {\n if (!expr) return true;\n try {\n return conditionPasses(this.eval(expr, ctx));\n } catch (e) {\n // An eval error is never a silent pass: the card/deck is unavailable\n // (schema 3.1), and the trace surfaces the diagnostic.\n if (this.tracing) {\n this.emit({ type: \"diagnostic\", where: where ?? \"condition\", message: e instanceof Error ? e.message : String(e) });\n }\n return false;\n }\n }\n\n // --- resolving asks (schema 2.6 + 3.6) -----------------------------------------\n\n private tagByGameId(group: TagGroup, gameId: string): Tag | undefined {\n return group.tags.find((t) => t.gameId === gameId);\n }\n\n /** A deal's ask: the hand's template bindings + chosen tags, or its rule's\n * bindings, plus the implicit home binding (schema 2.4). */\n private askForHand(hand: Hand<Expression>, box: Box<Expression>): AskDescriptor {\n const boundTags = new Map<string, string>();\n const askNames: Record<string, string> = {};\n let condition: Expression | undefined;\n if (hand.template !== undefined) {\n const template = this.internals.templatesById.get(hand.template);\n if (!template) throw new Error(`hand \"${effectiveGameId(hand)}\": unknown template \"${hand.template}\"`);\n for (const [groupId, tagId] of Object.entries(template.bindings ?? {})) {\n boundTags.set(groupId, tagId);\n }\n for (const [groupId, tagId] of Object.entries(hand.chosen ?? {})) {\n boundTags.set(groupId, tagId);\n const found = this.internals.groupsById.get(groupId);\n const tag = found?.group.tags.find((t) => t.id === tagId);\n if (found && tag) askNames[effectiveGameId(found.group)] = effectiveGameId(tag);\n }\n condition = template.condition;\n } else {\n for (const [groupId, tagId] of Object.entries(hand.rule?.bindings ?? {})) {\n boundTags.set(groupId, tagId);\n // ...and name it, exactly as the template branch above does: a card\n // reading @hand.<group> must not care HOW the group got bound\n // (design/hand-typing.md, the residues).\n const found = this.internals.groupsById.get(groupId);\n const tag = found?.group.tags.find((t) => t.id === tagId);\n if (found && tag) askNames[effectiveGameId(found.group)] = effectiveGameId(tag);\n }\n condition = hand.rule?.condition;\n }\n boundTags.set(PLACE_GROUP, hand.id);\n this.bindStateGroups(box, boundTags, askNames);\n return { box, hand, ...(condition !== undefined ? { condition } : {}), boundTags, askNames };\n }\n\n /** A peek's ask: raw criteria ({group gameId: tag gameId}), bindings only,\n * no condition slot (schema 3.1; the boundary, Reboot 4). */\n private askForPeek(box: Box<Expression>, criteria: Record<string, string>): AskDescriptor {\n const boundTags = new Map<string, string>();\n const askNames: Record<string, string> = {};\n for (const [groupRef, tagRef] of Object.entries(criteria)) {\n if (groupRef === PLACE_GROUP) {\n const hand = this.internals.handsByGameId.get(tagRef) ?? this.internals.handsById.get(tagRef);\n if (!hand) throw new Error(`peek: unknown hand \"${tagRef}\" in home criteria`);\n boundTags.set(PLACE_GROUP, hand.hand.id);\n continue;\n }\n const found = this.groupInBox(box, groupRef);\n if (!found) {\n throw new Error(`peek: unknown tag group \"${groupRef}\" in box \"${effectiveGameId(box)}\"`);\n }\n const tag = this.tagByGameId(found, tagRef) ?? found.tags.find((t) => t.id === tagRef);\n if (!tag) throw new Error(`peek: unknown tag \"${tagRef}\" in group \"${effectiveGameId(found)}\"`);\n boundTags.set(found.id, tag.id);\n askNames[effectiveGameId(found)] = effectiveGameId(tag);\n }\n this.bindStateGroups(box, boundTags, askNames);\n return { box, boundTags, askNames };\n }\n\n /**\n * Bind every `boundBy` group in the box from the property it names.\n *\n * The gap this closes: only a hand could bind a group, and `deal` takes no\n * criteria, so an axis driven by state (an act, a chapter) had nowhere to\n * gate. Runs AFTER the hand's own bindings and never overwrites one: an\n * explicit binding is a deliberate act and beats a default.\n *\n * A value naming no tag in the group leaves the group UNBOUND rather than\n * matching nothing. Unbound is a wildcard, so the ask still deals; a silent\n * empty hand would look like content that does not exist, and the diagnostic\n * is what says otherwise.\n */\n private bindStateGroups(box: Box<Expression>, boundTags: Map<string, string>, askNames: Record<string, string>): void {\n for (const group of box.tagGroups) {\n if (group.boundBy === undefined || boundTags.has(group.id)) continue;\n const ref = /^@(world|story)\\.([a-z][a-z0-9_-]*)$/.exec(group.boundBy);\n if (!ref) {\n this.emit({ type: \"diagnostic\", where: `tag group ${effectiveGameId(group)}`, message: `boundBy \"${group.boundBy}\" is not a @world or @story property reference` });\n continue;\n }\n let value: ScalarValue | undefined;\n try {\n value = this.getProperty(`${ref[1]}.${ref[2]}`);\n } catch {\n this.emit({ type: \"diagnostic\", where: `tag group ${effectiveGameId(group)}`, message: `boundBy \"${group.boundBy}\" names a property that is not declared` });\n continue;\n }\n const wanted = typeof value === \"string\" ? value : String(value);\n const tag = group.tags.find((t) => effectiveGameId(t) === wanted);\n if (!tag) {\n this.emit({ type: \"diagnostic\", where: `tag group ${effectiveGameId(group)}`, message: `${group.boundBy} is \"${wanted}\", which is not one of its tags` });\n continue;\n }\n boundTags.set(group.id, tag.id);\n askNames[effectiveGameId(group)] = effectiveGameId(tag);\n }\n }\n\n // --- @hand composition (schema 3.6) -------------------------------------------\n\n /** A store's full value view for one owner: the shared half under the\n * flow's half. Names are disjoint, so the spread is routing, not\n * shadowing. */\n private valuesOf(kind: Exclude<PartitionKind, \"story\">, id: string): PropertyBag {\n return {\n ...(this.internals.shared[kind].get(id)?.values ?? {}),\n ...(this.stores[kind].get(id)?.values ?? {}),\n };\n }\n\n private buildHandEnv(ask: AskDescriptor): HandEnv {\n const bag: PropertyBag = {};\n const sources = new Map<string, HandSource>();\n\n // 1. Tag properties of every bound tag (home binds a hand, not a tag).\n for (const [groupId, tagId] of ask.boundTags) {\n if (groupId === PLACE_GROUP) continue;\n for (const [name, value] of Object.entries(this.valuesOf(\"value\", tagId))) {\n bag[name] = value;\n sources.set(name, { kind: \"value\", id: tagId });\n }\n }\n // 2. Hand properties, when the ask is a deal.\n if (ask.hand) {\n for (const [name, value] of Object.entries(this.valuesOf(\"hand\", ask.hand.id))) {\n bag[name] = value;\n sources.set(name, { kind: \"hand\", id: ask.hand.id });\n }\n }\n // 3. Chosen tags / criteria, by group name (the tag's gameId as value).\n for (const [name, value] of Object.entries(ask.askNames)) {\n bag[name] = value;\n sources.set(name, { kind: \"criteria\" });\n }\n return { bag, sources, boundTags: ask.boundTags };\n }\n\n // --- the ask (schema 3.1 + 3.2) ------------------------------------------------\n\n /** The claims ledger, derived from THIS flow's board: card id -> holding\n * hands (schema 3.5). Claims are per flow - another flow holding the\n * card is another playthrough, not a rival hand. */\n private claims(): Map<string, number> {\n const counts = new Map<string, number>();\n for (const contents of this.boardContents.values()) {\n for (const id of contents) counts.set(id, (counts.get(id) ?? 0) + 1);\n }\n return counts;\n }\n\n /** @internal - every card id on THIS flow's board, one entry per holding\n * hand. The engine sums these across live flows for the shared ledger. */\n heldCardIds(): string[] {\n return [...this.boardContents.values()].flat();\n }\n\n private copiesOf(card: Card<Expression>): number {\n return card.copies ?? 1;\n }\n\n /** The claims step (schema 3.1 step 6) for one card, as a verdict or null\n * for \"available\". Two caps apply to a shared card and they are different\n * statements, so they get different verdicts: `copies` is your own board\n * filling up, `sharedCopies` is somebody else already holding it, and a\n * participant told \"claimed\" about a card sitting on another person's\n * table would read it as an engine fault (design/shared-scarcity 9.3.1).\n *\n * `mine` counts this flow's holdings, `world` every live flow's. */\n private claimVerdict(\n card: Card<Expression>,\n shared: boolean,\n mine: Map<string, number>,\n world: Map<string, number>,\n ): \"claimed\" | \"claimed-elsewhere\" | null {\n const id = card.id;\n if ((mine.get(id) ?? 0) >= this.copiesOf(card)) return \"claimed\";\n if (shared && (world.get(id) ?? 0) >= sharedCap(card)) return \"claimed-elsewhere\";\n return null;\n }\n\n /** Tag matching (schema 3.1 step 3): for every bound group the card lists\n * the bound tag or omits the group (wildcard); the home group inverts -\n * a homed card requires a matching home binding (schema 2.4). */\n private tagsMatch(card: Card<Expression>, boundTags: Map<string, string>): boolean {\n const home = card.tags?.[PLACE_GROUP];\n if (home !== undefined && home.length > 0) {\n const bound = boundTags.get(PLACE_GROUP);\n if (bound === undefined || !home.includes(bound)) return false;\n }\n for (const [groupId, tagId] of boundTags) {\n if (groupId === PLACE_GROUP) continue;\n const tags = card.tags?.[groupId];\n if (tags === undefined) {\n // Omission is a wildcard unless the group says otherwise. A required\n // group inverts it, which is what `place` has always done per card.\n if (this.internals.requiredGroups.has(groupId)) return false;\n continue;\n }\n if (!tags.includes(tagId)) return false;\n }\n return true;\n }\n\n /** Run one ask: availability filter then ranking. `claimed` decides the\n * claims step (step 6) per card, returning the verdict that refused it or\n * null for available. `trace` (when a subscriber exists) collects the\n * per-card verdicts. */\n private runAsk(\n ask: AskDescriptor,\n claimed: (card: Card<Expression>, shared: boolean) => \"claimed\" | \"claimed-elsewhere\" | null,\n trace?: { id: string; verdict: TraceVerdict; priority?: number; specificity?: number }[],\n ): { ordered: CardEntry[]; handEnv: HandEnv } {\n const { box } = ask;\n const handEnv = this.buildHandEnv(ask);\n const verdict = (id: string, v: TraceVerdict): void => {\n trace?.push({ id, verdict: v });\n };\n\n // The hand's condition: ask-constant, evaluated once (schema 3.1 step 4).\n if (!this.passes(ask.condition, this.evalCtx(box, undefined, handEnv), `hand ${ask.hand ? effectiveGameId(ask.hand) : \"\"} condition`)) {\n return { ordered: [], handEnv };\n }\n\n // Deck gates: evaluated once per ask, in deck (id) order (schema 2.5).\n const gateOk = new Map<string, boolean>();\n for (const deck of box.decks) {\n gateOk.set(deck.id, this.passes(deck.condition, this.evalCtx(box, deck, handEnv), `deck ${deck.gameId} gate`));\n }\n\n const turn = this.turnCounts.get(box.id) ?? 0;\n const scored: { entry: CardEntry; priority: number; spec: number }[] = [];\n for (const deck of box.decks) {\n // ONE context per deck, not per card. It is built from box, deck and\n // handEnv, none of which vary inside this loop, and a condition is a\n // read-only gate (schema 3.1), so nothing can write through it and make\n // sharing visible. Rebuilding it per card cost an EvalContext, a scopes\n // map and five bag wrappers each time: about half the garbage a peek over\n // a large box produced (port-review-2026-08.md, measured).\n const deckCtx = this.evalCtx(box, deck, handEnv);\n const deckShared = deck.shared ?? false;\n for (const card of deck.cards) {\n const shared = cardIsShared(card, deckShared);\n if (!gateOk.get(deck.id)) {\n verdict(card.id, \"deck-gate\");\n continue;\n }\n // Taken out of the world by somebody's shared one-shot. Checked\n // before the flow's own clock, because \"cooldown\" would point the\n // reader at a turn counter that has nothing to do with it.\n if (shared && this.engine.isTaken(card.id)) {\n verdict(card.id, \"taken\");\n continue;\n }\n if ((this.cooldowns[card.id] ?? 0) > turn) {\n verdict(card.id, \"cooldown\");\n continue;\n }\n if (!this.tagsMatch(card, handEnv.boundTags)) {\n verdict(card.id, \"tags\");\n continue;\n }\n // The label is only read when an eval THROWS and only when tracing, so\n // building it per card was pure waste on the path that matters. Built\n // when tracing is on, where the cost is already accepted.\n if (card.condition && !this.passes(card.condition, deckCtx,\n this.tracing ? `card ${card.gameId} condition` : undefined)) {\n verdict(card.id, \"condition\");\n continue;\n }\n const refused = claimed(card, shared); // claims, last (schema 3.1 step 6)\n if (refused) {\n verdict(card.id, refused);\n continue;\n }\n\n let priority: number;\n if (typeof card.priority === \"number\") {\n priority = card.priority;\n } else {\n try {\n const v = this.eval(card.priority, deckCtx);\n if (typeof v !== \"number\") {\n verdict(card.id, \"priority\");\n continue;\n }\n priority = v;\n } catch (e) {\n if (this.tracing) {\n this.emit({ type: \"diagnostic\", where: `card ${card.gameId} priority`, message: e instanceof Error ? e.message : String(e) });\n }\n verdict(card.id, \"priority\");\n continue;\n }\n }\n let spec = 0;\n if (box.ranking.specificity && card.condition) {\n const node = this.node(card.condition);\n spec = matchedSpecificity(node, (n) => {\n try {\n return conditionPasses(evaluate(n, deckCtx, storyletsDialect));\n } catch {\n return false;\n }\n });\n }\n scored.push({ entry: { card, deck, box }, priority, spec });\n }\n }\n\n scored.sort((a, b) => b.priority - a.priority || b.spec - a.spec); // stable\n // Seeded shuffle of each maximal tie run; runs of 1 consume no draws.\n let i = 0;\n while (i < scored.length) {\n let j = i + 1;\n while (j < scored.length\n && scored[j]!.priority === scored[i]!.priority\n && scored[j]!.spec === scored[i]!.spec) j++;\n if (j - i > 1) {\n const run = scored.slice(i, j);\n shuffleInPlace(run, this.prng);\n // Written back element by element, as all three ports do. It used to be\n // `scored.splice(i, j - i, ...run)`, which SPREADS one argument per\n // element: with every card at the default priority 0 the tie run is the\n // whole list, and a box of 150 000 such cards threw `RangeError:\n // Maximum call stack size exceeded` rather than dealing. Far-fetched\n // for one box, but it was a crash where the ports had no limit, and the\n // reference is supposed to be the thing they are transliterated from.\n for (let k = 0; k < run.length; k++) scored[i + k] = run[k]!;\n }\n i = j;\n }\n for (const s of scored) {\n trace?.push({ id: s.entry.card.id, verdict: \"dealt\", priority: s.priority, specificity: s.spec });\n }\n return { ordered: scored.map((s) => s.entry), handEnv };\n }\n\n /** Flip eligible-but-not-taken trace entries to \"capped\". */\n private capTrace(\n trace: { id: string; verdict: TraceVerdict; priority?: number; specificity?: number }[],\n taken: ReadonlySet<string>,\n ): void {\n for (const entry of trace) {\n if (entry.verdict === \"dealt\" && !taken.has(entry.id)) entry.verdict = \"capped\";\n }\n }\n\n private view(entry: CardEntry): DealtCard {\n const { card } = entry;\n return {\n id: card.id,\n gameId: effectiveGameId(card),\n ...(card.title !== undefined ? { title: card.title } : {}),\n ...(card.purpose !== undefined ? { purpose: card.purpose } : {}),\n ...(card.fields !== undefined ? { fields: card.fields } : {}),\n };\n }\n\n private handCapacity(hand: Hand<Expression>): number {\n if (hand.slots !== undefined) return hand.slots;\n const declared = hand.template !== undefined\n ? this.internals.templatesById.get(hand.template)?.slots\n : hand.rule?.slots;\n return declared === undefined || declared === \"unbounded\" ? Infinity : declared;\n }\n\n private resolveHand(ref: string): { hand: Hand<Expression>; box: Box<Expression> } {\n const found = this.internals.handsByGameId.get(ref) ?? this.internals.handsById.get(ref);\n if (!found) throw new Error(`unknown hand \"${ref}\"`);\n return found;\n }\n\n // --- host surface (schema 5) ---------------------------------------------------\n\n /** Look at the top of the stock through raw tag criteria (schema 3.1):\n * claims respected, nothing registered, nothing left behind but the\n * trace line. You can never play a card you only peeked. */\n peek(boxRef: string, criteria: Record<string, string> = {}, n?: number): RankedList {\n this.assertOpen();\n const box = this.internals.boxesByGameId.get(boxRef) ?? this.internals.boxesById.get(boxRef);\n if (!box) throw new Error(`unknown box \"${boxRef}\"`);\n const ask = this.askForPeek(box, criteria);\n const claimCounts = this.claims();\n // Skipped outright when the bundle shares nothing, which is most bundles:\n // the ledger walks every live flow's whole board, and an empty map answers\n // every question the same way a computed one would.\n const worldClaims = this.internals.hasShared ? this.engine.sharedClaims() : new Map<string, number>();\n const trace = this.tracing ? [] : undefined;\n const { ordered } = this.runAsk(ask, (card, shared) => this.claimVerdict(card, shared, claimCounts, worldClaims), trace);\n // CLAMPED. `slice(0, -1)` drops the last card and returns the rest, so a\n // negative n answered with almost the whole list here while every port\n // returned nothing (2026-08-29).\n const listed = n === undefined ? ordered : ordered.slice(0, Math.max(n, 0));\n if (trace) {\n this.capTrace(trace, new Set(listed.map((e) => e.card.id)));\n this.emit({ type: \"peek\", box: effectiveGameId(box), criteria, cards: trace }, this.turnCounts.get(box.id) ?? 0);\n }\n return { box: effectiveGameId(box), cards: listed.map((e) => this.view(e)) };\n }\n\n /** Refresh one hand (schema 3.5); returns its new shape. */\n deal(handRef: string): DealtCard[] {\n this.assertOpen();\n const { hand } = this.resolveHand(handRef);\n return this.dealMany([handRef])[effectiveGameId(hand)] ?? [];\n }\n\n /** Re-deal several / all hands (schema 3.5): seeded hand-order shuffle\n * (fairness), evict, seed the ledger from survivors, fill in order.\n * Returns the dealt slice - the new contents of exactly the hands this\n * call dealt, keyed by hand gameId (board() stays the whole-board read). */\n dealMany(handRefs?: string[]): Record<string, DealtCard[]> {\n this.assertOpen();\n const dealt = (handRefs ?? [...this.internals.handsById.keys()].sort())\n .map((ref) => this.resolveHand(ref));\n shuffleInPlace(dealt, this.prng);\n\n // Eviction first: drop dealt cards no longer available to their hand\n // (minus the claims check against their own seat).\n for (const { hand, box } of dealt) {\n const ask = this.askForHand(hand, box);\n const handEnv = this.buildHandEnv(ask);\n const conditionOk = this.passes(ask.condition, this.evalCtx(box, undefined, handEnv));\n const gateOk = new Map<string, boolean>();\n for (const deck of box.decks) {\n gateOk.set(deck.id, this.passes(deck.condition, this.evalCtx(box, deck, handEnv)));\n }\n const turn = this.turnCounts.get(box.id) ?? 0;\n // Trace events fire after the state they report has landed (a handler\n // reading the board sees the eviction), so they are collected here and\n // emitted once the survivors are set.\n const evicted: { card: string; reason: Extract<TraceEvent, { type: \"evict\" }>[\"reason\"] }[] = [];\n const evict = (cardId: string, reason: Extract<TraceEvent, { type: \"evict\" }>[\"reason\"]): false => {\n evicted.push({ card: cardId, reason });\n return false;\n };\n const survivors = (this.boardContents.get(hand.id) ?? []).filter((cardId) => {\n if (!conditionOk) return evict(cardId, \"hand-condition\");\n const entry = this.internals.cardsById.get(cardId);\n if (!entry) return evict(cardId, \"vanished\"); // edited content: dropped\n if (!gateOk.get(entry.deck.id)) return evict(cardId, \"deck-gate\");\n if ((this.cooldowns[cardId] ?? 0) > turn) return evict(cardId, \"cooldown\");\n if (!this.tagsMatch(entry.card, handEnv.boundTags)) return evict(cardId, \"tags\");\n if (!this.passes(entry.card.condition, this.evalCtx(box, entry.deck, handEnv), `card ${entry.card.gameId} condition`)) {\n return evict(cardId, \"condition\");\n }\n return true;\n });\n this.boardContents.set(hand.id, survivors);\n if (this.tracing) {\n for (const e of evicted) this.emit({ type: \"evict\", hand: hand.id, card: e.card, reason: e.reason }, turn);\n }\n }\n\n const claimCounts = this.claims();\n // The world ledger is taken once for the whole batch and kept in step with\n // the local one below, so two hands in the SAME deal cannot both take the\n // last shared copy. Skipped outright when the bundle shares nothing (most\n // bundles): an empty map answers every question the same way.\n const worldClaims = this.internals.hasShared ? this.engine.sharedClaims() : new Map<string, number>();\n for (const { hand, box } of dealt) {\n const contents = this.boardContents.get(hand.id) ?? [];\n const free = this.handCapacity(hand) - contents.length;\n if (free <= 0) continue;\n const ask = this.askForHand(hand, box);\n const own = new Set(contents);\n const trace = this.tracing ? [] : undefined;\n // At most once in any one hand; at most `copies` hands here, and at most\n // `sharedCopies` hands anywhere (schema 3.5, shared-scarcity 5).\n const { ordered } = this.runAsk(ask,\n (card, shared) => (own.has(card.id) ? \"claimed\" : this.claimVerdict(card, shared, claimCounts, worldClaims)), trace);\n const added = ordered.slice(0, free).map((e) => e.card.id);\n this.boardContents.set(hand.id, [...contents, ...added]);\n for (const id of added) {\n claimCounts.set(id, (claimCounts.get(id) ?? 0) + 1);\n worldClaims.set(id, (worldClaims.get(id) ?? 0) + 1);\n }\n // Emitted after the hand is set: a handler reading board() sees the deal.\n if (trace) {\n this.capTrace(trace, new Set(added));\n this.emit({ type: \"deal\", hand: effectiveGameId(hand), cards: trace }, this.turnCounts.get(box.id) ?? 0);\n }\n }\n\n return Object.fromEntries(dealt.map(({ hand }) => [\n effectiveGameId(hand),\n (this.boardContents.get(hand.id) ?? []).map((id) => this.view(this.internals.cardsById.get(id)!)),\n ]));\n }\n\n /** The board: current hand contents, in dealt order, keyed by hand gameId\n * (schema 5). Read it for what is out; peek the stock for what could\n * come.\n *\n * `boxRef` (a box gameId or id) narrows the read to that box's hands, in\n * the same shape and the same order: \"give me the barks hands\" is a\n * common host query, and boxes are how a game separates its storylet\n * systems, so the grouping belongs here rather than in every host. An\n * unknown box throws, as it does on turn() and peek(). */\n board(boxRef?: string): Record<string, DealtCard[]> {\n this.assertOpen();\n let keep: string | undefined;\n if (boxRef !== undefined) {\n const box = this.internals.boxesByGameId.get(boxRef) ?? this.internals.boxesById.get(boxRef);\n if (!box) throw new Error(`unknown box \"${boxRef}\"`);\n keep = box.id;\n }\n return Object.fromEntries([...this.boardContents.entries()]\n .filter(([handId]) => keep === undefined || this.internals.handsById.get(handId)!.box.id === keep)\n .map(([handId, ids]) => [\n effectiveGameId(this.internals.handsById.get(handId)!.hand),\n ids.map((id) => this.view(this.internals.cardsById.get(id)!)),\n ]));\n }\n\n /** Resolve a played/inspected card within a hand on the board. */\n private resolveDealt(cardId: string, handRef: string): { entry: CardEntry; ask: AskDescriptor } {\n const entry = this.internals.cardsById.get(cardId) ?? this.internals.cardsByGameId.get(cardId);\n if (!entry) throw new Error(`unknown card \"${cardId}\"`);\n const { hand, box } = this.resolveHand(handRef);\n if (!(this.boardContents.get(hand.id) ?? []).includes(entry.card.id)) {\n throw new Error(`card \"${effectiveGameId(entry.card)}\" is not dealt to hand \"${effectiveGameId(hand)}\"`);\n }\n return { entry, ask: this.askForHand(hand, box) };\n }\n\n /** Outcome availability, evaluated against CURRENT state on every ask\n * (schema 3.1/5) - never a deal-time snapshot. */\n outcomes(cardId: string, from: string): OutcomeView[] {\n this.assertOpen();\n const { entry, ask } = this.resolveDealt(cardId, from);\n const ctx = this.evalCtx(entry.box, entry.deck, this.buildHandEnv(ask));\n return entry.card.outcomes.map((o) => ({\n id: o.id,\n gameId: effectiveGameId(o),\n ...(o.title !== undefined ? { title: o.title } : {}),\n ...(o.purpose !== undefined ? { purpose: o.purpose } : {}),\n available: this.passes(o.condition, ctx),\n }));\n }\n\n /** Apply an outcome (schema 3.7): the card must sit in a hand on the\n * board (you never play a card from inside the deck). Throws before any\n * mutation on a gated-shut outcome or a bad write target. */\n play(cardId: string, outcomeGameId: string, from: string, opts: PlayOptions = {}): void {\n this.assertOpen();\n const { entry, ask } = this.resolveDealt(cardId, from);\n const outcome = entry.card.outcomes.find((o) => effectiveGameId(o) === outcomeGameId);\n if (!outcome) throw new Error(`card \"${effectiveGameId(entry.card)}\" has no outcome \"${outcomeGameId}\"`);\n\n const handEnv = this.buildHandEnv(ask);\n const ctx = this.evalCtx(entry.box, entry.deck, handEnv);\n if (!this.passes(outcome.condition, ctx)) {\n throw new Error(`outcome \"${outcomeGameId}\" on \"${effectiveGameId(entry.card)}\" is gated shut`);\n }\n\n // The played card's box's clock advances (schema 3.4); computed up\n // front so the play and its writes log as one action, one turn stamp.\n const newTurn = (this.turnCounts.get(entry.box.id) ?? 0)\n + (opts.advanceTurns ?? this.internals.bundle.settings.playAdvancesTurns);\n\n // Every right-hand side evaluates against PRE-play state, then all\n // writes land (schema 3.7).\n const writes: { target: string; value: ScalarValue }[] = [];\n for (const [target, expr] of Object.entries(outcome.changes)) {\n writes.push({ target, value: this.eval(expr, ctx) });\n }\n for (const { target, value } of writes) {\n const { path, prev } = this.applyWrite(target, value, entry, handEnv);\n if (this.tracing) this.emit({ type: \"write\", target, path, value, ...(prev !== undefined ? { prev } : {}) }, newTurn);\n }\n\n const record: PlayRecord = { card: effectiveGameId(entry.card), outcome: effectiveGameId(outcome), turn: newTurn };\n this.playLog.push(record);\n this.indexPlay(record);\n if (entry.card.redraw === \"never\") {\n // A shared one-shot leaves the world rather than this flow: the engine\n // holds it, so every flow is refused. A finite redraw deliberately does\n // NOT share, whatever the deck says - a cooldown is an absolute turn of\n // this flow's box clock, and there is no shared clock to compare it\n // against (design/shared-scarcity.md 9.3.2).\n if (cardIsShared(entry.card, entry.deck.shared ?? false)) this.engine.markTaken(entry.card.id);\n else this.cooldowns[entry.card.id] = Number.MAX_SAFE_INTEGER;\n } else if (typeof entry.card.redraw === \"number\") {\n this.cooldowns[entry.card.id] = newTurn + entry.card.redraw;\n }\n // The card leaves its hand, releasing its claim (schema 3.5/3.7).\n const handId = ask.hand!.id;\n this.boardContents.set(handId,\n (this.boardContents.get(handId) ?? []).filter((id) => id !== entry.card.id));\n this.turnCounts.set(entry.box.id, newTurn);\n // Emitted last: a handler reading the board and the clock sees the play.\n if (this.tracing) this.emit({ type: \"play\", card: entry.card.id, outcome: effectiveGameId(outcome), turn: newTurn }, newTurn);\n }\n\n /** Land one change in whichever partition declares the name: the flow's\n * bag when the property is per-flow, the shared bag when it is shared -\n * the union/partition invariant made executable. */\n private landIn(kind: Exclude<PartitionKind, \"story\"> | \"story\", id: string | undefined, name: string, value: ScalarValue, path: string): { path: string; prev?: ScalarValue } {\n const own = kind === \"story\" ? this.stores.story : id !== undefined ? this.stores[kind].get(id) : undefined;\n const shared = kind === \"story\" ? this.internals.shared.story : id !== undefined ? this.internals.shared[kind].get(id) : undefined;\n const bag = own !== undefined && own.get(name) !== undefined ? own\n : shared !== undefined && shared.get(name) !== undefined ? shared\n : undefined;\n if (bag === undefined) throw new Error(`no property at \"${path}\"`);\n // An engine write: the bag's subscribers fire (the firing rule).\n const change = bag.set(name, value);\n return { path, ...(change.prev !== undefined ? { prev: change.prev } : {}) };\n }\n\n /** Land one change; returns the resolved store path (for the trace) and\n * the value it replaced (for the log's \"0 -> 1\" reading). */\n private applyWrite(target: string, value: ScalarValue, entry: CardEntry, handEnv: HandEnv): { path: string; prev?: ScalarValue } {\n const match = /^@([a-z]+)\\.([A-Za-z_][A-Za-z0-9_-]*)$/.exec(target);\n if (!match) throw new Error(`bad change target \"${target}\"`);\n const [, scope, name] = match as unknown as [string, string, string];\n switch (scope) {\n case \"world\": {\n const resolver = this.internals.worldResolver;\n if (!resolver.set) throw new Error(`@world.${name} cannot be written: the host bound @world read-only`);\n const prev = resolver.get(name);\n resolver.set(name, value);\n return { path: `world.${name}`, ...(prev !== undefined ? { prev } : {}) };\n }\n case \"story\": return this.landIn(\"story\", undefined, name, value, `story.${name}`);\n case \"box\": return this.landIn(\"box\", entry.box.id, name, value, `box.${entry.box.id}.${name}`);\n case \"deck\": return this.landIn(\"deck\", entry.deck.id, name, value, `deck.${entry.deck.id}.${name}`);\n case \"hand\": {\n // Write-back routing (schema 3.6): the composed name remembers its\n // source store; writes to criteria/chosen-tag names are errors.\n const source = handEnv.sources.get(name);\n if (!source) throw new Error(`@hand.${name} is not composed in this ask`);\n if (source.kind === \"criteria\") throw new Error(`@hand.${name} is a chosen tag / criteria name and cannot be written`);\n return this.landIn(source.kind, source.id, name, value, `${source.kind}.${source.id}.${name}`);\n }\n default: throw new Error(`bad change target scope \"@${scope}\"`);\n }\n }\n\n /** Advance one box's clock (schema 3.4): a turn is one draw-from-stock\n * session for that box, on THIS flow's clock. */\n advanceTurns(boxRef: string, n = 1): void {\n this.assertOpen();\n const box = this.internals.boxesByGameId.get(boxRef) ?? this.internals.boxesById.get(boxRef);\n if (!box) throw new Error(`unknown box \"${boxRef}\"`);\n const next = (this.turnCounts.get(box.id) ?? 0) + n;\n this.turnCounts.set(box.id, next);\n if (this.tracing) this.emit({ type: \"turns\", box: effectiveGameId(box), turn: next }, next);\n }\n\n // --- state access (host surface + test tooling) ---------------------------------\n\n /** Every box, bundle order: identity + this flow's clock (the enumeration\n * surface examiners key their turns sections on; parity member). */\n listBoxes(): BoxView[] {\n this.assertOpen();\n return this.internals.bundle.boxes.map((b) => ({\n id: b.id,\n gameId: effectiveGameId(b),\n ...(b.title !== undefined ? { title: b.title } : {}),\n turn: this.turnCounts.get(b.id) ?? 0,\n }));\n }\n\n /** THIS flow's kernel bags with their store path prefixes (the state\n * logger's mount surface; parity member). The shared bags are the\n * Engine's listBags; the flows are rebuilt by loadGame, so consumers\n * re-enumerate after a load. */\n listBags(): BagMount[] {\n this.assertOpen();\n const mounts: BagMount[] = [{ prefix: \"story\", bag: this.stores.story }];\n for (const kind of [\"box\", \"deck\", \"hand\", \"value\"] as const) {\n for (const [id, bag] of this.stores[kind]) mounts.push({ prefix: `${kind}.${id}`, bag });\n }\n return mounts;\n }\n\n /** The flow's FULL merged view as examiner rows (the property examiner /\n * editor surface, parity across all runtimes): @world read through the\n * resolver, then per scope the shared values and this flow's own.\n * Bundle order: world, story, then per-box / per-deck / per-hand /\n * per-tag stores. */\n listProperties(): PropertyView[] {\n this.assertOpen();\n const out: PropertyView[] = [];\n for (const d of this.internals.bundle.world.properties) {\n const value = this.internals.worldResolver.get(d.name);\n out.push({\n path: `world.${d.name}`, name: d.name, type: d.type,\n value: value ?? d.default, default: d.default,\n ...(d.values !== undefined ? { values: d.values } : {}),\n ...(d.stages !== undefined ? { stages: d.stages } : {}),\n } as PropertyView);\n }\n const add = (prefix: string, shared: StateBag | undefined, own: StateBag | undefined): void => {\n for (const bag of [shared, own]) {\n if (bag === undefined) continue;\n for (const row of bag.rows()) out.push({ path: `${prefix}.${row.name}`, ...row });\n }\n };\n add(\"story\", this.internals.shared.story, this.stores.story);\n for (const kind of [\"box\", \"deck\", \"hand\", \"value\"] as const) {\n const ids = new Set([...this.internals.shared[kind].keys(), ...this.stores[kind].keys()]);\n for (const id of ids) add(`${kind}.${id}`, this.internals.shared[kind].get(id), this.stores[kind].get(id));\n }\n return out;\n }\n\n /** Read by path: \"world.x\", \"story.gold\", \"value.v_docks.danger\",\n * \"box.b_x.heat\", \"deck.k_main.n\", \"hand.h_board.owner\" - the flow's\n * merged view, routed by the declaration's sharing. */\n getProperty(path: string): ScalarValue {\n this.assertOpen();\n const found = this.resolvePath(path);\n const value = found.kind === \"world\" ? this.internals.worldResolver.get(found.name)\n : found.own?.get(found.name) ?? found.shared?.get(found.name);\n if (value === undefined) throw new Error(`no property at \"${path}\"`);\n return value;\n }\n\n setProperty(path: string, value: ScalarValue): void {\n this.assertOpen();\n const found = this.resolvePath(path);\n if (found.kind === \"world\") {\n if (!this.internals.worldResolver.set) throw new Error(`@world is read-only here: the host bound no write`);\n this.internals.worldResolver.set(found.name, value);\n return;\n }\n const bag = found.own !== undefined && found.own.get(found.name) !== undefined ? found.own\n : found.shared !== undefined && found.shared.get(found.name) !== undefined ? found.shared\n : undefined;\n if (bag === undefined) throw new Error(`no property at \"${path}\"`);\n // A host write: silent under the firing rule (no subscriber feedback\n // loop), but visible to the bag's audit hook.\n bag.set(found.name, value, { silent: true, reason: \"host setProperty\" });\n }\n\n private resolvePath(path: string): { kind: \"world\"; name: string } | { kind: \"bag\"; own?: StateBag; shared?: StateBag; name: string } {\n const parts = path.split(\".\");\n if (parts.length === 2 && parts[0] === \"world\") return { kind: \"world\", name: parts[1]! };\n if (parts.length === 2 && parts[0] === \"story\") {\n return { kind: \"bag\", own: this.stores.story, shared: this.internals.shared.story, name: parts[1]! };\n }\n if (parts.length === 3 && (parts[0] === \"box\" || parts[0] === \"deck\" || parts[0] === \"hand\" || parts[0] === \"value\")) {\n const kind = parts[0] as Exclude<PartitionKind, \"story\">;\n const own = this.stores[kind].get(parts[1]!);\n const shared = this.internals.shared[kind].get(parts[1]!);\n if (own === undefined && shared === undefined) throw new Error(`no ${parts[0]} store \"${parts[1]}\"`);\n return { kind: \"bag\", ...(own !== undefined ? { own } : {}), ...(shared !== undefined ? { shared } : {}), name: parts[2]! };\n }\n throw new Error(`bad property path \"${path}\"`);\n }\n\n // --- persistence (schema 4) -------------------------------------------------\n\n /** @internal - this flow's blob inside the engine's envelope. */\n snapshot(): FlowSave {\n return {\n props: partitionValues(this.stores),\n turns: Object.fromEntries(this.turnCounts),\n prng: this.prng.state(),\n cooldowns: this.cooldowns,\n board: Object.fromEntries(this.boardContents),\n playLog: this.playLog,\n };\n }\n\n /** @internal - restore a freshly opened flow from its blob (loadGame).\n * Orphaned keys (deleted entities) drop; new declarations keep defaults. */\n restore(saved: FlowSave): void {\n loadPartition(this.stores, saved.props);\n this.turnCounts = new Map(this.internals.bundle.boxes.map((b) => [b.id, 0]));\n for (const [boxId, turn] of Object.entries(saved.turns ?? {})) {\n if (this.turnCounts.has(boxId)) this.turnCounts.set(boxId, turn);\n }\n this.prng = makePrng(saved.prng);\n this.cooldowns = saved.cooldowns ?? {};\n this.playLog = saved.playLog ?? [];\n this.rebuildPlayIndex();\n this.boardContents = new Map(Object.entries(saved.board ?? {})\n .filter(([handId]) => this.internals.handsById.has(handId))\n .map(([handId, ids]) => [handId, ids.filter((id) => this.internals.cardsById.has(id))]));\n for (const handId of this.internals.handsById.keys()) {\n if (!this.boardContents.has(handId)) this.boardContents.set(handId, []);\n }\n }\n}\n","// ---------------------------------------------------------------------------\n// describeBundle - the bundle inspector's runtime half (design/engine-runtimes.md\n// section 2, piece 6).\n//\n// A BUNDLE-level API, deliberately NOT a session method: it answers the\n// integrator's question - \"I dropped a .storyletsc into my project, what may\n// my game code call?\" - from the imported asset alone, with no session, no\n// state and no game running. That makes the boundary rule (design 4) visible:\n// hands are what deal() takes, tag groups + tags are what peek() criteria are\n// drawn from, declared properties are what expressions read and a host may\n// set. Card lists are deliberately absent: cards are the engine's business,\n// counts are the orientation an integrator needs.\n//\n// Everything is in bundle order, so the description is deterministic and two\n// runtimes render the same rows in the same sequence. The property scopes are\n// the static twin of session.listProperties(): the same stores, in the same\n// order, before anything is instantiated (a hand instance carries its\n// template's declarations, exactly as the session's hand bags do).\n// ---------------------------------------------------------------------------\n\nimport { effectiveGameId } from \"@storylet-studio/model\";\nimport type {\n Box, Bundle, Expression, Hand, PropertyDecl, PropertyType, ScalarValue,\n} from \"@storylet-studio/model\";\n\n/** What bundle this is: the staleness/identity triple plus the schema tag. */\nexport interface BundleIdentity {\n /** The bundle schema tag (\"storylets/bundle@0\"). */\n schema: string;\n /** content.project - the project name a save must agree with. */\n project: string;\n /** content.version - the authored bundle version. */\n version: string;\n /** content.hash - hash32 over the canonical source shards (schema 2.8). */\n hash: string;\n /** \"full\" | \"stripped\": whether authoring metadata (titles) survived. */\n metadata: string;\n}\n\n/** One hand: the deal() surface. `gameId` is the name deal() is called with. */\nexport interface HandSummary {\n gameId: string;\n title?: string;\n /** The owning box's gameId (peek's first argument for the same stock). */\n box: string;\n /** The effective slot cap: the hand's override, else its template's or\n * rule's, else \"unbounded\". */\n slots: number | \"unbounded\";\n /** The hand template's gameId; absent for a standalone (inline-rule) hand. */\n template?: string;\n}\n\n/** One tag group and its tags, by gameId: the peek() criteria surface (a\n * criteria entry is `{ [group gameId]: tag gameId }`). */\nexport interface TagGroupSummary {\n gameId: string;\n tags: string[];\n}\n\n/** One box: identity, its ranking policy, its tag groups, and counts. */\nexport interface BoxSummary {\n gameId: string;\n title?: string;\n /** The only per-box ranking policy (Reboot 2.2). */\n ranking: { specificity: boolean };\n tagGroups: TagGroupSummary[];\n counts: {\n decks: number;\n cards: number;\n hands: number;\n templates: number;\n tagGroups: number;\n };\n}\n\n/** One declared property: what expressions read and what a host may set. */\nexport interface PropertySummary {\n name: string;\n type: PropertyType;\n default: ScalarValue;\n /** Enum / flags options, where declared. */\n values?: string[];\n purpose?: string;\n}\n\n/** The scope a declaration block belongs to. `tag` declarations compose into\n * @hand for any ask that binds the tag (schema 3.6). */\nexport type PropertyScopeKind = \"world\" | \"story\" | \"box\" | \"deck\" | \"hand\" | \"tag\";\n\n/** One scope's declared properties. `owner` is the owning entity's gameId\n * (empty for world / story); `box` names its box; `group` names a tag's\n * group. */\nexport interface PropertyScopeSummary {\n scope: PropertyScopeKind;\n owner: string;\n box?: string;\n group?: string;\n properties: PropertySummary[];\n}\n\n/**\n * One map the bundle was asked to carry (design/graphical-views.md 2).\n *\n * Counts rather than the geometry itself, which is the same judgement the rest\n * of this file makes: an inspector answers \"what is in here\", and a host that\n * wants the polygons reads `bundle.maps` directly. Reported because a bundle\n * that silently carried a map would fail the promise this API exists for.\n */\nexport interface MapSummary {\n /** The owning box, by gameId. */\n box: string;\n /** The tag group this is a map of, by gameId. */\n group: string;\n zones: number;\n backgrounds: number;\n}\n\n/** What a bundle offers a host, read from the asset alone. */\nexport interface BundleDescription {\n identity: BundleIdentity;\n /** Orientation, not inventory: no card lists (Reboot 2.1). */\n totals: {\n boxes: number;\n decks: number;\n cards: number;\n hands: number;\n templates: number;\n tagGroups: number;\n };\n boxes: BoxSummary[];\n /** Every hand in the bundle, box by box: the deal() surface. */\n hands: HandSummary[];\n /** world, story, then per box: the box, its decks, its hands, its tags.\n * Scopes that declare nothing are omitted (world and story always show,\n * so their absence reads as \"this bundle declares none\"). */\n properties: PropertyScopeSummary[];\n /** Maps carried as inert payload, when the build asked for them. Empty is\n * the normal state and means the bundle has no geometry in it. */\n maps: MapSummary[];\n}\n\nconst summarise = (decls: PropertyDecl[]): PropertySummary[] =>\n decls.map((d) => ({\n name: d.name,\n type: d.type,\n default: d.default,\n ...(d.values !== undefined ? { values: d.values } : {}),\n ...(d.purpose !== undefined ? { purpose: d.purpose } : {}),\n }));\n\n/** A hand's declared @hand state: a template instance inherits its template's\n * declarations, a standalone hand declares its own (schema 2.6) - the same\n * rule the session's hand bags are built on. */\nconst handDecls = (hand: Hand<Expression>, box: Box<Expression>): PropertyDecl[] => {\n if (hand.template !== undefined) {\n return box.handTemplates.find((t) => t.id === hand.template)?.properties ?? [];\n }\n return hand.properties ?? [];\n};\n\n/** The effective slot cap, resolved the way the session resolves capacity. */\nconst handSlots = (hand: Hand<Expression>, box: Box<Expression>): number | \"unbounded\" => {\n if (hand.slots !== undefined) return hand.slots;\n const declared = hand.template !== undefined\n ? box.handTemplates.find((t) => t.id === hand.template)?.slots\n : hand.rule?.slots;\n return declared === undefined ? \"unbounded\" : declared;\n};\n\n/** Describe a compiled bundle: the callable surface of an imported asset, no\n * session required (design/engine-runtimes.md 2, piece 6). Bundle order\n * throughout; the same shape every runtime returns. */\nexport function describeBundle(bundle: Bundle): BundleDescription {\n const boxes: BoxSummary[] = [];\n const hands: HandSummary[] = [];\n const properties: PropertyScopeSummary[] = [\n { scope: \"world\", owner: \"\", properties: summarise(bundle.world.properties) },\n { scope: \"story\", owner: \"\", properties: summarise(bundle.story.properties) },\n ];\n const totals = { boxes: 0, decks: 0, cards: 0, hands: 0, templates: 0, tagGroups: 0 };\n\n for (const box of bundle.boxes) {\n const boxGameId = effectiveGameId(box);\n const cards = box.decks.reduce((n, deck) => n + deck.cards.length, 0);\n boxes.push({\n gameId: boxGameId,\n ...(box.title !== undefined ? { title: box.title } : {}),\n ranking: { specificity: box.ranking.specificity },\n tagGroups: box.tagGroups.map((group) => ({\n gameId: effectiveGameId(group),\n tags: group.tags.map((tag) => effectiveGameId(tag)),\n })),\n counts: {\n decks: box.decks.length,\n cards,\n hands: box.hands.length,\n templates: box.handTemplates.length,\n tagGroups: box.tagGroups.length,\n },\n });\n totals.boxes += 1;\n totals.decks += box.decks.length;\n totals.cards += cards;\n totals.hands += box.hands.length;\n totals.templates += box.handTemplates.length;\n totals.tagGroups += box.tagGroups.length;\n\n for (const hand of box.hands) {\n const template = hand.template !== undefined\n ? box.handTemplates.find((t) => t.id === hand.template)\n : undefined;\n hands.push({\n gameId: effectiveGameId(hand),\n ...(hand.title !== undefined ? { title: hand.title } : {}),\n box: boxGameId,\n slots: handSlots(hand, box),\n ...(template !== undefined ? { template: effectiveGameId(template) } : {}),\n });\n }\n\n // The property scopes, in the session's store order: box, decks, hands,\n // tags. Empty declaration blocks are dropped (nothing to read or set).\n const push = (scope: PropertyScopeKind, owner: string, decls: PropertyDecl[], group?: string): void => {\n if (decls.length === 0) return;\n properties.push({\n scope, owner, box: boxGameId, ...(group !== undefined ? { group } : {}),\n properties: summarise(decls),\n });\n };\n push(\"box\", boxGameId, box.properties);\n for (const deck of box.decks) push(\"deck\", effectiveGameId(deck), deck.properties);\n for (const hand of box.hands) push(\"hand\", effectiveGameId(hand), handDecls(hand, box));\n for (const group of box.tagGroups) {\n for (const tag of group.tags) {\n push(\"tag\", effectiveGameId(tag), tag.properties ?? [], effectiveGameId(group));\n }\n }\n }\n\n return {\n identity: {\n schema: bundle.schema,\n project: bundle.content.project,\n version: bundle.content.version,\n hash: bundle.content.hash,\n metadata: bundle.metadata,\n },\n totals,\n boxes,\n hands,\n properties,\n maps: (bundle.maps ?? []).map((map) => ({\n box: map.box,\n group: map.group,\n zones: map.zones.length,\n backgrounds: map.backgrounds?.length ?? 0,\n })),\n };\n}\n"],"mappings":"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","names":["val"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../../../../expr/packages/expr/src/ast.ts","../../../../expr/packages/expr/src/evaluate.ts","../../../../expr/packages/expr/src/prng.ts","../../../../expr/packages/expr-specificity/src/index.ts","../../dialect/src/index.ts","../../model/src/index.ts","../../../../expr/packages/scoperegistry/src/index.ts","../src/engine.ts","../src/describe.ts"],"sourcesContent":["export { Engine, Flow } from \"./engine.js\";\n// The examiner row listProperties() returns: the shared kernel's\n// (@wildwinter/scoperegistry, the property implementation both product families use),\n// re-exported so a host typing a row needs no dependency on the kernel.\nexport type { PropertyRow } from \"@wildwinter/scoperegistry\";\nexport type {\n BagMount, BoxView, DealtCard, EngineLogEntry, EngineOptions, EngineTraceHandler, LogEntry, OpenFlowOptions,\n OutcomeView, PlayOptions, RankedList, TraceEvent, TraceHandler, TraceVerdict,\n} from \"./engine.js\";\nexport { describeBundle } from \"./describe.js\";\nexport type {\n BoxSummary, BundleDescription, BundleIdentity, HandSummary, MapSummary, PropertyScopeKind,\n PropertyScopeSummary, PropertySummary, TagGroupSummary,\n} from \"./describe.js\";\nexport { makePrng, shuffleInPlace } from \"./prng.js\";\nexport type { Prng } from \"./prng.js\";\n","// ---------------------------------------------------------------------------\n// AST - the in-memory expression tree and its serialised tagged-tuple form.\n//\n// The in-memory `ExprNode` is a discriminated union (kind field). The published\n// `AstNode` is the compact tagged-tuple form that goes into a compiled bundle's\n// { src, ast } envelope - what a runtime walks, never parses.\n//\n// This module is dialect-agnostic: scope tokens and function names are plain\n// strings here; meaning is supplied by a Dialect (see dialect.ts).\n// ---------------------------------------------------------------------------\n\nexport type ScalarValue = boolean | number | string | string[];\n\nexport type BinaryOp =\n | \"==\" | \"!=\" | \">\" | \">=\" | \"<\" | \"<=\"\n | \"+\" | \"-\" | \"*\" | \"/\"\n | \"and\" | \"or\";\n\nexport type UnaryOp = \"not\" | \"neg\";\n\nexport type ExprNode =\n | { kind: \"bool\"; value: boolean }\n | { kind: \"number\"; value: number }\n | { kind: \"string\"; value: string }\n // All property references are scoped: bare `@name` is canonicalised to\n // `@<defaultScope>.name` at parse time. Names are lowercased at parse time.\n | { kind: \"scopedvar\"; scope: string; name: string }\n | { kind: \"call\"; name: string; args: ExprNode[] }\n | { kind: \"unary\"; op: UnaryOp; operand: ExprNode }\n | { kind: \"binary\"; op: BinaryOp; left: ExprNode; right: ExprNode }\n // Produced only by flag-delta function argument parsing (see Dialect\n // `flagDeltaArgs`) - not valid elsewhere.\n | { kind: \"flagdelta\"; sign: \"+\" | \"-\"; name: string };\n\n/**\n * Path into an ExprNode tree. Each segment names the field on the parent node,\n * with numeric indices for array elements (call args).\n * binary.left -> [\"left\"]\n * binary.right.args[0] -> [\"right\", \"args\", 0]\n * top-level node -> []\n */\nexport type AstPath = readonly (string | number)[];\n\n// ---------------------------------------------------------------------------\n// Published tagged-tuple form (JSON arrays, opcode at index 0).\n// ---------------------------------------------------------------------------\n\nexport type AstNode =\n | [\"b\", boolean]\n | [\"n\", number]\n | [\"s\", string]\n | [\"sv\", string, string]\n | [\"u\", UnaryOp, AstNode]\n | [\"bin\", BinaryOp, AstNode, AstNode]\n | [\"call\", string, ...AstNode[]]\n | [\"fd\", \"+\" | \"-\", string];\n\n/** In-memory ExprNode -> published tagged-tuple AstNode. */\nexport function serialiseAst(node: ExprNode): AstNode {\n switch (node.kind) {\n case \"bool\": return [\"b\", node.value];\n case \"number\": return [\"n\", node.value];\n case \"string\": return [\"s\", node.value];\n case \"scopedvar\": return [\"sv\", node.scope, node.name];\n case \"unary\": return [\"u\", node.op, serialiseAst(node.operand)];\n case \"binary\": return [\"bin\", node.op, serialiseAst(node.left), serialiseAst(node.right)];\n case \"call\": return [\"call\", node.name, ...node.args.map(serialiseAst)];\n case \"flagdelta\": return [\"fd\", node.sign, node.name];\n }\n}\n\n/** Published tagged-tuple AstNode -> in-memory ExprNode. */\nexport function deserialiseAst(node: AstNode): ExprNode {\n switch (node[0]) {\n case \"b\": return { kind: \"bool\", value: node[1] };\n case \"n\": return { kind: \"number\", value: node[1] };\n case \"s\": return { kind: \"string\", value: node[1] };\n case \"sv\": return { kind: \"scopedvar\", scope: node[1], name: node[2] };\n case \"u\": return { kind: \"unary\", op: node[1], operand: deserialiseAst(node[2]) };\n case \"bin\": return { kind: \"binary\", op: node[1], left: deserialiseAst(node[2]), right: deserialiseAst(node[3]) };\n case \"call\": {\n const args = (node.slice(2) as AstNode[]).map(deserialiseAst);\n return { kind: \"call\", name: node[1], args };\n }\n case \"fd\": return { kind: \"flagdelta\", sign: node[1], name: node[2] };\n }\n}\n","// ---------------------------------------------------------------------------\n// Evaluator - walk an ExprNode against an EvalContext, parameterised by Dialect.\n//\n// Operators (binary/unary), short-circuiting, and type-checking are generic.\n// Scope resolution uses the context's scope maps + the Dialect's per-scope\n// missing-property policy. Function calls dispatch to the Dialect's functions.\n//\n// Ported from @storylets/engine (storylets/packages/engine/src/expression.ts),\n// generalised by injecting scopes + functions from the Dialect.\n// ---------------------------------------------------------------------------\n\nimport type { ExprNode, ScalarValue } from \"./ast.js\";\nimport type { Dialect, EvalContext, ScopeResolver } from \"./dialect.js\";\n\nexport class EvalError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"EvalError\";\n }\n}\n\nexport function evaluate(node: ExprNode, ctx: EvalContext, dialect: Dialect): ScalarValue {\n // Per-scope missing-property policy, precomputed once per top-level evaluate.\n const missingPolicy = new Map<string, \"false\" | \"throw\">(\n dialect.scopes.map((s) => [s.token, s.missing ?? \"false\"])\n );\n\n const rec = (n: ExprNode): ScalarValue => {\n switch (n.kind) {\n case \"bool\": return n.value;\n case \"number\": return n.value;\n case \"string\": return n.value;\n\n case \"scopedvar\": {\n const scope = ctx.scopes[n.scope];\n if (scope === undefined) {\n // Scope context absent -> graceful false. (A scope the dialect knows\n // about but the context didn't populate, or an unknown scope.)\n return false;\n }\n // A scope is either a static bag or a host resolver ({ get }). Bag values\n // are always ScalarValue (never functions), so a `get` function reliably\n // distinguishes a resolver.\n const val = typeof (scope as ScopeResolver).get === \"function\"\n ? (scope as ScopeResolver).get(n.name)\n : (scope as Record<string, ScalarValue>)[n.name];\n if (val === undefined) {\n // Property not declared on the present scope. Policy decides: \"false\"\n // for back-compat scopes, \"throw\" for scopes where a missing key is a\n // bug publish-time validation should have caught.\n if (missingPolicy.get(n.scope) === \"throw\") {\n throw new EvalError(`@${n.scope}.${n.name} is not declared on the current ${n.scope}.`);\n }\n return false;\n }\n return val;\n }\n\n case \"call\": {\n // `advance` is the language's own, the first core built-in: the next\n // stage in the argument's ladder, saturating at the last. Core rather\n // than dialect because it IS the quality design's insertion mechanism\n // (an outcome that never names its destination routes through an\n // inserted stage automatically), and every dialect should say it the\n // same way. A dialect that defines its own `advance` wins, for\n // back-compat with any dialect that already had one.\n if (n.name === \"advance\" && !dialect.functions[n.name]) {\n const arg = n.args[0];\n if (n.args.length !== 1 || arg === undefined) {\n throw new EvalError(`advance() takes exactly 1 argument, got ${n.args.length}`);\n }\n const ladder = ladderOf(arg, ctx);\n if (ladder === undefined) {\n throw new EvalError(\"advance() needs a quality reference (@scope.name of a quality property)\");\n }\n const current = stageIndex(rec(arg), ladder, \"advance\");\n return ladder[Math.min(current + 1, ladder.length - 1)]!;\n }\n const def = dialect.functions[n.name];\n if (!def) throw new EvalError(`unknown function '${n.name}'`);\n return def.eval(n.args, { evaluate: rec, ctx });\n }\n\n case \"flagdelta\":\n throw new EvalError(\"flagdelta node is only valid as an argument to a flag-delta function\");\n\n case \"unary\": {\n if (n.op === \"not\") {\n const val = rec(n.operand);\n if (typeof val !== \"boolean\") throw new EvalError(`'not' requires a boolean operand, got ${typeof val}`);\n return !val;\n }\n // neg\n const val = rec(n.operand);\n if (typeof val !== \"number\") throw new EvalError(`unary '-' requires a numeric operand, got ${typeof val}`);\n return -val;\n }\n\n case \"binary\": {\n // Short-circuit operators first\n if (n.op === \"and\") {\n const l = rec(n.left);\n if (typeof l !== \"boolean\") throw new EvalError(`'and' requires boolean operands, left is ${typeof l}`);\n if (!l) return false;\n const r = rec(n.right);\n if (typeof r !== \"boolean\") throw new EvalError(`'and' requires boolean operands, right is ${typeof r}`);\n return r;\n }\n if (n.op === \"or\") {\n const l = rec(n.left);\n if (typeof l !== \"boolean\") throw new EvalError(`'or' requires boolean operands, left is ${typeof l}`);\n if (l) return true;\n const r = rec(n.right);\n if (typeof r !== \"boolean\") throw new EvalError(`'or' requires boolean operands, right is ${typeof r}`);\n return r;\n }\n\n const left = rec(n.left);\n const right = rec(n.right);\n\n // Quality: when either operand REFERENCES a quality (the node carries\n // the scope+name the channel resolves), ordering compares by ladder\n // position and arithmetic is refused. Everything else is untouched,\n // so a context with no channel behaves exactly as before.\n const lLadder = ladderOf(n.left, ctx);\n const rLadder = ladderOf(n.right, ctx);\n const ladder = lLadder ?? rLadder;\n if (ladder !== undefined) {\n if (lLadder && rLadder && !sameLadder(lLadder, rLadder)) {\n if (n.op === \">\" || n.op === \">=\" || n.op === \"<\" || n.op === \"<=\") {\n throw new EvalError(`'${n.op}' compares two different qualities, whose stage orders are unrelated`);\n }\n }\n switch (n.op) {\n case \">\": return stageIndex(left, ladder, \">\") > stageIndex(right, ladder, \">\");\n case \">=\": return stageIndex(left, ladder, \">=\") >= stageIndex(right, ladder, \">=\");\n case \"<\": return stageIndex(left, ladder, \"<\") < stageIndex(right, ladder, \"<\");\n case \"<=\": return stageIndex(left, ladder, \"<=\") <= stageIndex(right, ladder, \"<=\");\n case \"+\": case \"-\": case \"*\": case \"/\":\n throw new EvalError(`'${n.op}' cannot be applied to a quality - a stage is a position, not a number; use advance() to move it`);\n default: break; // == and != fall through to plain value equality\n }\n }\n\n switch (n.op) {\n case \"==\": return valueEquals(left, right);\n case \"!=\": return !valueEquals(left, right);\n case \">\": assertNumbers(left, right, \">\"); return (left as number) > (right as number);\n case \">=\": assertNumbers(left, right, \">=\"); return (left as number) >= (right as number);\n case \"<\": assertNumbers(left, right, \"<\"); return (left as number) < (right as number);\n case \"<=\": assertNumbers(left, right, \"<=\"); return (left as number) <= (right as number);\n case \"+\":\n if (typeof left === \"number\" && typeof right === \"number\") return left + right;\n if (typeof left === \"string\" && typeof right === \"string\") return left + right;\n throw new EvalError(`'+' requires two numbers or two strings, got ${typeof left} and ${typeof right}`);\n case \"-\": assertNumbers(left, right, \"-\"); return (left as number) - (right as number);\n case \"*\": assertNumbers(left, right, \"*\"); return (left as number) * (right as number);\n case \"/\":\n assertNumbers(left, right, \"/\");\n if ((right as number) === 0) throw new EvalError(\"division by zero\");\n return (left as number) / (right as number);\n }\n }\n }\n };\n\n return rec(node);\n}\n\n/**\n * Equality for `==` / `!=`. Primitives compare by value (JS `===`); arrays\n * (the flags value type) compare as SETS: same members, ORDER IRRELEVANT.\n *\n * Plain `===` on arrays would be reference equality - two distinct arrays with\n * the same contents would never be equal, and a fresh array (from a scope read\n * or a function result) would never equal another. Mixed array/non-array\n * operands are unequal, and never an error.\n *\n * Order was significant until 2026-09-01, and that was wrong: a flags value IS\n * a set, and its stored order is an artefact of the order somebody happened to\n * add things in. `set_flags(@f, +a)` then `+b` compared UNEQUAL to the same two\n * flags added the other way round, which is a difference no author can see and\n * none intends. The Storylet Engine papered over it by sorting in `set_flags`,\n * which only holds while every producer sorts: a bundle's declared default, or\n * a host handing a list in, does not.\n *\n * Compared as MULTISETS (sorted copies), so a duplicated flag still counts. A\n * well-formed flags value has no duplicates, but equality should not be the\n * thing that decides what happens if one appears.\n */\nfunction valueEquals(a: ScalarValue, b: ScalarValue): boolean {\n if (Array.isArray(a) || Array.isArray(b)) {\n if (!Array.isArray(a) || !Array.isArray(b)) return false;\n if (a.length !== b.length) return false;\n const x = [...a].sort();\n const y = [...b].sort();\n for (let i = 0; i < x.length; i++) if (x[i] !== y[i]) return false;\n return true;\n }\n return a === b;\n}\n\nfunction assertNumbers(l: ScalarValue, r: ScalarValue, op: string): void {\n if (typeof l !== \"number\" || typeof r !== \"number\") {\n throw new EvalError(`'${op}' requires numeric operands, got ${typeof l} and ${typeof r}`);\n }\n}\n\n// --- quality (design: storylets-new/design/quality.md) -----------------------\n\n/** The ladder behind an operand NODE, when the context's quality channel says\n * it references a quality. Values are plain strings; the node is what carries\n * the (scope, name) the channel needs. */\nfunction ladderOf(node: ExprNode, ctx: EvalContext): readonly string[] | undefined {\n if (node.kind !== \"scopedvar\" || ctx.qualities === undefined) return undefined;\n return ctx.qualities(node.scope, node.name);\n}\n\n/** Index of a stage in a ladder; an unknown stage is an error naming the\n * value, never a silent pass (a drifted save is exactly what lands here). */\nfunction stageIndex(value: ScalarValue, ladder: readonly string[], op: string): number {\n if (typeof value !== \"string\") {\n throw new EvalError(`'${op}' on a quality compares stages, got ${typeof value}`);\n }\n const i = ladder.indexOf(value);\n if (i < 0) throw new EvalError(`\"${value}\" is not a stage of this quality (stages: ${ladder.join(\", \")})`);\n return i;\n}\n\nconst sameLadder = (a: readonly string[], b: readonly string[]): boolean =>\n a.length === b.length && a.every((x, i) => x === b[i]);\n","// ---------------------------------------------------------------------------\n// mulberry32 - the contractual PRNG.\n//\n// A fixed, published algorithm that both product families need and neither\n// owns. It lived in `@storylet-studio/runtime` as prng.ts and inline in\n// `@patterkit/runtime`'s engine.ts, plus separately in three of Patterplay's\n// harnesses, plus a hand port in each of six native runtimes: thirteen copies\n// of forty lines. It belongs here, in the package both families already depend\n// on, for the same reason the evaluator does.\n//\n// All arithmetic is unsigned 32-bit, matching JavaScript's `>>> 0` and\n// Math.imul.\n// ---------------------------------------------------------------------------\n\nexport interface Prng {\n /** One draw in [0, 1); advances the state. */\n next(): number;\n /** The persisted state (a uint32; feed back into makePrng to restore). */\n state(): number;\n}\n\n/**\n * ECMA-262 7.1.6 ToUint32, which is what `seed >>> 0` means.\n *\n * Written out rather than spelled `seed >>> 0` because THIS is the obligation a\n * port in a language without JavaScript's shift semantics has to reproduce, and\n * the shorthand hides it. Patterplay's C++ port cast the seed straight to an\n * integer type, which is undefined behaviour outside that type's range and gave\n * two wrong answers before the parity corpus pinned them.\n */\nexport function toUint32(seed: number): number {\n if (Number.isNaN(seed) || !Number.isFinite(seed)) return 0;\n const modded = Math.trunc(seed) % 4294967296;\n return modded < 0 ? modded + 4294967296 : modded;\n}\n\n/**\n * Seed a generator. The state is UNSIGNED throughout (`>>> 0`, never `| 0`):\n * the two produce identical draws and differ only in the sign of the number a\n * save persists, and Patterplay shipped `| 0` for long enough that over half of\n * all its saves carried a negative state its own native ports could not read\n * back.\n */\nexport function makePrng(seed: number): Prng {\n let s = toUint32(seed);\n return {\n next(): number {\n s = (s + 0x6d2b79f5) >>> 0;\n let t = Math.imul(s ^ (s >>> 15), 1 | s);\n t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n },\n state(): number {\n return s;\n },\n };\n}\n\n/** The contractual shuffle: Fisher-Yates, descending. Runs of one element\n * consume no draws (the loop never executes for length < 2). */\nexport function shuffleInPlace<T>(arr: T[], prng: Prng): void {\n for (let i = arr.length - 1; i > 0; i--) {\n const j = Math.floor(prng.next() * (i + 1));\n [arr[i], arr[j]] = [arr[j]!, arr[i]!];\n }\n}\n","// ---------------------------------------------------------------------------\n// @wildwinter/expr-specificity - public surface.\n//\n// Matched-constraint specificity: score how many atomic constraints in an\n// expression are actively holding it true against the current state. An\n// evaluation-aware walk (unlike a static clause count, an `or`'s score depends\n// on which branch is currently matching). Shared by Storylet Studio (storylet\n// draw priority) and Patter (dialogue best-match), which had independently\n// grown the same algorithm.\n//\n// Built on @wildwinter/expr's `ExprNode`. The host supplies truthiness via an\n// `evalTruthy` closure, so this package stays ignorant of the eval context,\n// the dialect, and the host's truthiness rule - each host keeps its own\n// behaviour while sharing one definition of the walk.\n// ---------------------------------------------------------------------------\n\nimport type { ExprNode } from \"@wildwinter/expr\";\n\n/** A call node, narrowed from the ExprNode union. */\ntype CallNode = Extract<ExprNode, { kind: \"call\" }>;\n\n/**\n * Evaluate an expression subtree to a boolean. Host-bound: the host closes over\n * its own evaluate + eval context + dialect and applies its own truthiness\n * coercion (Storylets' `conditionPasses`, Patter's `truthy`, etc.).\n */\nexport type EvalTruthy = (node: ExprNode) => boolean;\n\n/**\n * A call treated as a conjunction of constraints rather than a single atom, so\n * it contributes its operand count instead of 1. `check_flags` is the built-in\n * example (see {@link CHECK_FLAGS_COUNTING_CALL}).\n */\nexport interface CountingCall {\n /** The function name this rule applies to. */\n name: string;\n /** How many constraints the call contributes when it holds (at least 1). */\n count: (node: CallNode) => number;\n}\n\nexport interface MatchedSpecificityOptions {\n /**\n * Root polarity - the truth value the whole condition must have. Production\n * only ever scores conditions already known eligible, so this defaults to\n * `true` and rarely needs setting.\n */\n want?: boolean;\n /**\n * Calls scored by operand count rather than as a single atom. Defaults to\n * `[CHECK_FLAGS_COUNTING_CALL]`. Supply your own to add or replace rules.\n */\n countingCalls?: readonly CountingCall[];\n}\n\n/**\n * `check_flags(v, f1..fN)` counts as N constraints - an N-ary AND over the flag\n * operands - never fewer than 1. `args[0]` is the flags source, so the operand\n * count is `args.length - 1`.\n */\nexport const CHECK_FLAGS_COUNTING_CALL: CountingCall = {\n name: \"check_flags\",\n count: (node) => Math.max(1, node.args.length - 1),\n};\n\nconst DEFAULT_COUNTING_CALLS: readonly CountingCall[] = [CHECK_FLAGS_COUNTING_CALL];\n\n/**\n * Score how many atomic constraints in `node` are actively holding it true\n * against current state, via `evalTruthy`.\n *\n * The walk carries a polarity flag `want` (\"the truth value this subtree must\n * have for the whole to hold\"), applying De Morgan as it descends:\n * - atom: 1 if its truth matches `want`, else 0\n * - and: under `want`, both must hold -> sum; under `!want`, behaves as or\n * - or: under `want`, strongest branch -> max; under `!want`, behaves as and\n * - not: recurse with `want` flipped\n * - counting call (e.g. check_flags): its operand count when it must hold and\n * does, else the negated rules apply\n *\n * @example\n * // `@x == 5 and @y > 3` with both holding -> 2\n * matchedSpecificity(ast, node => conditionPasses(evaluate(node, ctx)))\n */\nexport function matchedSpecificity(\n node: ExprNode,\n evalTruthy: EvalTruthy,\n opts?: MatchedSpecificityOptions,\n): number {\n const countingCalls = opts?.countingCalls ?? DEFAULT_COUNTING_CALLS;\n return walk(node, opts?.want ?? true, evalTruthy, countingCalls);\n}\n\nfunction walk(\n node: ExprNode,\n want: boolean,\n evalTruthy: EvalTruthy,\n countingCalls: readonly CountingCall[],\n): number {\n if (node.kind === \"binary\" && (node.op === \"and\" || node.op === \"or\")) {\n const l = walk(node.left, want, evalTruthy, countingCalls);\n const r = walk(node.right, want, evalTruthy, countingCalls);\n // De Morgan: an `and` under negation behaves like an `or`, and vice versa.\n const behaveAsAnd = (node.op === \"and\") === want;\n if (behaveAsAnd) return l > 0 && r > 0 ? l + r : 0; // both must hold -> sum\n return Math.max(l, r); // either holds -> strongest branch\n }\n if (node.kind === \"unary\" && node.op === \"not\") {\n return walk(node.operand, !want, evalTruthy, countingCalls);\n }\n if (node.kind === \"call\") {\n const rule = countingCalls.find((c) => c.name === node.name);\n if (rule) {\n const operands = rule.count(node);\n const holds = evalTruthy(node);\n if (want) return holds ? operands : 0;\n return holds ? 0 : 1; // negated: De Morgan -> at least one operand fails -> 1\n }\n }\n // Any other node is an atom worth one constraint when its truth matches want.\n return evalTruthy(node) === want ? 1 : 0;\n}\n","// ---------------------------------------------------------------------------\n// @storylet-studio/dialect - the storylets expression dialect.\n//\n// One dialect drives runtime eval AND publish-time validation (schema 6.1).\n// Five scopes, fixed (Reboot 3); bare `@name` is `@story.name` (schema 6.2,\n// resolved 2026-07-19). Function eval semantics carry from the old engine's\n// storylets-dialect.ts where the function survives (random, check_flags,\n// set_flags); the play-history functions are the new set pinned in schema 6.3.\n// ---------------------------------------------------------------------------\n\nimport { EvalError } from \"@wildwinter/expr\";\nimport type { Dialect, EvalHelpers, ExprNode, ScalarValue } from \"@wildwinter/expr\";\n\n/** turns_since_played / _in when the card / value has never been played. */\nexport const NEVER_PLAYED = 9999;\n\n/**\n * Host callbacks the dialect's functions read from `EvalContext.host`. The\n * runtime supplies these (its PRNG, its play log); the compiler validates\n * without them.\n */\nexport interface StoryletsHost {\n /** One PRNG draw in [0, 1) - the session mulberry32 (schema 3.3). */\n nextRandom(): number;\n /** Plays of the card (gameId) from the play log. */\n countPlayed(card: string): number;\n /** Turns since the card (gameId) last played; NEVER_PLAYED when never. */\n turnsSincePlayed(card: string): number;\n /** Plays of cards belonging to the dimension value (both by gameId). */\n countPlayedIn(dimension: string, value: string): number;\n /** As above; NEVER_PLAYED when never. */\n turnsSincePlayedIn(dimension: string, value: string): number;\n}\n\nconst host = (h: EvalHelpers): Partial<StoryletsHost> =>\n (h.ctx.host ?? {}) as Partial<StoryletsHost>;\n\nconst stringArg = (fn: string, args: ExprNode[], h: EvalHelpers, i: number): string => {\n const v = h.evaluate(args[i]!);\n if (typeof v !== \"string\" || v === \"\") {\n throw new EvalError(`${fn}() argument ${i + 1} must be a non-empty string`);\n }\n return v;\n};\n\n/** Resolve the first argument of check_flags / set_flags to a flag set. */\nconst flagsArg = (fn: string, args: ExprNode[], h: EvalHelpers): string[] => {\n if (args.length === 0) {\n throw new EvalError(`${fn}() requires at least one argument (the flags property)`);\n }\n const v = h.evaluate(args[0]!);\n if (Array.isArray(v)) return v as string[];\n // An unset flags property may surface as false; treat as the empty set\n // (carried from the old dialect). Anything else is a type error.\n if (v === false) return [];\n throw new EvalError(`${fn}() first argument must be a flags property`);\n};\n\nexport const storyletsDialect: Dialect = {\n // A missing property in a PRESENT scope is always an error: every property\n // is declared with a default, so absence means a publish bug, a drifted\n // save, or a foreign scope the host never fed (schema 6.2).\n scopes: [\n { token: \"story\", missing: \"throw\" },\n { token: \"world\", missing: \"throw\" },\n { token: \"box\", missing: \"throw\" },\n { token: \"deck\", missing: \"throw\" },\n { token: \"hand\", missing: \"throw\" },\n ],\n defaultScope: \"story\",\n functions: {\n random: {\n minArgs: 2, maxArgs: 2, returnType: \"number\",\n eval(args: ExprNode[], h: EvalHelpers): ScalarValue {\n if (args.length !== 2) throw new EvalError(\"random(a, b) requires exactly 2 arguments\");\n const nextRandom = host(h).nextRandom;\n if (!nextRandom) throw new EvalError(\"random() called without a PRNG in context\");\n const a = h.evaluate(args[0]!);\n const b = h.evaluate(args[1]!);\n if (typeof a !== \"number\" || typeof b !== \"number\") {\n throw new EvalError(\"random(a, b) arguments must be numbers\");\n }\n if (!Number.isInteger(a) || !Number.isInteger(b)) {\n throw new EvalError(\"random(a, b) arguments must be integers\");\n }\n const lo = Math.min(a, b);\n const hi = Math.max(a, b);\n return Math.floor(nextRandom() * (hi - lo + 1)) + lo;\n },\n },\n check_flags: {\n minArgs: 1, returnType: \"boolean\", flagDeltaArgs: true,\n eval(args: ExprNode[], h: EvalHelpers): ScalarValue {\n const flags = flagsArg(\"check_flags\", args, h);\n for (let i = 1; i < args.length; i++) {\n const arg = args[i]!;\n if (arg.kind !== \"flagdelta\") {\n throw new EvalError(\"check_flags() flag args must be +flagName or -flagName\");\n }\n if (arg.sign === \"+\" ? !flags.includes(arg.name) : flags.includes(arg.name)) {\n return false;\n }\n }\n return true;\n },\n },\n set_flags: {\n minArgs: 1, returnType: \"flags\", flagDeltaArgs: true,\n eval(args: ExprNode[], h: EvalHelpers): ScalarValue {\n const result = [...flagsArg(\"set_flags\", args, h)];\n for (let i = 1; i < args.length; i++) {\n const arg = args[i]!;\n if (arg.kind !== \"flagdelta\") {\n throw new EvalError(\"set_flags() flag args must be +flagName or -flagName\");\n }\n if (arg.sign === \"+\") {\n if (!result.includes(arg.name)) result.push(arg.name);\n } else {\n const idx = result.indexOf(arg.name);\n if (idx >= 0) result.splice(idx, 1);\n }\n }\n // Sorted so a SAVE is deterministic: the same flags reached by different routes\n // serialise to the same bytes, which keeps save diffs and cross-runtime byte\n // comparisons stable. It is no longer what makes equality work - flags compare\n // as a SET since 2026-09-01 - so this is now about the stored form only, and\n // Patterplay not sorting is a difference that costs nothing.\n return result.sort();\n },\n },\n count_played: {\n minArgs: 1, maxArgs: 1, returnType: \"number\",\n eval(args: ExprNode[], h: EvalHelpers): ScalarValue {\n const card = stringArg(\"count_played\", args, h, 0);\n const fn = host(h).countPlayed;\n if (!fn) throw new EvalError(\"count_played() called without a play log in context\");\n return fn(card);\n },\n },\n turns_since_played: {\n minArgs: 1, maxArgs: 1, returnType: \"number\",\n eval(args: ExprNode[], h: EvalHelpers): ScalarValue {\n const card = stringArg(\"turns_since_played\", args, h, 0);\n const fn = host(h).turnsSincePlayed;\n if (!fn) throw new EvalError(\"turns_since_played() called without a play log in context\");\n return fn(card);\n },\n },\n count_played_in: {\n minArgs: 2, maxArgs: 2, returnType: \"number\",\n eval(args: ExprNode[], h: EvalHelpers): ScalarValue {\n const dimension = stringArg(\"count_played_in\", args, h, 0);\n const value = stringArg(\"count_played_in\", args, h, 1);\n const fn = host(h).countPlayedIn;\n if (!fn) throw new EvalError(\"count_played_in() called without a play log in context\");\n return fn(dimension, value);\n },\n },\n turns_since_played_in: {\n minArgs: 2, maxArgs: 2, returnType: \"number\",\n eval(args: ExprNode[], h: EvalHelpers): ScalarValue {\n const dimension = stringArg(\"turns_since_played_in\", args, h, 0);\n const value = stringArg(\"turns_since_played_in\", args, h, 1);\n const fn = host(h).turnsSincePlayedIn;\n if (!fn) throw new EvalError(\"turns_since_played_in() called without a play log in context\");\n return fn(dimension, value);\n },\n },\n },\n};\n","// ---------------------------------------------------------------------------\n// @storylet-studio/model - the shape source-of-truth.\n//\n// Transcribes design/storylets-schema.md (bundle, save) and\n// design/storylets-source.md (shards). Entity shapes are generic over their\n// expression representation E: source shards use plain `src` strings\n// (Card<string>), the compiled bundle uses { src, ast } envelopes\n// (Card<Expression>). No behaviour lives here.\n// ---------------------------------------------------------------------------\n\nimport type { Expression, ScalarValue } from \"@wildwinter/expr\";\n\nexport type { Expression, ScalarValue, AstNode } from \"@wildwinter/expr\";\n\n// --- shared declarations -----------------------------------------------------\n\nexport type PropertyType = \"boolean\" | \"number\" | \"string\" | \"enum\" | \"flags\" | \"quality\";\n\n/** A property declaration: @world / @story / @box / @deck / tag / hand\n * state. A declared property always has a value (`default` is required);\n * referencing an undeclared property is a publish-time error. */\nexport interface PropertyDecl {\n name: string;\n type: PropertyType;\n default: ScalarValue;\n values?: string[];\n /**\n * A quality's ordered ladder of stage names (design/quality.md). Order IS\n * the meaning: `>=` compares by position here, and `advance()` steps along\n * it. The one order-semantic list in the format, accepted as such: it is a\n * declaration, and inserting a stage mid-ladder is the design's whole point.\n */\n stages?: string[];\n /**\n * `@world` only. `false` makes the property read-only TO THE STORY: a\n * condition may read it, an outcome that writes it is a compile error. The\n * game still moves it through its resolver; this is the story's statement\n * of intent, not the game's policy. Mirrors Patter's `HostScopeDecl.writable`\n * name for name (Reboot.md 10, ruled 2026-09-03). Ignored on every other\n * scope. Absent = writable.\n */\n writable?: boolean;\n /**\n * The sharing axis (design/flows.md, Patter's flag adopted): is this\n * property's value one world value across all flows, or a copy per flow?\n * It does NOT change reference syntax - sharing is set here, on the\n * declaration, not by a different scope token. Absent = the scope\n * default: `@story` shared; box, deck, hand and tag properties per-flow.\n * On a `@world` declaration the flag is a validation error - `@world` is\n * the game's own state, always engine-level, never per-flow.\n */\n shared?: boolean;\n purpose?: string;\n}\n\n/** A card-template field (box-defined). Data for the host; the engine never\n * interprets fields and they are not addressable from expressions. */\nexport interface FieldDecl {\n name: string;\n type: PropertyType;\n default: ScalarValue;\n values?: string[];\n purpose?: string;\n}\n\n/** Cooldown policy, in turns (schema 3.4). */\nexport type RedrawPolicy = \"always\" | \"never\" | number;\n\n// --- gameId derivation (Patter's effectiveGameId, adopted 2026-07-20) --------\n//\n// gameId is the renameable host-facing address; it is OPTIONAL in source and\n// derived from the entity's title until the author pins one, so a rename of\n// the title carries the address with it (no \"new-deck\" stuck placeholder).\n// The compiler fills a concrete gameId into every bundle entity.\n\n/** Slugify a human label into a filename- / address-safe gameId. */\nexport function gameIdify(text: string): string {\n return text.toLowerCase().replace(/['’]/g, \"\")\n .replace(/[^a-z0-9-]+/g, \"-\").replace(/-+/g, \"-\").replace(/^-+|-+$/g, \"\");\n}\n\nexport function isValidGameId(gameId: string): boolean {\n return /^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/.test(gameId);\n}\n\n// --- property names (adopted 2026-08-18, with Patter, from one rule) ---------\n//\n// Design and argument: `@wildwinter/app-shell` src/property-names.ts. Not house\n// style: the rule is what `@wildwinter/expr` can parse. Its lexer takes an\n// identifier as /[a-zA-Z_][a-zA-Z0-9_]*/ and folds it to lower case, so\n// `@story.isNight` reaches a property called `isnight`, `@story.9lives` and\n// `@story.not` are parse errors, and `@story.is-night` is not an error at all: it\n// compiles to `@story.is` MINUS the string \"night\". That last one is why the rule\n// is enforced rather than trusted - it is the only violation that silently means\n// something else.\n//\n// Here rather than behind an import of the UI kit because the compiler, the CLI\n// and the embedded runtime resolve state by these. `property-name-parity.test.ts`\n// holds them to the shell's, and `property-name-grammar.test.ts` holds them to the\n// parser they came from.\n\n/** The words `@wildwinter/expr` lexes as keywords, so no property may be called one. */\n// A legal property NAME is a fact about the expression language, not about this\n// model: `not` is reserved because the tokeniser reads it as an operator. Both\n// families kept their own copy of the rule AND of the keyword list, a list\n// neither owned. @wildwinter/expr derives the list from its own tokeniser, so a\n// keyword added there cannot leave a stale copy here.\n//\n// Re-exported so nothing that imports them has to move.\nexport {\n propertyNameify, isValidPropertyName, isCaseOnlyPropertyName, RESERVED_PROPERTY_NAMES,\n} from \"@wildwinter/expr\";\n/** The effective address: a pinned gameId, else derived from the title, else\n * the immutable id (so there is always something addressable). */\nexport function effectiveGameId(entity: { gameId?: string; title?: string; id: string }): string {\n const pinned = entity.gameId?.trim();\n if (pinned) return pinned;\n const fromTitle = entity.title ? gameIdify(entity.title) : \"\";\n return fromTitle || entity.id;\n}\n\n/**\n * The first free gameId of the form `base`, `base-2`, `base-3`, ... not already\n * in `taken`.\n *\n * A gameId is API - `deal()` and the play log speak it - so a name minted for a\n * new or duplicated entity must not collide with an existing one. This lived in\n * two copies, one in the editor and one in the CLI's kit scaffolder, character\n * for character the same; two copies of an addressing rule can drift, and a\n * drift here means the same act produces different addresses depending on which\n * program did it. It is here, beside `gameIdify`, because both programs need it\n * and no UI touches it.\n */\nexport function freeGameId(base: string, taken: ReadonlySet<string>): string {\n let gameId = base;\n for (let n = 2; taken.has(gameId); n++) gameId = `${base}-${n}`;\n return gameId;\n}\n\n/**\n * The first free TITLE of the form `base`, `base 2`, `base 3`, ... whose\n * derived gameId is not already in `taken`.\n *\n * The sibling of `freeGameId` for the \"New box\", \"New deck\" case, where the\n * author is given a title and the address follows from it. The dedupe is on the\n * DERIVED gameId rather than the title, because two titles that slug to one\n * address are the collision that matters.\n */\n/**\n * An id-sorted collection in the order a person should SEE it.\n *\n * Storage is sorted by immutable id (source rule 5) so that two authors adding\n * one item each never touch the same line. That makes array position useless as\n * display order, so the order the author arranged rides in a sparse `order`\n * field, with position as the fallback and id to break a tie.\n *\n * One definition, because this rule has to give the same answer in four places\n * that a reader compares side by side: the compiler (what the bundle carries),\n * the editor (what the card document lists), the exports, and Find. When they\n * disagree, the editor shows one order and the game plays another.\n */\nexport function byDisplayOrder<T extends { id?: string; order?: number }>(items: readonly T[]): T[] {\n return items\n .map((x, i) => ({ x, key: x.order ?? i, i }))\n .sort((a, b) => a.key - b.key || ((a.x.id ?? \"\") < (b.x.id ?? \"\") ? -1 : (a.x.id ?? \"\") > (b.x.id ?? \"\") ? 1 : a.i - b.i))\n .map((e) => e.x);\n}\n\nexport function freeTitle(base: string, taken: ReadonlySet<string>): string {\n let title = base;\n for (let n = 2; taken.has(gameIdify(title)); n++) title = `${base} ${n}`;\n return title;\n}\n\n// --- entities (generic over expression representation E) ---------------------\n\nexport interface Outcome<E> {\n id: string;\n gameId?: string;\n title?: string;\n purpose?: string;\n /** Authored display order (sparse; one without it falls back to its id\n * position). Unlike `Card.order` this one IS compiled into the bundle:\n * which option is offered first is authorial, and a host reading a dealt\n * card's outcomes is building the player's menu. */\n order?: number;\n /** Gating; availability is always evaluated against current state. */\n condition?: E;\n /** Target (\"@scope.name\") -> expression; all right-hand sides evaluate\n * against pre-play state (schema 3.7). */\n changes: Record<string, E>;\n}\n\nexport interface Card<E> {\n id: string;\n gameId?: string;\n title?: string;\n purpose?: string;\n /** Authored display order within the deck (sparse; a card without one falls\n * back to its id position). Merges as a per-card value, so id-sorted storage\n * stays merge-clean (Reboot 7.4); dropped from the compiled bundle. */\n order?: number;\n condition?: E;\n /** Default 0; an expression must evaluate to a number. */\n priority: number | E;\n redraw: RedrawPolicy;\n /** Tags: tag group id -> tag ids. An absent group is a wildcard (matches\n * any binding of it), except the reserved home group, whose default\n * inverts (schema 2.4). Editors and fixtures speak gameIds; stored\n * references are ids. */\n tags?: Record<string, string[]>;\n /** How many hands may hold this card at once (schema 3.5): integer >= 1,\n * default 1. One copy is the exclusivity rule; copies: N is the\n * deliberate opt-out for interchangeable filler. Always counted WITHIN a\n * flow, whether or not the card is shared. */\n copies?: number;\n /** Scarcity across flows (design/shared-scarcity.md). Absent takes the\n * deck's flag; set here it overrides the deck, so a single unique card can\n * stay in the content it belongs to. A shared card's claims count every\n * flow's board, and a shared `redraw: \"never\"` is spent for everyone the\n * first time anyone plays it.\n *\n * A finite `redraw` stays PER FLOW even when shared: a cooldown is an\n * absolute turn of the card's box clock and clocks are per flow, so\n * \"3 turns of whose clock?\" has no answer. A world-wide timer is a @world\n * question, not an engine one (shared-scarcity 9.3.3). */\n shared?: boolean;\n /** The world cap: how many hands ACROSS EVERY FLOW may hold this at once.\n * Read only when the card is shared, and defaults to `copies`, so the\n * common case writes one number and \"five in the world, one to a customer\"\n * is `copies: 1, sharedCopies: 5`. */\n sharedCopies?: number;\n /** Card-template data: field name -> value, validated at publish. */\n fields?: Record<string, ScalarValue>;\n outcomes: Outcome<E>[];\n}\n\nexport interface Deck<E> {\n id: string;\n gameId?: string;\n title?: string;\n purpose?: string;\n /** The deck gate, evaluated once per draw in the draw's environment. */\n condition?: E;\n /** This pile is scarce across flows (design/shared-scarcity.md): every card\n * in it is shared unless the card says otherwise. The container is where\n * Patter puts its own shared-memory flag, and the deck is our container. */\n shared?: boolean;\n properties: PropertyDecl[];\n cards: Card<E>[];\n}\n\nexport interface Tag {\n id: string;\n gameId?: string;\n /**\n * This tag's own starting values for properties its GROUP declares\n * (design/hand-typing.md). The group says what the property IS; a tag says\n * only where it starts, so \"every zone has a haunting level\" is written once\n * and \"the cave starts at 2\" is written where it belongs.\n *\n * A name here that the group does not declare is an error: it would be a\n * value for nothing.\n */\n values?: Record<string, ScalarValue>;\n /** Authored display order (sparse; one without it falls back to its id\n * position). Merges as a per-item value, so id-sorted storage stays\n * merge-clean (Reboot 7.4). */\n order?: number;\n properties?: PropertyDecl[];\n /** Template-of-play extras (e.g. spatial geometry). Source only: preserved\n * in shards, never compiled into the bundle. */\n templates?: Record<string, unknown>;\n}\n\n/** A named axis for cross-cutting cards (schema 2.4, renamed from\n * Dimension). Tags are declared, not freeform. */\nexport interface TagGroup {\n id: string;\n gameId?: string;\n purpose?: string;\n /**\n * A property reference (`\"@story.act\"`) whose value names a tag in this group\n * by gameId. The engine reads it at every ask and binds the group, exactly as\n * if the asking hand had chosen that tag; a hand's own binding wins.\n *\n * For an axis driven by STATE rather than by place: acts, chapters, a\n * difficulty band. Without it, only a hand can bind a group, so such an axis\n * had nowhere to gate and every card needed its own condition.\n *\n * A reference rather than an expression on purpose (design/where-and-\n * selectors.md Part B): a computed binding belongs in a property the outcomes\n * maintain, and an expression here would make this type generic for no gain.\n */\n boundBy?: string;\n /**\n * What omitting this group means for a card. Default false: omission is a\n * wildcard, so the card matches whatever the group is bound to. True inverts\n * it, so a card that names no tag here is unavailable wherever the group IS\n * bound (and unaffected where it is not).\n *\n * `place` is the built-in instance of this pair: bound to the asking hand,\n * and inverted per card rather than per group.\n */\n required?: boolean;\n /** Authored display order (sparse; one without it falls back to its id\n * position). Merges as a per-item value, so id-sorted storage stays\n * merge-clean (Reboot 7.4). */\n order?: number;\n /**\n * Properties EVERY tag in this group has (design/hand-typing.md). The\n * declaration lives here and each tag carries only its own starting value in\n * `Tag.values`, which is the separation the format was missing: a tag's own\n * `properties` entry has to restate the type on every tag purely in order to\n * say the value, and a tag added later silently arrives without it.\n *\n * Compiled by FLATTENING onto each tag, so the bundle keeps its per-tag\n * shape and no runtime, port or bundle schema changes: source is where the\n * author works and where merges happen, the bundle is a compiled artefact\n * that can afford to be explicit.\n *\n * A tag may still declare its own `properties` for a group whose tags\n * genuinely differ. Declaring the same NAME both ways is an error.\n */\n properties?: PropertyDecl[];\n tags: Tag[];\n /** Template-of-play extras for the GROUP, the same bag its tags carry: this is\n * where a group is marked spatial and where that template keeps its own\n * group-level configuration. Source only, preserved but never compiled.\n *\n * A bag rather than a `spatial: true` flag because the marker and the\n * configuration are one thing (see model/spatial.ts), and because core is not\n * meant to grow a field per template of play. */\n templates?: Record<string, unknown>;\n}\n\n/** The reserved tag group (schema 2.4): present in every box without\n * declaration, its tags the box's hand ids. Every hand implicitly binds it to\n * itself; a card that names a place is available only at that place.\n *\n * Called `place` rather than `home` since 2026-08-21: one word for one thing\n * across the format, the editor and the exports. \"Where\" is the QUESTION a\n * card answers (at a place, or anywhere in a region); \"place\" is the direct\n * half of that answer. `home` was a metaphor an author had to learn, and it\n * leaked into hand-edited shards and the docs. */\nexport const PLACE_GROUP = \"place\";\n\n/** A declared kind of hand (schema 2.6): live-inherited, author-side only,\n * never called from game code. One condition governs every instance. */\nexport interface HandTemplate<E> {\n id: string;\n gameId?: string;\n title?: string;\n purpose?: string;\n /** Authored display order (sparse; one without it falls back to its id\n * position). Merges as a per-item value, so id-sorted storage stays\n * merge-clean (Reboot 7.4). */\n order?: number;\n\n /** Fixed tag bindings: tag group id -> tag id. */\n bindings?: Record<string, string>;\n /** The holes: tag group ids each instance fills (one tag each). */\n chooses?: string[];\n /** Shared availability condition, ANDed in (schema 3.1); evaluated per\n * instance against that instance's composed @hand. */\n condition?: E;\n /** Default slot cap. */\n slots: number | \"unbounded\";\n /** Declared @hand state every instance carries. */\n properties: PropertyDecl[];\n}\n\n/** A standalone hand's inline rule (schema 2.6): owned by the hand. */\nexport interface HandRule<E> {\n bindings?: Record<string, string>;\n condition?: E;\n slots: number | \"unbounded\";\n}\n\n/** A hand (schema 2.6): a template instance (template + chosen) or a\n * standalone hand (rule). Exactly one of template / rule. Fully concrete:\n * deal is name-only. */\nexport interface Hand<E> {\n id: string;\n /** The name deal() is called with; a rename is a breaking change\n * (Reboot 7.4). */\n gameId?: string;\n title?: string;\n purpose?: string;\n /** Hand template id (not gameId). */\n template?: string;\n /** Template instances: tag group id -> tag id, one per `chooses` hole. */\n chosen?: Record<string, string>;\n /** Standalone hands: the inline rule. */\n rule?: HandRule<E>;\n /** Override; defaults to the template's / rule's slots. The ONLY template\n * field an instance may override (schema 2.6). */\n slots?: number;\n /** Standalone hands' own @hand state (template instances inherit the\n * template's declarations). */\n properties?: PropertyDecl[];\n /** Authored display order within the box (sparse; authoring-only, never\n * compiled into the bundle - the compiler's explicit field list drops it). */\n order?: number;\n /** Template-of-play extras (e.g. a spatial pin). Source only. */\n templates?: Record<string, unknown>;\n}\n\nexport interface Box<E> {\n id: string;\n gameId?: string;\n title?: string;\n purpose?: string;\n /** The only per-box ranking policy (Reboot 2.2). */\n ranking: { specificity: boolean };\n /** The card template: what every card in this box carries. */\n fields: FieldDecl[];\n properties: PropertyDecl[];\n tagGroups: TagGroup[];\n decks: Deck<E>[];\n handTemplates: HandTemplate<E>[];\n hands: Hand<E>[];\n}\n\n// --- the compiled bundle (.storyletsc) ---------------------------------------\n\nexport const BUNDLE_SCHEMA = \"storylets/bundle@0\";\n\n/** Binds bundles to shards (staleness gate) and saves to bundles. */\nexport interface BundleContent {\n project: string;\n version: string;\n /** hash32 over the canonical source shards (schema 2.8). */\n hash: string;\n}\n\nexport interface BundleSettings {\n playAdvancesTurns: number;\n}\n\n/**\n * A map that a bundle was asked to carry: one spatial tag group's geometry,\n * flattened for a host to draw (design/graphical-views.md 2, \"The map MAY ship\").\n *\n * INERT PAYLOAD. Nothing in the engine reads this and nothing ever will: the\n * runtime deals in tag names. It is here so a host that wants an in-game map does\n * not have to invent its own export, and it is absent unless the project asked\n * for it (`export.map`), so a build that does not want a map carries no bytes.\n *\n * GAME IDS throughout, never internal ids. Internal ids are authoring identity\n * and mean nothing outside the project; a host matches these against the same\n * names it passes to `peek`. There is nothing here to strip either, which is why\n * `metadata: \"stripped\"` needs no special case: no titles, no purposes.\n *\n * Sites are deliberately NOT here. A site is where an author parked a hand while\n * working, held in the view sidecar precisely because it is not content, and a\n * host that wants to place a hand already has its zone from the compiled binding.\n */\nexport interface BundleMap {\n /** The owning box, by gameId (tag groups are box-scoped). */\n box: string;\n /** The tag group this is a map of, by gameId. */\n group: string;\n /** One entry per zone that has been drawn; a tag with no polygon is not a\n * place yet and is left out rather than shipped as an empty shape. */\n zones: { tag: string; polygon: ViewPoint[] }[];\n /** Background pictures, back to front, as bundle-relative paths. Hidden ones\n * do not ship: what an author put away is not something to spring on a host. */\n backgrounds?: BundleBackground[];\n}\n\n/** One shipped picture. `locked` and `hidden` are authoring state and do not\n * travel; the draw order is the array order. */\nexport interface BundleBackground {\n /** Where the file sits relative to the bundle (\"assets/<box>/<file>\"). */\n file: string;\n x: number;\n y: number;\n width: number;\n height: number;\n opacity?: number;\n}\n\nexport interface Bundle {\n schema: typeof BUNDLE_SCHEMA;\n content: BundleContent;\n metadata: \"full\" | \"stripped\";\n settings: BundleSettings;\n world: {\n properties: PropertyDecl[];\n /** ScopeRegistrySpec (@wildwinter/scoperegistry): the owned/foreign\n * split. Absent = engine-owned @world (standalone play). */\n registry?: unknown;\n };\n story: {\n properties: PropertyDecl[];\n };\n boxes: Box<Expression>[];\n /** Maps, when the project asked for them. Absent is the normal state. */\n maps?: BundleMap[];\n}\n\n// --- the save envelope --------------------------------------------------------\n\nexport const SAVE_SCHEMA = \"storylets/save@1\";\n\nexport interface PlayRecord {\n /** Card and outcome by gameId (feeds the play-history functions). */\n card: string;\n outcome: string;\n turn: number;\n}\n\n/** A property bag: name -> value. */\nexport type PropertyBag = Record<string, ScalarValue>;\n\n/** The per-scope property partitions one side of the sharing flag holds:\n * a save carries one of these for the shared values and one per flow\n * (design/flows.md). NO world key, in either: @world is the game's own\n * state, resolved through the world resolver and saved by whoever owns\n * it - \"host saves its container once, each engine saves its own\n * envelope\" (engine-runtimes.md 3.1). */\nexport interface PropsPartition {\n story: PropertyBag;\n box: Record<string, PropertyBag>;\n deck: Record<string, PropertyBag>;\n hand: Record<string, PropertyBag>;\n /** Tag state, keyed by tag id. */\n value: Record<string, PropertyBag>;\n}\n\n/** One flow's snapshot inside the envelope (schema 4). */\nexport interface FlowSave {\n /** The per-flow property partitions. */\n props: PropsPartition;\n /** Per-box turn counters, keyed by box id (schema 3.4) - per flow: there\n * is deliberately no global turn. */\n turns: Record<string, number>;\n /** mulberry32 state, uint32 (schema 3.3), per flow. */\n prng: number;\n /** Absolute next-eligible turn (of the card's box's clock) per card id;\n * MAX_SAFE_INTEGER = never (deliberately not Infinity, which\n * JSON-serialises to null). */\n cooldowns: Record<string, number>;\n /** Hand contents (card ids, in dealt order), keyed by hand id. The claims\n * ledger is derived from this (schema 3.5). */\n board: Record<string, string[]>;\n playLog: PlayRecord[];\n}\n\n/** The whole engine, one envelope: the shared partitions once, then every\n * live flow keyed by its id - Patter's shape (one shared blob + N flow\n * blobs; multi-flow and save/load are the same feature). */\n/** The engine's half of a save: what every flow shares. Properties, and the\n * cards a shared `redraw: \"never\"` has taken out of the world for good\n * (design/shared-scarcity.md). Claims are NOT here: they are derived from the\n * live boards, and each flow's board rides its own blob. */\nexport interface SharedSave {\n props: PropsPartition;\n /** Card ids, sorted, so a save is byte-stable for a diff. */\n spent: string[];\n}\n\nexport interface SaveEnvelope {\n schema: typeof SAVE_SCHEMA;\n content: BundleContent;\n shared: SharedSave;\n flows: Record<string, FlowSave>;\n}\n\n/** The .storyletsave FILE: the HOST's file, not the engine's - the engine's\n * envelope plus, when the host keeps one, its @world container. This is\n * \"host saves its container once, each engine saves its own envelope\"\n * folded into one file for the single-host case; the ENGINE never reads or\n * writes `world` (loadGame takes the envelope alone). */\nexport const SAVEFILE_SCHEMA = \"storylets/savefile@1\";\n\nexport interface SaveFile {\n schema: typeof SAVEFILE_SCHEMA;\n engine: SaveEnvelope;\n /** The host's @world values, saved and restored by the host. */\n world?: PropertyBag;\n}\n\n// --- source shards (design/storylets-source.md) --------------------------------\n\n/** The project folder: a macOS package, a plain folder elsewhere. */\nexport const PROJECT_FOLDER_EXTENSION = \".storylets\";\n/** The compiled bundle (strict JSON; generated, never hand-edited). */\nexport const BUNDLE_EXTENSION = \".storyletsc\";\n\n/**\n * Where a shipped background sits, relative to the bundle file.\n *\n * One function so the compiler (which writes the name into the bundle) and the\n * export op (which writes the bytes) cannot drift apart: a path agreed in two\n * places is a path that eventually disagrees. Per BOX, because two boxes may\n * each have their own `plan.png` and a build must not silently keep one of them.\n */\nexport const bundleAssetPath = (boxGameId: string, file: string): string =>\n `assets/${boxGameId}/${file}`;\n/** Per-type shard extensions, JSON5 inside (source doc section 2). */\nexport const SHARD_EXTENSIONS = {\n project: \".storyletproj\",\n box: \".storyletbox\",\n tags: \".storylettags\",\n hands: \".storylethands\",\n deck: \".storyletdeck\",\n /** The arrangement layer: where things SIT, never what they are. Its own shard\n * because positions churn (an afternoon of tidying a canvas touches every\n * card) and content does not, so a designer arranging and a writer editing\n * never collide on one file (design/graphical-views.md section 1.2). */\n view: \".storyletview\",\n /** Threaded comments: content-ADJACENT, so neither in a content shard (a\n * writer's deck edit must not conflict with a reviewer's comment) nor in the\n * arrangement sidecar (this is not where anything sits). One per box,\n * id-keyed (design/annotation.md). Documentation NOTES used to share this\n * file and were retired: `purpose` already says why a thing exists, and\n * Patterpad's typed routing has no destination here. */\n notes: \".storyletnotes\",\n} as const;\n\nexport const PROJECT_SCHEMA = \"storylets/project@0\";\nexport const BOX_SCHEMA = \"storylets/box@0\";\nexport const TAGS_SCHEMA = \"storylets/tags@0\";\nexport const HANDS_SCHEMA = \"storylets/hands@0\";\nexport const DECK_SCHEMA = \"storylets/deck@0\";\nexport const VIEW_SCHEMA = \"storylets/view@0\";\n/** The comment sidecar's schema. Still called \"notes\" on disk: the file already\n * held both, and renaming it would break every project for no gain. */\nexport const NOTES_SCHEMA = \"storylets/notes@0\";\n\n/** A point in a canvas's own coordinates. */\nexport interface ViewPoint {\n x: number;\n y: number;\n}\n\n/**\n * Canvas furniture: what an author draws AROUND the content to make sense of it\n * (design/graphical-views.md 3, \"Frames and sites\").\n *\n * Both canvases carry the same thing, which is why they share a type: a node\n * canvas and a map are different views of different material, but \"put a box\n * round this lot and call it act two\" is the same thought on either.\n *\n * It lives in the view sidecar because it is ARRANGEMENT. Nothing here is\n * content: no runtime reads it, no bundle carries it, and deleting the sidecar\n * loses only the drawing. Threaded comments are the\n * other thing entirely - they attach to entities and they travel - but a canvas\n * DRAWS their markers, while owning none of them.\n */\nexport interface CanvasFurniture {\n /** Titled areas behind the content, back to front (see `stacked`).\n *\n * There was a second kind, a `stickies` list, retired on 2026-08-10\n * (design/annotation.md): a dropped comment marker does the same job in a\n * fraction of the space, and an annotation that takes as much room as the\n * thing it is about is a bad trade on a canvas. */\n frames?: Frame[];\n}\n\n/**\n * A titled area behind a group of things: Unreal's comment box.\n *\n * Deliberately dumb about what is inside it. It has no membership list and\n * computes none: a frame is a thing an author DREW, and the cards under it are\n * whatever happens to be under it now. That is what keeps it honest when content\n * moves, and it is the same reasoning that keeps a zone's sites out of the map's\n * sidecar.\n */\nexport interface Frame extends ViewPoint {\n id: string;\n w: number;\n h: number;\n /** Shown in the frame's bar, and the handle it is dragged by. */\n title?: string;\n /** One of the furniture palette's names (see `FURNITURE_COLOURS`); the theme\n * decides what that looks like, so a frame does not carry a hex value that\n * would fight the palette on the day somebody switches theme. */\n colour?: string;\n /** Place in the frame band (sparse, `stacked`). Frames can nest. */\n z?: number;\n}\n\n/** The furniture palette: names, not colours. The theme maps them, so the same\n * shard reads correctly on linen and on baize. */\nexport const FURNITURE_COLOURS = [\"paper\", \"amber\", \"sage\", \"sky\", \"rose\", \"slate\"] as const;\nexport type FurnitureColour = typeof FURNITURE_COLOURS[number];\n\n/** One deck's node canvas: where its cards sit, and the furniture around them.\n * Sparse throughout. A card with no entry lays out by default, and an entry for\n * a card that no longer exists is inert, so there is no referential integrity to\n * maintain against content that moves underneath. */\nexport interface DeckCanvas extends CanvasFurniture {\n /** Keyed by CARD id. */\n cards?: Record<string, ViewPoint>;\n}\n\n/** The box's map: where its hands sit in space, and the furniture around them. */\nexport interface BoxMap extends CanvasFurniture {\n /** Keyed by HAND id. WHERE a site is, and nothing else.\n *\n * Which zone it is IN is not recorded here, and deliberately (2026-08-06,\n * with the rebinding drag): a hand that binds a zone already says so in its\n * own shard, as `chosen` or as a rule binding, and that is the truth the\n * runtime deals from. A copy here could only ever go on to disagree with it,\n * and a site whose recorded zone contradicts the hand it stands for would be\n * the most misleading thing on the map.\n *\n * Called `pins` until 2026-08-10 (design/annotation.md). No compatibility\n * branch: the only projects that exist are the examples in this repo, and they\n * were edited. */\n sites?: Record<string, ViewPoint>;\n}\n\n/** The arrangement layer for one box: where things SIT, never what they are.\n *\n * Its own shard on purpose (design/graphical-views.md section 1.2). Positions\n * churn, content does not: an afternoon of tidying a canvas touches every card,\n * and if that lived in the deck shard then a designer arranging and a writer\n * editing card text would collide on one file all day, while a content review\n * would be full of coordinates. Keyed by id throughout so the existing merge\n * engine handles two designers rearranging different things without a conflict.\n *\n * Source-only. It never reaches the compiled bundle, exactly as `order` does\n * not: the compiler reads the fields it names and this is not among them. */\nexport interface ViewShard {\n schema: typeof VIEW_SCHEMA;\n /** Keyed by DECK id: one node canvas each. */\n canvases?: Record<string, DeckCanvas>;\n map?: BoxMap;\n}\n\n/** A coverage input driver: during a coverage run the harness feeds a\n * host-seam property (`@world.x`) values from `values`, so content gated on\n * external state gets exercised (Patter's coverageDrivers, carried whole). */\nexport interface CoverageDriver {\n /** \"initial\": set once as each playthrough starts. \"recurring\": re-rolled\n * per turn at the cadence, so one run passes through several states. */\n kind: \"initial\" | \"recurring\";\n /** For recurring drivers: how often to re-roll per turn (default \"sometimes\"). */\n cadence?: \"rarely\" | \"sometimes\" | \"often\";\n /** The pool the harness picks from (uniform). Empty = inert. */\n values: ScalarValue[];\n}\n\n/** Authoring-side coverage configuration (never compiled into the bundle). */\nexport interface CoverageConfig {\n /** Property drivers, keyed by ref (\"@world.danger\"). */\n drivers?: Record<string, CoverageDriver>;\n\n}\n\nexport interface ProjectShard {\n schema: typeof PROJECT_SCHEMA;\n project: {\n id: string;\n name: string;\n version: string;\n };\n settings: BundleSettings;\n /** Coverage drivers + argument domains (authoring/testing config; stays\n * out of the compiled bundle). */\n coverage?: CoverageConfig;\n /** Validation switches (authoring config; never compiled). Off is written\n * as ABSENT, like `export.map`: a shard says what an author chose. */\n validation?: {\n /** Also warn when state is WRITTEN but nothing reads it. Off by default:\n * cards are routinely written ahead of the content that will read them,\n * so mid-development this warning is mostly noise. The read side (a gate\n * on state nothing writes) always warns, because that kills cards now. */\n warnUnreadWrites?: boolean;\n };\n world: {\n properties: PropertyDecl[];\n registry?: unknown;\n };\n story: {\n properties: PropertyDecl[];\n };\n /** Templates of play: configuration bags keyed by template name. Core\n * validates only what it knows. */\n templates: Record<string, unknown>;\n export: {\n bundle: string;\n metadata: \"full\" | \"stripped\";\n /**\n * Does a `.storyletpack` carry the boxes' binary assets (background images)?\n *\n * Default false, and a project-level DEFAULT rather than a rule: a pack is a\n * delivery, so the caller can override it per pack (2026-08-07). Some\n * projects would benefit from sending their pictures in certain\n * circumstances and others never would, which is why neither \"always\" nor\n * \"never\" is the answer.\n *\n * Nothing to do with the compiled bundle, which has its own switch: `map`.\n */\n packAssets?: boolean;\n /**\n * Does the compiled bundle carry the maps (zone shapes and background\n * pictures)?\n *\n * Default false, and the default matters: geometry is authoring data, the\n * runtime deals in tag names, and a shipping build should carry nothing it\n * does not use. But a host that wants an in-game map should not have to\n * invent its own export, and it is most useful early - a prototype with a\n * real map beats a prototype with a list of zone names.\n *\n * It sits beside `metadata` on purpose: that is already the switch for\n * \"authoring data that may or may not ship\", and this is its sibling rather\n * than a new concept. With it on, `export` also writes the background files\n * next to the bundle, and `describeBundle` says what is in there.\n */\n map?: boolean;\n };\n}\n\nexport interface BoxShard {\n schema: typeof BOX_SCHEMA;\n box: {\n id: string;\n gameId?: string;\n title?: string;\n purpose?: string;\n /** Authored display order among boxes (sparse; absent falls back to the\n * folder-name position). Authoring-only, like a card's (never compiled\n * into the bundle); merges as a per-field value. */\n order?: number;\n ranking: { specificity: boolean };\n fields: FieldDecl[];\n properties: PropertyDecl[];\n };\n}\n\n/** The box's tag groups: how its cards are filed. */\nexport interface TagsShard {\n schema: typeof TAGS_SCHEMA;\n groups: TagGroup[];\n}\n\n/** The box's hand templates + hands (the writer/programmer contract). */\nexport interface HandsShard {\n schema: typeof HANDS_SCHEMA;\n templates: HandTemplate<string>[];\n hands: Hand<string>[];\n}\n\nexport interface DeckShard {\n schema: typeof DECK_SCHEMA;\n deck: {\n id: string;\n gameId?: string;\n title?: string;\n purpose?: string;\n condition?: string;\n /** Scarce across flows: see Deck.shared. */\n shared?: boolean;\n /** Authored display order within the box (sparse; see BoxShard). */\n order?: number;\n properties: PropertyDecl[];\n };\n cards: Card<string>[];\n}\n\n// --- templates of play --------------------------------------------------------\n// The spatial template's types, field access and geometry. Re-exported here so the\n// package has one entry point, and kept in its own module because core schema and\n// a template of play are different things (Reboot 6).\nexport * from \"./spatial.js\";\n\n// How a hand reaches a tag group, and whether that binding is the hand's own to\n// change. Core schema rather than a template of play, but the map is what needed\n// it said out loud.\nexport * from \"./hands.js\";\n\n// Frames: what an author draws around the content. Arrangement,\n// so it lives in the sidecar and reads forgivingly (furniture.ts says why).\nexport * from \"./furniture.js\";\n\n// Threaded comments: the conversation about a thing, in its own sidecar.\nexport * from \"./comments.js\";\n\n// Guessing a property's type from what an outcome writes: the quick fix's input.\nexport * from \"./infer.js\";\n","// ---------------------------------------------------------------------------\n// @wildwinter/scoperegistry - the scope registry / runtime state container that\n// sits on top of @wildwinter/expr.\n//\n// expr is a stateless calculator: given an AST, an EvalContext (the state), and\n// a Dialect, it computes. This package is the *state* layer: it owns the world\n// state as a set of named scopes - each either an **owned** scope (a property\n// bag this registry stores and saves) or a **foreign** scope (host- or\n// other-engine-resolved at runtime, never stored here) - and produces the\n// `EvalContext` (for evaluation) and `ExpressionSchema` (for validation) that\n// expr consumes. Plus the `scopeRegistrySpec` interop format for importing a\n// foreign owner's scope declarations.\n//\n// Design: design/scope-registry.md (in the patter repo). expr never depends on\n// this; this depends one-way on expr.\n// ---------------------------------------------------------------------------\n\nimport type {\n EvalContext, ExpressionSchema, PropertyType, ScalarValue, ScopeResolver,\n} from \"@wildwinter/expr\";\n\nexport type { EvalContext, ExpressionSchema, PropertyType, ScalarValue, ScopeResolver } from \"@wildwinter/expr\";\n\n// ---------------------------------------------------------------------------\n// Declarations + the scopeRegistrySpec interop format\n// ---------------------------------------------------------------------------\n\n/**\n * A property declaration. `default` is used by an *owned* scope to seed its bag\n * (foreign scopes ignore it - the host owns the value). `writable: false` makes\n * a property read-only; default is read/write. (`type`/`values` feed validation.)\n */\nexport interface ScopeDeclaration {\n name: string;\n type: PropertyType;\n values?: string[]; // for enum / flags\n /** A quality's ordered ladder of stage names (quality.md). */\n stages?: string[];\n default?: ScalarValue; // owned scopes: seed value\n writable?: boolean; // default true\n}\n\n/** One scope in a `scopeRegistrySpec`: a token + (optional) declarations. */\nexport interface ScopeSpec {\n token: string;\n /** Scope-level read/write default for its declarations (default true). */\n writable?: boolean;\n /** Property declarations; omit for an opaque scope (any name, unchecked). */\n declarations?: ScopeDeclaration[];\n}\n\n/**\n * The interop format an owner (Storylet Studio, a host game) exports so another\n * engine can validate references into its scopes. Carried under the well-known\n * `scopeRegistrySpec` JSON key (inside a `.storyworld`, or a standalone file).\n */\nexport interface ScopeRegistrySpec {\n version: number;\n scopes: ScopeSpec[];\n}\n\n/** The spec versions this build understands. */\nexport const SUPPORTED_SPEC_VERSIONS = [1] as const;\n\n/**\n * Extract + validate a `scopeRegistrySpec` from any JSON value (a parsed\n * `.storyworld` bundle, or a vanilla `{ scopeRegistrySpec: ... }` manifest).\n * Returns null when the key is absent (so callers can probe arbitrary files);\n * throws on a malformed or unsupported-version spec.\n */\nexport function readScopeRegistrySpec(source: unknown): ScopeRegistrySpec | null {\n if (!source || typeof source !== \"object\") return null;\n const raw = (source as Record<string, unknown>).scopeRegistrySpec;\n if (raw === undefined) return null;\n if (typeof raw !== \"object\" || raw === null) throw new Error(\"scopeRegistrySpec must be an object\");\n const spec = raw as Record<string, unknown>;\n if (typeof spec.version !== \"number\") throw new Error(\"scopeRegistrySpec.version must be a number\");\n if (!(SUPPORTED_SPEC_VERSIONS as readonly number[]).includes(spec.version)) {\n throw new Error(`unsupported scopeRegistrySpec version ${spec.version} (supported: ${SUPPORTED_SPEC_VERSIONS.join(\", \")})`);\n }\n if (!Array.isArray(spec.scopes)) throw new Error(\"scopeRegistrySpec.scopes must be an array\");\n for (const s of spec.scopes) {\n if (!s || typeof s !== \"object\" || typeof (s as ScopeSpec).token !== \"string\") {\n throw new Error(\"each scopeRegistrySpec scope needs a string token\");\n }\n }\n return spec as unknown as ScopeRegistrySpec;\n}\n\n// ---------------------------------------------------------------------------\n// PropertyBag - the state kernel's unit of state (added 0.2.0; design:\n// storylets-new/design/engine-runtimes.md 3.1). A typed, declared property\n// bag with defaults, the firing rule (engine writes notify subscribers;\n// host writes are silent but always auditable), examiner rows, one\n// sanctioned clone door, and bare-value save/load. Owned registry scopes\n// are bags; products may also hold bag families of their own (per-box,\n// per-scene) and mount the shared ones.\n// ---------------------------------------------------------------------------\n\n/** One property change. `silent` marks a host write (the firing rule: it\n * reaches the audit hook but not subscribers); `reason` is the host's own\n * note for its log. */\nexport interface BagChange {\n name: string;\n prev?: ScalarValue;\n next: ScalarValue;\n silent: boolean;\n reason?: string;\n}\n\n/** One examiner row: what a property examiner/editor needs to render and\n * edit a declared property. */\nexport interface PropertyRow {\n name: string;\n /** The address this property answers to - what getProperty/setProperty take.\n * A bag composes it from its own `pathPrefix` and the name, so a row is\n * self-describing: an examiner can render and write a row without being told\n * separately where it came from.\n *\n * The PREFIX CARRIES ITS OWN SEPARATOR rather than the bag assuming a dot,\n * because a prefix is not always a bare scope token: the Storylet Engine\n * addresses a deck's properties as `deck.<id>.name`, so the prefix is already\n * a dotted path. Patterplay's `@patter.gold` and `@scene.mood` are the plain\n * case. (`@gold` also resolves - splitRef defaults an unqualified name to the\n * patter scope - but it is the shorthand, not the address a row reports.)\n *\n * With no prefix this is just the name. Both families forked this interface\n * to add exactly this field - once per runtime - which is the same reason\n * `stages` is here. */\n path: string;\n type: PropertyType;\n value: ScalarValue | undefined;\n default: ScalarValue;\n values?: string[];\n /** A quality's ordered stage ladder, so an inspector can offer the stages\n * instead of a free-text box. `quality` has been in PropertyType since the\n * ladder landed, and the evaluator compares stages by LADDER POSITION and\n * refuses an unknown one, so free text is not a soft failure: a typo breaks\n * play rather than being corrected. This row is the only thing an examiner\n * sees, so a ladder it cannot carry is a ladder no editor can offer. One\n * consumer forked this whole interface to add the field; the field belongs\n * here, beside the `values` it is the closed-set twin of. */\n stages?: string[];\n writable: boolean;\n}\n\nexport class PropertyBag {\n /** The live values record (stable identity across reseed, so an\n * EvalContext built over it stays valid). Read-path for evaluation;\n * writes go through `set` so the firing rule applies. */\n readonly values: Record<string, ScalarValue> = {};\n private decls = new Map<string, ScopeDeclaration>();\n private readonly subscribers = new Set<(change: BagChange) => void>();\n private readonly auditors = new Set<(change: BagChange) => void>();\n /** Name normalisation policy: lowercase by default (the registry's\n * long-standing contract); a product whose names are case-significant\n * passes identity. */\n private readonly norm: (name: string) => string;\n\n /** The address prefix this bag's rows carry, separator included (`@`,\n * `@scene.`, `world.`, `deck.<id>.`). Empty means a row's path is its name. */\n readonly pathPrefix: string;\n\n constructor(\n declarations: ScopeDeclaration[] = [],\n opts?: { normalise?: (name: string) => string; pathPrefix?: string },\n ) {\n this.norm = opts?.normalise ?? ((n) => n.toLowerCase());\n this.pathPrefix = opts?.pathPrefix ?? \"\";\n this.seed(declarations);\n }\n\n private seed(declarations: ScopeDeclaration[]): void {\n for (const d of declarations) {\n const name = this.norm(d.name);\n this.decls.set(name, d);\n // Cloned so bags seeded from one declaration set never share a\n // mutable default (flags arrays).\n this.values[name] = structuredClone(d.default ?? defaultFor(d));\n }\n }\n\n get(name: string): ScalarValue | undefined {\n return this.values[this.norm(name)];\n }\n\n /** Write a property. Engine writes (the default) notify subscribers;\n * pass `silent: true` for a host write, which reaches only the audit\n * hook. Throws on a read-only property. Returns the change. */\n set(name: string, value: ScalarValue, opts?: { silent?: boolean; reason?: string }): BagChange {\n const n = this.norm(name);\n if (this.decls.get(n)?.writable === false) throw new Error(`'${name}' is read-only`);\n const change: BagChange = {\n name: n,\n prev: this.values[n],\n next: value,\n silent: opts?.silent ?? false,\n reason: opts?.reason,\n };\n this.values[n] = value;\n for (const audit of this.auditors) audit(change);\n if (!change.silent) for (const fn of this.subscribers) fn(change);\n return change;\n }\n\n /** Notified of engine (non-silent) writes. Returns the unsubscribe. */\n subscribe(fn: (change: BagChange) => void): () => void {\n this.subscribers.add(fn);\n return () => this.subscribers.delete(fn);\n }\n\n /** Notified of EVERY write, silent or not. Returns the unsubscribe. */\n onAudit(fn: (change: BagChange) => void): () => void {\n this.auditors.add(fn);\n return () => this.auditors.delete(fn);\n }\n\n /** Examiner rows: the declared surface only (stray values are storage,\n * not surface). */\n rows(): PropertyRow[] {\n return [...this.decls.entries()].map(([name, d]) => rowFor(d, this.get(name), undefined, name, this.pathPrefix));\n }\n\n declarations(): ScopeDeclaration[] {\n return [...this.decls.values()];\n }\n\n /** The one sanctioned copy door: values deep-copied, declarations\n * duplicated, the normalisation policy carried, subscriptions NOT\n * carried. */\n clone(): PropertyBag {\n const c = new PropertyBag([], { normalise: this.norm, pathPrefix: this.pathPrefix });\n c.decls = new Map(this.decls);\n Object.assign(c.values, structuredClone(this.values));\n return c;\n }\n\n /** Clear and re-seed from new declarations, in place (the values record\n * keeps its identity, so contexts built over it stay valid). */\n reseed(declarations: ScopeDeclaration[]): void {\n for (const k of Object.keys(this.values)) delete this.values[k];\n this.decls.clear();\n this.seed(declarations);\n }\n\n /** Bare values, ready to embed in a product's save. */\n save(): Record<string, ScalarValue> {\n return structuredClone(this.values);\n }\n\n /** Lay saved values over the current ones (call after a fresh seed:\n * orphans land as strays, new declarations keep their defaults; the\n * product decides whether to prune). Does not fire events. */\n load(values: Record<string, ScalarValue>): void {\n for (const [k, v] of Object.entries(values)) this.values[this.norm(k)] = v;\n }\n}\n\nfunction rowFor(\n d: ScopeDeclaration,\n value: ScalarValue | undefined,\n writable?: boolean,\n name?: string,\n pathPrefix = \"\",\n): PropertyRow {\n const rowName = name ?? d.name.toLowerCase();\n return {\n name: rowName,\n path: pathPrefix + rowName,\n type: d.type,\n value,\n default: d.default ?? defaultFor(d),\n ...(d.values !== undefined ? { values: d.values } : {}),\n // `stages` was added to the row so an examiner could offer a quality's ladder\n // instead of a free-text box, and then never populated here: every quality row\n // this function built came out without one. Fixed 2026-09-02.\n ...(d.stages !== undefined ? { stages: d.stages } : {}),\n writable: writable ?? d.writable ?? true,\n };\n}\n\n// ---------------------------------------------------------------------------\n// The registry / state container\n// ---------------------------------------------------------------------------\n\ninterface OwnedScope {\n kind: \"owned\";\n bag: PropertyBag;\n}\ninterface ForeignScope {\n kind: \"foreign\";\n resolver: ScopeResolver;\n decls: Map<string, ScopeDeclaration>;\n scopeWritable: boolean;\n}\ntype Entry = OwnedScope | ForeignScope;\n\n/** The versioned owned-state fragment both product save envelopes embed\n * (design/engine-runtimes.md 3.1: one serialisation shape for bags). */\nexport interface OwnedStateFragment {\n version: number;\n scopes: Record<string, Record<string, ScalarValue>>;\n}\n\nexport const SAVE_FRAGMENT_VERSION = 1;\n\nexport class ScopeRegistry {\n private readonly scopes = new Map<string, Entry>();\n\n /**\n * Register a scope this registry **owns and stores**. Its bag is seeded from\n * each declaration's `default` (or a type default). Owned scopes are\n * type-checked (declarations) and serialized by `save`/`load`.\n */\n defineOwned(token: string, declarations: ScopeDeclaration[], pathPrefix?: string): this {\n // The scope knows its own token, so its rows can address themselves: `world.hp`.\n // The ADDRESS GRAMMAR is the product's, though, not the registry's - Patterplay\n // writes `@patter.gold` where the Storylet Engine writes `world.gold` - so a\n // caller may say how its addresses look. A bag MOUNTED here keeps whatever prefix\n // its holder gave it: the holder owns the addressing.\n return this.mountOwned(token, new PropertyBag(declarations, { pathPrefix: pathPrefix ?? `${token}.` }));\n }\n\n /**\n * Attach an EXISTING bag as an owned scope - the shared-container move: a\n * host (or the other product) holds the bag; this registry reads, writes\n * and lists it like its own, but the holder saves it.\n */\n mountOwned(token: string, bag: PropertyBag): this {\n this.assertFree(token);\n this.scopes.set(token, { kind: \"owned\", bag });\n return this;\n }\n\n /** An owned scope's bag (subscribe, audit, rows live there). */\n ownedBag(token: string): PropertyBag {\n const e = this.scopes.get(token);\n if (!e || e.kind !== \"owned\") throw new Error(`'@${token}' is not an owned scope`);\n return e.bag;\n }\n\n /**\n * Re-initialise an existing **owned** scope's bag from new declarations,\n * clearing its current values. For scope-local state that resets on a context\n * change (e.g. entering a new scene / site / deck) without disturbing other\n * scopes. Mutates the bag in place, so an `EvalContext` already built from this\n * registry stays valid.\n */\n reseedOwned(token: string, declarations: ScopeDeclaration[]): this {\n this.ownedBag(token).reseed(declarations);\n return this;\n }\n\n /**\n * Register a **foreign** scope backed by a host `{ get, set? }` resolver. The\n * values live in the host/other engine and are never stored or saved here.\n * `declarations` (optional, e.g. imported from a `scopeRegistrySpec`) are used\n * only for validation; omit them for an opaque scope.\n */\n defineForeign(\n token: string,\n resolver: ScopeResolver,\n declarations: ScopeDeclaration[] = [],\n scopeWritable = true,\n ): this {\n this.assertFree(token);\n const decls = new Map<string, ScopeDeclaration>();\n for (const d of declarations) decls.set(d.name.toLowerCase(), d);\n this.scopes.set(token, { kind: \"foreign\", resolver, decls, scopeWritable });\n return this;\n }\n\n has(token: string): boolean {\n return this.scopes.has(token);\n }\n\n /** Read a property; undefined if the scope or property is not present. */\n get(scope: string, name: string): ScalarValue | undefined {\n const e = this.scopes.get(scope);\n if (!e) return undefined;\n return e.kind === \"owned\" ? e.bag.get(name) : e.resolver.get(name.toLowerCase());\n }\n\n /** Write a property (an ENGINE write: the bag's subscribers fire; use\n * the bag directly for silent host writes). Throws on an unknown or\n * read-only scope/property. */\n set(scope: string, name: string, value: ScalarValue): void {\n const e = this.scopes.get(scope);\n if (!e) throw new Error(`unknown scope '@${scope}'`);\n if (e.kind === \"owned\") {\n try {\n e.bag.set(name, value);\n } catch {\n throw new Error(`'@${scope}.${name}' is read-only`);\n }\n return;\n }\n const n = name.toLowerCase();\n if (!this.foreignWritable(e, n)) throw new Error(`'@${scope}.${name}' is read-only`);\n e.resolver.set!(n, value);\n }\n\n private foreignWritable(e: ForeignScope, name: string): boolean {\n if (!e.resolver.set) return false; // no setter => read-only scope\n return e.decls.get(name)?.writable ?? e.scopeWritable;\n }\n\n /** Examiner rows across every scope with a declared surface: owned bags\n * first, then declared foreign scopes (values read through, writability\n * reflecting the resolver). Opaque foreign scopes are not listed. */\n listProperties(): ({ scope: string } & PropertyRow)[] {\n const out: ({ scope: string } & PropertyRow)[] = [];\n for (const [token, e] of this.scopes) {\n if (e.kind === \"owned\") {\n for (const row of e.bag.rows()) out.push({ scope: token, ...row });\n } else {\n for (const d of e.decls.values()) {\n out.push({\n scope: token,\n ...rowFor(d, e.resolver.get(d.name.toLowerCase()), this.foreignWritable(e, d.name.toLowerCase()),\n undefined, `${token}.`),\n });\n }\n }\n }\n return out;\n }\n\n /**\n * Build the `EvalContext` expr's `evaluate` consumes: owned scopes as static\n * bags, foreign scopes as their resolvers. `host` carries dialect-function\n * callbacks (PRNG, tag lookups) and is passed through untouched.\n */\n toEvalContext(host?: Record<string, unknown>): EvalContext {\n const scopes: EvalContext[\"scopes\"] = {};\n for (const [token, e] of this.scopes) {\n scopes[token] = e.kind === \"owned\" ? e.bag.values : e.resolver;\n }\n // The quality channel (quality.md): declared here once, so a host that\n // registers a quality gets ordering comparisons and advance() with no\n // further wiring. Only added when a quality exists, so contexts stay\n // byte-identical for products that declare none.\n const qualities = this.qualityLadders();\n return qualities.size === 0 ? { scopes, host } : {\n scopes, host,\n qualities: (scope, name) => qualities.get(scope)?.get(name.toLowerCase()),\n };\n }\n\n /** Every quality declaration's ladder, keyed scope token then name. */\n private qualityLadders(): Map<string, Map<string, readonly string[]>> {\n const out = new Map<string, Map<string, readonly string[]>>();\n for (const [token, e] of this.scopes) {\n const decls = e.kind === \"owned\" ? e.bag.declarations() : [...e.decls.values()];\n for (const d of decls) {\n if (d.type !== \"quality\" || d.stages === undefined) continue;\n let m = out.get(token);\n if (!m) { m = new Map(); out.set(token, m); }\n m.set(d.name.toLowerCase(), d.stages);\n }\n }\n return out;\n }\n\n /**\n * Build the `ExpressionSchema` expr's validator consumes. Scopes with no\n * declarations are **omitted** (opaque - references into them are not flagged);\n * declared scopes contribute their property types for validation.\n */\n toSchema(): ExpressionSchema {\n const properties = new Map<string, Map<string, { type: PropertyType; enumValues?: string[]; stages?: string[] }>>();\n for (const [token, e] of this.scopes) {\n const decls = e.kind === \"owned\" ? e.bag.declarations() : [...e.decls.values()];\n if (decls.length === 0) continue;\n const m = new Map<string, { type: PropertyType; enumValues?: string[]; stages?: string[] }>();\n for (const d of decls) m.set(d.name.toLowerCase(), {\n type: d.type, enumValues: d.values,\n ...(d.stages !== undefined ? { stages: d.stages } : {}),\n });\n properties.set(token, m);\n }\n return { properties };\n }\n\n /** Serialize **owned** scopes only (foreign scopes are host-owned,\n * host-saved), as bare bags - the 0.1.x shape, kept stable so existing\n * consumers' save formats are untouched. A product embedding the\n * versioned cross-product shape uses `saveFragment`. */\n save(): Record<string, Record<string, ScalarValue>> {\n const out: Record<string, Record<string, ScalarValue>> = {};\n for (const [token, e] of this.scopes) if (e.kind === \"owned\") out[token] = e.bag.save();\n return out;\n }\n\n /** Restore owned-scope values from a `save` blob. Unknown/foreign scopes\n * are ignored. */\n load(blob: Record<string, Record<string, ScalarValue>>): void {\n for (const [token, vals] of Object.entries(blob)) {\n const e = this.scopes.get(token);\n if (e?.kind === \"owned\") e.bag.load(vals);\n }\n }\n\n /** The versioned owned-state fragment (the one serialisation shape both\n * product families' save envelopes embed when they adopt the kernel;\n * design/engine-runtimes.md 3.1). `save()` wrapped with a version stamp. */\n saveFragment(): OwnedStateFragment {\n return { version: SAVE_FRAGMENT_VERSION, scopes: this.save() };\n }\n\n /** Restore from a versioned fragment; an unsupported version throws. */\n loadFragment(fragment: OwnedStateFragment): void {\n if (fragment.version !== SAVE_FRAGMENT_VERSION) {\n throw new Error(`unsupported owned-state fragment version ${fragment.version} (supported: ${SAVE_FRAGMENT_VERSION})`);\n }\n this.load(fragment.scopes);\n }\n\n private assertFree(token: string): void {\n if (this.scopes.has(token)) throw new Error(`scope '@${token}' is already registered`);\n }\n}\n\n/** The seed value for a declared property: its own `default`, else the type's.\n *\n * Exported because it was being written again wherever a declaration needed seeding, and a\n * copy of a defaults table is a copy that stops agreeing. Patterplay carried three of them in\n * one file, for its shared decls, its host-scope decls and its scene decls - three declaration\n * TYPES, one behaviour, and nothing to notice if a case drifted. The parameter is structurally\n * typed for exactly that reason: anything with `type` and the optional `default` / `values` /\n * `stages` fits, whatever the caller calls its declaration.\n *\n * A quality seeds at the FIRST rung of its ladder: the ladder's start is the story's start. */\nexport function defaultFor(d: Pick<ScopeDeclaration, \"type\" | \"default\" | \"values\" | \"stages\">): ScalarValue {\n if (d.default !== undefined) return d.default;\n switch (d.type) {\n case \"boolean\": return false;\n case \"number\": return 0;\n case \"string\": return \"\";\n case \"enum\": return d.values?.[0] ?? \"\";\n case \"flags\": return [];\n // A quality starts at the first rung of its ladder.\n case \"quality\": return d.stages?.[0] ?? \"\";\n // Unreachable for a well-typed declaration, and deliberately present anyway: a bundle\n // is DATA, and a hand-edited or newer-than-this-build one can carry a type string the\n // union does not have. Falling off the switch would seed `undefined`, which is not a\n // ScalarValue and travels a long way before it fails. Patterplay's copy of this had the\n // guard and this one did not, which is the drift you only find by removing a duplicate.\n default: return false;\n }\n}\n\n// ---------------------------------------------------------------------------\n// The state logger, which both product families had written twice each.\n// ---------------------------------------------------------------------------\nexport type {\n StateSnapshot, StateChange, LogMount, StateLoggerAdapter, StateLoggerOptions, StateLogger,\n} from \"./state-logger.js\";\nexport { createStateLogger, diffState } from \"./state-logger.js\";\n","// ---------------------------------------------------------------------------\n// The reference runtime: an Engine is the world + flow manager, and ALL play\n// happens on a Flow handle (design/flows.md; the shape is Patter's, adopted\n// deliberately so a host driving both engines holds two objects with the\n// same grammar). The dealing semantics of design/storylets-schema.md\n// section 3 run per flow, implemented exactly and held to the conformance\n// corpus.\n//\n// The flow model, in one place:\n// - an Engine owns the bundle, every lookup built from it, the SHARED\n// property partitions and the @world resolver; a Flow owns its own\n// PRNG, per-box clocks, cooldowns, board, claims, play history and the\n// per-flow property partitions. Flows meet only through shared state.\n// - sharing is a per-property `shared` flag on the declaration (never a\n// scope token): @story defaults shared; box, deck, hand and tag\n// properties default per-flow. Every name is shared XOR per-flow, so a\n// read is a union of two bags and a write routes by name.\n// - @world is the game's own state: always engine-level, resolved through\n// the host's resolver (EngineOptions.world) or a self-backed bag, and\n// NEVER in saveGame() - the host saves its container, each engine saves\n// its own envelope (engine-runtimes.md 3.1).\n// - there is no default flow and no ambient current flow: openFlow(id) is\n// the only way in, an existing id is REPLACED (the old flow closes),\n// and a closed flow's handle is INERT - every verb throws (Patter's\n// stale-handle rule).\n// - engine.getProperty serves world.* and shared refs only; a ref that\n// resolves per-flow throws, naming the fix (Patter's teaching rule).\n//\n// Key dealing contracts, unchanged from round 2 (all per flow now):\n// - two verbs: deal(hand) claims, peek(box, criteria) just looks; you can\n// never play a card you only peeked (3.1, look/use rule)\n// - availability order: deck gate -> cooldown -> tags -> hand condition ->\n// card condition -> claims (3.1)\n// - claims are physical WITHIN a flow: a card sits in at most `copies`\n// hands of that flow's board at once, at most once in any one hand; the\n// ledger is derived from the board contents (3.5)\n// - a SHARED card (its deck's flag, or its own overriding it) is scarce\n// across flows too: at most `sharedCopies` hands anywhere, counted over\n// every live flow's board, and a shared `redraw: \"never\"` is spent for\n// everyone the first time anyone plays it. A finite redraw deliberately\n// stays per flow - a cooldown is an absolute turn of a per-flow clock, so\n// there is nothing shared to compare it against (design/shared-scarcity.md)\n// - the reserved home group inverts the wildcard: a homed card is\n// available only to an ask binding its home (2.4)\n// - ranking: priority desc -> specificity desc (box toggle) -> seeded\n// shuffle of each maximal tie run (3.2)\n// - one PRNG per flow: expression random(), tie shuffles and the batch\n// deal's hand-order shuffle all advance it; state lives in the save (3.3)\n// - each box has its own turn counter PER FLOW; cooldowns are absolute\n// next-eligible turns of the card's box's clock, set at play time from\n// the post-advance turn; \"never\" is MAX_SAFE_INTEGER, not Infinity (3.4)\n// - @hand composes bound-tag props -> hand props -> chosen tags/criteria\n// (by group name), later shadowing earlier; writes route back to their\n// source; criteria names cannot be written (3.6)\n// - outcome availability is never snapshotted: outcomes() and play()\n// evaluate gates against current state (3.1, 3.7)\n// - a trace event fires after the state it reports has landed, so a\n// handler reading the flow inside it sees the effect (the Live Link's\n// board snapshot depends on this; the shared fixture pins it)\n// ---------------------------------------------------------------------------\n\nimport { deserialiseAst, evaluate } from \"@wildwinter/expr\";\nimport type { EvalContext, ExprNode, ScalarValue, ScopeResolver } from \"@wildwinter/expr\";\nimport { matchedSpecificity } from \"@wildwinter/expr-specificity\";\nimport { storyletsDialect, NEVER_PLAYED } from \"@storylet-studio/dialect\";\n\n/** The play-history indexes' key for one (group, tag) pair.\n *\n * A UNIT SEPARATOR (U+001F) joins them: ids are letters, digits and\n * underscores, so a control character cannot occur in one and two different\n * pairs can never collide into one key the way a \".\" or \":\" join could. NUL\n * would say the same thing and was the first choice, but GDScript will not\n * carry one in a string - it substitutes U+FFFD and warns on every parse - and\n * the four runtimes keep the same spelling. */\nconst tagKey = (groupId: string, tagId: string): string => `${groupId}\\u001f${tagId}`;\n\nimport type { StoryletsHost } from \"@storylet-studio/dialect\";\nimport { PLACE_GROUP, effectiveGameId } from \"@storylet-studio/model\";\nimport type {\n Box, Bundle, Card, Deck, Expression, FlowSave, Hand, HandTemplate,\n PlayRecord, PropertyBag, PropertyDecl, PropsPartition, SaveEnvelope, Tag, TagGroup,\n} from \"@storylet-studio/model\";\nimport { PropertyBag as StateBag } from \"@wildwinter/scoperegistry\";\nimport type { PropertyRow } from \"@wildwinter/scoperegistry\";\nimport { makePrng, shuffleInPlace } from \"./prng.js\";\nimport type { Prng } from \"./prng.js\";\n\nexport interface EngineOptions {\n /** Default seed for each flow's PRNG; override per flow in openFlow\n * (cross-runtime determinism, schema 3.3). Default 0. */\n seed?: number;\n /** Retain each flow's event log for introspection - the game-engine seam\n * (schema 5): every trace event, sequence-stamped and turn-stamped where\n * the event has a box context. `true` keeps the default 1000 entries\n * (oldest dropped first). Off by default; subscribeTrace stays the\n * zero-retention stream. */\n log?: boolean | { cap?: number };\n /**\n * The host's resolver for @world - the values the game owns and the\n * story reads (and, where `set` is offered, writes). Omit it and the\n * engine self-backs @world from the declared defaults. Engine-level,\n * shared by all flows, never in saveGame(): the host saves its container\n * once, each engine saves its own envelope (design/flows.md).\n */\n world?: ScopeResolver;\n /**\n * Diagnostics hook (opt-in, dev tooling only): fired when `openFlow` REPLACES\n * a flow that still had cards dealt, with the flow id and how many. The\n * behaviour is unchanged - replacing is deliberate and the same in Patter -\n * this only makes it observable, because the case it catches is a host\n * calling `openFlow` straight after `loadGame` to \"re-take\" its handle and\n * silently discarding the hand the save just restored (`getFlow` is the\n * call). Zero cost when unset; leave it unset in shipped games.\n */\n onReplacedFlow?: (id: string, dealt: number) => void;\n}\n\nexport interface OpenFlowOptions {\n /** Seed for this flow's PRNG (defaults to the engine's `seed`). */\n seed?: number;\n}\n\n/** A card view in a dealt hand or a peeked list. Carries NO outcome\n * availability - ask `outcomes()` for current truth (schema 5). */\nexport interface DealtCard {\n id: string;\n gameId: string;\n title?: string;\n purpose?: string;\n fields?: Record<string, ScalarValue>;\n}\n\nexport interface OutcomeView {\n id: string;\n gameId: string;\n title?: string;\n purpose?: string;\n /** Evaluated against CURRENT state at the moment of the ask. */\n available: boolean;\n}\n\n/** What a peek returns: the top of the stock, looked at and put back.\n * The engine has no pick policy (Reboot 2.1). */\nexport interface RankedList {\n box: string;\n cards: DealtCard[];\n}\n\nexport interface PlayOptions {\n /** Turn advance override; default settings.playAdvancesTurns. */\n advanceTurns?: number;\n}\n\n// --- the trace (schema 5): the deal/play log for tooling ----------------------\n\n/** Why a card did or did not make an ask, in availability order (schema 3.1). */\nexport type TraceVerdict =\n | \"dealt\" // in the hand / the returned list\n | \"capped\" // eligible, ranked below the size cap\n | \"cooldown\" // schema 3.1 step 1\n | \"deck-gate\" // step 2\n | \"tags\" // step 3 (incl. the home group's inverted default)\n | \"condition\" // steps 4-5 (a failing or erroring condition)\n | \"priority\" // a priority expression errored or was not a number\n | \"claimed\" // step 6: no free copy on YOUR board\n | \"claimed-elsewhere\" // step 6: another flow holds the world's copies\n | \"taken\"; // a shared redraw:never was spent, by anyone, for everyone\n\n/** One event on the deal/play log - \"why did Ambush at the ford get dealt\n * here?\" is answered by the ask event's per-card verdicts and keys. The\n * verb is the event type, so a peek is distinguishable from a deal when\n * reading a run back. */\nexport type TraceEvent =\n | {\n type: \"deal\";\n /** Hand gameId. */\n hand: string;\n cards: { id: string; verdict: TraceVerdict; priority?: number; specificity?: number }[];\n }\n | {\n type: \"peek\";\n /** Box gameId. */\n box: string;\n criteria: Record<string, string>;\n cards: { id: string; verdict: TraceVerdict; priority?: number; specificity?: number }[];\n }\n | { type: \"evict\"; hand: string; card: string; reason: TraceVerdict | \"hand-condition\" | \"vanished\" }\n | { type: \"play\"; card: string; outcome: string; turn: number }\n /** One landed outcome change; `path` is the resolved store location (a\n * routed @hand write shows where it actually went, schema 3.6). `prev`\n * is the value it replaced, so a log can read \"0 -> 1\". */\n | { type: \"write\"; target: string; path: string; value: ScalarValue; prev?: ScalarValue }\n /** An explicit clock advance via advanceTurns (schema 3.4); `turn` is the\n * box's new value. Plays stamp their own turn on the play event. */\n | { type: \"turns\"; box: string; turn: number }\n /** An expression eval error: never a silent pass (schema 3.1), always a\n * visible diagnostic. */\n | { type: \"diagnostic\"; where: string; message: string };\n\nexport type TraceHandler = (event: TraceEvent) => void;\n/** The engine-level tap: every flow's events, tagged with the flow id -\n * the tools' one stream. */\nexport type EngineTraceHandler = (flow: string, event: TraceEvent) => void;\n\n/** A retained log entry: the trace event plus its place in flow time.\n * `seq` orders the whole flow (monotonic; survives clearLog). `turn` is\n * the clock of the box the event happened in when it fired (peek: the box;\n * deal/evict: the hand's box; play and its writes: the played card's box,\n * stamped together with the play's own turn). Diagnostics carry no turn. */\nexport type LogEntry = TraceEvent & { seq: number; turn?: number };\n\n/** One entry on the ENGINE's log: the same event, plus the flow it happened\n * in. A run is several flows over shared state, so \"what happened in this\n * run\" is only answerable in one ordered stream, and only if each line says\n * who. The flow's own log stays flow-local and unchanged. */\nexport type EngineLogEntry = LogEntry & { flow: string };\n\n// --- internals ---------------------------------------------------------------\n\ninterface CardEntry {\n card: Card<Expression>;\n deck: Deck<Expression>;\n box: Box<Expression>;\n}\n\n/** Is this card scarce across flows (design/shared-scarcity.md)? The deck says\n * what the pile is for and the card may override it, the same inheritance a\n * property has with its scope default. Hoist the deck's flag out of a card\n * loop and pass the answer down: the ask runs this per card per deal. */\nconst cardIsShared = (card: Card<Expression>, deckShared: boolean): boolean =>\n card.shared ?? deckShared;\n\n/** How many hands ACROSS EVERY FLOW may hold this at once. Defaults to\n * `copies`, so the common case writes one number and only \"five in the world,\n * one to a customer\" needs both. Meaningless on an unshared card, and the\n * compiler warns when one sets it. */\nconst sharedCap = (card: Card<Expression>): number => card.sharedCopies ?? card.copies ?? 1;\n\ntype HandSource = { kind: \"value\"; id: string } | { kind: \"hand\"; id: string } | { kind: \"criteria\" };\n\n/** The composed @hand for one ask: the read bag, plus where each name\n * routes on write (schema 3.6). */\ninterface HandEnv {\n bag: PropertyBag;\n sources: Map<string, HandSource>;\n /** tag group id -> bound tag id (home included, its \"tag\" a hand id). */\n boundTags: Map<string, string>;\n}\n\n/** One ask, resolved: a deal (hand present, condition from its template or\n * rule) or a peek (criteria only, no condition - schema 3.1). */\ninterface AskDescriptor {\n box: Box<Expression>;\n hand?: Hand<Expression>;\n condition?: Expression;\n /** tag group id -> tag id, everything the ask binds (fixed + chosen +\n * criteria; for deals also home -> the hand's own id). */\n boundTags: Map<string, string>;\n /** Chosen tags / criteria surfaced into @hand by group gameId, the tag's\n * gameId as the value (schema 3.6). */\n askNames: Record<string, string>;\n}\n\n// Stores are shared-kernel bags (@wildwinter/scoperegistry, the properties\n// implementer Patter shares): identity normalisation because storylets\n// property names are case-significant as authored.\n// `pathPrefix` carries its own separator, so a bag composes its rows' addresses itself\n// (`story.gold`, `deck.tavern.drawn`) instead of every caller pasting a prefix onto a row.\nconst bagFromDecls = (decls: PropertyDecl[], pathPrefix: string): StateBag =>\n new StateBag(decls, { normalise: (n) => n, pathPrefix });\n\n// Truthiness for a bare condition. Booleans and numbers as you would expect;\n// a string passes when non-empty and a flag list when non-empty, matching\n// JavaScript's own coercion for those two.\n//\n// Until 2026-09-01 this admitted ONLY booleans and numbers, and Patterplay's\n// `truthy` admitted strings and lists as well. That was drift from writing the\n// two engines at different times, not a considered difference: the two share a\n// property registry, so the same value read from the same registry answered a\n// condition differently depending on which engine asked. expr-specificity calls\n// truthiness host-bound, and it is, but \"host-bound\" is licence for a host to\n// choose, not licence for two hosts in one family to disagree by accident.\nfunction conditionPasses(v: ScalarValue): boolean {\n if (typeof v === \"boolean\") return v;\n if (typeof v === \"number\") return v !== 0;\n if (typeof v === \"string\") return v !== \"\";\n return v.length > 0; // string[] (flags)\n}\n\n// PropertyView is gone. It was the shared PropertyRow plus a `path`, and `path` moved onto\n// that row on 2026-09-02 - so the name was a synonym, and a synonym for a shared type is how\n// the two families drifted in the first place: the same row called PropertyView here,\n// ScopePropertyRow next to it, PropertyRow in the kernel. listProperties() returns PropertyRow.\n\n/** One kernel bag with its store path prefix (story / box.<id> / deck.<id>\n * / hand.<id> / value.<id>): the state logger's mount surface\n * (design/engine-runtimes.md 3.4 - the logger builds on the PropertyBag\n * audit hook, so it needs the bags themselves, not just their rows).\n * The Engine lists the shared bags, a Flow its own; the @world container\n * is the host's bag and the host mounts it itself. loadGame() replaces\n * every bag, so re-enumerate after a load. */\nexport interface BagMount {\n prefix: string;\n bag: StateBag;\n}\n\n/** One box on the enumeration surface (examiners, hosts): identity plus\n * its clock (per flow). */\nexport interface BoxView {\n id: string;\n gameId: string;\n title?: string;\n turn: number;\n}\n\n/** The sharing default per scope (design/flows.md, the old system's rule):\n * @story is the playthrough family's globals, shared; the narrower scopes\n * are geographic, per-flow, so \"this flow's danger in the docks\" stays\n * expressible. A declaration's `shared` flag overrides. */\nconst SCOPE_DEFAULT_SHARED = { story: true, box: false, deck: false, hand: false, value: false } as const;\ntype FlaggedScope = keyof typeof SCOPE_DEFAULT_SHARED;\n\nconst isShared = (scope: FlaggedScope, d: PropertyDecl): boolean => d.shared ?? SCOPE_DEFAULT_SHARED[scope];\nconst sharedHalf = (scope: FlaggedScope, decls: PropertyDecl[]): PropertyDecl[] =>\n decls.filter((d) => isShared(scope, d));\nconst flowHalf = (scope: FlaggedScope, decls: PropertyDecl[]): PropertyDecl[] =>\n decls.filter((d) => !isShared(scope, d));\n\n/** One side's five stores (shared on the engine, per-flow on each flow). */\ninterface Partition {\n story: StateBag;\n box: Map<string, StateBag>;\n deck: Map<string, StateBag>;\n hand: Map<string, StateBag>;\n value: Map<string, StateBag>;\n}\n\ntype PartitionKind = keyof Partition;\n\n/** Everything a Flow shares with its Engine: the bundle-derived lookups\n * (immutable), the shared stores (replaced wholesale by loadGame/reset),\n * and the seams. One object, held by both classes - the two are one\n * machine in two lifetimes. */\ninterface Internals {\n bundle: Bundle;\n logCap?: number;\n cardsById: Map<string, CardEntry>;\n cardsByGameId: Map<string, CardEntry>;\n boxesByGameId: Map<string, Box<Expression>>;\n boxesById: Map<string, Box<Expression>>;\n handsById: Map<string, { hand: Hand<Expression>; box: Box<Expression> }>;\n handsByGameId: Map<string, { hand: Hand<Expression>; box: Box<Expression> }>;\n templatesById: Map<string, HandTemplate<Expression>>;\n groupsById: Map<string, { group: TagGroup; box: Box<Expression> }>;\n requiredGroups: Set<string>;\n nodeCache: WeakMap<Expression, ExprNode>;\n ladders: {\n world: Map<string, readonly string[]>;\n story: Map<string, readonly string[]>;\n box: Map<string, Map<string, readonly string[]>>;\n deck: Map<string, Map<string, readonly string[]>>;\n value: Map<string, Map<string, readonly string[]>>;\n hand: Map<string, Map<string, readonly string[]>>;\n };\n hasQualities: boolean;\n /** Does ANY deck or card in the bundle opt into shared scarcity? False for\n * the overwhelming majority of projects, and when it is false the two\n * claim-ledger walks in dealing are skipped entirely. Same idea as\n * `hasQualities` above: a bundle that does not use a feature must not pay\n * for it. */\n hasShared: boolean;\n /** The per-flow halves of every declaration list, precomputed once: each\n * new flow builds its bags from these. */\n flowDecls: { story: PropertyDecl[]; box: Map<string, PropertyDecl[]>; deck: Map<string, PropertyDecl[]>; hand: Map<string, PropertyDecl[]>; value: Map<string, PropertyDecl[]> };\n /** The shared stores. Reassigned wholesale by loadGame/reset. */\n shared: Partition;\n /** @world: the host's resolver, or the self-backed bag's. */\n worldResolver: ScopeResolver;\n /** @world names declared `writable: false`: the story's promise, kept at\n * runtime as the compiler keeps it at publish (Reboot.md 10). */\n worldReadOnly: Set<string>;\n /** `turn` is the box clock the event happened on, where the caller knows it\n * - the same stamp the flow's own log carries. Unity and Unreal passed it\n * from the start; JS and Godot dropped it, so their examiners printed \"[-]\"\n * on every deal, peek, evict and write line while the other two printed the\n * real turn. Four runtimes, two different run logs (2026-08-29). */\n emitEngine: (flow: string, event: TraceEvent, turn?: number) => void;\n engineTracing: () => boolean;\n}\n\nconst handDeclsOf = (internals: Internals, hand: Hand<Expression>): PropertyDecl[] => {\n if (hand.template !== undefined) {\n return internals.templatesById.get(hand.template)?.properties\n ?? internals.bundle.boxes.flatMap((b) => b.handTemplates).find((t) => t.id === hand.template)?.properties\n ?? [];\n }\n return hand.properties ?? [];\n};\n\n/** Build one side of the partition from the bundle. */\nconst buildPartition = (internals: Internals, half: (scope: FlaggedScope, decls: PropertyDecl[]) => PropertyDecl[]): Partition => {\n const b = internals.bundle;\n return {\n story: bagFromDecls(half(\"story\", b.story.properties), \"story.\"),\n box: new Map(b.boxes.map((box) => [box.id, bagFromDecls(half(\"box\", box.properties), `box.${box.id}.`)])),\n deck: new Map(b.boxes.flatMap((box) => box.decks.map(\n (deck): [string, StateBag] => [deck.id, bagFromDecls(half(\"deck\", deck.properties), `deck.${deck.id}.`)]))),\n // A template instance inherits the template's property declarations;\n // a standalone hand declares its own (schema 2.6).\n hand: new Map(b.boxes.flatMap((box) => box.hands.map(\n (hand): [string, StateBag] => [hand.id, bagFromDecls(half(\"hand\", handDeclsOf(internals, hand)), `hand.${hand.id}.`)]))),\n value: new Map(b.boxes.flatMap((box) => box.tagGroups.flatMap((group) => group.tags.map(\n (tag): [string, StateBag] => [tag.id, bagFromDecls(half(\"value\", tag.properties ?? []), `value.${tag.id}.`)])))),\n };\n};\n\nconst partitionValues = (p: Partition): PropsPartition => ({\n story: p.story.values,\n box: Object.fromEntries([...p.box].map(([id, bag]) => [id, bag.values])),\n deck: Object.fromEntries([...p.deck].map(([id, bag]) => [id, bag.values])),\n hand: Object.fromEntries([...p.hand].map(([id, bag]) => [id, bag.values])),\n value: Object.fromEntries([...p.value].map(([id, bag]) => [id, bag.values])),\n});\n\nconst loadPartition = (p: Partition, values: PropsPartition | undefined): void => {\n // Fresh defaults are already in the bags; the saved values land over\n // them: orphaned keys (deleted entities, re-flagged properties) drop;\n // newly declared properties keep defaults.\n p.story.load(values?.story ?? {});\n for (const kind of [\"box\", \"deck\", \"hand\", \"value\"] as const) {\n for (const [id, bag] of Object.entries(values?.[kind] ?? {})) {\n p[kind].get(id)?.load(bag);\n }\n }\n};\n\n// --- the Engine ---------------------------------------------------------------\n\nexport class Engine {\n private readonly internals: Internals;\n private readonly seed: number;\n private readonly onReplacedFlow: EngineOptions[\"onReplacedFlow\"];\n private readonly flowsById = new Map<string, Flow>();\n private readonly engineTraceHandlers = new Set<EngineTraceHandler>();\n /** The host's @world binding, if the engine was built with one: it\n * outlives reset/loadGame (the host's container is the host's). The\n * self-backed resolver is rebuilt instead. */\n private readonly hostWorld?: ScopeResolver;\n\n constructor(bundle: Bundle, opts: EngineOptions = {}) {\n this.seed = opts.seed ?? 0;\n this.onReplacedFlow = opts.onReplacedFlow;\n if (opts.world !== undefined) this.hostWorld = opts.world;\n const internals: Internals = {\n bundle,\n ...(opts.log ? { logCap: typeof opts.log === \"object\" ? (opts.log.cap ?? 1000) : 1000 } : {}),\n cardsById: new Map(), cardsByGameId: new Map(),\n boxesByGameId: new Map(), boxesById: new Map(),\n handsById: new Map(), handsByGameId: new Map(),\n templatesById: new Map(), groupsById: new Map(),\n requiredGroups: new Set(),\n nodeCache: new WeakMap(),\n ladders: { world: new Map(), story: new Map(), box: new Map(), deck: new Map(), value: new Map(), hand: new Map() },\n hasQualities: false,\n hasShared: false,\n flowDecls: { story: [], box: new Map(), deck: new Map(), hand: new Map(), value: new Map() },\n shared: undefined as unknown as Partition,\n worldResolver: undefined as unknown as ScopeResolver,\n worldReadOnly: new Set<string>(),\n emitEngine: (flow, event, turn) => {\n if (this.internals.logCap !== undefined) {\n this.engineLog.push({ ...event, flow, seq: this.engineSeq++, ...(turn !== undefined ? { turn } : {}) });\n if (this.engineLog.length > this.internals.logCap) {\n this.engineLog.splice(0, this.engineLog.length - this.internals.logCap);\n }\n }\n for (const h of this.engineTraceHandlers) h(flow, event);\n },\n engineTracing: () => this.engineTraceHandlers.size > 0,\n };\n this.internals = internals;\n\n for (const box of bundle.boxes) {\n internals.boxesById.set(box.id, box);\n internals.boxesByGameId.set(effectiveGameId(box), box);\n for (const group of box.tagGroups) {\n internals.groupsById.set(group.id, { group, box });\n if (group.required === true) internals.requiredGroups.add(group.id);\n }\n for (const deck of box.decks) {\n if (deck.shared === true) internals.hasShared = true;\n for (const card of deck.cards) {\n const entry = { card, deck, box };\n internals.cardsById.set(card.id, entry);\n internals.cardsByGameId.set(effectiveGameId(card), entry);\n if (card.shared === true) internals.hasShared = true;\n }\n }\n for (const template of box.handTemplates) {\n internals.templatesById.set(template.id, template);\n }\n for (const hand of box.hands) {\n internals.handsById.set(hand.id, { hand, box });\n internals.handsByGameId.set(effectiveGameId(hand), { hand, box });\n }\n }\n this.initLadders();\n\n // The per-flow halves, precomputed once (a bundle's declarations never\n // change): each openFlow builds its bags from these.\n internals.flowDecls = {\n story: flowHalf(\"story\", bundle.story.properties),\n box: new Map(bundle.boxes.map((box) => [box.id, flowHalf(\"box\", box.properties)])),\n deck: new Map(bundle.boxes.flatMap((box) => box.decks.map(\n (deck): [string, PropertyDecl[]] => [deck.id, flowHalf(\"deck\", deck.properties)]))),\n hand: new Map(bundle.boxes.flatMap((box) => box.hands.map(\n (hand): [string, PropertyDecl[]] => [hand.id, flowHalf(\"hand\", handDeclsOf(internals, hand))]))),\n value: new Map(bundle.boxes.flatMap((box) => box.tagGroups.flatMap((group) => group.tags.map(\n (tag): [string, PropertyDecl[]] => [tag.id, flowHalf(\"value\", tag.properties ?? [])])))),\n };\n\n this.initShared(this.hostWorld);\n }\n\n /** Build the shared stores and the @world seam. `hostWorld` sticks for the\n * engine's lifetime; reset/loadGame rebuild the shared bags around it. */\n private initShared(hostWorld?: ScopeResolver): void {\n const internals = this.internals;\n internals.shared = buildPartition(internals, sharedHalf);\n internals.worldReadOnly = new Set(internals.bundle.world.properties.filter((d) => d.writable === false).map((d) => d.name));\n if (hostWorld !== undefined) {\n internals.worldResolver = hostWorld;\n } else {\n // Standalone: self-backed from the declared defaults. Still FOREIGN\n // in spirit - never in saveGame(); a host that wants @world to\n // persist saves the container itself (play-helpers ships one).\n const bag = bagFromDecls(internals.bundle.world.properties, \"world.\");\n internals.worldResolver = {\n get: (n) => bag.get(n),\n set: (n, v) => { bag.set(n, v); },\n };\n }\n }\n\n /** Quality ladders by scope for the eval channel (design/quality.md):\n * world/story keyed by name; box/deck/value keyed by owner id then name.\n * Built once - a bundle's declarations never change. Ladders are\n * declaration-level, so the sharing flag does not touch them. */\n private initLadders(): void {\n const internals = this.internals;\n const grab = (decls: PropertyDecl[] | undefined): Map<string, readonly string[]> => {\n const m = new Map<string, readonly string[]>();\n for (const d of decls ?? []) if (d.type === \"quality\" && d.stages !== undefined) m.set(d.name, d.stages);\n return m;\n };\n const b = internals.bundle;\n internals.ladders.world = grab(b.world.properties);\n internals.ladders.story = grab(b.story.properties);\n for (const box of b.boxes) {\n internals.ladders.box.set(box.id, grab(box.properties));\n for (const deck of box.decks) internals.ladders.deck.set(deck.id, grab(deck.properties));\n for (const group of box.tagGroups) {\n for (const tag of group.tags) internals.ladders.value.set(tag.id, grab(tag.properties));\n }\n for (const hand of box.hands) internals.ladders.hand.set(hand.id, grab(handDeclsOf(internals, hand)));\n }\n const any = (m: Map<string, Map<string, readonly string[]>>): boolean =>\n [...m.values()].some((x) => x.size > 0);\n internals.hasQualities = internals.ladders.world.size > 0 || internals.ladders.story.size > 0\n || any(internals.ladders.box) || any(internals.ladders.deck)\n || any(internals.ladders.value) || any(internals.ladders.hand);\n }\n\n // --- flow management (Patter's surface, name for name) ----------------------\n\n /** Open (or REPLACE) the named flow. An existing id's flow is closed\n * first - re-opening a name is a reset of that name's whole per-flow\n * state; shared state is untouched. There is no default flow: \"main\" is\n * a caller convention, not an engine rule. */\n openFlow(id: string, opts: OpenFlowOptions = {}): Flow {\n // Replacing an existing id KEEPS its place in the order. `close()` would\n // drop the key, and a JS Map re-inserts a deleted key at the END, so\n // openFlow(\"a\"); openFlow(\"b\"); openFlow(\"a\") listed [b, a] here and\n // [a, b] on all three ports - a different `flows()` order and, since\n // `saveGame` keys its flows in that order, a different `.storyletsave`\n // byte stream for the same run (2026-08-29). markClosed without dropFlow\n // is the difference: the old handle goes inert, the slot stays put.\n const existing = this.flowsById.get(id);\n if (existing) {\n // Say so BEFORE the old flow goes inert, while its board is still readable.\n const dealt = existing.heldCardIds().length;\n if (dealt > 0) this.onReplacedFlow?.(id, dealt);\n existing.markClosed();\n }\n const flow = new Flow(this, this.internals, id, opts.seed ?? this.seed);\n this.flowsById.set(id, flow);\n return flow;\n }\n\n getFlow(id: string): Flow | undefined {\n return this.flowsById.get(id);\n }\n\n /** Every live flow, open order. */\n flows(): Flow[] {\n return [...this.flowsById.values()];\n }\n\n /** Close the named flow: its handle goes INERT (every verb throws). A\n * dropped-but-held flow must not keep writing shared state (Patter's\n * stale-handle lesson). Unknown ids are a quiet no-op, like closing a\n * closed door. */\n closeFlow(id: string): void {\n const flow = this.flowsById.get(id);\n if (!flow) return;\n this.flowsById.delete(id);\n flow.markClosed();\n }\n\n /** @internal - Flow.close() routes here so both doors agree. */\n dropFlow(id: string, flow: Flow): void {\n if (this.flowsById.get(id) === flow) this.flowsById.delete(id);\n }\n\n /** Close every flow and reseed the shared state to its defaults (the\n * self-backed @world included; a host-bound @world is the host's and is\n * not touched). */\n reset(): void {\n // The log is a run-lifetime utility and is not saved; a reset is a new run.\n // All three ports cleared it here and the reference did not, so `reset()`\n // (and `loadGame`, which calls it) left the previous run's entries in place\n // with `seq` continuing across the boundary - while the same call on Godot,\n // Unity or Unreal returned an empty log (2026-08-29).\n this.engineLog = [];\n for (const flow of this.flowsById.values()) flow.markClosed();\n this.flowsById.clear();\n this.spent.clear();\n this.initShared(this.hostWorld);\n }\n\n // --- shared scarcity (design/shared-scarcity.md) -----------------------------\n\n /** Cards a shared `redraw: \"never\"` has taken out of the world, by card id.\n * The claim ledger is DERIVED from live boards and so needs no storage;\n * this one is durable, so it rides the save's shared half. */\n private spent = new Set<string>();\n\n /** @internal */\n isTaken(cardId: string): boolean {\n return this.spent.has(cardId);\n }\n\n /** @internal */\n markTaken(cardId: string): void {\n this.spent.add(cardId);\n }\n\n // --- the run's log (design/shared-scarcity.md 8.2) ---------------------------\n\n /** Every flow's events in one ordered stream, each tagged with its flow.\n * Opt in with the same `log` option the flow logs use; capped the same way.\n *\n * This exists because a flow's own log cannot answer the question a run\n * raises: when a story action in ANOTHER flow moves shared state, your\n * flow's log says nothing and your value simply changes. Reading a run\n * needs one stream that says who did what, and merging the per-flow logs by\n * hand is a thing every host would otherwise have to write. */\n private engineLog: EngineLogEntry[] = [];\n private engineSeq = 0;\n\n log(): readonly EngineLogEntry[] {\n return this.engineLog;\n }\n\n clearLog(): void {\n this.engineLog = [];\n }\n\n /** @internal - shared claims across every LIVE flow, card id -> holders.\n * Derived, which is what makes closeFlow and the openFlow replace release\n * what a flow was holding: its board leaves the map with it. */\n sharedClaims(): Map<string, number> {\n const counts = new Map<string, number>();\n for (const flow of this.flowsById.values()) {\n for (const id of flow.heldCardIds()) counts.set(id, (counts.get(id) ?? 0) + 1);\n }\n return counts;\n }\n\n // --- engine-level state access ----------------------------------------------\n\n /**\n * Read shared state by path: \"world.x\", \"story.gold\" (when shared),\n * \"box.b_x.heat\" (when shared). A ref that resolves PER-FLOW throws,\n * naming the fix - silently answering with some flow's copy (or a junk\n * default) was the bug Patter's engine.getProperty guard exists to stop.\n */\n getProperty(path: string): ScalarValue {\n const found = this.resolveShared(path);\n const value = found.kind === \"world\" ? this.internals.worldResolver.get(found.name) : found.bag.get(found.name);\n if (value === undefined) throw new Error(`no property at \"${path}\"`);\n return value;\n }\n\n setProperty(path: string, value: ScalarValue): void {\n const found = this.resolveShared(path);\n if (found.kind === \"world\") {\n if (!this.internals.worldResolver.set) {\n throw new Error(`@world is read-only here: the host bound no write`);\n }\n this.internals.worldResolver.set(found.name, value);\n return;\n }\n // A host write: silent under the firing rule (no subscriber feedback\n // loop), but visible to the bag's audit hook.\n found.bag.set(found.name, value, { silent: true, reason: \"host setProperty\" });\n }\n\n private resolveShared(path: string): { kind: \"world\"; name: string } | { kind: \"bag\"; bag: StateBag; name: string } {\n const parts = path.split(\".\");\n const perFlow = (): never => {\n throw new Error(`\"${path}\" is per-flow state - read it on a Flow, not the Engine`);\n };\n if (parts.length === 2 && parts[0] === \"world\") return { kind: \"world\", name: parts[1]! };\n if (parts.length === 2 && parts[0] === \"story\") {\n const name = parts[1]!;\n if (this.internals.shared.story.get(name) !== undefined) return { kind: \"bag\", bag: this.internals.shared.story, name };\n if (this.internals.flowDecls.story.some((d) => d.name === name)) perFlow();\n throw new Error(`no property at \"${path}\"`);\n }\n if (parts.length === 3 && (parts[0] === \"box\" || parts[0] === \"deck\" || parts[0] === \"hand\" || parts[0] === \"value\")) {\n const kind = parts[0] as Exclude<PartitionKind, \"story\">;\n const [, id, name] = parts as unknown as [string, string, string];\n const bag = this.internals.shared[kind].get(id);\n if (bag !== undefined && bag.get(name) !== undefined) return { kind: \"bag\", bag, name };\n if (this.internals.flowDecls[kind].get(id)?.some((d) => d.name === name)) perFlow();\n if (bag === undefined && !this.internals.flowDecls[kind].has(id)) throw new Error(`no ${kind} store \"${id}\"`);\n throw new Error(`no property at \"${path}\"`);\n }\n throw new Error(`bad property path \"${path}\"`);\n }\n\n /** The shared surface as examiner rows: @world (read through the\n * resolver) then the shared partitions. Per-flow rows live on each Flow. */\n listProperties(): PropertyRow[] {\n const out: PropertyRow[] = [];\n for (const d of this.internals.bundle.world.properties) {\n const value = this.internals.worldResolver.get(d.name);\n out.push({\n path: `world.${d.name}`, name: d.name, type: d.type,\n value: value ?? d.default, default: d.default,\n ...(d.values !== undefined ? { values: d.values } : {}),\n ...(d.stages !== undefined ? { stages: d.stages } : {}),\n // @world is FOREIGN - a host resolver backs it - so writability is whether that\n // resolver can be written at all, which is the shared registry's own rule for a\n // foreign scope. The `as PropertyView` cast this replaced was hiding the field's\n // absence: the row type has always required it, and these rows shipped without one.\n writable: this.internals.worldResolver.set !== undefined,\n });\n }\n // The bag composes its rows' addresses from its own pathPrefix, so the prefix here is\n // only the caller's label for the mount; the row arrives already addressed.\n const add = (_prefix: string, bag: StateBag): void => {\n for (const row of bag.rows()) out.push(row);\n };\n add(\"story\", this.internals.shared.story);\n for (const [id, bag] of this.internals.shared.box) add(`box.${id}`, bag);\n for (const [id, bag] of this.internals.shared.deck) add(`deck.${id}`, bag);\n for (const [id, bag] of this.internals.shared.hand) add(`hand.${id}`, bag);\n for (const [id, bag] of this.internals.shared.value) add(`value.${id}`, bag);\n return out;\n }\n\n /** The SHARED kernel bags with their store path prefixes (the state\n * logger's mount surface). The @world container is the host's own bag -\n * the host mounts it itself. */\n listBags(): BagMount[] {\n const mounts: BagMount[] = [{ prefix: \"story\", bag: this.internals.shared.story }];\n for (const kind of [\"box\", \"deck\", \"hand\", \"value\"] as const) {\n for (const [id, bag] of this.internals.shared[kind]) mounts.push({ prefix: `${kind}.${id}`, bag });\n }\n return mounts;\n }\n\n /** Every flow's trace, one stream, each event tagged with its flow id. */\n subscribeTrace(handler: EngineTraceHandler): () => void {\n this.engineTraceHandlers.add(handler);\n return () => this.engineTraceHandlers.delete(handler);\n }\n\n // --- persistence (schema 4) -------------------------------------------------\n\n /** The whole engine, one envelope: the shared partitions once, then\n * every live flow keyed by its id. @world is NEVER here - the host\n * saves its container, each engine saves its own envelope. */\n saveGame(): SaveEnvelope {\n return structuredClone({\n schema: \"storylets/save@1\" as const,\n content: this.internals.bundle.content,\n shared: { props: partitionValues(this.internals.shared), spent: [...this.spent].sort() },\n flows: Object.fromEntries([...this.flowsById].map(([id, flow]) => [id, flow.snapshot()])),\n });\n }\n\n /** Restore: shared state once, then every flow REBUILT from its blob.\n * Handles held from before the load are closed and inert (Patter's\n * rule); take fresh ones from getFlow()/flows(). */\n loadGame(envelope: SaveEnvelope): void {\n if (envelope.content.project !== this.internals.bundle.content.project) {\n throw new Error(`save is for project \"${envelope.content.project}\", bundle is \"${this.internals.bundle.content.project}\"`);\n }\n const env = structuredClone(envelope);\n this.reset();\n loadPartition(this.internals.shared, env.shared.props);\n for (const id of env.shared.spent ?? []) this.spent.add(id);\n for (const [id, saved] of Object.entries(env.flows ?? {})) {\n this.openFlow(id).restore(saved);\n }\n }\n}\n\n// --- the Flow -----------------------------------------------------------------\n\nexport class Flow {\n readonly id: string;\n private readonly engine: Engine;\n private readonly internals: Internals;\n private closed = false;\n\n private prng: Prng;\n /** Per-box turn counters, keyed by box id (schema 3.4) - per flow. */\n private turnCounts = new Map<string, number>();\n private cooldowns: Record<string, number> = {};\n /** The board: hand contents (card ids, dealt order), keyed by hand id. */\n private boardContents = new Map<string, string[]>();\n private playLog: PlayRecord[] = [];\n // --- play-history indexes -------------------------------------------------\n // The four play-history host functions used to SCAN playLog on every call,\n // and they are called once per candidate card per ask, so dealing was\n // O(candidates x playLog): a shipped game got measurably slower the longer\n // somebody played it, which is the failure mode nobody meets in testing.\n // Measured before the change, 2000 cards: a box with no history condition\n // held flat at 0.3ms while `count_played` went 0.8ms -> 27.9ms as the log\n // reached 4000 plays.\n //\n // These are a pure summary of `playLog`, maintained where it is appended and\n // rebuilt where it is replaced, so they cannot drift from it. They are NOT\n // saved: `playLog` is the record, this is a derivation, and rebuilding on\n // load keeps the save format untouched.\n //\n // The tag keys are the played card's OWN (groupId, tagId) pairs, which is\n // what makes the box-local rule survive: a group name resolves inside the\n // ASKING box, so a card in another box carries different ids and cannot\n // match, exactly as the per-record `inTag` check used to decide.\n private playCount = new Map<string, number>();\n private lastPlayOf = new Map<string, PlayRecord>();\n private tagPlayCount = new Map<string, number>();\n private lastPlayInTag = new Map<string, PlayRecord>();\n /** The per-flow property partitions (the not-shared halves). */\n private stores: Partition;\n\n private traceHandlers = new Set<TraceHandler>();\n private logEntries: LogEntry[] = [];\n private logSeq = 0;\n\n /** Merged read view per scope, built once (bags are stable for the\n * flow's life): the flow's own bag first, the shared bag behind it.\n * Names are disjoint (shared XOR per-flow by declaration), so \"first\"\n * is routing, not shadowing. */\n private readonly storyReader: ScopeResolver;\n private readonly boxReaders = new Map<string, ScopeResolver>();\n private readonly deckReaders = new Map<string, ScopeResolver>();\n\n /** @internal - built by Engine.openFlow / Engine.loadGame only. */\n constructor(engine: Engine, internals: Internals, id: string, seed: number) {\n this.engine = engine;\n this.internals = internals;\n this.id = id;\n this.prng = makePrng(seed);\n this.stores = buildPartition(internals, flowHalf);\n for (const box of internals.bundle.boxes) {\n this.turnCounts.set(box.id, 0);\n for (const hand of box.hands) this.boardContents.set(hand.id, []);\n }\n const pair = (own: StateBag | undefined, shared: StateBag | undefined): ScopeResolver => ({\n get: (n) => own?.get(n) ?? shared?.get(n),\n });\n // `internals.shared` is reassigned wholesale by loadGame/reset, but a\n // load rebuilds every Flow too, so a live flow's readers and the\n // shared partition are always the same generation.\n this.storyReader = pair(this.stores.story, internals.shared.story);\n for (const box of internals.bundle.boxes) {\n this.boxReaders.set(box.id, pair(this.stores.box.get(box.id), internals.shared.box.get(box.id)));\n for (const deck of box.decks) {\n this.deckReaders.set(deck.id, pair(this.stores.deck.get(deck.id), internals.shared.deck.get(deck.id)));\n }\n }\n }\n\n // --- lifetime ----------------------------------------------------------------\n\n get isClosed(): boolean {\n return this.closed;\n }\n\n /** Close this flow: the handle goes inert, every verb throws. */\n close(): void {\n if (this.closed) return;\n this.engine.dropFlow(this.id, this);\n this.markClosed();\n }\n\n /** @internal */\n markClosed(): void {\n this.closed = true;\n }\n\n private assertOpen(): void {\n if (this.closed) throw new Error(`flow \"${this.id}\" is closed`);\n }\n\n /** A box's current turn (schema 3.4), on THIS flow's clock. */\n turn(boxRef: string): number {\n this.assertOpen();\n const box = this.internals.boxesByGameId.get(boxRef) ?? this.internals.boxesById.get(boxRef);\n if (!box) throw new Error(`unknown box \"${boxRef}\"`);\n return this.turnCounts.get(box.id) ?? 0;\n }\n\n /** Subscribe to this flow's deal/play trace (schema 5). Returns the\n * unsubscribe. With no subscribers anywhere the flow does no trace work. */\n subscribeTrace(handler: TraceHandler): () => void {\n this.traceHandlers.add(handler);\n return () => this.traceHandlers.delete(handler);\n }\n\n private get tracing(): boolean {\n return this.traceHandlers.size > 0 || this.internals.logCap !== undefined || this.internals.engineTracing();\n }\n\n private emit(event: TraceEvent, turn?: number): void {\n if (this.internals.logCap !== undefined) {\n this.logEntries.push({ ...event, seq: this.logSeq++, ...(turn !== undefined ? { turn } : {}) });\n if (this.logEntries.length > this.internals.logCap) this.logEntries.splice(0, this.logEntries.length - this.internals.logCap);\n }\n for (const handler of this.traceHandlers) handler(event);\n this.internals.emitEngine(this.id, event, turn);\n }\n\n /** The retained flow log (opt-in via the Engine's `log`), oldest first,\n * capped. The introspection seam for hosts and tools; the durable play\n * history in a save stays `playLog` (schema 4) - the log is a\n * flow-lifetime utility and is NOT saved. */\n log(): readonly LogEntry[] {\n return this.logEntries;\n }\n\n /** Empty the retained log; `seq` keeps counting, so ordering across a\n * clear stays meaningful. */\n clearLog(): void {\n this.logEntries = [];\n }\n\n // --- expression plumbing ----------------------------------------------------\n\n private node(expr: Expression): ExprNode {\n let node = this.internals.nodeCache.get(expr);\n if (!node) {\n node = deserialiseAst(expr.ast);\n this.internals.nodeCache.set(expr, node);\n }\n return node;\n }\n\n /** Tag group names are box-scoped: two boxes may name a group the same way\n * (schema 1 - boxes namespace their groups), so a name is only ever\n * resolved inside the box being asked, never bundle-wide. Ids are\n * project-unique and accepted here too, still confined to the box. */\n private groupInBox(box: Box<Expression>, ref: string): TagGroup | undefined {\n return box.tagGroups.find((g) => effectiveGameId(g) === ref)\n ?? box.tagGroups.find((g) => g.id === ref);\n }\n\n /** Fold one play into the indexes. O(the card's tags), not O(the log). */\n private indexPlay(record: PlayRecord): void {\n this.playCount.set(record.card, (this.playCount.get(record.card) ?? 0) + 1);\n this.lastPlayOf.set(record.card, record);\n const entry = this.internals.cardsByGameId.get(record.card);\n if (!entry) return;\n for (const [groupId, tagIds] of Object.entries(entry.card.tags ?? {})) {\n for (const tagId of tagIds) {\n const key = tagKey(groupId, tagId);\n this.tagPlayCount.set(key, (this.tagPlayCount.get(key) ?? 0) + 1);\n this.lastPlayInTag.set(key, record);\n }\n }\n }\n\n /** Rebuild the indexes from the log. Called wherever `playLog` is REPLACED\n * rather than appended to, which is `restore` alone. */\n private rebuildPlayIndex(): void {\n this.playCount.clear();\n this.lastPlayOf.clear();\n this.tagPlayCount.clear();\n this.lastPlayInTag.clear();\n for (const record of this.playLog) this.indexPlay(record);\n }\n\n /** `box` is the box whose ask is being evaluated: the play-history\n * functions take a bare group name, so it resolves there (a card's tags\n * reference its own box's group, which keeps the counts box-local).\n * History is THIS flow's: countPlayed answers \"have I done this\". */\n /** One host per box, built once.\n *\n * The closures below read `this.playCount`, `this.turnCounts` and the rest\n * LIVE, so a cached host answers with current state - which is what makes\n * caching safe rather than a snapshot bug. Unreal did this from the start\n * (`hostsByBox_`, built at flow construction) and the other three rebuilt a\n * host, and its closures, on every `evalCtx` call: once per deck per ask,\n * and once per surviving card in the eviction pass. Structural divergence\n * in one port AND the allocation the audit flagged, so the other three\n * copied it (2026-08-29). Lazy rather than eager, so a bundle's unvisited\n * boxes cost nothing. */\n private hostsByBox = new Map<string, StoryletsHost>();\n\n private host(box: Box<Expression>): StoryletsHost {\n const cached = this.hostsByBox.get(box.id);\n if (cached !== undefined) return cached;\n const made = this.makeHost(box);\n this.hostsByBox.set(box.id, made);\n return made;\n }\n\n private makeHost(box: Box<Expression>): StoryletsHost {\n /** A group NAME and tag name resolved in THIS box, as the index's key.\n * Resolved once per call now, where `inTag` used to resolve it again for\n * every record in the log. Undefined when either name is unknown here,\n * which is the old per-record `false` and answers \"never\". */\n const keyOf = (group: string, tag: string): string | undefined => {\n const found = this.groupInBox(box, group);\n const t = found?.tags.find((v) => v.gameId === tag);\n return found && t ? tagKey(found.id, t.id) : undefined;\n };\n /** Turns-since is measured on the played card's box's clock (3.4). */\n const since = (record: PlayRecord): number => {\n const entry = this.internals.cardsByGameId.get(record.card);\n if (!entry) return NEVER_PLAYED;\n return (this.turnCounts.get(entry.box.id) ?? 0) - record.turn;\n };\n return {\n nextRandom: () => this.prng.next(),\n countPlayed: (card) => this.playCount.get(card) ?? 0,\n turnsSincePlayed: (card) => {\n const last = this.lastPlayOf.get(card);\n return last ? since(last) : NEVER_PLAYED;\n },\n countPlayedIn: (group, tag) => {\n const key = keyOf(group, tag);\n return key === undefined ? 0 : this.tagPlayCount.get(key) ?? 0;\n },\n turnsSincePlayedIn: (group, tag) => {\n const key = keyOf(group, tag);\n const last = key === undefined ? undefined : this.lastPlayInTag.get(key);\n return last ? since(last) : NEVER_PLAYED;\n },\n };\n }\n\n /** The evaluation environment (schema 3.1/6.2): @box/@deck resolve to the\n * card under evaluation; in hand-condition contexts @deck is an empty bag,\n * so any reference is an eval error (missing-policy throw). Every scope\n * is the flow's MERGED view - its own copies over the shared values,\n * names disjoint - and @world reads through the engine's resolver. */\n private evalCtx(box: Box<Expression>, deck: Deck<Expression> | undefined, handEnv: HandEnv): EvalContext {\n return {\n scopes: {\n world: this.internals.worldResolver,\n story: this.storyReader,\n box: this.boxReaders.get(box.id) ?? {},\n deck: deck ? this.deckReaders.get(deck.id) ?? {} : {},\n hand: handEnv.bag,\n },\n host: this.host(box) as unknown as Record<string, unknown>,\n // The quality channel, answering for THIS ask's box and deck. Only wired\n // when a quality exists, so a bundle without one evaluates byte-\n // identically to before the feature.\n ...(this.internals.hasQualities ? {\n qualities: (scope: string, name: string): readonly string[] | undefined =>\n scope === \"world\" ? this.internals.ladders.world.get(name)\n : scope === \"story\" ? this.internals.ladders.story.get(name)\n : scope === \"box\" ? this.internals.ladders.box.get(box.id)?.get(name)\n : scope === \"deck\" && deck ? this.internals.ladders.deck.get(deck.id)?.get(name)\n // @hand is composed, so the ladder belongs to whatever supplied the\n // value THIS ask: the bound tag, or the asking hand. `sources` is\n // already the map that answers that, because write-back needs it.\n : scope === \"hand\" ? this.handLadder(handEnv, name)\n : undefined,\n } : {}),\n };\n }\n\n /** The ladder behind one composed @hand name, or undefined when the name is\n * not a quality (or came from criteria, which are tag NAMES, never state). */\n private handLadder(handEnv: HandEnv, name: string): readonly string[] | undefined {\n const source = handEnv.sources.get(name);\n if (!source) return undefined;\n return source.kind === \"value\" ? this.internals.ladders.value.get(source.id)?.get(name)\n : source.kind === \"hand\" ? this.internals.ladders.hand.get(source.id)?.get(name)\n : undefined;\n }\n\n private eval(expr: Expression, ctx: EvalContext): ScalarValue {\n return evaluate(this.node(expr), ctx, storyletsDialect);\n }\n\n private passes(expr: Expression | undefined, ctx: EvalContext, where?: string): boolean {\n if (!expr) return true;\n try {\n return conditionPasses(this.eval(expr, ctx));\n } catch (e) {\n // An eval error is never a silent pass: the card/deck is unavailable\n // (schema 3.1), and the trace surfaces the diagnostic.\n if (this.tracing) {\n this.emit({ type: \"diagnostic\", where: where ?? \"condition\", message: e instanceof Error ? e.message : String(e) });\n }\n return false;\n }\n }\n\n // --- resolving asks (schema 2.6 + 3.6) -----------------------------------------\n\n private tagByGameId(group: TagGroup, gameId: string): Tag | undefined {\n return group.tags.find((t) => t.gameId === gameId);\n }\n\n /** A deal's ask: the hand's template bindings + chosen tags, or its rule's\n * bindings, plus the implicit home binding (schema 2.4). */\n private askForHand(hand: Hand<Expression>, box: Box<Expression>): AskDescriptor {\n const boundTags = new Map<string, string>();\n const askNames: Record<string, string> = {};\n let condition: Expression | undefined;\n if (hand.template !== undefined) {\n const template = this.internals.templatesById.get(hand.template);\n if (!template) throw new Error(`hand \"${effectiveGameId(hand)}\": unknown template \"${hand.template}\"`);\n for (const [groupId, tagId] of Object.entries(template.bindings ?? {})) {\n boundTags.set(groupId, tagId);\n }\n for (const [groupId, tagId] of Object.entries(hand.chosen ?? {})) {\n boundTags.set(groupId, tagId);\n const found = this.internals.groupsById.get(groupId);\n const tag = found?.group.tags.find((t) => t.id === tagId);\n if (found && tag) askNames[effectiveGameId(found.group)] = effectiveGameId(tag);\n }\n condition = template.condition;\n } else {\n for (const [groupId, tagId] of Object.entries(hand.rule?.bindings ?? {})) {\n boundTags.set(groupId, tagId);\n // ...and name it, exactly as the template branch above does: a card\n // reading @hand.<group> must not care HOW the group got bound\n // (design/hand-typing.md, the residues).\n const found = this.internals.groupsById.get(groupId);\n const tag = found?.group.tags.find((t) => t.id === tagId);\n if (found && tag) askNames[effectiveGameId(found.group)] = effectiveGameId(tag);\n }\n condition = hand.rule?.condition;\n }\n boundTags.set(PLACE_GROUP, hand.id);\n this.bindStateGroups(box, boundTags, askNames);\n return { box, hand, ...(condition !== undefined ? { condition } : {}), boundTags, askNames };\n }\n\n /** A peek's ask: raw criteria ({group gameId: tag gameId}), bindings only,\n * no condition slot (schema 3.1; the boundary, Reboot 4). */\n private askForPeek(box: Box<Expression>, criteria: Record<string, string>): AskDescriptor {\n const boundTags = new Map<string, string>();\n const askNames: Record<string, string> = {};\n for (const [groupRef, tagRef] of Object.entries(criteria)) {\n if (groupRef === PLACE_GROUP) {\n const hand = this.internals.handsByGameId.get(tagRef) ?? this.internals.handsById.get(tagRef);\n if (!hand) throw new Error(`peek: unknown hand \"${tagRef}\" in home criteria`);\n boundTags.set(PLACE_GROUP, hand.hand.id);\n continue;\n }\n const found = this.groupInBox(box, groupRef);\n if (!found) {\n throw new Error(`peek: unknown tag group \"${groupRef}\" in box \"${effectiveGameId(box)}\"`);\n }\n const tag = this.tagByGameId(found, tagRef) ?? found.tags.find((t) => t.id === tagRef);\n if (!tag) throw new Error(`peek: unknown tag \"${tagRef}\" in group \"${effectiveGameId(found)}\"`);\n boundTags.set(found.id, tag.id);\n askNames[effectiveGameId(found)] = effectiveGameId(tag);\n }\n this.bindStateGroups(box, boundTags, askNames);\n return { box, boundTags, askNames };\n }\n\n /**\n * Bind every `boundBy` group in the box from the property it names.\n *\n * The gap this closes: only a hand could bind a group, and `deal` takes no\n * criteria, so an axis driven by state (an act, a chapter) had nowhere to\n * gate. Runs AFTER the hand's own bindings and never overwrites one: an\n * explicit binding is a deliberate act and beats a default.\n *\n * A value naming no tag in the group leaves the group UNBOUND rather than\n * matching nothing. Unbound is a wildcard, so the ask still deals; a silent\n * empty hand would look like content that does not exist, and the diagnostic\n * is what says otherwise.\n */\n private bindStateGroups(box: Box<Expression>, boundTags: Map<string, string>, askNames: Record<string, string>): void {\n for (const group of box.tagGroups) {\n if (group.boundBy === undefined || boundTags.has(group.id)) continue;\n const ref = /^@(world|story)\\.([a-z][a-z0-9_-]*)$/.exec(group.boundBy);\n if (!ref) {\n this.emit({ type: \"diagnostic\", where: `tag group ${effectiveGameId(group)}`, message: `boundBy \"${group.boundBy}\" is not a @world or @story property reference` });\n continue;\n }\n let value: ScalarValue | undefined;\n try {\n value = this.getProperty(`${ref[1]}.${ref[2]}`);\n } catch {\n this.emit({ type: \"diagnostic\", where: `tag group ${effectiveGameId(group)}`, message: `boundBy \"${group.boundBy}\" names a property that is not declared` });\n continue;\n }\n const wanted = typeof value === \"string\" ? value : String(value);\n const tag = group.tags.find((t) => effectiveGameId(t) === wanted);\n if (!tag) {\n this.emit({ type: \"diagnostic\", where: `tag group ${effectiveGameId(group)}`, message: `${group.boundBy} is \"${wanted}\", which is not one of its tags` });\n continue;\n }\n boundTags.set(group.id, tag.id);\n askNames[effectiveGameId(group)] = effectiveGameId(tag);\n }\n }\n\n // --- @hand composition (schema 3.6) -------------------------------------------\n\n /** A store's full value view for one owner: the shared half under the\n * flow's half. Names are disjoint, so the spread is routing, not\n * shadowing. */\n private valuesOf(kind: Exclude<PartitionKind, \"story\">, id: string): PropertyBag {\n return {\n ...(this.internals.shared[kind].get(id)?.values ?? {}),\n ...(this.stores[kind].get(id)?.values ?? {}),\n };\n }\n\n private buildHandEnv(ask: AskDescriptor): HandEnv {\n const bag: PropertyBag = {};\n const sources = new Map<string, HandSource>();\n\n // 1. Tag properties of every bound tag (home binds a hand, not a tag).\n for (const [groupId, tagId] of ask.boundTags) {\n if (groupId === PLACE_GROUP) continue;\n for (const [name, value] of Object.entries(this.valuesOf(\"value\", tagId))) {\n bag[name] = value;\n sources.set(name, { kind: \"value\", id: tagId });\n }\n }\n // 2. Hand properties, when the ask is a deal.\n if (ask.hand) {\n for (const [name, value] of Object.entries(this.valuesOf(\"hand\", ask.hand.id))) {\n bag[name] = value;\n sources.set(name, { kind: \"hand\", id: ask.hand.id });\n }\n }\n // 3. Chosen tags / criteria, by group name (the tag's gameId as value).\n for (const [name, value] of Object.entries(ask.askNames)) {\n bag[name] = value;\n sources.set(name, { kind: \"criteria\" });\n }\n return { bag, sources, boundTags: ask.boundTags };\n }\n\n // --- the ask (schema 3.1 + 3.2) ------------------------------------------------\n\n /** The claims ledger, derived from THIS flow's board: card id -> holding\n * hands (schema 3.5). Claims are per flow - another flow holding the\n * card is another playthrough, not a rival hand. */\n private claims(): Map<string, number> {\n const counts = new Map<string, number>();\n for (const contents of this.boardContents.values()) {\n for (const id of contents) counts.set(id, (counts.get(id) ?? 0) + 1);\n }\n return counts;\n }\n\n /** @internal - every card id on THIS flow's board, one entry per holding\n * hand. The engine sums these across live flows for the shared ledger. */\n heldCardIds(): string[] {\n return [...this.boardContents.values()].flat();\n }\n\n private copiesOf(card: Card<Expression>): number {\n return card.copies ?? 1;\n }\n\n /** The claims step (schema 3.1 step 6) for one card, as a verdict or null\n * for \"available\". Two caps apply to a shared card and they are different\n * statements, so they get different verdicts: `copies` is your own board\n * filling up, `sharedCopies` is somebody else already holding it, and a\n * participant told \"claimed\" about a card sitting on another person's\n * table would read it as an engine fault (design/shared-scarcity 9.3.1).\n *\n * `mine` counts this flow's holdings, `world` every live flow's. */\n private claimVerdict(\n card: Card<Expression>,\n shared: boolean,\n mine: Map<string, number>,\n world: Map<string, number>,\n ): \"claimed\" | \"claimed-elsewhere\" | null {\n const id = card.id;\n if ((mine.get(id) ?? 0) >= this.copiesOf(card)) return \"claimed\";\n if (shared && (world.get(id) ?? 0) >= sharedCap(card)) return \"claimed-elsewhere\";\n return null;\n }\n\n /** Tag matching (schema 3.1 step 3): for every bound group the card lists\n * the bound tag or omits the group (wildcard); the home group inverts -\n * a homed card requires a matching home binding (schema 2.4). */\n private tagsMatch(card: Card<Expression>, boundTags: Map<string, string>): boolean {\n const home = card.tags?.[PLACE_GROUP];\n if (home !== undefined && home.length > 0) {\n const bound = boundTags.get(PLACE_GROUP);\n if (bound === undefined || !home.includes(bound)) return false;\n }\n for (const [groupId, tagId] of boundTags) {\n if (groupId === PLACE_GROUP) continue;\n const tags = card.tags?.[groupId];\n if (tags === undefined) {\n // Omission is a wildcard unless the group says otherwise. A required\n // group inverts it, which is what `place` has always done per card.\n if (this.internals.requiredGroups.has(groupId)) return false;\n continue;\n }\n if (!tags.includes(tagId)) return false;\n }\n return true;\n }\n\n /** Run one ask: availability filter then ranking. `claimed` decides the\n * claims step (step 6) per card, returning the verdict that refused it or\n * null for available. `trace` (when a subscriber exists) collects the\n * per-card verdicts. */\n private runAsk(\n ask: AskDescriptor,\n claimed: (card: Card<Expression>, shared: boolean) => \"claimed\" | \"claimed-elsewhere\" | null,\n trace?: { id: string; verdict: TraceVerdict; priority?: number; specificity?: number }[],\n ): { ordered: CardEntry[]; handEnv: HandEnv } {\n const { box } = ask;\n const handEnv = this.buildHandEnv(ask);\n const verdict = (id: string, v: TraceVerdict): void => {\n trace?.push({ id, verdict: v });\n };\n\n // The hand's condition: ask-constant, evaluated once (schema 3.1 step 4).\n if (!this.passes(ask.condition, this.evalCtx(box, undefined, handEnv), `hand ${ask.hand ? effectiveGameId(ask.hand) : \"\"} condition`)) {\n return { ordered: [], handEnv };\n }\n\n // Deck gates: evaluated once per ask, in deck (id) order (schema 2.5).\n const gateOk = new Map<string, boolean>();\n for (const deck of box.decks) {\n gateOk.set(deck.id, this.passes(deck.condition, this.evalCtx(box, deck, handEnv), `deck ${deck.gameId} gate`));\n }\n\n const turn = this.turnCounts.get(box.id) ?? 0;\n const scored: { entry: CardEntry; priority: number; spec: number }[] = [];\n for (const deck of box.decks) {\n // ONE context per deck, not per card. It is built from box, deck and\n // handEnv, none of which vary inside this loop, and a condition is a\n // read-only gate (schema 3.1), so nothing can write through it and make\n // sharing visible. Rebuilding it per card cost an EvalContext, a scopes\n // map and five bag wrappers each time: about half the garbage a peek over\n // a large box produced (port-review-2026-08.md, measured).\n const deckCtx = this.evalCtx(box, deck, handEnv);\n const deckShared = deck.shared ?? false;\n for (const card of deck.cards) {\n const shared = cardIsShared(card, deckShared);\n if (!gateOk.get(deck.id)) {\n verdict(card.id, \"deck-gate\");\n continue;\n }\n // Taken out of the world by somebody's shared one-shot. Checked\n // before the flow's own clock, because \"cooldown\" would point the\n // reader at a turn counter that has nothing to do with it.\n if (shared && this.engine.isTaken(card.id)) {\n verdict(card.id, \"taken\");\n continue;\n }\n if ((this.cooldowns[card.id] ?? 0) > turn) {\n verdict(card.id, \"cooldown\");\n continue;\n }\n if (!this.tagsMatch(card, handEnv.boundTags)) {\n verdict(card.id, \"tags\");\n continue;\n }\n // The label is only read when an eval THROWS and only when tracing, so\n // building it per card was pure waste on the path that matters. Built\n // when tracing is on, where the cost is already accepted.\n if (card.condition && !this.passes(card.condition, deckCtx,\n this.tracing ? `card ${card.gameId} condition` : undefined)) {\n verdict(card.id, \"condition\");\n continue;\n }\n const refused = claimed(card, shared); // claims, last (schema 3.1 step 6)\n if (refused) {\n verdict(card.id, refused);\n continue;\n }\n\n let priority: number;\n if (typeof card.priority === \"number\") {\n priority = card.priority;\n } else {\n try {\n const v = this.eval(card.priority, deckCtx);\n if (typeof v !== \"number\") {\n verdict(card.id, \"priority\");\n continue;\n }\n priority = v;\n } catch (e) {\n if (this.tracing) {\n this.emit({ type: \"diagnostic\", where: `card ${card.gameId} priority`, message: e instanceof Error ? e.message : String(e) });\n }\n verdict(card.id, \"priority\");\n continue;\n }\n }\n let spec = 0;\n if (box.ranking.specificity && card.condition) {\n const node = this.node(card.condition);\n spec = matchedSpecificity(node, (n) => {\n try {\n return conditionPasses(evaluate(n, deckCtx, storyletsDialect));\n } catch {\n return false;\n }\n });\n }\n scored.push({ entry: { card, deck, box }, priority, spec });\n }\n }\n\n scored.sort((a, b) => b.priority - a.priority || b.spec - a.spec); // stable\n // Seeded shuffle of each maximal tie run; runs of 1 consume no draws.\n let i = 0;\n while (i < scored.length) {\n let j = i + 1;\n while (j < scored.length\n && scored[j]!.priority === scored[i]!.priority\n && scored[j]!.spec === scored[i]!.spec) j++;\n if (j - i > 1) {\n const run = scored.slice(i, j);\n shuffleInPlace(run, this.prng);\n // Written back element by element, as all three ports do. It used to be\n // `scored.splice(i, j - i, ...run)`, which SPREADS one argument per\n // element: with every card at the default priority 0 the tie run is the\n // whole list, and a box of 150 000 such cards threw `RangeError:\n // Maximum call stack size exceeded` rather than dealing. Far-fetched\n // for one box, but it was a crash where the ports had no limit, and the\n // reference is supposed to be the thing they are transliterated from.\n for (let k = 0; k < run.length; k++) scored[i + k] = run[k]!;\n }\n i = j;\n }\n for (const s of scored) {\n trace?.push({ id: s.entry.card.id, verdict: \"dealt\", priority: s.priority, specificity: s.spec });\n }\n return { ordered: scored.map((s) => s.entry), handEnv };\n }\n\n /** Flip eligible-but-not-taken trace entries to \"capped\". */\n private capTrace(\n trace: { id: string; verdict: TraceVerdict; priority?: number; specificity?: number }[],\n taken: ReadonlySet<string>,\n ): void {\n for (const entry of trace) {\n if (entry.verdict === \"dealt\" && !taken.has(entry.id)) entry.verdict = \"capped\";\n }\n }\n\n private view(entry: CardEntry): DealtCard {\n const { card } = entry;\n return {\n id: card.id,\n gameId: effectiveGameId(card),\n ...(card.title !== undefined ? { title: card.title } : {}),\n ...(card.purpose !== undefined ? { purpose: card.purpose } : {}),\n ...(card.fields !== undefined ? { fields: card.fields } : {}),\n };\n }\n\n private handCapacity(hand: Hand<Expression>): number {\n if (hand.slots !== undefined) return hand.slots;\n const declared = hand.template !== undefined\n ? this.internals.templatesById.get(hand.template)?.slots\n : hand.rule?.slots;\n return declared === undefined || declared === \"unbounded\" ? Infinity : declared;\n }\n\n private resolveHand(ref: string): { hand: Hand<Expression>; box: Box<Expression> } {\n const found = this.internals.handsByGameId.get(ref) ?? this.internals.handsById.get(ref);\n if (!found) throw new Error(`unknown hand \"${ref}\"`);\n return found;\n }\n\n // --- host surface (schema 5) ---------------------------------------------------\n\n /** Look at the top of the stock through raw tag criteria (schema 3.1):\n * claims respected, nothing registered, nothing left behind but the\n * trace line. You can never play a card you only peeked. */\n peek(boxRef: string, criteria: Record<string, string> = {}, n?: number): RankedList {\n this.assertOpen();\n const box = this.internals.boxesByGameId.get(boxRef) ?? this.internals.boxesById.get(boxRef);\n if (!box) throw new Error(`unknown box \"${boxRef}\"`);\n const ask = this.askForPeek(box, criteria);\n const claimCounts = this.claims();\n // Skipped outright when the bundle shares nothing, which is most bundles:\n // the ledger walks every live flow's whole board, and an empty map answers\n // every question the same way a computed one would.\n const worldClaims = this.internals.hasShared ? this.engine.sharedClaims() : new Map<string, number>();\n const trace = this.tracing ? [] : undefined;\n const { ordered } = this.runAsk(ask, (card, shared) => this.claimVerdict(card, shared, claimCounts, worldClaims), trace);\n // CLAMPED. `slice(0, -1)` drops the last card and returns the rest, so a\n // negative n answered with almost the whole list here while every port\n // returned nothing (2026-08-29).\n const listed = n === undefined ? ordered : ordered.slice(0, Math.max(n, 0));\n if (trace) {\n this.capTrace(trace, new Set(listed.map((e) => e.card.id)));\n this.emit({ type: \"peek\", box: effectiveGameId(box), criteria, cards: trace }, this.turnCounts.get(box.id) ?? 0);\n }\n return { box: effectiveGameId(box), cards: listed.map((e) => this.view(e)) };\n }\n\n /** Refresh one hand (schema 3.5); returns its new shape. */\n deal(handRef: string): DealtCard[] {\n this.assertOpen();\n const { hand } = this.resolveHand(handRef);\n return this.dealMany([handRef])[effectiveGameId(hand)] ?? [];\n }\n\n /** Re-deal several / all hands (schema 3.5): seeded hand-order shuffle\n * (fairness), evict, seed the ledger from survivors, fill in order.\n * Returns the dealt slice - the new contents of exactly the hands this\n * call dealt, keyed by hand gameId (board() stays the whole-board read). */\n dealMany(handRefs?: string[]): Record<string, DealtCard[]> {\n this.assertOpen();\n const dealt = (handRefs ?? [...this.internals.handsById.keys()].sort())\n .map((ref) => this.resolveHand(ref));\n shuffleInPlace(dealt, this.prng);\n\n // Eviction first: drop dealt cards no longer available to their hand\n // (minus the claims check against their own seat).\n for (const { hand, box } of dealt) {\n const ask = this.askForHand(hand, box);\n const handEnv = this.buildHandEnv(ask);\n const conditionOk = this.passes(ask.condition, this.evalCtx(box, undefined, handEnv));\n const gateOk = new Map<string, boolean>();\n for (const deck of box.decks) {\n gateOk.set(deck.id, this.passes(deck.condition, this.evalCtx(box, deck, handEnv)));\n }\n const turn = this.turnCounts.get(box.id) ?? 0;\n // Trace events fire after the state they report has landed (a handler\n // reading the board sees the eviction), so they are collected here and\n // emitted once the survivors are set.\n const evicted: { card: string; reason: Extract<TraceEvent, { type: \"evict\" }>[\"reason\"] }[] = [];\n const evict = (cardId: string, reason: Extract<TraceEvent, { type: \"evict\" }>[\"reason\"]): false => {\n evicted.push({ card: cardId, reason });\n return false;\n };\n const survivors = (this.boardContents.get(hand.id) ?? []).filter((cardId) => {\n if (!conditionOk) return evict(cardId, \"hand-condition\");\n const entry = this.internals.cardsById.get(cardId);\n if (!entry) return evict(cardId, \"vanished\"); // edited content: dropped\n if (!gateOk.get(entry.deck.id)) return evict(cardId, \"deck-gate\");\n if ((this.cooldowns[cardId] ?? 0) > turn) return evict(cardId, \"cooldown\");\n if (!this.tagsMatch(entry.card, handEnv.boundTags)) return evict(cardId, \"tags\");\n if (!this.passes(entry.card.condition, this.evalCtx(box, entry.deck, handEnv), `card ${entry.card.gameId} condition`)) {\n return evict(cardId, \"condition\");\n }\n return true;\n });\n this.boardContents.set(hand.id, survivors);\n if (this.tracing) {\n for (const e of evicted) this.emit({ type: \"evict\", hand: hand.id, card: e.card, reason: e.reason }, turn);\n }\n }\n\n const claimCounts = this.claims();\n // The world ledger is taken once for the whole batch and kept in step with\n // the local one below, so two hands in the SAME deal cannot both take the\n // last shared copy. Skipped outright when the bundle shares nothing (most\n // bundles): an empty map answers every question the same way.\n const worldClaims = this.internals.hasShared ? this.engine.sharedClaims() : new Map<string, number>();\n for (const { hand, box } of dealt) {\n const contents = this.boardContents.get(hand.id) ?? [];\n const free = this.handCapacity(hand) - contents.length;\n if (free <= 0) continue;\n const ask = this.askForHand(hand, box);\n const own = new Set(contents);\n const trace = this.tracing ? [] : undefined;\n // At most once in any one hand; at most `copies` hands here, and at most\n // `sharedCopies` hands anywhere (schema 3.5, shared-scarcity 5).\n const { ordered } = this.runAsk(ask,\n (card, shared) => (own.has(card.id) ? \"claimed\" : this.claimVerdict(card, shared, claimCounts, worldClaims)), trace);\n const added = ordered.slice(0, free).map((e) => e.card.id);\n this.boardContents.set(hand.id, [...contents, ...added]);\n for (const id of added) {\n claimCounts.set(id, (claimCounts.get(id) ?? 0) + 1);\n worldClaims.set(id, (worldClaims.get(id) ?? 0) + 1);\n }\n // Emitted after the hand is set: a handler reading board() sees the deal.\n if (trace) {\n this.capTrace(trace, new Set(added));\n this.emit({ type: \"deal\", hand: effectiveGameId(hand), cards: trace }, this.turnCounts.get(box.id) ?? 0);\n }\n }\n\n return Object.fromEntries(dealt.map(({ hand }) => [\n effectiveGameId(hand),\n (this.boardContents.get(hand.id) ?? []).map((id) => this.view(this.internals.cardsById.get(id)!)),\n ]));\n }\n\n /** The board: current hand contents, in dealt order, keyed by hand gameId\n * (schema 5). Read it for what is out; peek the stock for what could\n * come.\n *\n * `boxRef` (a box gameId or id) narrows the read to that box's hands, in\n * the same shape and the same order: \"give me the barks hands\" is a\n * common host query, and boxes are how a game separates its storylet\n * systems, so the grouping belongs here rather than in every host. An\n * unknown box throws, as it does on turn() and peek(). */\n board(boxRef?: string): Record<string, DealtCard[]> {\n this.assertOpen();\n let keep: string | undefined;\n if (boxRef !== undefined) {\n const box = this.internals.boxesByGameId.get(boxRef) ?? this.internals.boxesById.get(boxRef);\n if (!box) throw new Error(`unknown box \"${boxRef}\"`);\n keep = box.id;\n }\n return Object.fromEntries([...this.boardContents.entries()]\n .filter(([handId]) => keep === undefined || this.internals.handsById.get(handId)!.box.id === keep)\n .map(([handId, ids]) => [\n effectiveGameId(this.internals.handsById.get(handId)!.hand),\n ids.map((id) => this.view(this.internals.cardsById.get(id)!)),\n ]));\n }\n\n /** Resolve a played/inspected card within a hand on the board. */\n private resolveDealt(cardId: string, handRef: string): { entry: CardEntry; ask: AskDescriptor } {\n const entry = this.internals.cardsById.get(cardId) ?? this.internals.cardsByGameId.get(cardId);\n if (!entry) throw new Error(`unknown card \"${cardId}\"`);\n const { hand, box } = this.resolveHand(handRef);\n if (!(this.boardContents.get(hand.id) ?? []).includes(entry.card.id)) {\n throw new Error(`card \"${effectiveGameId(entry.card)}\" is not dealt to hand \"${effectiveGameId(hand)}\"`);\n }\n return { entry, ask: this.askForHand(hand, box) };\n }\n\n /** Outcome availability, evaluated against CURRENT state on every ask\n * (schema 3.1/5) - never a deal-time snapshot. */\n outcomes(cardId: string, from: string): OutcomeView[] {\n this.assertOpen();\n const { entry, ask } = this.resolveDealt(cardId, from);\n const ctx = this.evalCtx(entry.box, entry.deck, this.buildHandEnv(ask));\n return entry.card.outcomes.map((o) => ({\n id: o.id,\n gameId: effectiveGameId(o),\n ...(o.title !== undefined ? { title: o.title } : {}),\n ...(o.purpose !== undefined ? { purpose: o.purpose } : {}),\n available: this.passes(o.condition, ctx),\n }));\n }\n\n /** Apply an outcome (schema 3.7): the card must sit in a hand on the\n * board (you never play a card from inside the deck). Throws before any\n * mutation on a gated-shut outcome or a bad write target. */\n play(cardId: string, outcomeGameId: string, from: string, opts: PlayOptions = {}): void {\n this.assertOpen();\n const { entry, ask } = this.resolveDealt(cardId, from);\n const outcome = entry.card.outcomes.find((o) => effectiveGameId(o) === outcomeGameId);\n if (!outcome) throw new Error(`card \"${effectiveGameId(entry.card)}\" has no outcome \"${outcomeGameId}\"`);\n\n const handEnv = this.buildHandEnv(ask);\n const ctx = this.evalCtx(entry.box, entry.deck, handEnv);\n if (!this.passes(outcome.condition, ctx)) {\n throw new Error(`outcome \"${outcomeGameId}\" on \"${effectiveGameId(entry.card)}\" is gated shut`);\n }\n\n // The played card's box's clock advances (schema 3.4); computed up\n // front so the play and its writes log as one action, one turn stamp.\n const newTurn = (this.turnCounts.get(entry.box.id) ?? 0)\n + (opts.advanceTurns ?? this.internals.bundle.settings.playAdvancesTurns);\n\n // Every right-hand side evaluates against PRE-play state, then all\n // writes land (schema 3.7).\n const writes: { target: string; value: ScalarValue }[] = [];\n for (const [target, expr] of Object.entries(outcome.changes)) {\n writes.push({ target, value: this.eval(expr, ctx) });\n }\n for (const { target, value } of writes) {\n const { path, prev } = this.applyWrite(target, value, entry, handEnv);\n if (this.tracing) this.emit({ type: \"write\", target, path, value, ...(prev !== undefined ? { prev } : {}) }, newTurn);\n }\n\n const record: PlayRecord = { card: effectiveGameId(entry.card), outcome: effectiveGameId(outcome), turn: newTurn };\n this.playLog.push(record);\n this.indexPlay(record);\n if (entry.card.redraw === \"never\") {\n // A shared one-shot leaves the world rather than this flow: the engine\n // holds it, so every flow is refused. A finite redraw deliberately does\n // NOT share, whatever the deck says - a cooldown is an absolute turn of\n // this flow's box clock, and there is no shared clock to compare it\n // against (design/shared-scarcity.md 9.3.2).\n if (cardIsShared(entry.card, entry.deck.shared ?? false)) this.engine.markTaken(entry.card.id);\n else this.cooldowns[entry.card.id] = Number.MAX_SAFE_INTEGER;\n } else if (typeof entry.card.redraw === \"number\") {\n this.cooldowns[entry.card.id] = newTurn + entry.card.redraw;\n }\n // The card leaves its hand, releasing its claim (schema 3.5/3.7).\n const handId = ask.hand!.id;\n this.boardContents.set(handId,\n (this.boardContents.get(handId) ?? []).filter((id) => id !== entry.card.id));\n this.turnCounts.set(entry.box.id, newTurn);\n // Emitted last: a handler reading the board and the clock sees the play.\n if (this.tracing) this.emit({ type: \"play\", card: entry.card.id, outcome: effectiveGameId(outcome), turn: newTurn }, newTurn);\n }\n\n /** Land one change in whichever partition declares the name: the flow's\n * bag when the property is per-flow, the shared bag when it is shared -\n * the union/partition invariant made executable. */\n private landIn(kind: Exclude<PartitionKind, \"story\"> | \"story\", id: string | undefined, name: string, value: ScalarValue, path: string): { path: string; prev?: ScalarValue } {\n const own = kind === \"story\" ? this.stores.story : id !== undefined ? this.stores[kind].get(id) : undefined;\n const shared = kind === \"story\" ? this.internals.shared.story : id !== undefined ? this.internals.shared[kind].get(id) : undefined;\n const bag = own !== undefined && own.get(name) !== undefined ? own\n : shared !== undefined && shared.get(name) !== undefined ? shared\n : undefined;\n if (bag === undefined) throw new Error(`no property at \"${path}\"`);\n // An engine write: the bag's subscribers fire (the firing rule).\n const change = bag.set(name, value);\n return { path, ...(change.prev !== undefined ? { prev: change.prev } : {}) };\n }\n\n /** Land one change; returns the resolved store path (for the trace) and\n * the value it replaced (for the log's \"0 -> 1\" reading). */\n private applyWrite(target: string, value: ScalarValue, entry: CardEntry, handEnv: HandEnv): { path: string; prev?: ScalarValue } {\n const match = /^@([a-z]+)\\.([A-Za-z_][A-Za-z0-9_-]*)$/.exec(target);\n if (!match) throw new Error(`bad change target \"${target}\"`);\n const [, scope, name] = match as unknown as [string, string, string];\n switch (scope) {\n case \"world\": {\n const resolver = this.internals.worldResolver;\n if (!resolver.set) throw new Error(`@world.${name} cannot be written: the host bound @world read-only`);\n // The story's own promise, kept here as the compiler keeps it at publish;\n // the host's setProperty is its own path and never asks. Patter's runtime\n // refuses the same write through the shared kernel, so both read one way.\n if (this.internals.worldReadOnly.has(name)) throw new Error(`'@world.${name}' is read-only (writable: false)`);\n const prev = resolver.get(name);\n resolver.set(name, value);\n return { path: `world.${name}`, ...(prev !== undefined ? { prev } : {}) };\n }\n case \"story\": return this.landIn(\"story\", undefined, name, value, `story.${name}`);\n case \"box\": return this.landIn(\"box\", entry.box.id, name, value, `box.${entry.box.id}.${name}`);\n case \"deck\": return this.landIn(\"deck\", entry.deck.id, name, value, `deck.${entry.deck.id}.${name}`);\n case \"hand\": {\n // Write-back routing (schema 3.6): the composed name remembers its\n // source store; writes to criteria/chosen-tag names are errors.\n const source = handEnv.sources.get(name);\n if (!source) throw new Error(`@hand.${name} is not composed in this ask`);\n if (source.kind === \"criteria\") throw new Error(`@hand.${name} is a chosen tag / criteria name and cannot be written`);\n return this.landIn(source.kind, source.id, name, value, `${source.kind}.${source.id}.${name}`);\n }\n default: throw new Error(`bad change target scope \"@${scope}\"`);\n }\n }\n\n /** Advance one box's clock (schema 3.4): a turn is one draw-from-stock\n * session for that box, on THIS flow's clock. */\n advanceTurns(boxRef: string, n = 1): void {\n this.assertOpen();\n const box = this.internals.boxesByGameId.get(boxRef) ?? this.internals.boxesById.get(boxRef);\n if (!box) throw new Error(`unknown box \"${boxRef}\"`);\n const next = (this.turnCounts.get(box.id) ?? 0) + n;\n this.turnCounts.set(box.id, next);\n if (this.tracing) this.emit({ type: \"turns\", box: effectiveGameId(box), turn: next }, next);\n }\n\n // --- state access (host surface + test tooling) ---------------------------------\n\n /** Every box, bundle order: identity + this flow's clock (the enumeration\n * surface examiners key their turns sections on; parity member). */\n listBoxes(): BoxView[] {\n this.assertOpen();\n return this.internals.bundle.boxes.map((b) => ({\n id: b.id,\n gameId: effectiveGameId(b),\n ...(b.title !== undefined ? { title: b.title } : {}),\n turn: this.turnCounts.get(b.id) ?? 0,\n }));\n }\n\n /** THIS flow's kernel bags with their store path prefixes (the state\n * logger's mount surface; parity member). The shared bags are the\n * Engine's listBags; the flows are rebuilt by loadGame, so consumers\n * re-enumerate after a load. */\n listBags(): BagMount[] {\n this.assertOpen();\n const mounts: BagMount[] = [{ prefix: \"story\", bag: this.stores.story }];\n for (const kind of [\"box\", \"deck\", \"hand\", \"value\"] as const) {\n for (const [id, bag] of this.stores[kind]) mounts.push({ prefix: `${kind}.${id}`, bag });\n }\n return mounts;\n }\n\n /** The flow's FULL merged view as examiner rows (the property examiner /\n * editor surface, parity across all runtimes): @world read through the\n * resolver, then per scope the shared values and this flow's own.\n * Bundle order: world, story, then per-box / per-deck / per-hand /\n * per-tag stores. */\n listProperties(): PropertyRow[] {\n this.assertOpen();\n const out: PropertyRow[] = [];\n for (const d of this.internals.bundle.world.properties) {\n const value = this.internals.worldResolver.get(d.name);\n out.push({\n path: `world.${d.name}`, name: d.name, type: d.type,\n value: value ?? d.default, default: d.default,\n ...(d.values !== undefined ? { values: d.values } : {}),\n ...(d.stages !== undefined ? { stages: d.stages } : {}),\n // @world is FOREIGN - a host resolver backs it - so writability is whether that\n // resolver can be written at all, which is the shared registry's own rule for a\n // foreign scope. The `as PropertyView` cast this replaced was hiding the field's\n // absence: the row type has always required it, and these rows shipped without one.\n writable: this.internals.worldResolver.set !== undefined,\n });\n }\n const add = (_prefix: string, shared: StateBag | undefined, own: StateBag | undefined): void => {\n for (const bag of [shared, own]) {\n if (bag === undefined) continue;\n for (const row of bag.rows()) out.push(row);\n }\n };\n add(\"story\", this.internals.shared.story, this.stores.story);\n for (const kind of [\"box\", \"deck\", \"hand\", \"value\"] as const) {\n const ids = new Set([...this.internals.shared[kind].keys(), ...this.stores[kind].keys()]);\n for (const id of ids) add(`${kind}.${id}`, this.internals.shared[kind].get(id), this.stores[kind].get(id));\n }\n return out;\n }\n\n /** Read by path: \"world.x\", \"story.gold\", \"value.v_docks.danger\",\n * \"box.b_x.heat\", \"deck.k_main.n\", \"hand.h_board.owner\" - the flow's\n * merged view, routed by the declaration's sharing. */\n getProperty(path: string): ScalarValue {\n this.assertOpen();\n const found = this.resolvePath(path);\n const value = found.kind === \"world\" ? this.internals.worldResolver.get(found.name)\n : found.own?.get(found.name) ?? found.shared?.get(found.name);\n if (value === undefined) throw new Error(`no property at \"${path}\"`);\n return value;\n }\n\n setProperty(path: string, value: ScalarValue): void {\n this.assertOpen();\n const found = this.resolvePath(path);\n if (found.kind === \"world\") {\n if (!this.internals.worldResolver.set) throw new Error(`@world is read-only here: the host bound no write`);\n this.internals.worldResolver.set(found.name, value);\n return;\n }\n const bag = found.own !== undefined && found.own.get(found.name) !== undefined ? found.own\n : found.shared !== undefined && found.shared.get(found.name) !== undefined ? found.shared\n : undefined;\n if (bag === undefined) throw new Error(`no property at \"${path}\"`);\n // A host write: silent under the firing rule (no subscriber feedback\n // loop), but visible to the bag's audit hook.\n bag.set(found.name, value, { silent: true, reason: \"host setProperty\" });\n }\n\n private resolvePath(path: string): { kind: \"world\"; name: string } | { kind: \"bag\"; own?: StateBag; shared?: StateBag; name: string } {\n const parts = path.split(\".\");\n if (parts.length === 2 && parts[0] === \"world\") return { kind: \"world\", name: parts[1]! };\n if (parts.length === 2 && parts[0] === \"story\") {\n return { kind: \"bag\", own: this.stores.story, shared: this.internals.shared.story, name: parts[1]! };\n }\n if (parts.length === 3 && (parts[0] === \"box\" || parts[0] === \"deck\" || parts[0] === \"hand\" || parts[0] === \"value\")) {\n const kind = parts[0] as Exclude<PartitionKind, \"story\">;\n const own = this.stores[kind].get(parts[1]!);\n const shared = this.internals.shared[kind].get(parts[1]!);\n if (own === undefined && shared === undefined) throw new Error(`no ${parts[0]} store \"${parts[1]}\"`);\n return { kind: \"bag\", ...(own !== undefined ? { own } : {}), ...(shared !== undefined ? { shared } : {}), name: parts[2]! };\n }\n throw new Error(`bad property path \"${path}\"`);\n }\n\n // --- persistence (schema 4) -------------------------------------------------\n\n /** @internal - this flow's blob inside the engine's envelope. */\n snapshot(): FlowSave {\n return {\n props: partitionValues(this.stores),\n turns: Object.fromEntries(this.turnCounts),\n prng: this.prng.state(),\n cooldowns: this.cooldowns,\n board: Object.fromEntries(this.boardContents),\n playLog: this.playLog,\n };\n }\n\n /** @internal - restore a freshly opened flow from its blob (loadGame).\n * Orphaned keys (deleted entities) drop; new declarations keep defaults. */\n restore(saved: FlowSave): void {\n loadPartition(this.stores, saved.props);\n this.turnCounts = new Map(this.internals.bundle.boxes.map((b) => [b.id, 0]));\n for (const [boxId, turn] of Object.entries(saved.turns ?? {})) {\n if (this.turnCounts.has(boxId)) this.turnCounts.set(boxId, turn);\n }\n this.prng = makePrng(saved.prng);\n this.cooldowns = saved.cooldowns ?? {};\n this.playLog = saved.playLog ?? [];\n this.rebuildPlayIndex();\n this.boardContents = new Map(Object.entries(saved.board ?? {})\n .filter(([handId]) => this.internals.handsById.has(handId))\n .map(([handId, ids]) => [handId, ids.filter((id) => this.internals.cardsById.has(id))]));\n for (const handId of this.internals.handsById.keys()) {\n if (!this.boardContents.has(handId)) this.boardContents.set(handId, []);\n }\n }\n}\n","// ---------------------------------------------------------------------------\n// describeBundle - the bundle inspector's runtime half (design/engine-runtimes.md\n// section 2, piece 6).\n//\n// A BUNDLE-level API, deliberately NOT a session method: it answers the\n// integrator's question - \"I dropped a .storyletsc into my project, what may\n// my game code call?\" - from the imported asset alone, with no session, no\n// state and no game running. That makes the boundary rule (design 4) visible:\n// hands are what deal() takes, tag groups + tags are what peek() criteria are\n// drawn from, declared properties are what expressions read and a host may\n// set. Card lists are deliberately absent: cards are the engine's business,\n// counts are the orientation an integrator needs.\n//\n// Everything is in bundle order, so the description is deterministic and two\n// runtimes render the same rows in the same sequence. The property scopes are\n// the static twin of session.listProperties(): the same stores, in the same\n// order, before anything is instantiated (a hand instance carries its\n// template's declarations, exactly as the session's hand bags do).\n// ---------------------------------------------------------------------------\n\nimport { effectiveGameId } from \"@storylet-studio/model\";\nimport type {\n Box, Bundle, Expression, Hand, PropertyDecl, PropertyType, ScalarValue,\n} from \"@storylet-studio/model\";\n\n/** What bundle this is: the staleness/identity triple plus the schema tag. */\nexport interface BundleIdentity {\n /** The bundle schema tag (\"storylets/bundle@0\"). */\n schema: string;\n /** content.project - the project name a save must agree with. */\n project: string;\n /** content.version - the authored bundle version. */\n version: string;\n /** content.hash - hash32 over the canonical source shards (schema 2.8). */\n hash: string;\n /** \"full\" | \"stripped\": whether authoring metadata (titles) survived. */\n metadata: string;\n}\n\n/** One hand: the deal() surface. `gameId` is the name deal() is called with. */\nexport interface HandSummary {\n gameId: string;\n title?: string;\n /** The owning box's gameId (peek's first argument for the same stock). */\n box: string;\n /** The effective slot cap: the hand's override, else its template's or\n * rule's, else \"unbounded\". */\n slots: number | \"unbounded\";\n /** The hand template's gameId; absent for a standalone (inline-rule) hand. */\n template?: string;\n}\n\n/** One tag group and its tags, by gameId: the peek() criteria surface (a\n * criteria entry is `{ [group gameId]: tag gameId }`). */\nexport interface TagGroupSummary {\n gameId: string;\n tags: string[];\n}\n\n/** One box: identity, its ranking policy, its tag groups, and counts. */\nexport interface BoxSummary {\n gameId: string;\n title?: string;\n /** The only per-box ranking policy (Reboot 2.2). */\n ranking: { specificity: boolean };\n tagGroups: TagGroupSummary[];\n counts: {\n decks: number;\n cards: number;\n hands: number;\n templates: number;\n tagGroups: number;\n };\n}\n\n/** One declared property: what expressions read and what a host may set. */\nexport interface PropertySummary {\n name: string;\n type: PropertyType;\n default: ScalarValue;\n /** Enum / flags options, where declared. */\n values?: string[];\n purpose?: string;\n}\n\n/** The scope a declaration block belongs to. `tag` declarations compose into\n * @hand for any ask that binds the tag (schema 3.6). */\nexport type PropertyScopeKind = \"world\" | \"story\" | \"box\" | \"deck\" | \"hand\" | \"tag\";\n\n/** One scope's declared properties. `owner` is the owning entity's gameId\n * (empty for world / story); `box` names its box; `group` names a tag's\n * group. */\nexport interface PropertyScopeSummary {\n scope: PropertyScopeKind;\n owner: string;\n box?: string;\n group?: string;\n properties: PropertySummary[];\n}\n\n/**\n * One map the bundle was asked to carry (design/graphical-views.md 2).\n *\n * Counts rather than the geometry itself, which is the same judgement the rest\n * of this file makes: an inspector answers \"what is in here\", and a host that\n * wants the polygons reads `bundle.maps` directly. Reported because a bundle\n * that silently carried a map would fail the promise this API exists for.\n */\nexport interface MapSummary {\n /** The owning box, by gameId. */\n box: string;\n /** The tag group this is a map of, by gameId. */\n group: string;\n zones: number;\n backgrounds: number;\n}\n\n/** What a bundle offers a host, read from the asset alone. */\nexport interface BundleDescription {\n identity: BundleIdentity;\n /** Orientation, not inventory: no card lists (Reboot 2.1). */\n totals: {\n boxes: number;\n decks: number;\n cards: number;\n hands: number;\n templates: number;\n tagGroups: number;\n };\n boxes: BoxSummary[];\n /** Every hand in the bundle, box by box: the deal() surface. */\n hands: HandSummary[];\n /** world, story, then per box: the box, its decks, its hands, its tags.\n * Scopes that declare nothing are omitted (world and story always show,\n * so their absence reads as \"this bundle declares none\"). */\n properties: PropertyScopeSummary[];\n /** Maps carried as inert payload, when the build asked for them. Empty is\n * the normal state and means the bundle has no geometry in it. */\n maps: MapSummary[];\n}\n\nconst summarise = (decls: PropertyDecl[]): PropertySummary[] =>\n decls.map((d) => ({\n name: d.name,\n type: d.type,\n default: d.default,\n ...(d.values !== undefined ? { values: d.values } : {}),\n ...(d.purpose !== undefined ? { purpose: d.purpose } : {}),\n }));\n\n/** A hand's declared @hand state: a template instance inherits its template's\n * declarations, a standalone hand declares its own (schema 2.6) - the same\n * rule the session's hand bags are built on. */\nconst handDecls = (hand: Hand<Expression>, box: Box<Expression>): PropertyDecl[] => {\n if (hand.template !== undefined) {\n return box.handTemplates.find((t) => t.id === hand.template)?.properties ?? [];\n }\n return hand.properties ?? [];\n};\n\n/** The effective slot cap, resolved the way the session resolves capacity. */\nconst handSlots = (hand: Hand<Expression>, box: Box<Expression>): number | \"unbounded\" => {\n if (hand.slots !== undefined) return hand.slots;\n const declared = hand.template !== undefined\n ? box.handTemplates.find((t) => t.id === hand.template)?.slots\n : hand.rule?.slots;\n return declared === undefined ? \"unbounded\" : declared;\n};\n\n/** Describe a compiled bundle: the callable surface of an imported asset, no\n * session required (design/engine-runtimes.md 2, piece 6). Bundle order\n * throughout; the same shape every runtime returns. */\nexport function describeBundle(bundle: Bundle): BundleDescription {\n const boxes: BoxSummary[] = [];\n const hands: HandSummary[] = [];\n const properties: PropertyScopeSummary[] = [\n { scope: \"world\", owner: \"\", properties: summarise(bundle.world.properties) },\n { scope: \"story\", owner: \"\", properties: summarise(bundle.story.properties) },\n ];\n const totals = { boxes: 0, decks: 0, cards: 0, hands: 0, templates: 0, tagGroups: 0 };\n\n for (const box of bundle.boxes) {\n const boxGameId = effectiveGameId(box);\n const cards = box.decks.reduce((n, deck) => n + deck.cards.length, 0);\n boxes.push({\n gameId: boxGameId,\n ...(box.title !== undefined ? { title: box.title } : {}),\n ranking: { specificity: box.ranking.specificity },\n tagGroups: box.tagGroups.map((group) => ({\n gameId: effectiveGameId(group),\n tags: group.tags.map((tag) => effectiveGameId(tag)),\n })),\n counts: {\n decks: box.decks.length,\n cards,\n hands: box.hands.length,\n templates: box.handTemplates.length,\n tagGroups: box.tagGroups.length,\n },\n });\n totals.boxes += 1;\n totals.decks += box.decks.length;\n totals.cards += cards;\n totals.hands += box.hands.length;\n totals.templates += box.handTemplates.length;\n totals.tagGroups += box.tagGroups.length;\n\n for (const hand of box.hands) {\n const template = hand.template !== undefined\n ? box.handTemplates.find((t) => t.id === hand.template)\n : undefined;\n hands.push({\n gameId: effectiveGameId(hand),\n ...(hand.title !== undefined ? { title: hand.title } : {}),\n box: boxGameId,\n slots: handSlots(hand, box),\n ...(template !== undefined ? { template: effectiveGameId(template) } : {}),\n });\n }\n\n // The property scopes, in the session's store order: box, decks, hands,\n // tags. Empty declaration blocks are dropped (nothing to read or set).\n const push = (scope: PropertyScopeKind, owner: string, decls: PropertyDecl[], group?: string): void => {\n if (decls.length === 0) return;\n properties.push({\n scope, owner, box: boxGameId, ...(group !== undefined ? { group } : {}),\n properties: summarise(decls),\n });\n };\n push(\"box\", boxGameId, box.properties);\n for (const deck of box.decks) push(\"deck\", effectiveGameId(deck), deck.properties);\n for (const hand of box.hands) push(\"hand\", effectiveGameId(hand), handDecls(hand, box));\n for (const group of box.tagGroups) {\n for (const tag of group.tags) {\n push(\"tag\", effectiveGameId(tag), tag.properties ?? [], effectiveGameId(group));\n }\n }\n }\n\n return {\n identity: {\n schema: bundle.schema,\n project: bundle.content.project,\n version: bundle.content.version,\n hash: bundle.content.hash,\n metadata: bundle.metadata,\n },\n totals,\n boxes,\n hands,\n properties,\n maps: (bundle.maps ?? []).map((map) => ({\n box: map.box,\n group: map.group,\n zones: map.zones.length,\n backgrounds: map.backgrounds?.length ?? 0,\n })),\n };\n}\n"],"mappings":"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","names":["val"]}
|