@cyberart-io/engine 0.0.8 → 0.0.9

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.
@@ -0,0 +1,60 @@
1
+ # Selection trace
2
+
3
+ Content-selection and presentation-decision diagnostics. Hosts record which projection revision, binding, content hash, sequence step, layer, caption, and fallback actually won. The same query/export API is browser-safe (`@cyberart-io/engine`) and headless. There is no Player UI.
4
+
5
+ Related: [Replay inspector](replay-inspector.md) (CYB-65 causation ids, `DEFAULT_SENSITIVE_KEYS` / `REDACTED_VALUE`, bounded export), [Production scenario](production-scenario.md) (CYB-82 evidence bundle `selectionTrace` field), [Content revision](content-revision.md) (CYB-79), [Presentation bindings](presentation-bindings.md) (CYB-83), [Presentation sequences](presentation-sequences.md) (CYB-78). Back to the [package README](../README.md).
6
+
7
+ ## One-command reproduce (this repo)
8
+
9
+ ```bash
10
+ pnpm exec vitest run packages/engine/src/canvas/cyb-85-selection-trace.repro.spec.ts
11
+ ```
12
+
13
+ ## When to use
14
+
15
+ | Surface | Import | Use |
16
+ |---|---|---|
17
+ | Production host | `createSelectionTrace` from `@cyberart-io/engine` | Call `recordSelectionDecision` as bindings, revisions, assets, and sequences resolve. Export JSON. |
18
+ | Vitest / jsdom | same, or `@cyberart-io/engine/headless` | Query/export/import the same records. `attachSelectionTrace` hangs the export on a CYB-82 evidence bundle. |
19
+
20
+ Compose with `createReplayInspector` — import it, do not replace it. Link records with `correlationId` / `causationId` / `envelopeId`.
21
+
22
+ Generic fixture ids only: `whistle`, `ripple`, `room`, `npc`, revision `8` vs `9`.
23
+
24
+ ## Contract
25
+
26
+ 1. **Decision record.** One JSON object covers state-projection revision, each binding predicate/priority/winner, requested vs activated content identity (revision, manifest version, publisher/source, hashes), staging/cache/supersession/rejection/rollback/last-known-good, resolved asset ref/hash/readiness/fallback, sequence invocation/step/track/interrupt/skip/replay, layer/region/caption/audio intent, and snapshot/replay provenance.
27
+ 2. **Reason codes.** `binding-conflict`, `asset-failure`, `revision-rollback`, `sequence-interruption`, and `text-only-fallback` are distinct. Hosts may add more strings.
28
+ 3. **Correlation.** Records carry `correlationId` / `causationId` / `envelopeId` plus `initiatingEventType`. Export includes matching CYB-65 inspector records when an inspector is attached or imported.
29
+ 4. **Redaction.** Credentials, private prompts, signed URLs, and non-whitelisted host-projection fields become `REDACTED_VALUE`. Hosts whitelist safe projection keys; an empty whitelist redacts every projection field. Array projections are whitelisted per element; a bare primitive projection is redacted. Signed URLs pasted into prose (`summary`, `staging.detail`, `rejectedReason`) are replaced in place.
30
+ 5. **Bounds.** `maxRecords` (default 512) drops oldest rows. `sampleRate` may drop noise; the five distinct failure codes always record.
31
+ 6. **Export / import.** JSON-serializable. Import restores records, inspector linkage, and snapshot revision/seed. Same query API in browser and headless.
32
+ 7. **Evidence.** `attachSelectionTrace(bundle, export)` sets `ProductionScenarioEvidenceBundle.selectionTrace`. The scenario runner is unchanged.
33
+
34
+ ```ts
35
+ import {
36
+ attachSelectionTrace,
37
+ createReplayInspector,
38
+ createSelectionTrace,
39
+ } from '@cyberart-io/engine';
40
+
41
+ const inspector = createReplayInspector();
42
+ const trace = createSelectionTrace({
43
+ inspector,
44
+ projectionWhitelist: ['inventory', 'roomId', 'lineId'],
45
+ });
46
+ trace.recordSelectionDecision({
47
+ kind: 'asset',
48
+ reason: 'text-only-fallback',
49
+ summary: 'npc audio not ready; caption selected',
50
+ correlationId: envelope.correlationId,
51
+ envelopeId: envelope.id,
52
+ initiatingEventType: 'host.state.accepted',
53
+ asset: { logicalRef: 'npc.line.audio', ready: false, fallback: 'npc.line.caption' },
54
+ });
55
+ trace.setSnapshotProvenance({ revision: 8, schemaVersion: 2, seed });
56
+ const exported = trace.exportTrace({ correlationId: envelope.correlationId });
57
+ const evidence = attachSelectionTrace(bundle, exported);
58
+ inspector.destroy();
59
+ trace.destroy();
60
+ ```
@@ -0,0 +1,72 @@
1
+ # Semantic layers
2
+
3
+ Named visual regions published by the cart: mask, polygon, and/or depth in the shared [normalized](normalized-geometry.md) coordinate system. The host drives hover / focus / selected and supplies accessibility names and roles. Geometry, blend, and hit-test policy stay with the cart.
4
+
5
+ Related: [visual layers](visual-layers.md), [compositor](compositor.md), [normalized geometry](normalized-geometry.md), [browser harness](browser-harness.md). Built on this: [presentation sequences](presentation-sequences.md) (focus track), [presentation bindings](presentation-bindings.md) (`setRegionState`, hit-test policy via `restore`), [production scenario](production-scenario.md) (semantic hash in the evidence bundle). Back to the [package README](../README.md).
6
+
7
+ ## One-command reproduce (this repo)
8
+
9
+ ```bash
10
+ pnpm exec vitest run packages/engine/src/canvas/cyb-73-semantic-layers.repro.spec.ts
11
+ ```
12
+
13
+ ## When to use
14
+
15
+ | Surface | Import | Use |
16
+ |---|---|---|
17
+ | Production host | `createSemanticLayerController` from `@cyberart-io/engine` | Enumerate published regions, `setRegionState`, `setRegionA11y`, `hitTest`. |
18
+ | Vitest / jsdom | same, after `installHeadlessCanvas()` | `inspectPublished()` — no DOM overlay. |
19
+ | Browser harness | `semanticLayers` on `createBrowserHarness` | A11y snapshot lists published ids / names / roles. |
20
+
21
+ Generic ids only: `cabinet`, `plaque`, `stage`. The cart authors geometry; the host owns the a11y tree and pointer focus.
22
+
23
+ ## Hit-test policies
24
+
25
+ | Policy | Behavior |
26
+ |---|---|
27
+ | `pass-through` | Published for SAM / a11y, never wins `hitTest`. |
28
+ | `absorb` | First absorbing hit (after exclusive/depth sort) claims the pointer. |
29
+ | `exclusive` | Exclusive hits beat non-exclusive overlapping regions. |
30
+ | `depth-ordered` | Among remaining hits, higher `geometry.depth` wins, then `order`. |
31
+
32
+ ## `createSemanticLayerController(options)`
33
+
34
+ ```ts
35
+ import { createSemanticLayerController } from '@cyberart-io/engine';
36
+
37
+ const regions = createSemanticLayerController({
38
+ compositor,
39
+ visualLayers,
40
+ regions: [
41
+ {
42
+ id: 'cabinet',
43
+ hitTest: 'absorb',
44
+ blend: 'source-over',
45
+ compositorLayerId: 'hotspot',
46
+ visualLayerId: 'hotspot',
47
+ geometry: {
48
+ polygon: [
49
+ { x: 0.2, y: 0.2 },
50
+ { x: 0.5, y: 0.2 },
51
+ { x: 0.5, y: 0.5 },
52
+ { x: 0.2, y: 0.5 },
53
+ ],
54
+ depth: 0.4,
55
+ },
56
+ visuals: {
57
+ idle: { version: 'idle', blend: 'source-over' },
58
+ hover: { version: 'hover', blend: 'screen' },
59
+ },
60
+ },
61
+ ],
62
+ });
63
+
64
+ regions.setRegionA11y('cabinet', { name: 'Arcade cabinet', role: 'button' });
65
+ regions.setRegionState('cabinet', { hover: true });
66
+ const hit = regions.hitTest({ x: 0.3, y: 0.3 });
67
+ const sam = regions.inspectPublished();
68
+ ```
69
+
70
+ `inspectPublished()` returns `{ id, geometryKinds, a11y }` so a Segment Anything–style client can label cart-authored regions instead of reverse-engineering pixels. `geometryKinds` lists `mask`, `polygon`, `rect`, and/or `depth` as declared — a box is `rect`, not a full-frame depth field.
71
+
72
+ Hosts persist `regions.snapshot()` JSON inside envelope `hostState`. Restore validates the full region set (ids, geometry, mask, blend, hit-test policy) before mutating. Tampered or unknown-id JSON returns `{ ok: false }` and leaves live state unchanged. Unknown visual-layer versions fail restore or throw from `setRegionState`; a missing compositor layer is skipped until the host creates it.
package/docs/snapshots.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Portable save envelope for carts and embedding hosts. Schema **1** is the previous engine-owned `CartStateBundle` (`CART_STATE_BUNDLE_VERSION = 1`). Schema **2** wraps that blob in `engineState` and keeps host-owned data in `hostState` / `hostStateRef`. Cyberart migrates envelopes in memory; the host owns persistence (local storage, a database, cross-user saves). This package is not the database of record.
4
4
 
5
- Related: [deterministic mode](deterministic-mode.md) (`rng` / clock), [capability manifest](capability-manifest.md) (cart id). Back to the [package README](../README.md).
5
+ Related: [deterministic mode](deterministic-mode.md) (`rng` / clock), [capability manifest](capability-manifest.md) (cart id). Modules that persist their own `snapshot()` JSON inside envelope `hostState` and validate before restore: [semantic layers](semantic-layers.md), [presentation bindings](presentation-bindings.md), [portal lifecycle](portal-lifecycle.md), [job orchestration](job-orchestration.md), [world graph](world-graph.md), [world patch](world-patch.md), [content revision](content-revision.md). Envelope `provenance` comes from [remote cart manifests](remote-cart-manifest.md). Back to the [package README](../README.md).
6
6
 
7
7
  ## One-command reproduce (this repo)
8
8
 
@@ -4,7 +4,7 @@ Versioned overlay / mask / sprite declarations with deterministic show, hide, re
4
4
 
5
5
  Hosts persist `controller.snapshot()` JSON inside envelope `hostState`. This module does not edit the snapshot envelope.
6
6
 
7
- Related: [presentation cue](presentation-cue.md), [compositor](compositor.md), [asset resolver](asset-resolver.md), [snapshots](snapshots.md). Back to the [package README](../README.md).
7
+ Related: [presentation cue](presentation-cue.md), [compositor](compositor.md), [asset resolver](asset-resolver.md), [snapshots](snapshots.md). Built on this: [semantic layers](semantic-layers.md) (named regions over these layers), [presentation sequences](presentation-sequences.md) (visual track), [presentation bindings](presentation-bindings.md) (`visual-layer` targets, one accepted revision is one layer set). Back to the [package README](../README.md).
8
8
 
9
9
  ## One-command reproduce (this repo)
10
10
 
@@ -0,0 +1,39 @@
1
+ # World graph
2
+
3
+ Optional, headless-capable spatial graph for rooms, regions, frontiers, discovery, and entity transit. Hosts supply cost/policy functions and semantic time. The module does not render maps, run an economy, or encode combat, quest, or narrative rules.
4
+
5
+ Related: [Events and router](events.md) (CYB-59 contracts), [Snapshots](snapshots.md), [Job orchestration](job-orchestration.md) (generated frontier *work*, not graph identity). Built on this: [World patch](world-patch.md) (optional graph composition; a patch's node/edge ops are applied here atomically with the world revision). Back to the [package README](../README.md).
6
+
7
+ ## One-command reproduce (this repo)
8
+
9
+ ```bash
10
+ pnpm exec vitest run packages/engine/src/canvas/cyb-81-world-graph.repro.spec.ts
11
+ ```
12
+
13
+ ## When to use
14
+
15
+ | Surface | Import | Use |
16
+ |---|---|---|
17
+ | Production host | `createWorldGraph` from `@cyberart-io/engine` | Persist `snapshot()` in envelope `hostState`. Call `findPath` / `reachable` with host policy. |
18
+ | Vitest / jsdom | same, or `@cyberart-io/engine/headless` | Same API. `inspect()` is enough for calculation carts. Projections are data, not pixels. |
19
+
20
+ ## Contract
21
+
22
+ 1. **Stable IDs.** Nodes and edges keep host-authored ids and integer `version`s. Add/remove does not rewrite unrelated identities.
23
+ 2. **Canonical vs known.** `projectCanonical()` is the full graph. `projectKnown(observerId)` is only discovered nodes/edges plus unresolved frontiers adjacent to known edges. `visibility: 'canonical'` edges are always known.
24
+ 3. **Access.** Edges are `open`, `locked`, or `disabled`. Lock requirements are opaque JSON for the host policy. Traversal never inspects real time.
25
+ 4. **Semantic time.** `departedAt`, `expectedArrival`, and query `semanticTime` are host numbers. Completing transit is an explicit `completeTransit` call.
26
+ 5. **Patches.** `applyPatch` adds nodes/edges atomically; failure rolls back. Generated Room Eight is a patch, not a rename.
27
+ 6. **Restore** validates JSON, schema version, and referential integrity before mutate. Tampered snapshots return `{ ok: false }` and leave the graph unchanged. Pass `migrations` (`SnapshotMigration`, n → n+1) to lift older snapshots.
28
+ 7. **Events.** Typed `world.graph.state.*` / `world.graph.diagnostic.*` contracts from `worldGraphEventContracts()`.
29
+
30
+ ```ts
31
+ import { createWorldGraph } from '@cyberart-io/engine/headless';
32
+
33
+ const graph = createWorldGraph({ graphId: 'adventure' });
34
+ graph.applyPatch({ nodes, edges });
35
+ graph.discover('walker', { nodeIds: ['lodge', 'room-1'], edgeIds: ['lodge-room-1'] });
36
+ const minimap = graph.projectLocal('walker', 'room-1');
37
+ const bigMap = graph.projectRegional('walker');
38
+ const path = graph.findPath('lodge', 'station', hostPolicy, { semanticTime: day });
39
+ ```
@@ -0,0 +1,61 @@
1
+ # World patch
2
+
3
+ Transactional validation and atomic application of a generated world patch. Rooms, exits, characters, assets, dialogue, graph edges, and presentation bindings become one world revision or none. This is not a generic database transaction and does not make Cyberart the host's database of record.
4
+
5
+ Related: [Job orchestration](job-orchestration.md) (typed job result, host-owned apply), [World graph](world-graph.md) (optional `applyPatch` composition), [Content revision](content-revision.md) and [Presentation bindings](presentation-bindings.md) (availability checks, not activation), [Replay inspector](replay-inspector.md) (`DEFAULT_SENSITIVE_KEYS` / `REDACTED_VALUE`), [Snapshots](snapshots.md). Back to the [package README](../README.md).
6
+
7
+ ## One-command reproduce (this repo)
8
+
9
+ ```bash
10
+ pnpm exec vitest run packages/engine/src/canvas/cyb-84-world-patch.repro.spec.ts
11
+ ```
12
+
13
+ ## When to use
14
+
15
+ | Surface | Import | Use |
16
+ |---|---|---|
17
+ | Production host | `createWorldPatchApplier` from `@cyberart-io/engine` | Inject a persistence adapter. Persist `snapshot()` in envelope `hostState`. Call `commit` only under host policy. |
18
+ | Vitest / jsdom | same, or `@cyberart-io/engine/headless` | `createMemoryWorldPersistence` is enough. Tests may supply a copy-on-write host adapter. |
19
+
20
+ The host owns domain policy, authorization, persistence, and when a ready patch may become canon. Job completion time does not leak into canonical game time: `dryRun` a validated patch and `commit` later.
21
+
22
+ ## Contract
23
+
24
+ 1. **Envelope.** `patchId`, `schemaVersion`, `baseRevision`, `idempotencyKey`, typed operations, producer/job provenance. Unknown fields and unknown ops fail closed.
25
+ 2. **Dry-run.** `dryRun(patch)` validates schema, referential integrity, preconditions, cycles, asset/content availability, binding targets, and host domain validators. `inspect()` is unchanged.
26
+ 3. **Atomic commit.** `commit` dry-runs, then swaps one complete world revision. Observers never see a half-applied multi-entity patch.
27
+ 4. **Stale base.** A patch whose `baseRevision` is not the current revision is rejected with `stale-base` and structured expected/actual revisions. There is no silent rebase.
28
+ 5. **Idempotency.** Re-submitting an accepted `patchId` returns the same revision and does not emit again. A new patch may `supersedes` an accepted id.
29
+ 6. **Persistence.** Hosts inject `begin` / `applyWorldRevision` / `commit` / `rollback`, plus optional `publish`. `createMemoryWorldPersistence` is the in-memory reference; `rollback` restores the `begin()` snapshot. If post-commit publication throws, the previous revision is restored via `persistWorld`, not rollback-after-commit.
30
+ 7. **Ordering.** Operations sort by explicit `order`, then `(op, kind, id)` — never `Object.keys` order.
31
+ 8. **Events.** Exactly one `world.patch.state.accepted` per newly accepted revision: patch id, old/new revision, changed identities, producer/content provenance. Rejected and superseded patches are audited.
32
+ 9. **Restore.** `restore` validates snapshot schema before mutate. It reloads the accepted world revision and, when present, the optional sidecar `graph` snapshot; it does not rerun the producing job. Failed graph restore reverts the world to the pre-restore revision.
33
+ 10. **Limits.** Operation, entity, byte, and diagnostic counts are bounded.
34
+ 11. **Graph composition.** Optional `WorldGraph` is applied by restoring a computed snapshot: `add` sets missing nodes/edges, `replace`/`revise` overwrite, `link` overwrites edges (including `from`/`to`), and `remove`/`tombstone`/`unlink` delete. Failure is `graph-apply-failed` and leaves canon unchanged.
35
+
36
+ ```ts
37
+ import {
38
+ createMemoryWorldPersistence,
39
+ createWorldPatchApplier,
40
+ } from '@cyberart-io/engine';
41
+
42
+ const world = createWorldPatchApplier({
43
+ persistence: createMemoryWorldPersistence(),
44
+ content: { available: [{ revision: '8' }] },
45
+ bindings: { listedIds: ['lobby-room'] },
46
+ now: () => hostClock,
47
+ });
48
+
49
+ world.dryRun(patch); // diagnostics only
50
+ world.commit(patch); // one revision, or the previous world unchanged
51
+ world.snapshot(); // exact revision for hostState, plus optional graph
52
+ ```
53
+
54
+ | Event | When |
55
+ |---|---|
56
+ | `world.patch.state.accepted` | Atomic commit of one complete revision: patch id, old/new revision, producer, jobId, contentRevisions |
57
+ | `world.patch.state.rejected` | Validation, stale-base, graph, or publish failure; canon unchanged |
58
+ | `world.patch.state.superseded` | An accepted patch id was replaced |
59
+ | `world.patch.diagnostic.lifecycle` | Machine-readable rejection detail |
60
+
61
+ Contracts: `worldPatchEventContracts()`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cyberart-io/engine",
3
- "version": "0.0.8",
3
+ "version": "0.0.9",
4
4
  "description": "CyberArt host engine: mount carts, events, capability manifests, geometry, runtime groups, and a Node/jsdom headless entry.",
5
5
  "type": "module",
6
6
  "license": "SEE LICENSE IN LICENSE",
@@ -9,7 +9,8 @@
9
9
  "dist/index.d.ts",
10
10
  "dist/headless.js",
11
11
  "dist/headless.d.ts",
12
- "docs"
12
+ "docs",
13
+ "CHANGELOG.md"
13
14
  ],
14
15
  "main": "./dist/index.js",
15
16
  "module": "./dist/index.js",