@substrat-run/contracts 0.116.0 → 0.117.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/events.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { z } from 'zod';
2
- import { dataSubjectId, eventId, instant, moduleId, permissionKey, principalId, scopeId, tenantId, } from './ids.js';
2
+ import { capabilityId, dataSubjectId, eventId, instant, moduleId, permissionKey, principalId, scopeId, tenantId, } from './ids.js';
3
3
  import { impersonationStamp } from './impersonation.js';
4
4
  // Opaque ref — the kernel owns no entities (D-1); attachment contracts bind here.
5
5
  export const entityRef = z.object({
@@ -23,7 +23,17 @@ export const systemActor = z.object({ system: moduleId });
23
23
  * who did not.
24
24
  */
25
25
  export const connectorActor = z.object({ connection: z.string().min(1) });
26
- export const actor = z.union([principalId, systemActor, connectorActor]);
26
+ /**
27
+ * WHOEVER HELD A CAPABILITY acted — a link share, a claim link (#1672).
28
+ *
29
+ * The fourth member, and a member rather than a principal for #97's reason: the
30
+ * person holding a link is nobody the checker knows, and recording them as a
31
+ * principal would put a person in the trail who does not exist. The id names the
32
+ * capability's directory row, which says who minted it, for what, and until when —
33
+ * so the trail can answer "reached through Anna's link" without inventing a guest.
34
+ */
35
+ export const capabilityActor = z.object({ capability: capabilityId });
36
+ export const actor = z.union([principalId, systemActor, connectorActor, capabilityActor]);
27
37
  /**
28
38
  * What authorized a mutation (K-34). Each entry is a permission the emitting operation
29
39
  * checked-and-passed; `grant` — present only when the allow resolved through a
@@ -137,6 +147,25 @@ export const timelineEntry = z.object({
137
147
  type: eventType,
138
148
  occurredAt: instant,
139
149
  actor,
150
+ /**
151
+ * Why this entry could not be read whole (#1636). ABSENT on every row the kernel
152
+ * wrote, which is what "decoded whole" looks like, so a healthy page reads exactly
153
+ * as it did before.
154
+ *
155
+ * An entity's history is a LIST, and a strict decode let one row whose JSON would
156
+ * not parse throw for the whole page — and end a cause walk in an exception rather
157
+ * than at the link it could not read. So the read is tolerant and SAYS SO: every
158
+ * column that did not decode is named here, and its field comes back EMPTY rather
159
+ * than guessed at — `actor` as the self-naming `{ system: 'undecodable' }` marker,
160
+ * a JSON field as `null`. Every field still satisfies this schema; a row whose id,
161
+ * type, time or PII class does not is never returned as one of these at all.
162
+ *
163
+ * On a history entry this is what separates an undecodable `payload` from an
164
+ * ERASED one: both read `null`, and only an erasure is a fact about the event.
165
+ *
166
+ * Reachable without a forge: `importDump` replays a dump's rows verbatim.
167
+ */
168
+ decodeError: z.string().min(1).optional(),
140
169
  });
141
170
  /**
142
171
  * A timeline entry plus what a history VIEW needs — the second layer of #800.
@@ -249,6 +278,11 @@ export const causeTerminal = z.enum([
249
278
  * A cause named an event this scope's outbox does not hold. Should not happen —
250
279
  * the spine is append-only and never pruned — so it is reported rather than
251
280
  * smoothed over: silently stopping here would look exactly like a complete chain.
281
+ *
282
+ * Also the ending when the last entry's cause could not be DECODED (#1636 — its
283
+ * `decodeError` names `caused_by` or `operation`): the trail cannot be followed
284
+ * further, and reading the undecodable cause as a null one would call a fragment
285
+ * a complete chain.
252
286
  */
253
287
  'missing',
254
288
  /**
@@ -288,9 +322,32 @@ export const deliveryState = z.enum([
288
322
  /** Ran, threw, and will not be tried again. The failure stands. */
289
323
  'dead',
290
324
  ]);
325
+ /**
326
+ * Who a delivery row belongs to (#1643): a module id, or `executor:<id>` for an executor.
327
+ *
328
+ * `_substrat_deliveries.consumer_module` holds both, and the contract typed it as a bare
329
+ * `ModuleId` — which a decode cannot honour, since `executor:mailer` is not one (the colon).
330
+ * The cast hid that; a decode against `moduleId` would have thrown on every healthy executor
331
+ * row. So the schema names the two shapes the column holds. The inferred type is unchanged
332
+ * (`ModuleId`), and every value the old one accepted is still accepted.
333
+ *
334
+ * The `executor:` branch matches the WRITER, not a tidier id. `registerExecutor` and
335
+ * `registerConnector` accept any string (`scope-host.ts`) and both adapters persist
336
+ * `executor:${id}`, so the kernel can itself write `executor:` with an empty id, or one with a
337
+ * newline. A reader that refused those would throw the whole dead-letter page or effects walk on
338
+ * a healthy delivery. It accepts whatever registration could have produced; tightening
339
+ * registration is a contract change, and #1645 carries it.
340
+ */
341
+ export const deliveryConsumer = z.union([
342
+ moduleId,
343
+ z
344
+ .string()
345
+ .startsWith('executor:')
346
+ .brand(),
347
+ ]);
291
348
  export const eventDelivery = z.object({
292
- /** The module whose consumer this row is about. */
293
- consumer: moduleId,
349
+ /** The module whose consumer this row is about — or `executor:<id>`, see `deliveryConsumer`. */
350
+ consumer: deliveryConsumer,
294
351
  state: deliveryState,
295
352
  /** Delivered: when. Retrying or dead: when it was last attempted. */
296
353
  at: instant,
@@ -311,6 +368,14 @@ export const eventDelivery = z.object({
311
368
  * alarm, a seed, an attachment RPC), or the row predates the column.
312
369
  */
313
370
  invocationId: z.string().nullable(),
371
+ /**
372
+ * Why this delivery could not be read whole (#1643). ABSENT on every row the kernel
373
+ * wrote. A nullable column that broke its schema reads as `null` beside this reason;
374
+ * `state` is resolved from the stored `next_attempt_at` and `error`, so it stays the
375
+ * fact even when `error` itself did not decode. A row whose consumer, time or
376
+ * `attempts` does not decode is never returned as one of these at all.
377
+ */
378
+ decodeError: z.string().min(1).optional(),
314
379
  });
315
380
  /** How far the forward walk got, with the same care as `causeTerminal`. */
316
381
  export const effectsTerminal = z.enum([
@@ -327,6 +392,62 @@ export const effectsTerminal = z.enum([
327
392
  */
328
393
  'cycle',
329
394
  ]);
395
+ /**
396
+ * One delivery that gave up (#1525), with enough of its event to find it again —
397
+ * `readDeadLetters`' entry.
398
+ *
399
+ * The scope-wide read `walkEventEffects` could not be: that walk reaches a delivery
400
+ * only THROUGH its event, so a dead letter was visible only to someone who already knew
401
+ * which record to open. An in-scope consumer does not retry, so one failure is terminal
402
+ * and these rows wait for a human.
403
+ *
404
+ * No payload, deliberately. The envelope is enough to open the event's own reads, and a
405
+ * list that decoded every payload would be a disclosure decision per row.
406
+ */
407
+ export const deadLetter = z.object({
408
+ eventId,
409
+ eventType,
410
+ occurredAt: instant,
411
+ /** The entity the event was about — what a reader opens next. */
412
+ entity: entityRef,
413
+ /**
414
+ * The call the EVENT came from (#1237). Null for a seed or internal call, or an
415
+ * event older than the column.
416
+ *
417
+ * It is not, in general, the call that attempted the delivery — see
418
+ * `attemptInvocationId`, which is. This one said it was until #1525 put the
419
+ * delivery's own id beside it, and the rows in this very list are where the two
420
+ * come apart most often.
421
+ */
422
+ invocationId: z.string().nullable(),
423
+ /**
424
+ * The call the LAST attempt ran in (#1525) — the one that gave up, since these rows
425
+ * are terminal. Pairs with `at`, which is when that attempt happened.
426
+ *
427
+ * Usually NOT `invocationId`: an executor's first attempt runs in the emitting
428
+ * call's post-commit tail, and every retry after it in a drain that is a different
429
+ * call or none. A row that exhausted its attempts therefore most often names a
430
+ * later call, or null. An in-scope consumer does not retry, so for those two the
431
+ * ids do agree — and that agreement is a fact about consumers, not a rule.
432
+ *
433
+ * Null is two facts: the attempt carried no call (a drain, an alarm, a seed), or
434
+ * the row predates the column.
435
+ */
436
+ attemptInvocationId: z.string().nullable(),
437
+ /** The consumer that gave up — a module id, or `executor:<id>` for an executor. */
438
+ consumer: deliveryConsumer,
439
+ /** When it was last attempted, which for a dead row is when it gave up. */
440
+ at: instant,
441
+ error: z.string(),
442
+ attempts: z.number().int().nonnegative(),
443
+ /**
444
+ * Why this row could not be read whole (#1643). ABSENT on every row the kernel wrote.
445
+ * Only the two invocation ids are nullable columns, so those are what can come back
446
+ * `null` beside this reason; a row whose event id, type, time, entity, consumer, error
447
+ * or `attempts` does not decode is never returned as one of these at all.
448
+ */
449
+ decodeError: z.string().min(1).optional(),
450
+ });
330
451
  /**
331
452
  * One event as it leaves the scope for Tier 2 (#1334) — the exact-history lake
332
453
  * the master plan commits to (§5.3: "domain events → Pipelines → Iceberg on R2").
@@ -1 +1 @@
1
- {"version":3,"file":"events.js","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"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"}
package/dist/ids.d.ts CHANGED
@@ -15,6 +15,8 @@ export declare const platformRequestId: z.core.$ZodBranded<z.ZodString, "Platfor
15
15
  export type PlatformRequestId = z.infer<typeof platformRequestId>;
16
16
  export declare const dataSubjectId: z.core.$ZodBranded<z.ZodString, "DataSubjectId", "out">;
17
17
  export type DataSubjectId = z.infer<typeof dataSubjectId>;
18
+ export declare const capabilityId: z.core.$ZodBranded<z.ZodString, "CapabilityId", "out">;
19
+ export type CapabilityId = z.infer<typeof capabilityId>;
18
20
  export declare const moduleId: z.core.$ZodBranded<z.ZodString, "ModuleId", "out">;
19
21
  export type ModuleId = z.infer<typeof moduleId>;
20
22
  /**
@@ -57,6 +59,16 @@ export type Instant = z.infer<typeof instant>;
57
59
  */
58
60
  export declare const calendarDate: z.ZodISODate;
59
61
  export type CalendarDate = z.infer<typeof calendarDate>;
62
+ /**
63
+ * The longest permission key, in bytes (#1655). Not a style choice: the checker finds
64
+ * a subject's grants with `relation LIKE 'granted:<key>%'`, and a Durable Object's
65
+ * SQLite refuses any LIKE pattern over 50 bytes — node's allows 50 000, so no node
66
+ * suite can see it. `granted:` is 8 bytes and `%` is 1, leaving 41. A longer key would
67
+ * parse, deploy, and then make every check of it throw on a hosted scope. The key
68
+ * alphabet is ASCII, so characters are bytes; it has no `_` or `%`, so it needs no
69
+ * escaping inside the pattern either.
70
+ */
71
+ export declare const PERMISSION_KEY_MAX_LENGTH = 41;
60
72
  export declare const permissionKey: z.core.$ZodBranded<z.ZodString, "PermissionKey", "out">;
61
73
  export type PermissionKey = z.infer<typeof permissionKey>;
62
74
  export declare const slug: z.ZodString;
package/dist/ids.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"ids.d.ts","sourceRoot":"","sources":["../src/ids.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAQxB,eAAO,MAAM,QAAQ,oDAA6C,CAAC;AACnE,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,QAAQ,CAAC,CAAC;AAEhD,eAAO,MAAM,OAAO,mDAA4C,CAAC;AACjE,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,OAAO,CAAC,CAAC;AAE9C,eAAO,MAAM,WAAW,uDAAgD,CAAC;AACzE,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAMtD,eAAO,MAAM,KAAK,iDAA0C,CAAC;AAC7D,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,KAAK,CAAC,CAAC;AAK1C,eAAO,MAAM,eAAe,2DAAoD,CAAC;AACjF,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAE9D,eAAO,MAAM,OAAO,mDAA4C,CAAC;AACjE,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,OAAO,CAAC,CAAC;AAK9C,eAAO,MAAM,iBAAiB,6DAAsD,CAAC;AACrF,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAElE,eAAO,MAAM,aAAa,yDAAkD,CAAC;AAC7E,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAG1D,eAAO,MAAM,QAAQ,oDAGC,CAAC;AACvB,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,QAAQ,CAAC,CAAC;AAEhD;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,OAAO,mDAOC,CAAC;AACtB,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,OAAO,CAAC,CAAC;AAE9C;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,YAAY,cAAe,CAAC;AACzC,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAGxD,eAAO,MAAM,aAAa,yDAGC,CAAC;AAC5B,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAE1D,eAAO,MAAM,IAAI,aAAwD,CAAC;AAE1E;;;;;;;;GAQG;AACH,eAAO,MAAM,YAAY,aAEwD,CAAC"}
1
+ {"version":3,"file":"ids.d.ts","sourceRoot":"","sources":["../src/ids.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAQxB,eAAO,MAAM,QAAQ,oDAA6C,CAAC;AACnE,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,QAAQ,CAAC,CAAC;AAEhD,eAAO,MAAM,OAAO,mDAA4C,CAAC;AACjE,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,OAAO,CAAC,CAAC;AAE9C,eAAO,MAAM,WAAW,uDAAgD,CAAC;AACzE,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAMtD,eAAO,MAAM,KAAK,iDAA0C,CAAC;AAC7D,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,KAAK,CAAC,CAAC;AAK1C,eAAO,MAAM,eAAe,2DAAoD,CAAC;AACjF,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAE9D,eAAO,MAAM,OAAO,mDAA4C,CAAC;AACjE,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,OAAO,CAAC,CAAC;AAK9C,eAAO,MAAM,iBAAiB,6DAAsD,CAAC;AACrF,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAElE,eAAO,MAAM,aAAa,yDAAkD,CAAC;AAC7E,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAO1D,eAAO,MAAM,YAAY,wDAAiD,CAAC;AAC3E,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAGxD,eAAO,MAAM,QAAQ,oDAGC,CAAC;AACvB,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,QAAQ,CAAC,CAAC;AAEhD;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,OAAO,mDAOC,CAAC;AACtB,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,OAAO,CAAC,CAAC;AAE9C;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,YAAY,cAAe,CAAC;AACzC,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAExD;;;;;;;;GAQG;AACH,eAAO,MAAM,yBAAyB,KAAK,CAAC;AAG5C,eAAO,MAAM,aAAa,yDAIC,CAAC;AAC5B,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAE1D,eAAO,MAAM,IAAI,aAAwD,CAAC;AAE1E;;;;;;;;GAQG;AACH,eAAO,MAAM,YAAY,aAEwD,CAAC"}
package/dist/ids.js CHANGED
@@ -21,6 +21,12 @@ export const eventId = z.string().regex(ULID).brand();
21
21
  // other id so a request id can't be confused with an event or scope id.
22
22
  export const platformRequestId = z.string().regex(ULID).brand();
23
23
  export const dataSubjectId = z.string().regex(ULID).brand();
24
+ // A capability (#1672) — authority carried by a secret rather than held by a principal:
25
+ // "anyone with this link may read this folder until Friday". Branded distinctly from
26
+ // PrincipalId for the reason PlatformActorId is: whoever holds the link is not a person
27
+ // the checker knows, and an audit view that showed one as a principal would be lying.
28
+ // The id names the directory row; the SECRET is a separate value only its hash is kept of.
29
+ export const capabilityId = z.string().regex(ULID).brand();
24
30
  // npm-package-shaped, e.g. '@substrat-run/engine-workorder'
25
31
  export const moduleId = z
26
32
  .string()
@@ -71,10 +77,21 @@ export const instant = z
71
77
  * field it already exposes without changing any caller's type.
72
78
  */
73
79
  export const calendarDate = z.iso.date();
80
+ /**
81
+ * The longest permission key, in bytes (#1655). Not a style choice: the checker finds
82
+ * a subject's grants with `relation LIKE 'granted:<key>%'`, and a Durable Object's
83
+ * SQLite refuses any LIKE pattern over 50 bytes — node's allows 50 000, so no node
84
+ * suite can see it. `granted:` is 8 bytes and `%` is 1, leaving 41. A longer key would
85
+ * parse, deploy, and then make every check of it throw on a hosted scope. The key
86
+ * alphabet is ASCII, so characters are bytes; it has no `_` or `%`, so it needs no
87
+ * escaping inside the pattern either.
88
+ */
89
+ export const PERMISSION_KEY_MAX_LENGTH = 41;
74
90
  // Module-namespaced permission key, e.g. 'workorder:create'
75
91
  export const permissionKey = z
76
92
  .string()
77
93
  .regex(/^[a-z0-9-]+:[a-z0-9-]+$/)
94
+ .max(PERMISSION_KEY_MAX_LENGTH)
78
95
  .brand();
79
96
  export const slug = z.string().regex(/^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/);
80
97
  /**
package/dist/ids.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"ids.js","sourceRoot":"","sources":["../src/ids.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,oFAAoF;AACpF,oFAAoF;AACpF,oEAAoE;AAEpE,MAAM,IAAI,GAAG,0BAA0B,CAAC;AAExC,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,EAAc,CAAC;AAGnE,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,EAAa,CAAC;AAGjE,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,EAAiB,CAAC;AAGzE,oFAAoF;AACpF,sFAAsF;AACtF,qFAAqF;AACrF,8EAA8E;AAC9E,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,EAAW,CAAC;AAG7D,qFAAqF;AACrF,sFAAsF;AACtF,kEAAkE;AAClE,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,EAAqB,CAAC;AAGjF,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,EAAa,CAAC;AAGjE,sGAAsG;AACtG,sGAAsG;AACtG,wEAAwE;AACxE,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,EAAuB,CAAC;AAGrF,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,EAAmB,CAAC;AAG7E,4DAA4D;AAC5D,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC;KACtB,MAAM,EAAE;KACR,KAAK,CAAC,wDAAwD,CAAC;KAC/D,KAAK,EAAc,CAAC;AAGvB;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC;KACrB,MAAM,EAAE;KACR,QAAQ,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;KAC1B,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE;IACf,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACzB,OAAO,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;AAC3D,CAAC,CAAC;KACD,KAAK,EAAa,CAAC;AAGtB;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;AAGzC,4DAA4D;AAC5D,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC;KAC3B,MAAM,EAAE;KACR,KAAK,CAAC,yBAAyB,CAAC;KAChC,KAAK,EAAmB,CAAC;AAG5B,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC;AAE1E;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC;KAC1B,MAAM,EAAE;KACR,KAAK,CAAC,uEAAuE,CAAC,CAAC"}
1
+ {"version":3,"file":"ids.js","sourceRoot":"","sources":["../src/ids.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -31,6 +31,7 @@ export * from './control-plane.js';
31
31
  export * from './permission.js';
32
32
  export * from './impersonation.js';
33
33
  export * from './events.js';
34
+ export * from './capability.js';
34
35
  export * from './errors.js';
35
36
  export * from './platform-request.js';
36
37
  export * from './denial.js';
@@ -47,4 +48,5 @@ export * from './client-context.js';
47
48
  export * from './model-usage.js';
48
49
  export * from './seam.js';
49
50
  export * from './signals.js';
51
+ export * from './mcp.js';
50
52
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,uBAAuB,CAAC;AACtC,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC;AACxB,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,uBAAuB,CAAC;AACtC,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC;AACxB,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC"}
package/dist/index.js CHANGED
@@ -31,6 +31,7 @@ export * from './control-plane.js';
31
31
  export * from './permission.js';
32
32
  export * from './impersonation.js';
33
33
  export * from './events.js';
34
+ export * from './capability.js';
34
35
  export * from './errors.js';
35
36
  export * from './platform-request.js';
36
37
  export * from './denial.js';
@@ -47,4 +48,5 @@ export * from './client-context.js';
47
48
  export * from './model-usage.js';
48
49
  export * from './seam.js';
49
50
  export * from './signals.js';
51
+ export * from './mcp.js';
50
52
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,uBAAuB,CAAC;AACtC,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC;AACxB,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,uBAAuB,CAAC;AACtC,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC;AACxB,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC"}
package/dist/mcp.d.ts ADDED
@@ -0,0 +1,39 @@
1
+ /**
2
+ * A vertical's MCP endpoint, named the ONE way both of its ends name it (#1619).
3
+ *
4
+ * The endpoint `mountOperations` mounts is an OAuth protected resource, and its identifier
5
+ * is a string two parties have to agree on byte for byte. The vertical publishes it in its
6
+ * RFC 9728 document and holds a presented token to it (`aud`). The platform registers it
7
+ * at the vertical's issuer, which refuses to mint for any `resource` it has no row for
8
+ * (RFC 8707). If each side built the string itself, one would eventually add a trailing
9
+ * slash the other did not, and the only symptom would be `invalid_target` at a login that
10
+ * never renders.
11
+ *
12
+ * So both sides call these. `@substrat-run/vertical-host` uses them for the document and
13
+ * for the `aud` check. The dashboard uses them for the resources it registers, one per
14
+ * hostname the app answers on, because the identifier is the URL a client actually
15
+ * reached.
16
+ */
17
+ /** Where the MCP endpoint lives under a vertical's API base path: `${basePath}/mcp`. */
18
+ export declare function mcpEndpointPath(basePath?: string): string;
19
+ /**
20
+ * The fleet's convention, `/api/mcp`, which is `mountOperations`' default. It is the only
21
+ * path the platform can register without asking the vertical, so a vertical that mounts
22
+ * the endpoint elsewhere (`mcp.path`) or pins a different `resource` is not covered by
23
+ * the platform's registration.
24
+ */
25
+ export declare const MCP_ENDPOINT_PATH: string;
26
+ /**
27
+ * An MCP endpoint's resource identifier: its own absolute URL on the origin a client
28
+ * reached it at. `origin` is `scheme://host[:port]` with no trailing slash, which is what
29
+ * `new URL(…).origin` returns.
30
+ */
31
+ export declare function mcpResourceOf(origin: string, path?: string): string;
32
+ /**
33
+ * The delivered-config key through which the platform tells a team auth-server which MCP
34
+ * endpoints it may mint for: `${MCP_RESOURCES_CONFIG_PREFIX}<app scope id>`, whose value is
35
+ * that app's whole set as a JSON array of `mcpResourceOf` identifiers, or `""` for none.
36
+ * The dashboard writes it. `demos/auth-server/src/resources.ts` turns it into rows.
37
+ */
38
+ export declare const MCP_RESOURCES_CONFIG_PREFIX = "substrat:resources:";
39
+ //# sourceMappingURL=mcp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,wFAAwF;AACxF,wBAAgB,eAAe,CAAC,QAAQ,SAAS,GAAG,MAAM,CAEzD;AAED;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,QAAoB,CAAC;AAEnD;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,GAAE,MAA0B,GAAG,MAAM,CAEtF;AAED;;;;;GAKG;AACH,eAAO,MAAM,2BAA2B,wBAAwB,CAAC"}
package/dist/mcp.js ADDED
@@ -0,0 +1,43 @@
1
+ /**
2
+ * A vertical's MCP endpoint, named the ONE way both of its ends name it (#1619).
3
+ *
4
+ * The endpoint `mountOperations` mounts is an OAuth protected resource, and its identifier
5
+ * is a string two parties have to agree on byte for byte. The vertical publishes it in its
6
+ * RFC 9728 document and holds a presented token to it (`aud`). The platform registers it
7
+ * at the vertical's issuer, which refuses to mint for any `resource` it has no row for
8
+ * (RFC 8707). If each side built the string itself, one would eventually add a trailing
9
+ * slash the other did not, and the only symptom would be `invalid_target` at a login that
10
+ * never renders.
11
+ *
12
+ * So both sides call these. `@substrat-run/vertical-host` uses them for the document and
13
+ * for the `aud` check. The dashboard uses them for the resources it registers, one per
14
+ * hostname the app answers on, because the identifier is the URL a client actually
15
+ * reached.
16
+ */
17
+ /** Where the MCP endpoint lives under a vertical's API base path: `${basePath}/mcp`. */
18
+ export function mcpEndpointPath(basePath = '/api') {
19
+ return `${basePath}/mcp`;
20
+ }
21
+ /**
22
+ * The fleet's convention, `/api/mcp`, which is `mountOperations`' default. It is the only
23
+ * path the platform can register without asking the vertical, so a vertical that mounts
24
+ * the endpoint elsewhere (`mcp.path`) or pins a different `resource` is not covered by
25
+ * the platform's registration.
26
+ */
27
+ export const MCP_ENDPOINT_PATH = mcpEndpointPath();
28
+ /**
29
+ * An MCP endpoint's resource identifier: its own absolute URL on the origin a client
30
+ * reached it at. `origin` is `scheme://host[:port]` with no trailing slash, which is what
31
+ * `new URL(…).origin` returns.
32
+ */
33
+ export function mcpResourceOf(origin, path = MCP_ENDPOINT_PATH) {
34
+ return `${origin}${path}`;
35
+ }
36
+ /**
37
+ * The delivered-config key through which the platform tells a team auth-server which MCP
38
+ * endpoints it may mint for: `${MCP_RESOURCES_CONFIG_PREFIX}<app scope id>`, whose value is
39
+ * that app's whole set as a JSON array of `mcpResourceOf` identifiers, or `""` for none.
40
+ * The dashboard writes it. `demos/auth-server/src/resources.ts` turns it into rows.
41
+ */
42
+ export const MCP_RESOURCES_CONFIG_PREFIX = 'substrat:resources:';
43
+ //# sourceMappingURL=mcp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.js","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,wFAAwF;AACxF,MAAM,UAAU,eAAe,CAAC,QAAQ,GAAG,MAAM;IAC/C,OAAO,GAAG,QAAQ,MAAM,CAAC;AAC3B,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,eAAe,EAAE,CAAC;AAEnD;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,MAAc,EAAE,IAAI,GAAW,iBAAiB;IAC5E,OAAO,GAAG,MAAM,GAAG,IAAI,EAAE,CAAC;AAC5B,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG,qBAAqB,CAAC"}
@@ -55,9 +55,15 @@ export declare const checkSubject: z.ZodUnion<readonly [z.ZodObject<{
55
55
  }, z.core.$strip>, z.ZodObject<{
56
56
  kind: z.ZodLiteral<"system">;
57
57
  id: z.core.$ZodBranded<z.ZodString, "ModuleId", "out">;
58
+ }, z.core.$strip>, z.ZodObject<{
59
+ kind: z.ZodLiteral<"capability">;
60
+ id: z.core.$ZodBranded<z.ZodString, "CapabilityId", "out">;
58
61
  }, z.core.$strip>]>;
59
62
  export type CheckSubject = z.infer<typeof checkSubject>;
60
- /** The tuple-store ref for a subject: `principal:01J…` / `connection:01J…` / `system:@scope/mod`. */
63
+ /**
64
+ * The tuple-store ref for a subject: `principal:01J…` / `connection:01J…` /
65
+ * `system:@scope/mod` / `capability:01J…`.
66
+ */
61
67
  export declare const subjectRef: (subject: CheckSubject) => string;
62
68
  /**
63
69
  * A capability granted to a CONNECTION rather than a principal (#97).
@@ -136,9 +142,10 @@ export type CapabilityGrant = z.infer<typeof capabilityGrant>;
136
142
  * Narrow by construction: it reaches only scopes of the module it names, and only
137
143
  * the one permission. It is projected from the module's declared `schedules`
138
144
  * (`scheduleSpec.permissions`) at scope provisioning, so what a schedule may do is
139
- * both readable in the permission diff (code) and revocable per scope (runtime — a
140
- * revoke fails the operation's own `ctx.check` closed, which is how scheduling is
141
- * disabled for a tenant without a special "off" code path).
145
+ * readable in the permission diff (code). Turning a scope's schedules OFF is not a
146
+ * revoke of one of these but the schedule kill switch, `systemSwitch` below (#1666):
147
+ * a per-permission revoke would leave the gate open and fail the schedule's own
148
+ * `ctx.check` on every pass, and a re-grant must not be able to turn it back on.
142
149
  */
143
150
  export declare const systemGrant: z.ZodObject<{
144
151
  moduleId: z.core.$ZodBranded<z.ZodString, "ModuleId", "out">;
@@ -151,6 +158,63 @@ export declare const systemGrant: z.ZodObject<{
151
158
  grantedBy: z.core.$ZodBranded<z.ZodString, "PlatformActorId", "out">;
152
159
  }, z.core.$strip>;
153
160
  export type SystemGrant = z.infer<typeof systemGrant>;
161
+ /**
162
+ * The schedule kill switch (#1666) — one module's scheduled work on ONE scope, turned
163
+ * off by `HostAdmin.revokeFromSystem` and back on by `restoreToSystem`.
164
+ *
165
+ * **Module-wide, never per permission.** A grant is per permission and schedules share
166
+ * permissions, so "one schedule" is not expressible as a grant revoke without switching
167
+ * off its siblings too. And a per-permission revoke is worse than none: the gate would
168
+ * stay open on the module's other live grant, and the schedule's own `ctx.check` would
169
+ * then fail it on every pass — noise in place of silence.
170
+ *
171
+ * `reason` is required and lands in the admin log beside the actor, because "who turned
172
+ * a tenant's schedules off, and why" is the question the log exists to answer — a
173
+ * switch pulled in an incident has no other record of what the incident was.
174
+ *
175
+ * The scope is required: the switch is per scope. A tenant-wide form would be a
176
+ * different decision about blast radius, and it is not this one.
177
+ */
178
+ export declare const systemSwitch: z.ZodObject<{
179
+ moduleId: z.core.$ZodBranded<z.ZodString, "ModuleId", "out">;
180
+ node: z.ZodObject<{
181
+ tenantId: z.core.$ZodBranded<z.ZodString, "TenantId", "out">;
182
+ scopeId: z.core.$ZodBranded<z.ZodString, "ScopeId", "out">;
183
+ }, z.core.$strip>;
184
+ reason: z.ZodString;
185
+ }, z.core.$strip>;
186
+ export type SystemSwitch = z.infer<typeof systemSwitch>;
187
+ /**
188
+ * What the far end of the switch did in the scope's own storage (#1666) — the wire
189
+ * shape `/internal/system-switch` answers with, and what a local host computes itself.
190
+ *
191
+ * `held: false` means the scope holds no `system:<module>` grant and no switch marker
192
+ * for that module at all — a typo'd module id, or a module this scope never ran. Nothing
193
+ * was written. It is an answer, not an error, so that a deployment which predates the
194
+ * route (and answers 404) can never be mistaken for one that simply held nothing.
195
+ */
196
+ export declare const systemSwitchOutcome: z.ZodObject<{
197
+ held: z.ZodBoolean;
198
+ changed: z.ZodBoolean;
199
+ permissions: z.ZodArray<z.core.$ZodBranded<z.ZodString, "PermissionKey", "out">>;
200
+ }, z.core.$strip>;
201
+ export type SystemSwitchOutcome = z.infer<typeof systemSwitchOutcome>;
202
+ /**
203
+ * What `revokeFromSystem` / `restoreToSystem` answer (#1666) — the position the switch is now
204
+ * in. `operationId` names this call's rows on the admin log (its intent, then its outcome),
205
+ * so an operator can tie what the route answered to what the log recorded.
206
+ */
207
+ export declare const systemSwitchResult: z.ZodObject<{
208
+ operationId: z.ZodString;
209
+ moduleId: z.core.$ZodBranded<z.ZodString, "ModuleId", "out">;
210
+ schedules: z.ZodEnum<{
211
+ off: "off";
212
+ on: "on";
213
+ }>;
214
+ changed: z.ZodBoolean;
215
+ permissions: z.ZodArray<z.core.$ZodBranded<z.ZodString, "PermissionKey", "out">>;
216
+ }, z.core.$strip>;
217
+ export type SystemSwitchResult = z.infer<typeof systemSwitchResult>;
154
218
  export declare const objectRef: z.core.$ZodBranded<z.ZodString, "ObjectRef", "out">;
155
219
  export type ObjectRef = z.infer<typeof objectRef>;
156
220
  export declare const relationName: z.ZodString;
@@ -1 +1 @@
1
- {"version":3,"file":"permission.d.ts","sourceRoot":"","sources":["../src/permission.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAiBxB,eAAO,MAAM,IAAI;;;iBAGf,CAAC;AACH,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC;AAExC,eAAO,MAAM,OAAO,aAAwD,CAAC;AAE7E,eAAO,MAAM,cAAc;;;;iBAUzB,CAAC;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAE5D;;;;;;GAMG;AACH,eAAO,MAAM,UAAU;;;;;iBAAsC,CAAC;AAC9D,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAEpD,eAAO,MAAM,cAAc;;;;;;;iBAIzB,CAAC;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAM5D;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,YAAY;;;;;;;;;mBAUvB,CAAC;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAExD,qGAAqG;AACrG,eAAO,MAAM,UAAU,YAAa,YAAY,KAAG,MAAyC,CAAC;AAE7F;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe;;;;;;;;;iBAM1B,CAAC;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAE9D;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB;;;;;;;;;;iBAahC,CAAC;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAE1E;;;;;;;;GAQG;AACH,eAAO,MAAM,wBAAwB;;;;iBAInC,CAAC;AACH,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAEhF,eAAO,MAAM,eAAe;;;;;;;;;;;;;iBAO1B,CAAC;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAE9D;;;;;;;;;;GAUG;AACH,eAAO,MAAM,WAAW;;;;;;;;;iBAMtB,CAAC;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAgBtD,eAAO,MAAM,SAAS,qDAGC,CAAC;AACxB,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,SAAS,CAAC,CAAC;AAGlD,eAAO,MAAM,YAAY,aAAqC,CAAC;AAE/D,eAAO,MAAM,aAAa;;;;iBAIxB,CAAC;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAQ1D,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;8BAUnB,CAAC;AACH,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,QAAQ,CAAC,CAAC;AAOhD;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,QAAQ;;;;;;8BAGnB,CAAC;AACH,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,QAAQ,CAAC,CAAC;AAEhD;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,SAAS,aAAa,EAAE,GAC9B,MAAM,GAAG,SAAS,CAOpB;AAED,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;iBAS/B,CAAC;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC"}
1
+ {"version":3,"file":"permission.d.ts","sourceRoot":"","sources":["../src/permission.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { z } from 'zod';
2
- import { instant, moduleId, permissionKey, platformActorId, principalId, scopeId, tenantId, } from './ids.js';
2
+ import { capabilityId, instant, moduleId, permissionKey, platformActorId, principalId, scopeId, tenantId, } from './ids.js';
3
3
  import { entityRef } from './events.js';
4
4
  // ============================================================================
5
5
  // Authored surface — what humans and agents write (design doc §4.1).
@@ -60,8 +60,17 @@ export const checkSubject = z.union([
60
60
  // `{ system: <moduleId> }` on events, so scheduled work reads as the schedule, not
61
61
  // as a human who happened to sit down at 03:00.
62
62
  z.object({ kind: z.literal('system'), id: moduleId }),
63
+ // WHOEVER HOLDS A CAPABILITY'S SECRET (#1672) — a link share. Resolved against the
64
+ // capability's own directory row rather than against tuples: the row IS the grant
65
+ // (one entity and its declared descendants, specific keys), no `capability:` tuple is
66
+ // ever written, and the minter's own authority is re-checked on every use — so a
67
+ // capability can never hold more than the principal who minted it holds right now.
68
+ z.object({ kind: z.literal('capability'), id: capabilityId }),
63
69
  ]);
64
- /** The tuple-store ref for a subject: `principal:01J…` / `connection:01J…` / `system:@scope/mod`. */
70
+ /**
71
+ * The tuple-store ref for a subject: `principal:01J…` / `connection:01J…` /
72
+ * `system:@scope/mod` / `capability:01J…`.
73
+ */
65
74
  export const subjectRef = (subject) => `${subject.kind}:${subject.id}`;
66
75
  /**
67
76
  * A capability granted to a CONNECTION rather than a principal (#97).
@@ -130,9 +139,10 @@ export const capabilityGrant = z.object({
130
139
  * Narrow by construction: it reaches only scopes of the module it names, and only
131
140
  * the one permission. It is projected from the module's declared `schedules`
132
141
  * (`scheduleSpec.permissions`) at scope provisioning, so what a schedule may do is
133
- * both readable in the permission diff (code) and revocable per scope (runtime — a
134
- * revoke fails the operation's own `ctx.check` closed, which is how scheduling is
135
- * disabled for a tenant without a special "off" code path).
142
+ * readable in the permission diff (code). Turning a scope's schedules OFF is not a
143
+ * revoke of one of these but the schedule kill switch, `systemSwitch` below (#1666):
144
+ * a per-permission revoke would leave the gate open and fail the schedule's own
145
+ * `ctx.check` on every pass, and a re-grant must not be able to turn it back on.
136
146
  */
137
147
  export const systemGrant = z.object({
138
148
  moduleId,
@@ -141,6 +151,56 @@ export const systemGrant = z.object({
141
151
  expiresAt: instant.optional(),
142
152
  grantedBy: platformActorId,
143
153
  });
154
+ /**
155
+ * The schedule kill switch (#1666) — one module's scheduled work on ONE scope, turned
156
+ * off by `HostAdmin.revokeFromSystem` and back on by `restoreToSystem`.
157
+ *
158
+ * **Module-wide, never per permission.** A grant is per permission and schedules share
159
+ * permissions, so "one schedule" is not expressible as a grant revoke without switching
160
+ * off its siblings too. And a per-permission revoke is worse than none: the gate would
161
+ * stay open on the module's other live grant, and the schedule's own `ctx.check` would
162
+ * then fail it on every pass — noise in place of silence.
163
+ *
164
+ * `reason` is required and lands in the admin log beside the actor, because "who turned
165
+ * a tenant's schedules off, and why" is the question the log exists to answer — a
166
+ * switch pulled in an incident has no other record of what the incident was.
167
+ *
168
+ * The scope is required: the switch is per scope. A tenant-wide form would be a
169
+ * different decision about blast radius, and it is not this one.
170
+ */
171
+ export const systemSwitch = z.object({
172
+ moduleId,
173
+ node: z.object({ tenantId, scopeId }),
174
+ reason: z.string().trim().min(1).max(500),
175
+ });
176
+ /**
177
+ * What the far end of the switch did in the scope's own storage (#1666) — the wire
178
+ * shape `/internal/system-switch` answers with, and what a local host computes itself.
179
+ *
180
+ * `held: false` means the scope holds no `system:<module>` grant and no switch marker
181
+ * for that module at all — a typo'd module id, or a module this scope never ran. Nothing
182
+ * was written. It is an answer, not an error, so that a deployment which predates the
183
+ * route (and answers 404) can never be mistaken for one that simply held nothing.
184
+ */
185
+ export const systemSwitchOutcome = z.object({
186
+ held: z.boolean(),
187
+ /** False on a repeat — the switch was already in that position (idempotent). */
188
+ changed: z.boolean(),
189
+ /** The grants this call tombstoned (off) or restored (on), by permission key. */
190
+ permissions: z.array(permissionKey),
191
+ });
192
+ /**
193
+ * What `revokeFromSystem` / `restoreToSystem` answer (#1666) — the position the switch is now
194
+ * in. `operationId` names this call's rows on the admin log (its intent, then its outcome),
195
+ * so an operator can tie what the route answered to what the log recorded.
196
+ */
197
+ export const systemSwitchResult = z.object({
198
+ operationId: z.string().min(1),
199
+ moduleId,
200
+ schedules: z.enum(['on', 'off']),
201
+ changed: z.boolean(),
202
+ permissions: z.array(permissionKey),
203
+ });
144
204
  // ============================================================================
145
205
  // Evaluation representation — relationship tuples (design doc §4.2, plan D-23).
146
206
  // Internal to the checker; verticals never author these. The fixed derivation