@substrat-run/contracts 0.87.0 → 0.88.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.
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Optimistic concurrency on the operation surface (#129).
3
+ *
4
+ * Two people open the same record, both save, and the second write silently
5
+ * destroys the first. Nobody notices until the data is gone — there is no error,
6
+ * no log line, and no way to reconstruct what was lost. This is the vocabulary
7
+ * that lets an operation refuse the second write instead.
8
+ *
9
+ * ## What a version is, and why it is not in here
10
+ *
11
+ * The version is the ULID of the last event about the entity (`entityVersionOf`
12
+ * in the kernel, #901). This module holds only the WIRE half — the header names
13
+ * and the comparison — because contracts sits below the spine: it can say what an
14
+ * `ETag` is called and what makes one match, and must not know which table
15
+ * answers the question.
16
+ *
17
+ * ## Why an opaque token rather than a number
18
+ *
19
+ * A caller compares; it never reads. That is what lets the version be a ULID
20
+ * today and something else later without a client noticing, and it is also what
21
+ * stops a client doing arithmetic on it — `If-Match: <version + 1>` is not a
22
+ * thing anyone can write.
23
+ *
24
+ * ## The direction this fails
25
+ *
26
+ * ANY event about the entity moves the version, including one that changed
27
+ * nothing the caller read. So a precondition built on it is CONSERVATIVE: it can
28
+ * refuse a write that would in fact have been safe, and it cannot admit one that
29
+ * would not. Documented here as well as in the kernel because this is the half a
30
+ * client author reads when they are debugging a 412 they believe is spurious.
31
+ */
32
+ /**
33
+ * The response header carrying an entity's current version.
34
+ *
35
+ * Strong, never weak (`W/"…"`): the comparison is exact, and a weak validator
36
+ * means "semantically equivalent", which is precisely the judgement no generic
37
+ * layer is entitled to make about a domain entity.
38
+ */
39
+ export declare const ETAG_HEADER = "ETag";
40
+ /** The request header carrying the version the caller believes it is writing over. */
41
+ export declare const IF_MATCH_HEADER = "If-Match";
42
+ /**
43
+ * The headers a cross-origin browser client cannot read unless the server says it
44
+ * may — the same trap already documented for `Link` and `X-Total-Count` in
45
+ * `PAGE_EXPOSED_HEADERS`, and worse here.
46
+ *
47
+ * A `Link` a browser cannot read looks like "there is only one page". An `ETag` a
48
+ * browser cannot read looks like nothing at all: `response.headers.get('ETag')` is
49
+ * `null`, the client sends no `If-Match`, the server has nothing to compare, and
50
+ * every write succeeds. The protection silently switches itself off, in the one
51
+ * deployment shape (an SPA on another origin) where two editors are most likely.
52
+ *
53
+ * So a vertical exposing its API cross-origin must expose these, and this constant
54
+ * is what it lists rather than a string it retypes.
55
+ */
56
+ export declare const CONCURRENCY_EXPOSED_HEADERS: readonly ["ETag"];
57
+ /**
58
+ * Format a version as an `ETag` value.
59
+ *
60
+ * Quoted, per RFC 9110 §8.8.3 — an entity-tag is a quoted string and a bare token
61
+ * is malformed. Intermediaries do parse this: an unquoted value is the kind of
62
+ * thing that works against a dev server and is stripped by a proxy in production.
63
+ */
64
+ export declare function etagOf(version: string): string;
65
+ /**
66
+ * Does the caller's `If-Match` admit this version?
67
+ *
68
+ * Handles the three spellings RFC 9110 §13.1.1 allows a client to send: the quoted
69
+ * tag, a comma-separated list of them, and `*` (meaning "any current version" —
70
+ * i.e. the entity must merely EXIST, which for us means it has a version at all).
71
+ *
72
+ * A weak tag (`W/"…"`) never matches. §13.1.1 requires the strong comparison
73
+ * function for `If-Match`, and honouring a weak one here would admit exactly the
74
+ * write this exists to refuse.
75
+ *
76
+ * `version` is null when the entity has no events yet. Nothing matches that except
77
+ * an absent header, which is not this function's call to make — a caller that sent
78
+ * `If-Match` against an entity with no version is asking to write over something
79
+ * that was never written, and gets a refusal.
80
+ */
81
+ export declare function ifMatchAdmits(ifMatch: string, version: string | null): boolean;
82
+ //# sourceMappingURL=concurrency.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"concurrency.d.ts","sourceRoot":"","sources":["../src/concurrency.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,WAAW,SAAS,CAAC;AAElC,sFAAsF;AACtF,eAAO,MAAM,eAAe,aAAa,CAAC;AAE1C;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,2BAA2B,mBAAyB,CAAC;AAElE;;;;;;GAMG;AACH,wBAAgB,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAQ9E"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Optimistic concurrency on the operation surface (#129).
3
+ *
4
+ * Two people open the same record, both save, and the second write silently
5
+ * destroys the first. Nobody notices until the data is gone — there is no error,
6
+ * no log line, and no way to reconstruct what was lost. This is the vocabulary
7
+ * that lets an operation refuse the second write instead.
8
+ *
9
+ * ## What a version is, and why it is not in here
10
+ *
11
+ * The version is the ULID of the last event about the entity (`entityVersionOf`
12
+ * in the kernel, #901). This module holds only the WIRE half — the header names
13
+ * and the comparison — because contracts sits below the spine: it can say what an
14
+ * `ETag` is called and what makes one match, and must not know which table
15
+ * answers the question.
16
+ *
17
+ * ## Why an opaque token rather than a number
18
+ *
19
+ * A caller compares; it never reads. That is what lets the version be a ULID
20
+ * today and something else later without a client noticing, and it is also what
21
+ * stops a client doing arithmetic on it — `If-Match: <version + 1>` is not a
22
+ * thing anyone can write.
23
+ *
24
+ * ## The direction this fails
25
+ *
26
+ * ANY event about the entity moves the version, including one that changed
27
+ * nothing the caller read. So a precondition built on it is CONSERVATIVE: it can
28
+ * refuse a write that would in fact have been safe, and it cannot admit one that
29
+ * would not. Documented here as well as in the kernel because this is the half a
30
+ * client author reads when they are debugging a 412 they believe is spurious.
31
+ */
32
+ /**
33
+ * The response header carrying an entity's current version.
34
+ *
35
+ * Strong, never weak (`W/"…"`): the comparison is exact, and a weak validator
36
+ * means "semantically equivalent", which is precisely the judgement no generic
37
+ * layer is entitled to make about a domain entity.
38
+ */
39
+ export const ETAG_HEADER = 'ETag';
40
+ /** The request header carrying the version the caller believes it is writing over. */
41
+ export const IF_MATCH_HEADER = 'If-Match';
42
+ /**
43
+ * The headers a cross-origin browser client cannot read unless the server says it
44
+ * may — the same trap already documented for `Link` and `X-Total-Count` in
45
+ * `PAGE_EXPOSED_HEADERS`, and worse here.
46
+ *
47
+ * A `Link` a browser cannot read looks like "there is only one page". An `ETag` a
48
+ * browser cannot read looks like nothing at all: `response.headers.get('ETag')` is
49
+ * `null`, the client sends no `If-Match`, the server has nothing to compare, and
50
+ * every write succeeds. The protection silently switches itself off, in the one
51
+ * deployment shape (an SPA on another origin) where two editors are most likely.
52
+ *
53
+ * So a vertical exposing its API cross-origin must expose these, and this constant
54
+ * is what it lists rather than a string it retypes.
55
+ */
56
+ export const CONCURRENCY_EXPOSED_HEADERS = [ETAG_HEADER];
57
+ /**
58
+ * Format a version as an `ETag` value.
59
+ *
60
+ * Quoted, per RFC 9110 §8.8.3 — an entity-tag is a quoted string and a bare token
61
+ * is malformed. Intermediaries do parse this: an unquoted value is the kind of
62
+ * thing that works against a dev server and is stripped by a proxy in production.
63
+ */
64
+ export function etagOf(version) {
65
+ return `"${version}"`;
66
+ }
67
+ /**
68
+ * Does the caller's `If-Match` admit this version?
69
+ *
70
+ * Handles the three spellings RFC 9110 §13.1.1 allows a client to send: the quoted
71
+ * tag, a comma-separated list of them, and `*` (meaning "any current version" —
72
+ * i.e. the entity must merely EXIST, which for us means it has a version at all).
73
+ *
74
+ * A weak tag (`W/"…"`) never matches. §13.1.1 requires the strong comparison
75
+ * function for `If-Match`, and honouring a weak one here would admit exactly the
76
+ * write this exists to refuse.
77
+ *
78
+ * `version` is null when the entity has no events yet. Nothing matches that except
79
+ * an absent header, which is not this function's call to make — a caller that sent
80
+ * `If-Match` against an entity with no version is asking to write over something
81
+ * that was never written, and gets a refusal.
82
+ */
83
+ export function ifMatchAdmits(ifMatch, version) {
84
+ const candidates = ifMatch
85
+ .split(',')
86
+ .map((raw) => raw.trim())
87
+ .filter((raw) => raw.length > 0);
88
+ if (candidates.includes('*'))
89
+ return version !== null;
90
+ if (version === null)
91
+ return false;
92
+ return candidates.includes(etagOf(version));
93
+ }
94
+ //# sourceMappingURL=concurrency.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"concurrency.js","sourceRoot":"","sources":["../src/concurrency.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,MAAM,CAAC;AAElC,sFAAsF;AACtF,MAAM,CAAC,MAAM,eAAe,GAAG,UAAU,CAAC;AAE1C;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAAC,WAAW,CAAU,CAAC;AAElE;;;;;;GAMG;AACH,MAAM,UAAU,MAAM,CAAC,OAAe;IACpC,OAAO,IAAI,OAAO,GAAG,CAAC;AACxB,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,aAAa,CAAC,OAAe,EAAE,OAAsB;IACnE,MAAM,UAAU,GAAG,OAAO;SACvB,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;SACxB,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACnC,IAAI,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,OAAO,KAAK,IAAI,CAAC;IACtD,IAAI,OAAO,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IACnC,OAAO,UAAU,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;AAC9C,CAAC"}
@@ -0,0 +1,121 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * The read side of the K-35 denial log — a scope-local record of every ENFORCED
4
+ * permission refusal (`assertAllowed`), written on the deny path as a fresh
5
+ * autocommit AFTER the rollback it is evidence of.
6
+ *
7
+ * This is the *other* kind of evidence from a conformance receipt. A receipt says
8
+ * "we attempted the attack in CI at commit X"; these rows say "on your data, in
9
+ * production, here is every refusal, by whom, against which key". K-35 made the
10
+ * case for the row itself: a denial is the one event where an actor's intent and
11
+ * the permission model visibly disagree.
12
+ *
13
+ * Two properties of the log shape everything below, and both come straight from
14
+ * K-35's own reasoning about why denials are NOT admin-log entries:
15
+ *
16
+ * 1. **The volume is attacker-influenceable.** A probing client mints unlimited
17
+ * rows, so a newest-first page of raw rows is the wrong default view — 200 rows
18
+ * from one prober hide everyone else. That is why `denialSummary` exists beside
19
+ * the row list, and why K-35 called rate-bucketing sanctionable up front.
20
+ * 2. **The window is a storage bound, not a retention policy.** Rows `drain` rather
21
+ * than expire (K-24's split). Until a Tier-2 sink exists, what is here is simply
22
+ * what has not been pruned — so the summary reports the window's own floor
23
+ * (`windowOldestAt`) rather than letting a caller read absence as "never happened".
24
+ */
25
+ /** How many denial rows an unbounded read returns — a screenful, newest-first. */
26
+ export declare const DEFAULT_DENIAL_LIMIT = 50;
27
+ /** The hard ceiling on one page of denial rows, and on one page of buckets. */
28
+ export declare const DENIAL_LIMIT_MAX = 200;
29
+ /**
30
+ * One recorded refusal. `scopeId` is null for a tenant-node check (one that named no
31
+ * scope); `operation` is null when the denial unwound something that was not an
32
+ * operation invocation. `drainedAt` marks a row already shipped to a Tier-2 sink and
33
+ * therefore eligible to be pruned — bookkeeping, not a judgement about the denial.
34
+ */
35
+ export declare const permissionDenial: z.ZodObject<{
36
+ id: z.ZodString;
37
+ actor: z.ZodUnion<readonly [z.core.$ZodBranded<z.ZodString, "PrincipalId", "out">, z.ZodObject<{
38
+ system: z.core.$ZodBranded<z.ZodString, "ModuleId", "out">;
39
+ }, z.core.$strip>, z.ZodObject<{
40
+ connection: z.ZodString;
41
+ }, z.core.$strip>]>;
42
+ permission: z.core.$ZodBranded<z.ZodString, "PermissionKey", "out">;
43
+ tenantId: z.core.$ZodBranded<z.ZodString, "TenantId", "out">;
44
+ scopeId: z.ZodNullable<z.core.$ZodBranded<z.ZodString, "ScopeId", "out">>;
45
+ operation: z.ZodNullable<z.ZodString>;
46
+ at: z.ZodString;
47
+ drainedAt: z.ZodNullable<z.ZodString>;
48
+ }, z.core.$strip>;
49
+ export type PermissionDenial = z.infer<typeof permissionDenial>;
50
+ /**
51
+ * What narrows a denial read. Every field is an exact match except the `since`/`until`
52
+ * bounds on `at` (inclusive lower, exclusive upper) — enough to answer "who probed
53
+ * this key", "what did this actor try", and "what happened during the incident window"
54
+ * without a SQL console.
55
+ *
56
+ * `actor` takes the LOGICAL actor — a bare principal ULID, or the object form for a
57
+ * system/connection actor (`{"system":"invoicing"}`). The writer persists
58
+ * `JSON.stringify(actor)`, so a principal is stored with its quotes; normalizing to that
59
+ * encoding is the reader's job (`storedActor` in the kernel's query builder), not every
60
+ * caller's.
61
+ */
62
+ export declare const denialFilter: z.ZodObject<{
63
+ actor: z.ZodOptional<z.ZodString>;
64
+ permission: z.ZodOptional<z.ZodString>;
65
+ operation: z.ZodOptional<z.ZodString>;
66
+ since: z.ZodOptional<z.ZodString>;
67
+ until: z.ZodOptional<z.ZodString>;
68
+ limit: z.ZodOptional<z.ZodNumber>;
69
+ }, z.core.$strip>;
70
+ export type DenialFilter = z.infer<typeof denialFilter>;
71
+ /**
72
+ * One (actor, permission) bucket — K-35's "first occurrence + count per actor/key/
73
+ * window", which is the shape that survives a flood. `operations` is the number of
74
+ * DISTINCT operations the actor was refused this key on, and it is the discriminator
75
+ * worth the extra aggregate: one operation refused four hundred times is a broken
76
+ * screen or a misconfigured role, while the same count spread across a dozen
77
+ * operations is someone walking the surface.
78
+ */
79
+ export declare const denialBucket: z.ZodObject<{
80
+ actor: z.ZodUnion<readonly [z.core.$ZodBranded<z.ZodString, "PrincipalId", "out">, z.ZodObject<{
81
+ system: z.core.$ZodBranded<z.ZodString, "ModuleId", "out">;
82
+ }, z.core.$strip>, z.ZodObject<{
83
+ connection: z.ZodString;
84
+ }, z.core.$strip>]>;
85
+ permission: z.core.$ZodBranded<z.ZodString, "PermissionKey", "out">;
86
+ count: z.ZodNumber;
87
+ operations: z.ZodNumber;
88
+ firstAt: z.ZodString;
89
+ lastAt: z.ZodString;
90
+ }, z.core.$strip>;
91
+ export type DenialBucket = z.infer<typeof denialBucket>;
92
+ /**
93
+ * The bucketed view of a scope's denial log, plus the facts that keep it honest.
94
+ *
95
+ * `total` counts every row matching the filter, so a caller can tell a capped bucket
96
+ * list from a complete one. `windowOldestAt` is deliberately computed WITHOUT the
97
+ * filter: it is a statement about the log, not about the query — the earliest moment
98
+ * this scope can still speak to. An empty result older than it means "no denials";
99
+ * an empty result at it means "we no longer hold that far back".
100
+ */
101
+ export declare const denialSummary: z.ZodObject<{
102
+ buckets: z.ZodArray<z.ZodObject<{
103
+ actor: z.ZodUnion<readonly [z.core.$ZodBranded<z.ZodString, "PrincipalId", "out">, z.ZodObject<{
104
+ system: z.core.$ZodBranded<z.ZodString, "ModuleId", "out">;
105
+ }, z.core.$strip>, z.ZodObject<{
106
+ connection: z.ZodString;
107
+ }, z.core.$strip>]>;
108
+ permission: z.core.$ZodBranded<z.ZodString, "PermissionKey", "out">;
109
+ count: z.ZodNumber;
110
+ operations: z.ZodNumber;
111
+ firstAt: z.ZodString;
112
+ lastAt: z.ZodString;
113
+ }, z.core.$strip>>;
114
+ total: z.ZodNumber;
115
+ actors: z.ZodNumber;
116
+ windowOldestAt: z.ZodNullable<z.ZodString>;
117
+ windowNewestAt: z.ZodNullable<z.ZodString>;
118
+ drained: z.ZodNumber;
119
+ }, z.core.$strip>;
120
+ export type DenialSummary = z.infer<typeof denialSummary>;
121
+ //# sourceMappingURL=denial.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"denial.d.ts","sourceRoot":"","sources":["../src/denial.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,kFAAkF;AAClF,eAAO,MAAM,oBAAoB,KAAK,CAAC;AACvC,+EAA+E;AAC/E,eAAO,MAAM,gBAAgB,MAAM,CAAC;AAEpC;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;iBAc3B,CAAC;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAEhE;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,YAAY;;;;;;;iBASvB,CAAC;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAExD;;;;;;;GAOG;AACH,eAAO,MAAM,YAAY;;;;;;;;;;;iBAQvB,CAAC;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAExD;;;;;;;;GAQG;AACH,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;iBAgBxB,CAAC;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC"}
package/dist/denial.js ADDED
@@ -0,0 +1,117 @@
1
+ import { z } from 'zod';
2
+ import { actor } from './events.js';
3
+ import { permissionKey, scopeId, tenantId } from './ids.js';
4
+ /**
5
+ * The read side of the K-35 denial log — a scope-local record of every ENFORCED
6
+ * permission refusal (`assertAllowed`), written on the deny path as a fresh
7
+ * autocommit AFTER the rollback it is evidence of.
8
+ *
9
+ * This is the *other* kind of evidence from a conformance receipt. A receipt says
10
+ * "we attempted the attack in CI at commit X"; these rows say "on your data, in
11
+ * production, here is every refusal, by whom, against which key". K-35 made the
12
+ * case for the row itself: a denial is the one event where an actor's intent and
13
+ * the permission model visibly disagree.
14
+ *
15
+ * Two properties of the log shape everything below, and both come straight from
16
+ * K-35's own reasoning about why denials are NOT admin-log entries:
17
+ *
18
+ * 1. **The volume is attacker-influenceable.** A probing client mints unlimited
19
+ * rows, so a newest-first page of raw rows is the wrong default view — 200 rows
20
+ * from one prober hide everyone else. That is why `denialSummary` exists beside
21
+ * the row list, and why K-35 called rate-bucketing sanctionable up front.
22
+ * 2. **The window is a storage bound, not a retention policy.** Rows `drain` rather
23
+ * than expire (K-24's split). Until a Tier-2 sink exists, what is here is simply
24
+ * what has not been pruned — so the summary reports the window's own floor
25
+ * (`windowOldestAt`) rather than letting a caller read absence as "never happened".
26
+ */
27
+ /** How many denial rows an unbounded read returns — a screenful, newest-first. */
28
+ export const DEFAULT_DENIAL_LIMIT = 50;
29
+ /** The hard ceiling on one page of denial rows, and on one page of buckets. */
30
+ export const DENIAL_LIMIT_MAX = 200;
31
+ /**
32
+ * One recorded refusal. `scopeId` is null for a tenant-node check (one that named no
33
+ * scope); `operation` is null when the denial unwound something that was not an
34
+ * operation invocation. `drainedAt` marks a row already shipped to a Tier-2 sink and
35
+ * therefore eligible to be pruned — bookkeeping, not a judgement about the denial.
36
+ */
37
+ export const permissionDenial = z.object({
38
+ /** ULID — chronological, so it is also the sort key. */
39
+ id: z.string().min(1),
40
+ /** WHO was refused: a principal, a `{ system }` module, or a `{ connection }`. */
41
+ actor,
42
+ /** The key `assertAllowed` checked and refused. */
43
+ permission: permissionKey,
44
+ tenantId,
45
+ scopeId: scopeId.nullable(),
46
+ /** The operation the denial rolled back, e.g. `workorder/complete`. */
47
+ operation: z.string().nullable(),
48
+ /** ISO 8601. */
49
+ at: z.string().min(1),
50
+ drainedAt: z.string().nullable(),
51
+ });
52
+ /**
53
+ * What narrows a denial read. Every field is an exact match except the `since`/`until`
54
+ * bounds on `at` (inclusive lower, exclusive upper) — enough to answer "who probed
55
+ * this key", "what did this actor try", and "what happened during the incident window"
56
+ * without a SQL console.
57
+ *
58
+ * `actor` takes the LOGICAL actor — a bare principal ULID, or the object form for a
59
+ * system/connection actor (`{"system":"invoicing"}`). The writer persists
60
+ * `JSON.stringify(actor)`, so a principal is stored with its quotes; normalizing to that
61
+ * encoding is the reader's job (`storedActor` in the kernel's query builder), not every
62
+ * caller's.
63
+ */
64
+ export const denialFilter = z.object({
65
+ actor: z.string().min(1).optional(),
66
+ permission: z.string().min(1).optional(),
67
+ operation: z.string().min(1).optional(),
68
+ /** ISO 8601, inclusive. */
69
+ since: z.string().min(1).optional(),
70
+ /** ISO 8601, exclusive. */
71
+ until: z.string().min(1).optional(),
72
+ limit: z.number().int().min(1).max(DENIAL_LIMIT_MAX).optional(),
73
+ });
74
+ /**
75
+ * One (actor, permission) bucket — K-35's "first occurrence + count per actor/key/
76
+ * window", which is the shape that survives a flood. `operations` is the number of
77
+ * DISTINCT operations the actor was refused this key on, and it is the discriminator
78
+ * worth the extra aggregate: one operation refused four hundred times is a broken
79
+ * screen or a misconfigured role, while the same count spread across a dozen
80
+ * operations is someone walking the surface.
81
+ */
82
+ export const denialBucket = z.object({
83
+ actor,
84
+ permission: permissionKey,
85
+ count: z.number().int().positive(),
86
+ operations: z.number().int().nonnegative(),
87
+ /** ISO 8601 — the first occurrence still in the window (see `windowOldestAt`). */
88
+ firstAt: z.string().min(1),
89
+ lastAt: z.string().min(1),
90
+ });
91
+ /**
92
+ * The bucketed view of a scope's denial log, plus the facts that keep it honest.
93
+ *
94
+ * `total` counts every row matching the filter, so a caller can tell a capped bucket
95
+ * list from a complete one. `windowOldestAt` is deliberately computed WITHOUT the
96
+ * filter: it is a statement about the log, not about the query — the earliest moment
97
+ * this scope can still speak to. An empty result older than it means "no denials";
98
+ * an empty result at it means "we no longer hold that far back".
99
+ */
100
+ export const denialSummary = z.object({
101
+ buckets: z.array(denialBucket),
102
+ /** Rows matching the filter. Bucket counts sum to this when `buckets` is uncapped. */
103
+ total: z.number().int().nonnegative(),
104
+ /** Distinct actors among the matching rows. */
105
+ actors: z.number().int().nonnegative(),
106
+ /**
107
+ * The oldest row STILL HELD, filter ignored — the window's floor, null when the log
108
+ * is empty. The window is a storage bound and not a retention policy (K-35): what is
109
+ * absent before this instant was not necessarily never recorded.
110
+ */
111
+ windowOldestAt: z.string().nullable(),
112
+ /** The newest row held, filter ignored. */
113
+ windowNewestAt: z.string().nullable(),
114
+ /** Rows already shipped to a Tier-2 sink, filter ignored — prunable, not pruned. */
115
+ drained: z.number().int().nonnegative(),
116
+ });
117
+ //# sourceMappingURL=denial.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"denial.js","sourceRoot":"","sources":["../src/denial.ts"],"names":[],"mappings":"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"}
package/dist/errors.d.ts CHANGED
@@ -140,7 +140,12 @@ export declare const PROBLEM_EXTENSIONS: {
140
140
  message: z.ZodString;
141
141
  }, z.core.$strip>>>;
142
142
  }, z.core.$strip>;
143
- readonly precondition_failed: z.ZodObject<{}, z.core.$strict>;
143
+ readonly precondition_failed: z.ZodObject<{
144
+ entity: z.ZodOptional<z.ZodObject<{
145
+ entityType: z.ZodString;
146
+ entityId: z.ZodString;
147
+ }, z.core.$strip>>;
148
+ }, z.core.$strip>;
144
149
  readonly rate_limited: z.ZodObject<{
145
150
  retryAfter: z.ZodOptional<z.ZodNumber>;
146
151
  }, z.core.$strip>;
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"}
package/dist/errors.js CHANGED
@@ -102,7 +102,19 @@ export const PROBLEM_EXTENSIONS = {
102
102
  not_found: z.strictObject({}),
103
103
  conflict: z.object({ reason: z.string().min(1).optional() }),
104
104
  validation_failed: z.object({ errors: z.array(validationIssue).optional() }),
105
- precondition_failed: z.strictObject({}),
105
+ precondition_failed: z.object({
106
+ /**
107
+ * The entity whose version moved under the caller (#129).
108
+ *
109
+ * **The current version is deliberately NOT carried.** Handing it back turns
110
+ * the obvious client fix into a blind retry with the new tag, which writes
111
+ * over the change that caused the refusal — the exact lost update the
112
+ * precondition exists to prevent, now with a 412 in the log claiming it was
113
+ * prevented. A client that wants to proceed re-reads, and re-reading is what
114
+ * gives its user something to merge.
115
+ */
116
+ entity: entityRef.optional(),
117
+ }),
106
118
  rate_limited: z.object({ retryAfter: z.number().int().nonnegative().optional() }),
107
119
  unavailable: z.strictObject({}),
108
120
  internal: z.strictObject({}),
@@ -162,9 +174,11 @@ export const ERROR_NAME_PREFIX = 'Substrat.';
162
174
  * Keeping `PermissionDenied` named `PermissionDenied` rather than renaming it to the
163
175
  * generic form is deliberate: `vertical-host`'s classifier and several verticals match
164
176
  * on that exact string today, and a rename would be a silent behaviour change bundled
165
- * into a refactor. `ZodError` earns its row because a parse failure crossing the hop
166
- * loses its `issues` arraythe code is all that is left, and `validation_failed`
167
- * without fields still beats `internal`.
177
+ * into a refactor. `ZodError` earns its row because a parse failure can arrive with its
178
+ * prototype gone and only its `name` lefta duplicate copy of zod, a structured clone,
179
+ * the legacy pre-envelope RPC path. `validation_failed` without fields still beats
180
+ * `internal`. On the envelope path the fields are no longer lost: `toWireFailure` carries
181
+ * them as `extensions.errors` (#831).
168
182
  */
169
183
  const CODE_BY_ERROR_NAME = {
170
184
  PermissionDenied: 'permission_denied',
@@ -236,11 +250,29 @@ export function isSubstratError(err) {
236
250
  }
237
251
  /** Zod's issue list, flattened to the wire shape. */
238
252
  export function validationIssuesFrom(error) {
239
- return error.issues.map((issue) => ({
240
- path: issue.path.map(String).join('.'),
241
- message: issue.message,
253
+ return flattenIssues(error.issues);
254
+ }
255
+ function flattenIssues(issues) {
256
+ return issues.map((issue) => ({
257
+ path: (issue.path ?? []).map(String).join('.'),
258
+ message: typeof issue.message === 'string' ? issue.message : String(issue.message),
242
259
  }));
243
260
  }
261
+ /**
262
+ * A parse failure's field issues, read BY SHAPE rather than by `instanceof`.
263
+ *
264
+ * Same doctrine as `errorCodeOf` one screen up, for the same two reasons: two copies
265
+ * of zod in one build make `instanceof` a coin toss, and `vertical-host`'s classifier
266
+ * already reads a parse failure this way (`isParseFailure`). `issues` is zod's own
267
+ * array and nothing else on these paths carries one.
268
+ *
269
+ * Returns `undefined` — not `[]` — for a throw that is not a parse failure, so a
270
+ * caller can tell "no issues to report" from "not that kind of error at all".
271
+ */
272
+ function parseIssuesOf(err) {
273
+ const issues = err?.issues;
274
+ return Array.isArray(issues) ? flattenIssues(issues) : undefined;
275
+ }
244
276
  /**
245
277
  * Map any throw onto a problem body and its status — the one function replacing every
246
278
  * hand-rolled `onError` and the control plane's regex table.
@@ -251,12 +283,27 @@ export function validationIssuesFrom(error) {
251
283
  * quietly widening it in the name of better errors.
252
284
  */
253
285
  export function toProblem(err, instance) {
254
- if (err instanceof z.ZodError) {
255
- return build('validation_failed', 'the input did not parse', instance, {
256
- errors: validationIssuesFrom(err),
257
- });
258
- }
259
286
  const code = errorCodeOf(err);
287
+ if (code === 'validation_failed') {
288
+ // #831. The issues are the whole value of a parse failure, and they reach here two
289
+ // ways: live on the throw (in-process), or in `extensions.errors` once
290
+ // `toWireFailure` carried them across the ScopeDO hop.
291
+ //
292
+ // Only a PARSE failure takes this branch, and the `errors` list is what identifies
293
+ // one. `validation_failed` is also thrown SEMANTICALLY — `endDate precedes
294
+ // startDate`, `invalid interval`, `at most one party may sign as primary` — where
295
+ // the sentence IS the information and no field list exists. Those fall through to
296
+ // the general branch below and keep their own message, exactly as before.
297
+ const carried = err?.extensions?.errors;
298
+ const errors = parseIssuesOf(err) ?? (Array.isArray(carried) ? carried : undefined);
299
+ if (errors !== undefined) {
300
+ // The detail is the canonical sentence rather than the throw's message: a raw
301
+ // `ZodError` stringifies its whole issue list into `message` as JSON, and echoing
302
+ // that beside the parsed `errors` array publishes the same thing twice — in the
303
+ // shape this change exists to stop clients re-parsing.
304
+ return build('validation_failed', 'the input did not parse', instance, { errors });
305
+ }
306
+ }
260
307
  if (code !== undefined && err instanceof Error) {
261
308
  // `internal` is still generic even when a throw asked for it by name: the rule is
262
309
  // about what reaches a client, not about who chose the code.
@@ -329,9 +376,31 @@ export function toWireFailure(err) {
329
376
  name: err.name,
330
377
  message: err.message,
331
378
  code,
332
- extensions: { ...(err.extensions ?? {}) },
379
+ extensions: extensionsFor(code, err),
333
380
  };
334
381
  }
382
+ /**
383
+ * The extensions a throw carries onto the wire.
384
+ *
385
+ * A `SubstratError` already holds its own, declared and parsed at the throw site. A
386
+ * `ZodError` holds none — it holds `issues`, which is the same information in zod's
387
+ * shape rather than ours, and #831's whole complaint was that this function dropped it:
388
+ * the field list survived only as JSON inside `message`, leaving every vertical to
389
+ * re-parse a string for what `validationIssue` already models.
390
+ *
391
+ * That mattered more after #893 than before it. The host now parses a declared
392
+ * operation input at the scope door, so on the hosted path the refusal is raised
393
+ * INSIDE the ScopeDO and this is the only seam it crosses — while the same operation
394
+ * under `adapter-sqlite` throws in-process with `issues` intact. Structured in a
395
+ * scenario test, bare in production, is the worst of the two available failures.
396
+ */
397
+ function extensionsFor(code, err) {
398
+ const declared = { ...(err.extensions ?? {}) };
399
+ if (code !== 'validation_failed' || declared.errors !== undefined)
400
+ return declared;
401
+ const issues = parseIssuesOf(err);
402
+ return issues === undefined ? declared : { ...declared, errors: issues };
403
+ }
335
404
  /**
336
405
  * Rebuild a throw from the wire.
337
406
  *
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"}