@pouchy_ai/world-sdk 0.29.0 → 0.31.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/CHANGELOG.md CHANGED
@@ -1,5 +1,56 @@
1
1
  # @pouchy_ai/world-sdk
2
2
 
3
+ ## 0.31.0
4
+
5
+ - **`WorldStateView`** — `getWorldState().state` is typed, instead of
6
+ `Record<string, unknown>`. The same shape is published in the world OpenAPI
7
+ (it said `anyObj`), and a census derives the field list from the projection
8
+ itself so the document and the runtime cannot drift.
9
+
10
+ Asked by an integrator building highlight triggers who needed three things
11
+ from `state` and could not answer any of them from anything published. They
12
+ declined to guess the keys from one live call, on the grounds that a key
13
+ which is merely PRESENT is a feature that vanishes silently on some later
14
+ change — and the symptom would have been "highlights stopped firing", with no
15
+ error. The prose that was there had already drifted: it never mentioned
16
+ `completedNodes`, which is exactly the field they concluded did not exist.
17
+
18
+ Two answers that surprise people, both because `getProgress` beside it
19
+ filters differently:
20
+
21
+ - **`flags` is EVERY flag**, not only those an author marked `public: true`.
22
+ That filter belongs to the progress checkpoint, whose audience is a
23
+ player's client. This door is the operator's, so forwarding these bytes to
24
+ a reader — including the spoiler risk in a flag's NAME — is your decision.
25
+ - **`completedNodes` gives node IDS.** The checkpoint reports only
26
+ `completedNodeCount` and says outright it is not a denominator.
27
+
28
+ Also additive on the envelope: `environmentId` and `storyPackageRef` are
29
+ returned by the route and were named in neither plane's document.
30
+
31
+ ## 0.30.0
32
+
33
+ - **`SKIP_COST_MODEL_VERSION` / `SKIP_COST_MODEL_DIGEST`** — the cost model's
34
+ identity as of this build, so you can detect that the server regrouped a code
35
+ instead of finding out from your ledger.
36
+
37
+ Asked directly after 0.29.0 shipped: does `skipSpentNoModelCall` track the
38
+ server, and would a regrouping be a major bump? The answers are **no** and
39
+ **we will not promise that**. A published package is a SNAPSHOT — regroup a
40
+ code server-side and a pinned client keeps the old answer forever, with no
41
+ error, no code change of yours and green tests. And a promise to bump is a
42
+ claim about human behaviour with no process behind it; the same shape this
43
+ project already declined to sign for the moderation defaults.
44
+
45
+ So the grouping is published as data instead. `GET /v1/world/openapi` carries
46
+ `x-pouchy-cost-model` (`version`, `digest`, `noModelCall`, `modelMayHaveRun`)
47
+ on the `skippedRoles[].code` schema. Compare it against these two constants
48
+ and alarm on a mismatch — a check that fires on the condition itself rather
49
+ than on our remembering to signal it.
50
+
51
+ The digest covers group MEMBERSHIP only: reordering the enum or rewording a
52
+ comment never moves it; a code changing group always does.
53
+
3
54
  ## 0.29.0
4
55
 
5
56
  - **`skippedRoles[].code`** — the machine half of "why this role did not
package/dist/index.d.ts CHANGED
@@ -4,7 +4,7 @@
4
4
  * a project is running — which is exactly the field you reach for when a
5
5
  * customer's integration behaves like an older SDK than they say they have.
6
6
  * It sat at '0.1.0' for eight releases before anything compared the two. */
7
- export declare const WORLD_SDK_VERSION = "0.29.0";
7
+ export declare const WORLD_SDK_VERSION = "0.31.0";
8
8
  export declare const DEFAULT_BASE_URL = "https://pouchy.ai/v1";
9
9
  /** One direction a beat could take. The WHOLE of what a deliberation shows a
10
10
  * player: no reasoning, no role secrets, no simulated effects, no scores. */
@@ -526,6 +526,43 @@ export interface EditorialDraftRow {
526
526
  * purpose: one word answering both is how a delivery outage reads as a
527
527
  * content problem. */
528
528
  /** The shared refusal taxonomy (Batch 7). Only `narrative_conflict` is content. */
529
+ /** The USER projection of world state — what `getWorldState` returns.
530
+ *
531
+ * Typed from 0.31.0. Before that it was `Record<string, unknown>`, and an
532
+ * integrator building highlight triggers could not answer three basic
533
+ * questions from anything published — the spec said `anyObj` and its prose
534
+ * summary had drifted, omitting `completedNodes` entirely. They declined to
535
+ * guess the keys from one live call, on the grounds that a key which is merely
536
+ * PRESENT is a feature that disappears silently later. They were right, and
537
+ * this is the fix.
538
+ *
539
+ * TWO THINGS THAT SURPRISE PEOPLE, both because the progress checkpoint beside
540
+ * this filters differently:
541
+ *
542
+ * - `flags` is EVERY flag, not only those an author marked `public: true`.
543
+ * That filter belongs to `getProgress`, whose audience is a player's client.
544
+ * This door is the operator's — if you forward these bytes to a reader, the
545
+ * decision (and the spoiler risk in a flag's NAME) is yours.
546
+ * - `completedNodes` gives the node IDS. The checkpoint reports only
547
+ * `completedNodeCount`, and says outright that it is not a denominator.
548
+ *
549
+ * The role-private layer is never here. */
550
+ export interface WorldStateView {
551
+ stateRevision: number;
552
+ clock: number;
553
+ sceneId?: string;
554
+ location?: string;
555
+ flags: Record<string, boolean | number | string>;
556
+ completedNodes: string[];
557
+ factsVisible: string[];
558
+ relations: Record<string, string>;
559
+ entities: Record<string, string>;
560
+ lastEntries: Array<{
561
+ entryId: string;
562
+ kind: string;
563
+ at: number;
564
+ }>;
565
+ }
529
566
  export type WorldRejectionCode = 'narrative_conflict' | 'policy_rejection' | 'schema_rejection' | 'canon_rejection' | 'concurrency_rejection' | 'repair_failure';
530
567
  /** WHY a role that was in the cast did not speak — the machine half of
531
568
  * `skippedRoles[].reason`, added 2026-09-09.
@@ -542,6 +579,21 @@ export type WorldRejectionCode = 'narrative_conflict' | 'policy_rejection' | 'sc
542
579
  * so a consumer does not re-derive it. Absent on turns from a server predating
543
580
  * the taxonomy — read that as unknown, never as a value. */
544
581
  export type WorldSkipCode = 'not_focused' | 'role_cap_reached' | 'no_actor_bound' | 'deadline_exhausted' | 'not_admitted' | 'actor_unavailable' | 'session_busy' | 'content_policy' | 'turn_error' | 'no_message' | 'effect_refused' | 'conflict_undelivered';
582
+ /** The cost model's version and digest AS OF THIS SDK BUILD.
583
+ *
584
+ * `skipSpentNoModelCall` below is a SNAPSHOT — a published package cannot
585
+ * track a server that regroups a code later, and nothing would error if it
586
+ * did: your code would not change, your tests would stay green, and your
587
+ * billing would drift. So compare these against `x-pouchy-cost-model` in
588
+ * `GET /v1/world/openapi` (the same document you already read for the enum) and
589
+ * alarm on a mismatch. That check is worth more than any promise about version
590
+ * bumps, because it fires on the condition itself rather than on our
591
+ * remembering to signal it.
592
+ *
593
+ * The digest covers group MEMBERSHIP only: reordering the enum or rewording a
594
+ * comment never moves it. */
595
+ export declare const SKIP_COST_MODEL_VERSION = "1.0.0";
596
+ export declare const SKIP_COST_MODEL_DIGEST = "4a8369322817e3fa";
545
597
  /** Did this skip happen before any model call — is the role's silence free?
546
598
  *
547
599
  * `turn_error` is deliberately NOT in the free set even though it often is:
@@ -1151,7 +1203,7 @@ export declare class PouchyWorldClient {
1151
1203
  getWorldState(environmentId: string, worldInstanceId: string): Promise<{
1152
1204
  worldInstanceId: string;
1153
1205
  environmentRevision: number;
1154
- state: Record<string, unknown>;
1206
+ state: WorldStateView;
1155
1207
  }>;
1156
1208
  /** What this world's own record proves about itself. World API 1.19.
1157
1209
  *
package/dist/index.js CHANGED
@@ -23,7 +23,7 @@ import { createHash, createHmac, randomUUID } from 'node:crypto';
23
23
  * a project is running — which is exactly the field you reach for when a
24
24
  * customer's integration behaves like an older SDK than they say they have.
25
25
  * It sat at '0.1.0' for eight releases before anything compared the two. */
26
- export const WORLD_SDK_VERSION = '0.29.0';
26
+ export const WORLD_SDK_VERSION = '0.31.0';
27
27
  export const DEFAULT_BASE_URL = 'https://pouchy.ai/v1';
28
28
  /** Read the commit turn id out of an envelope, so the signature covers the id
29
29
  * the server will commit under. The payload half is base64url JSON; the
@@ -306,6 +306,21 @@ export function describeTurn(result) {
306
306
  ` delivery ${result.deliveryStatus}`
307
307
  };
308
308
  }
309
+ /** The cost model's version and digest AS OF THIS SDK BUILD.
310
+ *
311
+ * `skipSpentNoModelCall` below is a SNAPSHOT — a published package cannot
312
+ * track a server that regroups a code later, and nothing would error if it
313
+ * did: your code would not change, your tests would stay green, and your
314
+ * billing would drift. So compare these against `x-pouchy-cost-model` in
315
+ * `GET /v1/world/openapi` (the same document you already read for the enum) and
316
+ * alarm on a mismatch. That check is worth more than any promise about version
317
+ * bumps, because it fires on the condition itself rather than on our
318
+ * remembering to signal it.
319
+ *
320
+ * The digest covers group MEMBERSHIP only: reordering the enum or rewording a
321
+ * comment never moves it. */
322
+ export const SKIP_COST_MODEL_VERSION = '1.0.0';
323
+ export const SKIP_COST_MODEL_DIGEST = '4a8369322817e3fa';
309
324
  /** Did this skip happen before any model call — is the role's silence free?
310
325
  *
311
326
  * `turn_error` is deliberately NOT in the free set even though it often is:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pouchy_ai/world-sdk",
3
- "version": "0.29.0",
3
+ "version": "0.31.0",
4
4
  "description": "Server-side TypeScript client for Pouchy World \u2014 story packages, world definitions, world sessions, coordinated turns, trusted events, replay verification and script drafts. Node only: it holds a project Secret Key and a source signing key, which never belong in a browser or a mobile app.",
5
5
  "type": "module",
6
6
  "license": "SEE LICENSE IN LICENSE",