@pouchy_ai/world-sdk 0.15.0 → 0.16.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 +22 -0
- package/README.md +1 -1
- package/dist/index.d.ts +82 -1
- package/dist/index.js +31 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# @pouchy_ai/world-sdk
|
|
2
2
|
|
|
3
|
+
## 0.16.0
|
|
4
|
+
|
|
5
|
+
- `scanConsistency()` — what a world's own record proves about itself. Ten
|
|
6
|
+
deterministic findings, each a comparison between committed facts and the
|
|
7
|
+
pinned story package. Read-only: it commits nothing, asks no model, and
|
|
8
|
+
repairs nothing.
|
|
9
|
+
- **`code` is a closed set that may grow.** A published member is never removed,
|
|
10
|
+
renamed, or widened in meaning; a criterion found to be wrong is deprecated
|
|
11
|
+
and replaced beside it. Handle an unknown code as informational rather than
|
|
12
|
+
failing on it — that is what makes a minor bump safe to take.
|
|
13
|
+
- **Read `coverage` before trusting an empty `findings`.** Some checks read
|
|
14
|
+
fields older ledger rows do not carry, and those entries are counted there
|
|
15
|
+
rather than skipped in silence. A clean report with non-empty coverage is
|
|
16
|
+
clean about less than the whole world.
|
|
17
|
+
- `incomplete` is a status, not an empty result: the walk is capped, a `cursor`
|
|
18
|
+
comes back, and the state- and chain-level checks do not run on a partial
|
|
19
|
+
walk. `entriesScanned` stays honest even once `findingsTruncated` is true.
|
|
20
|
+
- Rate limited on two axes (project and IP, 30/min each, both required).
|
|
21
|
+
`status: 'rate_limited'` arrives with HTTP 429 and `retryAfterSec`. If the
|
|
22
|
+
shared limiter is unreachable the scan still runs — a read-only diagnostic
|
|
23
|
+
should not vanish when a world is being investigated.
|
|
24
|
+
|
|
3
25
|
## 0.15.0
|
|
4
26
|
|
|
5
27
|
- `getProgress()` — where a story is and whether it can go on, as a DERIVED
|
package/README.md
CHANGED
|
@@ -52,7 +52,7 @@ directions a beat could take, then commit the one the player picked. Off unless
|
|
|
52
52
|
the world's published revision declares it; the `envelope` is server-side only.
|
|
53
53
|
|
|
54
54
|
**Reading** — `getWorldState`, `getProgress`, `getTurn`, `listTurns`,
|
|
55
|
-
`listTurnsSince`, `replayLedger`, `replayLedgerToEnd`.
|
|
55
|
+
`listTurnsSince`, `replayLedger`, `replayLedgerToEnd`, `scanConsistency`.
|
|
56
56
|
|
|
57
57
|
**Which credential does what.** This matters more than it looks: one of them
|
|
58
58
|
expires within the hour.
|
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.
|
|
7
|
+
export declare const WORLD_SDK_VERSION = "0.16.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. */
|
|
@@ -641,6 +641,65 @@ export interface WorldClientOptions {
|
|
|
641
641
|
* default is generous on purpose, and lower is usually wrong. */
|
|
642
642
|
timeoutMs?: number;
|
|
643
643
|
}
|
|
644
|
+
/** What a world's own record proves about itself. World API 1.19.
|
|
645
|
+
*
|
|
646
|
+
* DETERMINISTIC ONLY. Every finding is a comparison between committed facts
|
|
647
|
+
* and the story package the instance pins — never a judgement about writing.
|
|
648
|
+
* Nothing here repairs anything, and nothing here is a suggestion.
|
|
649
|
+
*
|
|
650
|
+
* `code` is a CLOSED set that may GROW. A published member is never removed,
|
|
651
|
+
* renamed, or widened in meaning; a criterion later found to be wrong is
|
|
652
|
+
* deprecated and replaced beside it. So handle an unknown code as
|
|
653
|
+
* informational rather than failing on it — that is what makes a minor bump
|
|
654
|
+
* safe to take. */
|
|
655
|
+
export type WorldConsistencyFindingCode = 'revision_mismatch' | 'ledger_drift' | 'ledger_missing_entries' | 'unrecorded_beat_claim' | 'orphan_branch_reference' | 'node_prereq_violation' | 'effect_without_grant' | 'flag_schema_violation' | 'relation_change_without_cause' | 'verbatim_secret_disclosure';
|
|
656
|
+
export interface WorldConsistencyEvidence {
|
|
657
|
+
turnId?: string;
|
|
658
|
+
seq?: number;
|
|
659
|
+
roleId?: string;
|
|
660
|
+
sceneId?: string;
|
|
661
|
+
nodeId?: string;
|
|
662
|
+
branchId?: string;
|
|
663
|
+
flagKey?: string;
|
|
664
|
+
effectKind?: string;
|
|
665
|
+
/** Only on verbatim matches, and only the matched fragment — never a line. */
|
|
666
|
+
quote?: string;
|
|
667
|
+
/** Passed through from a committed rejection AS EVIDENCE. It is not this
|
|
668
|
+
* finding's classification; the two vocabularies stay separate. */
|
|
669
|
+
ledgerRejectionCode?: string;
|
|
670
|
+
}
|
|
671
|
+
export interface WorldConsistencyFinding {
|
|
672
|
+
code: WorldConsistencyFindingCode;
|
|
673
|
+
layer: 'deterministic';
|
|
674
|
+
status: 'proven';
|
|
675
|
+
severity: 'blocking' | 'warning' | 'info';
|
|
676
|
+
/** Never empty. A finding nobody can check is an accusation. */
|
|
677
|
+
evidence: WorldConsistencyEvidence[];
|
|
678
|
+
}
|
|
679
|
+
/** What a check could NOT examine. Read this before trusting an empty
|
|
680
|
+
* `findings`: a clean report with non-empty coverage is clean about less than
|
|
681
|
+
* the whole world. Absence of a finding is not proof of absence. */
|
|
682
|
+
export interface WorldConsistencyCoverage {
|
|
683
|
+
code: WorldConsistencyFindingCode;
|
|
684
|
+
skipped: number;
|
|
685
|
+
reason: 'evidence_field_absent' | 'scan_incomplete';
|
|
686
|
+
}
|
|
687
|
+
export type WorldConsistencyReport = {
|
|
688
|
+
status: 'complete' | 'incomplete';
|
|
689
|
+
contractVersion: number;
|
|
690
|
+
findings: WorldConsistencyFinding[];
|
|
691
|
+
coverage: WorldConsistencyCoverage[];
|
|
692
|
+
entriesScanned: number;
|
|
693
|
+
findingsTruncated: boolean;
|
|
694
|
+
/** Present only when `status` is `incomplete`. Pass it back to continue. */
|
|
695
|
+
cursor?: number;
|
|
696
|
+
} | {
|
|
697
|
+
status: 'rate_limited';
|
|
698
|
+
retryAfterSec: number;
|
|
699
|
+
} | {
|
|
700
|
+
status: 'unavailable';
|
|
701
|
+
reason: 'world_unavailable';
|
|
702
|
+
};
|
|
644
703
|
export declare class PouchyWorldClient {
|
|
645
704
|
readonly projectId: string;
|
|
646
705
|
private readonly baseUrl;
|
|
@@ -692,6 +751,28 @@ export declare class PouchyWorldClient {
|
|
|
692
751
|
environmentRevision: number;
|
|
693
752
|
state: Record<string, unknown>;
|
|
694
753
|
}>;
|
|
754
|
+
/** What this world's own record proves about itself. World API 1.19.
|
|
755
|
+
*
|
|
756
|
+
* A read-only scan: it commits nothing, asks no model, and repairs nothing.
|
|
757
|
+
* Findings are deterministic — each one is two recorded things that cannot
|
|
758
|
+
* both be true — so they are safe to act on without a human re-reading the
|
|
759
|
+
* story, which is exactly what the model-assisted layer is not.
|
|
760
|
+
*
|
|
761
|
+
* Check `status` first. `incomplete` means the walk was capped or the
|
|
762
|
+
* datastore stopped answering: pass `cursor` back to continue, and do NOT
|
|
763
|
+
* read an empty `findings` on that arm as a clean bill of health.
|
|
764
|
+
*
|
|
765
|
+
* READ `coverage` BEFORE TRUSTING AN EMPTY `findings`. Some checks depend
|
|
766
|
+
* on fields that older ledger rows do not carry, and those entries are
|
|
767
|
+
* counted there rather than skipped in silence. A clean report that could
|
|
768
|
+
* not examine half the history is not the same as a clean world.
|
|
769
|
+
*
|
|
770
|
+
* Rate limited on two axes, project and IP. `status: 'rate_limited'`
|
|
771
|
+
* arrives with HTTP 429 and `retryAfterSec`.
|
|
772
|
+
*/
|
|
773
|
+
scanConsistency(environmentId: string, worldInstanceId: string, opts?: {
|
|
774
|
+
cursor?: number;
|
|
775
|
+
}): Promise<WorldConsistencyReport>;
|
|
695
776
|
/** Where the story is, and whether it can go on. World API 1.18.
|
|
696
777
|
*
|
|
697
778
|
* A DERIVED checkpoint: nothing is stored to answer it, no model is asked,
|
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.
|
|
26
|
+
export const WORLD_SDK_VERSION = '0.16.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
|
|
@@ -297,6 +297,36 @@ export class PouchyWorldClient {
|
|
|
297
297
|
getWorldState(environmentId, worldInstanceId) {
|
|
298
298
|
return this.read(`/projects/${this.projectId}/environments/${environmentId}/instances/${worldInstanceId}/state`, `/admin/environments/${environmentId}/instances/${worldInstanceId}/state`);
|
|
299
299
|
}
|
|
300
|
+
/** What this world's own record proves about itself. World API 1.19.
|
|
301
|
+
*
|
|
302
|
+
* A read-only scan: it commits nothing, asks no model, and repairs nothing.
|
|
303
|
+
* Findings are deterministic — each one is two recorded things that cannot
|
|
304
|
+
* both be true — so they are safe to act on without a human re-reading the
|
|
305
|
+
* story, which is exactly what the model-assisted layer is not.
|
|
306
|
+
*
|
|
307
|
+
* Check `status` first. `incomplete` means the walk was capped or the
|
|
308
|
+
* datastore stopped answering: pass `cursor` back to continue, and do NOT
|
|
309
|
+
* read an empty `findings` on that arm as a clean bill of health.
|
|
310
|
+
*
|
|
311
|
+
* READ `coverage` BEFORE TRUSTING AN EMPTY `findings`. Some checks depend
|
|
312
|
+
* on fields that older ledger rows do not carry, and those entries are
|
|
313
|
+
* counted there rather than skipped in silence. A clean report that could
|
|
314
|
+
* not examine half the history is not the same as a clean world.
|
|
315
|
+
*
|
|
316
|
+
* Rate limited on two axes, project and IP. `status: 'rate_limited'`
|
|
317
|
+
* arrives with HTTP 429 and `retryAfterSec`.
|
|
318
|
+
*/
|
|
319
|
+
scanConsistency(environmentId, worldInstanceId, opts = {}) {
|
|
320
|
+
// The query rides the third argument, not the path template. Both are
|
|
321
|
+
// sent identically; keeping the path a pure template is what lets the
|
|
322
|
+
// admin-lane gate check that every `/admin/...` the SDK sends is a route
|
|
323
|
+
// that actually exists.
|
|
324
|
+
const q = new URLSearchParams();
|
|
325
|
+
if (opts.cursor !== undefined)
|
|
326
|
+
q.set('cursor', String(opts.cursor));
|
|
327
|
+
const suffix = q.toString() ? `?${q}` : '';
|
|
328
|
+
return this.read(`/projects/${this.projectId}/environments/${environmentId}/instances/${worldInstanceId}/consistency`, `/admin/environments/${environmentId}/instances/${worldInstanceId}/consistency`, suffix);
|
|
329
|
+
}
|
|
300
330
|
/** Where the story is, and whether it can go on. World API 1.18.
|
|
301
331
|
*
|
|
302
332
|
* A DERIVED checkpoint: nothing is stored to answer it, no model is asked,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pouchy_ai/world-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.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",
|