@substrat-run/kernel 0.133.0 → 0.135.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.
Files changed (56) hide show
  1. package/dist/attachment-extractor.d.ts +188 -0
  2. package/dist/attachment-extractor.d.ts.map +1 -0
  3. package/dist/attachment-extractor.js +243 -0
  4. package/dist/attachment-extractor.js.map +1 -0
  5. package/dist/attachment-text.d.ts +283 -0
  6. package/dist/attachment-text.d.ts.map +1 -0
  7. package/dist/attachment-text.js +497 -0
  8. package/dist/attachment-text.js.map +1 -0
  9. package/dist/capability.d.ts +34 -1
  10. package/dist/capability.d.ts.map +1 -1
  11. package/dist/capability.js +62 -16
  12. package/dist/capability.js.map +1 -1
  13. package/dist/idempotency.d.ts +4 -3
  14. package/dist/idempotency.d.ts.map +1 -1
  15. package/dist/idempotency.js +15 -7
  16. package/dist/idempotency.js.map +1 -1
  17. package/dist/index.d.ts +12 -6
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +7 -4
  20. package/dist/index.js.map +1 -1
  21. package/dist/job-run.d.ts.map +1 -1
  22. package/dist/job-run.js +3 -2
  23. package/dist/job-run.js.map +1 -1
  24. package/dist/lifecycle-flow.d.ts +6 -1
  25. package/dist/lifecycle-flow.d.ts.map +1 -1
  26. package/dist/lifecycle-flow.js +1 -1
  27. package/dist/lifecycle-flow.js.map +1 -1
  28. package/dist/list-index.d.ts +2 -1
  29. package/dist/list-index.d.ts.map +1 -1
  30. package/dist/list-index.js +9 -0
  31. package/dist/list-index.js.map +1 -1
  32. package/dist/platform-sweep.d.ts +9 -21
  33. package/dist/platform-sweep.d.ts.map +1 -1
  34. package/dist/platform-sweep.js +30 -1
  35. package/dist/platform-sweep.js.map +1 -1
  36. package/dist/refusal-query.d.ts +42 -0
  37. package/dist/refusal-query.d.ts.map +1 -0
  38. package/dist/refusal-query.js +79 -0
  39. package/dist/refusal-query.js.map +1 -0
  40. package/dist/scope-host.d.ts +167 -2
  41. package/dist/scope-host.d.ts.map +1 -1
  42. package/dist/scope-host.js +120 -1
  43. package/dist/scope-host.js.map +1 -1
  44. package/dist/search-index.d.ts +7 -0
  45. package/dist/search-index.d.ts.map +1 -1
  46. package/dist/search-index.js +7 -0
  47. package/dist/search-index.js.map +1 -1
  48. package/dist/subject-redaction.d.ts +151 -6
  49. package/dist/subject-redaction.d.ts.map +1 -1
  50. package/dist/subject-redaction.js +212 -8
  51. package/dist/subject-redaction.js.map +1 -1
  52. package/dist/timeline.d.ts +65 -1
  53. package/dist/timeline.d.ts.map +1 -1
  54. package/dist/timeline.js +136 -1
  55. package/dist/timeline.js.map +1 -1
  56. package/package.json +2 -2
@@ -26,8 +26,10 @@
26
26
  *
27
27
  * What it therefore does NOT reach is an intent kind that carries a subject's PII
28
28
  * WITHOUT carrying the classified event — an intent payload has no `piiClass` of its
29
- * own, so the kernel has nothing to read. No kind does that today (kernel-design.md
30
- * §13.1 limit 7 says so and names the walk), and a kind that started to would be
29
+ * own, so the kernel has nothing to read. One shipped kind can: a `sweep-runs` entry's
30
+ * `error` is a scheduled operation's throw, and that text gets its own walk on the subject's
31
+ * id (`redactSubjectSweepRunIntents`, at the end of this file). Any other kind is limit 7 in
32
+ * kernel-design.md §13.1, and a kind that started carrying a person directly would be
31
33
  * inventing an unclassified PII store inside the spine.
32
34
  *
33
35
  * This is a kernel module rather than two copies of the same SQL for
@@ -119,13 +121,29 @@ export interface SubjectRedactionCounts {
119
121
  * a count of rewritten cells would read larger than anything a DSAR answer could say.
120
122
  */
121
123
  jobRuns: number;
124
+ /**
125
+ * Recorded idempotent responses (#1632) that named the subject and now hold the tombstone.
126
+ * Not on the receipt — a cached reply is not another copy of an event — but answered, so a
127
+ * coordinator can tell a host that looked from one that never did.
128
+ */
129
+ idempotencyResults: number;
130
+ /**
131
+ * Every intent in the journal holding this subject's tombstone after the pass, whether this
132
+ * pass or an earlier one wrote it. The directory half needs them (`redactSubjectDirectoryText`):
133
+ * a drain failure about one of these intents quotes its `last_error`. All of them rather than
134
+ * the new ones, so an erasure that crashed between the two halves converges on its re-run.
135
+ */
136
+ intentIds: string[];
122
137
  }
123
138
  /**
124
- * What a ScopeDO from after #1600 and before #1632 answers — the job-run count absent,
125
- * because that host never looked at the job tables. The coordinator refuses it rather than
126
- * reading the absence as zero (see `redactSubject`'s callers).
139
+ * What an older ScopeDO answers. One from after #1600 and before #1632 has no job-run count,
140
+ * because that host never looked at the job tables; one from before the free-text half has
141
+ * the count but no `idempotencyResults` or `intentIds`. The coordinator refuses both rather
142
+ * than reading an absence as zero (see `redactSubject`'s callers).
127
143
  */
128
- export type LegacySubjectRedactionCounts = Omit<SubjectRedactionCounts, 'jobRuns'>;
144
+ export type LegacySubjectRedactionCounts = Omit<SubjectRedactionCounts, 'jobRuns' | 'idempotencyResults' | 'intentIds'> & {
145
+ jobRuns?: number;
146
+ };
129
147
  /**
130
148
  * The candidate read: every intent whose stored payload TEXT contains the subject id.
131
149
  *
@@ -183,6 +201,27 @@ export declare function platformRequestRedactionParams(id: string, subjectId: st
183
201
  * a meaning for.
184
202
  */
185
203
  export declare function intentPayloadCarriesSubject(payloadText: string, subjectId: string): boolean;
204
+ /**
205
+ * Is this payload one we already redacted?
206
+ *
207
+ * **Asked of the WHOLE payload, once, and never inside the walk (#1600 review).** The
208
+ * first cut short-circuited the walk at any object carrying the marker key, which made
209
+ * `{ _substratRedacted: false, event: <a real envelope> }` a payload the erasure stepped
210
+ * straight past, PII and all — and the comment beside it claimed the check was redundant
211
+ * belt-and-braces because a tombstone has no `piiClass`. That was true of the tombstone
212
+ * and false of everything else wearing its key. An intent payload is `unknown` and module
213
+ * code chooses it, so a marker that means "stop looking" must not be something a payload
214
+ * can merely CONTAIN.
215
+ *
216
+ * The invariant asked instead is un-forgeable in the only way that matters: *a payload
217
+ * that is nothing but a redaction tombstone is already redacted*. One top-level key, and
218
+ * that key's value says why. Anything beside the marker is not this, gets walked, and is
219
+ * judged on its own contents — which is exactly right, because something beside the
220
+ * marker is something the erasure might need to reach. Inner fields beyond `reason` are
221
+ * deliberately not pinned: a later tombstone that carries more would still be nothing but
222
+ * a tombstone, and hard-coding its shape here is how idempotency would quietly regress.
223
+ */
224
+ export declare function isRedactedPayload(parsed: unknown): boolean;
186
225
  /**
187
226
  * The note a redaction leaves on a delivery of a redacted event that had failed.
188
227
  *
@@ -260,4 +299,110 @@ export declare const JOB_STEP_REDACTION_SQL = "UPDATE _substrat_job_steps\n
260
299
  * redacted-note, at (ended_at), at (updated_at), id.
261
300
  */
262
301
  export declare const JOB_RUN_REDACTION_SQL = "UPDATE _substrat_job_runs\n SET payload = CASE WHEN ? = 1 THEN ? ELSE payload END,\n cursor = CASE WHEN ? = 1 THEN ? ELSE cursor END,\n last_error = CASE WHEN status = 'running' THEN ? ELSE ? END,\n next_attempt_at = CASE WHEN status = 'running' THEN NULL ELSE next_attempt_at END,\n ended_at = COALESCE(ended_at, ?),\n updated_at = ?,\n status = CASE WHEN status = 'running' THEN 'failed' ELSE status END\n WHERE id = ?";
302
+ /**
303
+ * The note a redaction leaves where a failure's text named the subject: an ops-failure
304
+ * message, an issue's exemplar, a sweep record's error, or that error still queued inside a
305
+ * `sweep-runs` intent. One note for all four, because the drain lands the last into the third
306
+ * and a reader should meet the same sentence wherever the redaction found the text.
307
+ */
308
+ export declare const REDACTED_FAILURE_NOTE = "redacted by subject erasure (#37) \u2014 what this failure said is gone; that it happened, and when, is not";
309
+ /**
310
+ * The idempotency ledger's half (#1632): a recorded response that names the subject.
311
+ *
312
+ * `result` is an operation's return value, kept for a day so a retry is answered without
313
+ * running again — and an operation that returns a person's record returns their id with it.
314
+ * Nothing else in the row says whose response it is, so the link is the direct one: the
315
+ * subject's id appears in the stored JSON. A `DataSubjectId` is a ULID, so the match does not
316
+ * happen by coincidence. A response that names the person but not their id is not reached.
317
+ *
318
+ * The result becomes the intent tombstone; every other column stays, so the key is still
319
+ * recorded and a retry is still not executed twice. `replayFor` refuses a tombstoned result
320
+ * instead of replaying it. Idempotent: a row already holding this subject's tombstone is
321
+ * skipped. Returns how many rows it rewrote.
322
+ */
323
+ export declare function redactSubjectIdempotency(sql: RedactionSql, subjectId: string, at: string): number;
324
+ /**
325
+ * Every intent in the journal that holds this subject's tombstone — the ids the directory
326
+ * half links its drain-failure rows through. Read after the intent redaction, so it covers
327
+ * this pass's tombstones and every earlier pass's.
328
+ */
329
+ export declare function redactedIntentIds(sql: RedactionSql, subjectId: string): string[];
330
+ /**
331
+ * The scope's free-text half (#1632), shared by both adapters so the order is one fact: a
332
+ * recorded idempotent response and a queued `sweep-runs` entry's error that name the subject,
333
+ * and THEN the intents holding its tombstone — read after every other intent write, so the ids
334
+ * cover this pass's tombstones and every earlier one's.
335
+ */
336
+ export declare function redactSubjectScopeText(sql: RedactionSql, subjectId: string, at: string): Pick<SubjectRedactionCounts, 'idempotencyResults' | 'intentIds'>;
337
+ /**
338
+ * A `sweep-runs` intent's queued error text (#1632).
339
+ *
340
+ * A CP-less pass reports its schedule outcomes as one `sweep-runs` intent; the drain lands
341
+ * each entry in the directory's `_substrat_sweep_runs`, and the intent itself is kept like
342
+ * every other. So an entry's `error` — a scheduled operation's throw — is held twice, and the
343
+ * directory half alone would leave this copy. Only `entries[].error` is rewritten, and only
344
+ * where it names the subject's id: the payload keeps its shape and every other field, so a
345
+ * pending intent still drains (the note is a valid `error`) and lands the note instead of the
346
+ * text. Idempotent: the note does not name the subject.
347
+ */
348
+ export declare function redactSubjectSweepRunIntents(sql: RedactionSql, subjectId: string): void;
349
+ /**
350
+ * How the drain words an ops failure about one intent. The reader below parses the same
351
+ * prefix, so the directory walk and the writer cannot drift about the link between them.
352
+ */
353
+ export declare function platformIntentFailureMessage(intentId: string, text: string): string;
354
+ /** The intent an ops-failure message is about, or null — `platformIntentFailureMessage` read back. */
355
+ export declare function intentIdOfFailureMessage(message: string): string | null;
356
+ /** What the directory half is handed: the erased scope's tenant, and the scope half's intent ids. */
357
+ export interface SubjectTextTarget {
358
+ tenantId: string;
359
+ scopeId: string;
360
+ subjectId: string;
361
+ intentIds: string[];
362
+ }
363
+ /**
364
+ * Whose failure an issue exemplar was copied from, as the issue upsert records it beside
365
+ * `last_tenant_id`: a tenant's, or the platform's own (a failure with no tenant). NULL is never
366
+ * written. It is reserved for an issue from before the columns that no retained row attributes,
367
+ * so "the platform's" and "nobody knows" stay different facts.
368
+ *
369
+ * A kind column rather than a sentinel in `last_tenant_id`, so that column stays what its name
370
+ * says — a tenant id or nothing — for any reader or join, and a later owner kind is a new value
371
+ * here instead of a second magic string.
372
+ */
373
+ export type IssueExemplarOwner = 'tenant' | 'platform';
374
+ /** The owner kind both adapters' issue upserts write, from the failure's tenant. */
375
+ export declare function issueExemplarOwner(tenantId: string | null): IssueExemplarOwner;
376
+ /**
377
+ * #1632: the one-time backfill of an issue's exemplar owner, run as the columns are added to
378
+ * a directory that predates them. A row is attributed only when the retained ops-failure rows
379
+ * carrying its exemplar (same fingerprint, same text) all have one origin: a single tenant, or
380
+ * only the platform. When they name none, or more than one origin, the row stays unknown
381
+ * (NULL), and erasure skips it. Rows whose evidence already expired stay unknown too, so the
382
+ * gap fails closed.
383
+ */
384
+ export declare const ISSUE_EXEMPLAR_OWNER_BACKFILL_SQL = "UPDATE _substrat_issues\n SET last_tenant_id = (SELECT MIN(o.tenant_id) FROM _substrat_ops_failures o\n WHERE o.fingerprint = _substrat_issues.fingerprint\n AND o.message = _substrat_issues.last_message),\n last_owner_kind = CASE WHEN (SELECT MIN(o.tenant_id) FROM _substrat_ops_failures o\n WHERE o.fingerprint = _substrat_issues.fingerprint\n AND o.message = _substrat_issues.last_message) IS NULL\n THEN 'platform' ELSE 'tenant' END\n WHERE last_owner_kind IS NULL\n AND (SELECT COUNT(DISTINCT COALESCE(o.tenant_id, '')) FROM _substrat_ops_failures o\n WHERE o.fingerprint = _substrat_issues.fingerprint\n AND o.message = _substrat_issues.last_message) = 1";
385
+ /**
386
+ * The directory's half (#1632): three tables of failure text the control plane keeps.
387
+ *
388
+ * - `_substrat_ops_failures.message` — the drain's record of an intent it gave up on, or
389
+ * settled `failed`, quotes that intent's `last_error`. When the intent is one the erasure
390
+ * tombstoned (`intentIds`, in this tenant and scope), the message is a copy of text the
391
+ * scope half already redacted, and goes with it. A row in this tenant, or the platform's
392
+ * own row with no tenant, that names the subject's id goes too.
393
+ * - `_substrat_issues.last_message` — the newest exemplar of an ops-failure group. Its
394
+ * writer records whose failure it copied (`last_owner_kind`, `last_tenant_id`, in the same
395
+ * statement), and erasure reads that rather than the ops-failure rows, which issues outlive.
396
+ * A tenant's exemplar is rewritten only for that tenant, by the same two links; the
397
+ * platform's own on a direct id match, as its ops-failure row is. An exemplar of unknown
398
+ * owner (a legacy row nothing attributed) is skipped: the matched text can come from
399
+ * anyone's request, so an unattributed row is never read as this tenant's.
400
+ * - `_substrat_sweep_runs.error` — a scheduled operation's throw, matched on the subject's
401
+ * id in this tenant's rows or the platform's own. There is no link to an event here.
402
+ *
403
+ * Rows for another tenant are never touched. Free text that names the person but not their
404
+ * id, on a row with no intent link, is not reached. Idempotent: the note names neither an
405
+ * intent nor the subject.
406
+ */
407
+ export declare function redactSubjectDirectoryText(sql: RedactionSql, target: SubjectTextTarget): void;
263
408
  //# sourceMappingURL=subject-redaction.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"subject-redaction.d.ts","sourceRoot":"","sources":["../src/subject-redaction.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,sBAAsB,CAAC;AAE1D;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAI3E;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,oBAAoB,+GACwE,CAAC;AAE1G;;;;;;;;;GASG;AACH,eAAO,MAAM,qBAAqB,6HACqF,CAAC;AAExH,mDAAmD;AACnD,MAAM,WAAW,iCAAiC;IAChD,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;OAKG;IACH,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,MAAM,MAAM,4BAA4B,GAAG,IAAI,CAAC,sBAAsB,EAAE,SAAS,CAAC,CAAC;AAEnF;;;;;;;;;;;;GAYG;AACH,wBAAgB,6BAA6B,CAAC,SAAS,EAAE,MAAM,GAAG;IAChE,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAOA;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,8BAA8B,qXAO3B,CAAC;AAEjB,wFAAwF;AACxF,wBAAgB,8BAA8B,CAC5C,EAAE,EAAE,MAAM,EACV,SAAS,EAAE,MAAM,EACjB,EAAE,EAAE,MAAM,GACT,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAGlD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,2BAA2B,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAS3F;AAmDD;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB,mHAC0E,CAAC;AAE9G;;;;;;;;GAQG;AACH,eAAO,MAAM,4BAA4B,oMAG2D,CAAC;AAIrG;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,6HACyF,CAAC;AAExH;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,gHAC4E,CAAC;AAE5G;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC,EAAE,KAAK,OAAO,EAAE,CAAC;AAEnG;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAsE7F;AAWD;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,sGAEF,CAAC;AAElC;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,+dAQlB,CAAC"}
1
+ {"version":3,"file":"subject-redaction.d.ts","sourceRoot":"","sources":["../src/subject-redaction.ts"],"names":[],"mappings":"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"}
@@ -26,14 +26,17 @@
26
26
  *
27
27
  * What it therefore does NOT reach is an intent kind that carries a subject's PII
28
28
  * WITHOUT carrying the classified event — an intent payload has no `piiClass` of its
29
- * own, so the kernel has nothing to read. No kind does that today (kernel-design.md
30
- * §13.1 limit 7 says so and names the walk), and a kind that started to would be
29
+ * own, so the kernel has nothing to read. One shipped kind can: a `sweep-runs` entry's
30
+ * `error` is a scheduled operation's throw, and that text gets its own walk on the subject's
31
+ * id (`redactSubjectSweepRunIntents`, at the end of this file). Any other kind is limit 7 in
32
+ * kernel-design.md §13.1, and a kind that started carrying a person directly would be
31
33
  * inventing an unclassified PII store inside the spine.
32
34
  *
33
35
  * This is a kernel module rather than two copies of the same SQL for
34
36
  * `platformRequestHistoryQuery`'s reason, sharpened: three surfaces answer one question
35
37
  * from this table, and a privacy guarantee that holds on one adapter is not a guarantee.
36
38
  */
39
+ import { SWEEP_RUNS_KIND } from '@substrat-run/contracts';
37
40
  /**
38
41
  * The one key a redacted intent payload carries, and nothing else in the system does.
39
42
  *
@@ -95,6 +98,14 @@ export const REDACTED_INTENT_NOTE = 'redacted by subject erasure (#37) — what
95
98
  * routed, so nothing re-routes the event to replace this row.
96
99
  */
97
100
  export const CANCELLED_INTENT_NOTE = 'cancelled by subject erasure (#37) — the payload was redacted before the drain reached it, so this intent never ran';
101
+ /**
102
+ * The needle every walk in this file searches a stored text for: the subject id with the
103
+ * quotes JSON.stringify adds stripped, keeping the escaped body — the exact run of characters
104
+ * a serialized payload holds.
105
+ */
106
+ function subjectNeedle(subjectId) {
107
+ return JSON.stringify(subjectId).slice(1, -1);
108
+ }
98
109
  /**
99
110
  * The candidate read: every intent whose stored payload TEXT contains the subject id.
100
111
  *
@@ -111,9 +122,7 @@ export const CANCELLED_INTENT_NOTE = 'cancelled by subject erasure (#37) — the
111
122
  export function platformRequestRedactionQuery(subjectId) {
112
123
  return {
113
124
  sql: 'SELECT id, payload FROM _substrat_platform_requests WHERE instr(payload, ?) > 0',
114
- // Strip the quotes JSON.stringify adds and keep the escaped body — the exact run of
115
- // characters the serialized payload holds.
116
- params: [JSON.stringify(subjectId).slice(1, -1)],
125
+ params: [subjectNeedle(subjectId)],
117
126
  };
118
127
  }
119
128
  /**
@@ -197,7 +206,7 @@ export function intentPayloadCarriesSubject(payloadText, subjectId) {
197
206
  * deliberately not pinned: a later tombstone that carries more would still be nothing but
198
207
  * a tombstone, and hard-coding its shape here is how idempotency would quietly regress.
199
208
  */
200
- function isRedactedPayload(parsed) {
209
+ export function isRedactedPayload(parsed) {
201
210
  if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed))
202
211
  return false;
203
212
  const keys = Object.keys(parsed);
@@ -282,8 +291,7 @@ export const CANCELLED_JOB_NOTE = 'stopped by subject erasure (#37) — this run
282
291
  * Returns the number of distinct runs touched.
283
292
  */
284
293
  export function redactSubjectJobRuns(sql, subjectId, at) {
285
- // The needle, spelled as `platformRequestRedactionQuery` spells it.
286
- const needle = JSON.stringify(subjectId).slice(1, -1);
294
+ const needle = subjectNeedle(subjectId);
287
295
  const tombstone = redactedIntentPayload(subjectId, at);
288
296
  const runs = new Set();
289
297
  const hits = new Map();
@@ -379,4 +387,200 @@ export const JOB_RUN_REDACTION_SQL = `UPDATE _substrat_job_runs
379
387
  updated_at = ?,
380
388
  status = CASE WHEN status = 'running' THEN 'failed' ELSE status END
381
389
  WHERE id = ?`;
390
+ // -- the spine's free-text copies (#1632) ---------------------------------------------
391
+ /**
392
+ * The note a redaction leaves where a failure's text named the subject: an ops-failure
393
+ * message, an issue's exemplar, a sweep record's error, or that error still queued inside a
394
+ * `sweep-runs` intent. One note for all four, because the drain lands the last into the third
395
+ * and a reader should meet the same sentence wherever the redaction found the text.
396
+ */
397
+ export const REDACTED_FAILURE_NOTE = 'redacted by subject erasure (#37) — what this failure said is gone; that it happened, and when, is not';
398
+ /**
399
+ * The idempotency ledger's half (#1632): a recorded response that names the subject.
400
+ *
401
+ * `result` is an operation's return value, kept for a day so a retry is answered without
402
+ * running again — and an operation that returns a person's record returns their id with it.
403
+ * Nothing else in the row says whose response it is, so the link is the direct one: the
404
+ * subject's id appears in the stored JSON. A `DataSubjectId` is a ULID, so the match does not
405
+ * happen by coincidence. A response that names the person but not their id is not reached.
406
+ *
407
+ * The result becomes the intent tombstone; every other column stays, so the key is still
408
+ * recorded and a retry is still not executed twice. `replayFor` refuses a tombstoned result
409
+ * instead of replaying it. Idempotent: a row already holding this subject's tombstone is
410
+ * skipped. Returns how many rows it rewrote.
411
+ */
412
+ export function redactSubjectIdempotency(sql, subjectId, at) {
413
+ const rows = sql('SELECT subject, key, result FROM _substrat_idempotency WHERE instr(result, ?) > 0', [subjectNeedle(subjectId)]);
414
+ const tombstone = redactedIntentPayload(subjectId, at);
415
+ let redacted = 0;
416
+ for (const row of rows) {
417
+ if (isRedactedPayloadText(row.result, subjectId))
418
+ continue;
419
+ sql('UPDATE _substrat_idempotency SET result = ? WHERE subject = ? AND key = ?', [
420
+ tombstone,
421
+ row.subject,
422
+ row.key,
423
+ ]);
424
+ redacted += 1;
425
+ }
426
+ return redacted;
427
+ }
428
+ /**
429
+ * Every intent in the journal that holds this subject's tombstone — the ids the directory
430
+ * half links its drain-failure rows through. Read after the intent redaction, so it covers
431
+ * this pass's tombstones and every earlier pass's.
432
+ */
433
+ export function redactedIntentIds(sql, subjectId) {
434
+ const q = platformRequestRedactionQuery(subjectId);
435
+ const rows = sql(q.sql, q.params);
436
+ return rows.filter((r) => isRedactedPayloadText(r.payload, subjectId)).map((r) => r.id);
437
+ }
438
+ /**
439
+ * The scope's free-text half (#1632), shared by both adapters so the order is one fact: a
440
+ * recorded idempotent response and a queued `sweep-runs` entry's error that name the subject,
441
+ * and THEN the intents holding its tombstone — read after every other intent write, so the ids
442
+ * cover this pass's tombstones and every earlier one's.
443
+ */
444
+ export function redactSubjectScopeText(sql, subjectId, at) {
445
+ const idempotencyResults = redactSubjectIdempotency(sql, subjectId, at);
446
+ redactSubjectSweepRunIntents(sql, subjectId);
447
+ return { idempotencyResults, intentIds: redactedIntentIds(sql, subjectId) };
448
+ }
449
+ /**
450
+ * A `sweep-runs` intent's queued error text (#1632).
451
+ *
452
+ * A CP-less pass reports its schedule outcomes as one `sweep-runs` intent; the drain lands
453
+ * each entry in the directory's `_substrat_sweep_runs`, and the intent itself is kept like
454
+ * every other. So an entry's `error` — a scheduled operation's throw — is held twice, and the
455
+ * directory half alone would leave this copy. Only `entries[].error` is rewritten, and only
456
+ * where it names the subject's id: the payload keeps its shape and every other field, so a
457
+ * pending intent still drains (the note is a valid `error`) and lands the note instead of the
458
+ * text. Idempotent: the note does not name the subject.
459
+ */
460
+ export function redactSubjectSweepRunIntents(sql, subjectId) {
461
+ const rows = sql('SELECT id, payload FROM _substrat_platform_requests WHERE kind = ? AND instr(payload, ?) > 0', [SWEEP_RUNS_KIND, subjectNeedle(subjectId)]);
462
+ for (const row of rows) {
463
+ let parsed;
464
+ try {
465
+ parsed = JSON.parse(row.payload);
466
+ }
467
+ catch {
468
+ continue;
469
+ }
470
+ if (typeof parsed !== 'object' || parsed === null)
471
+ continue;
472
+ const entries = parsed.entries;
473
+ if (!Array.isArray(entries))
474
+ continue;
475
+ let changed = false;
476
+ const rewritten = entries.map((entry) => {
477
+ if (typeof entry !== 'object' || entry === null)
478
+ return entry;
479
+ const error = entry.error;
480
+ if (typeof error !== 'string' || !error.includes(subjectId))
481
+ return entry;
482
+ changed = true;
483
+ return { ...entry, error: REDACTED_FAILURE_NOTE };
484
+ });
485
+ if (!changed)
486
+ continue;
487
+ sql('UPDATE _substrat_platform_requests SET payload = ? WHERE id = ?', [
488
+ JSON.stringify({ ...parsed, entries: rewritten }),
489
+ row.id,
490
+ ]);
491
+ }
492
+ }
493
+ const PLATFORM_INTENT_FAILURE_PREFIX = 'platform intent ';
494
+ /**
495
+ * How the drain words an ops failure about one intent. The reader below parses the same
496
+ * prefix, so the directory walk and the writer cannot drift about the link between them.
497
+ */
498
+ export function platformIntentFailureMessage(intentId, text) {
499
+ return `${PLATFORM_INTENT_FAILURE_PREFIX}${intentId} ${text}`;
500
+ }
501
+ /** The intent an ops-failure message is about, or null — `platformIntentFailureMessage` read back. */
502
+ export function intentIdOfFailureMessage(message) {
503
+ if (!message.startsWith(PLATFORM_INTENT_FAILURE_PREFIX))
504
+ return null;
505
+ const rest = message.slice(PLATFORM_INTENT_FAILURE_PREFIX.length);
506
+ const end = rest.indexOf(' ');
507
+ return end > 0 ? rest.slice(0, end) : null;
508
+ }
509
+ /** The owner kind both adapters' issue upserts write, from the failure's tenant. */
510
+ export function issueExemplarOwner(tenantId) {
511
+ return tenantId === null ? 'platform' : 'tenant';
512
+ }
513
+ /**
514
+ * #1632: the one-time backfill of an issue's exemplar owner, run as the columns are added to
515
+ * a directory that predates them. A row is attributed only when the retained ops-failure rows
516
+ * carrying its exemplar (same fingerprint, same text) all have one origin: a single tenant, or
517
+ * only the platform. When they name none, or more than one origin, the row stays unknown
518
+ * (NULL), and erasure skips it. Rows whose evidence already expired stay unknown too, so the
519
+ * gap fails closed.
520
+ */
521
+ export const ISSUE_EXEMPLAR_OWNER_BACKFILL_SQL = `UPDATE _substrat_issues
522
+ SET last_tenant_id = (SELECT MIN(o.tenant_id) FROM _substrat_ops_failures o
523
+ WHERE o.fingerprint = _substrat_issues.fingerprint
524
+ AND o.message = _substrat_issues.last_message),
525
+ last_owner_kind = CASE WHEN (SELECT MIN(o.tenant_id) FROM _substrat_ops_failures o
526
+ WHERE o.fingerprint = _substrat_issues.fingerprint
527
+ AND o.message = _substrat_issues.last_message) IS NULL
528
+ THEN 'platform' ELSE 'tenant' END
529
+ WHERE last_owner_kind IS NULL
530
+ AND (SELECT COUNT(DISTINCT COALESCE(o.tenant_id, '')) FROM _substrat_ops_failures o
531
+ WHERE o.fingerprint = _substrat_issues.fingerprint
532
+ AND o.message = _substrat_issues.last_message) = 1`;
533
+ /**
534
+ * The directory's half (#1632): three tables of failure text the control plane keeps.
535
+ *
536
+ * - `_substrat_ops_failures.message` — the drain's record of an intent it gave up on, or
537
+ * settled `failed`, quotes that intent's `last_error`. When the intent is one the erasure
538
+ * tombstoned (`intentIds`, in this tenant and scope), the message is a copy of text the
539
+ * scope half already redacted, and goes with it. A row in this tenant, or the platform's
540
+ * own row with no tenant, that names the subject's id goes too.
541
+ * - `_substrat_issues.last_message` — the newest exemplar of an ops-failure group. Its
542
+ * writer records whose failure it copied (`last_owner_kind`, `last_tenant_id`, in the same
543
+ * statement), and erasure reads that rather than the ops-failure rows, which issues outlive.
544
+ * A tenant's exemplar is rewritten only for that tenant, by the same two links; the
545
+ * platform's own on a direct id match, as its ops-failure row is. An exemplar of unknown
546
+ * owner (a legacy row nothing attributed) is skipped: the matched text can come from
547
+ * anyone's request, so an unattributed row is never read as this tenant's.
548
+ * - `_substrat_sweep_runs.error` — a scheduled operation's throw, matched on the subject's
549
+ * id in this tenant's rows or the platform's own. There is no link to an event here.
550
+ *
551
+ * Rows for another tenant are never touched. Free text that names the person but not their
552
+ * id, on a row with no intent link, is not reached. Idempotent: the note names neither an
553
+ * intent nor the subject.
554
+ */
555
+ export function redactSubjectDirectoryText(sql, target) {
556
+ const needle = subjectNeedle(target.subjectId);
557
+ sql(`UPDATE _substrat_ops_failures SET message = ?
558
+ WHERE instr(message, ?) > 0 AND (tenant_id IS NULL OR tenant_id = ?)`, [REDACTED_FAILURE_NOTE, needle, target.tenantId]);
559
+ sql(`UPDATE _substrat_issues SET last_message = ?
560
+ WHERE instr(last_message, ?) > 0
561
+ AND ((last_owner_kind = 'tenant' AND last_tenant_id = ?) OR last_owner_kind = 'platform')`, [REDACTED_FAILURE_NOTE, needle, target.tenantId]);
562
+ sql(`UPDATE _substrat_sweep_runs SET error = ?
563
+ WHERE instr(error, ?) > 0 AND (tenant_id IS NULL OR tenant_id = ?)`, [REDACTED_FAILURE_NOTE, needle, target.tenantId]);
564
+ if (target.intentIds.length === 0)
565
+ return;
566
+ const intents = new Set(target.intentIds);
567
+ // Rows whose text the drain wrote about one of those intents — read back by the grammar it
568
+ // wrote them in, so the SQL only narrows to the prefix and the id decides.
569
+ const redactLinked = (table, key, text, where, params) => {
570
+ const rows = sql(`SELECT ${key} AS key, ${text} AS text FROM ${table} WHERE ${where}instr(${text}, ?) = 1`, [...params, PLATFORM_INTENT_FAILURE_PREFIX]);
571
+ for (const row of rows) {
572
+ const id = intentIdOfFailureMessage(row.text);
573
+ if (id !== null && intents.has(id)) {
574
+ sql(`UPDATE ${table} SET ${text} = ? WHERE ${key} = ?`, [REDACTED_FAILURE_NOTE, row.key]);
575
+ }
576
+ }
577
+ };
578
+ redactLinked('_substrat_ops_failures', 'id', 'message', 'tenant_id = ? AND scope_id = ? AND ', [
579
+ target.tenantId,
580
+ target.scopeId,
581
+ ]);
582
+ redactLinked('_substrat_issues', 'fingerprint', 'last_message', "last_owner_kind = 'tenant' AND last_tenant_id = ? AND ", [
583
+ target.tenantId,
584
+ ]);
585
+ }
382
586
  //# sourceMappingURL=subject-redaction.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"subject-redaction.js","sourceRoot":"","sources":["../src/subject-redaction.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"subject-redaction.js","sourceRoot":"","sources":["../src/subject-redaction.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { type EntityRef, type EventId, type HistoryEntry, type CauseChain, type EffectsTree, type InvocationEvents, type DeadLetter, type ListPage, type Page, type TimelineEntry, type EventFacetInput, type EventFacetResult } from '@substrat-run/contracts';
1
+ import { type EntityRef, type EventId, type HistoryEntry, type CauseChain, type EffectsTree, type InvocationEvents, type DeadLetter, type ListPage, type Page, type TimelineEntry, type ScopeTimelineEntry, type ScopeHistoryEntry, type EventFacetInput, type EventFacetResult } from '@substrat-run/contracts';
2
2
  import type { ScopedSql } from './scope-host.js';
3
3
  /**
4
4
  * Reading an entity's history out of the spine (#800).
@@ -98,6 +98,70 @@ export declare function readTimeline(ctx: TimelineReader, entity: EntityRef, pag
98
98
  * can disclose what an event said.
99
99
  */
100
100
  export declare function readHistory(ctx: TimelineReader, entity: EntityRef, page?: ListPage): Page<HistoryEntry>;
101
+ /**
102
+ * The page params of a scope-wide walk (#1582): a `ListPage` whose `cursor` is the
103
+ * WATERMARK, plus one optional equality filter.
104
+ *
105
+ * `entityType` narrows the walk to events about one kind of entity — what an offline
106
+ * mirror of one entity type, or a projection over it, wants. Equality only, for K-41's
107
+ * reason: a richer filter is where a page read becomes a query language. A read that
108
+ * needs more is an operation with its own name.
109
+ */
110
+ export interface ScopeWalkPage extends ListPage {
111
+ entityType?: string;
112
+ }
113
+ /**
114
+ * Everything that happened in this scope, since a watermark — the envelope only
115
+ * (#1582).
116
+ *
117
+ * `readTimeline` with the entity unpinned, and each entry carrying the `entity` it
118
+ * was about. This is the read a projection IS, and an offline mirror under another
119
+ * name: a per-scope monotonic sequence resumed from a client-held watermark.
120
+ *
121
+ * **The watermark is the `id` of the last entry you APPLIED, not `nextCursor`.**
122
+ * `nextCursor` is null on a short page, which means "caught up", and a caller that
123
+ * stored it would restart from the beginning on its next poll. Keep the last id;
124
+ * pass it back as `cursor`; the walk is exclusive, so nothing is applied twice.
125
+ *
126
+ * ## It checks nothing — and here that is most load-bearing
127
+ *
128
+ * Same posture as `readTimeline`, stated again because the stakes are higher: a
129
+ * per-entity read can be gated by a per-entity check, but THIS read returns events
130
+ * about every entity in the scope, including ones the caller may not read. So the
131
+ * caller's check must be one that justifies seeing all of them — a SCOPE-WIDE
132
+ * permission, checked first:
133
+ *
134
+ * ```ts
135
+ * assertAllowed(await ctx.check(AUDIT.read)); // no entity: the whole scope
136
+ * return readScopeTimeline(ctx, { ...input, entityType: 'workorder' });
137
+ * ```
138
+ *
139
+ * A caller who can only justify SOME entities must not use this read and filter
140
+ * afterwards without saying so: post-filtering with `ctx.check(perm, entry.entity)`
141
+ * per row is legitimate, but it changes the page size (a page of 20 can come back
142
+ * with 3) and the cursor must then advance by the last row EXAMINED, not the last
143
+ * row returned — see callout's `portal-orders` for that shape. A walk that only
144
+ * visits what the caller may read is a different read with a different cost, and
145
+ * is deliberately not this one.
146
+ */
147
+ export declare function readScopeTimeline(ctx: TimelineReader, page?: ScopeWalkPage): Page<ScopeTimelineEntry>;
148
+ /**
149
+ * Everything that happened in this scope, since a watermark — with what was said
150
+ * and under what authority (#1582).
151
+ *
152
+ * `readHistory` with the entity unpinned. Every field decodes exactly as it does
153
+ * there, through the same mapper, so the nulls keep their meanings: `payload` null
154
+ * after a shred (the row stays), `authorization` null for a row written before
155
+ * K-34, `operation` null for a consumer emit or a pre-column row, `version` from
156
+ * the outbox COLUMN and never the envelope. A hand-rolled scope walk reads every
157
+ * one of those as missing data; that is the reason this exists.
158
+ *
159
+ * Same watermark rule as `readScopeTimeline` — keep the last applied `id`, not
160
+ * `nextCursor`. Same permission posture, with the payload making it heavier still:
161
+ * this read discloses what every event in the scope SAID, so the caller's scope-wide
162
+ * check comes first, and nothing here makes it for them.
163
+ */
164
+ export declare function readScopeHistory(ctx: TimelineReader, page?: ScopeWalkPage): Page<ScopeHistoryEntry>;
101
165
  /**
102
166
  * Walk one event's causal chain backwards (#1237) — "this invoice exists; what
103
167
  * started that?"
@@ -1 +1 @@
1
- {"version":3,"file":"timeline.d.ts","sourceRoot":"","sources":["../src/timeline.ts"],"names":[],"mappings":"AAAA,OAAO,EAOL,KAAK,SAAS,EACd,KAAK,OAAO,EAEZ,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,WAAW,EAEhB,KAAK,gBAAgB,EACrB,KAAK,UAAU,EAMf,KAAK,QAAQ,EACb,KAAK,IAAI,EACT,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACtB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,KAAK,EAAE,SAAS,EAAY,MAAM,iBAAiB,CAAC;AAE3D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuDG;AAEH,oFAAoF;AACpF,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;CACxC;AAmID;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAC1B,GAAG,EAAE,cAAc,EACnB,MAAM,EAAE,SAAS,EACjB,IAAI,CAAC,EAAE,QAAQ,GACd,IAAI,CAAC,aAAa,CAAC,CAKrB;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,WAAW,CACzB,GAAG,EAAE,cAAc,EACnB,MAAM,EAAE,SAAS,EACjB,IAAI,CAAC,EAAE,QAAQ,GACd,IAAI,CAAC,YAAY,CAAC,CAKpB;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,cAAc,EACnB,OAAO,EAAE,OAAO,EAChB,QAAQ,SAAK,GACZ,UAAU,CAiEZ;AAkDD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,cAAc,EACnB,OAAO,EAAE,OAAO,EAChB,QAAQ,SAAK,GACZ,WAAW,CAoFb;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,cAAc,EACnB,YAAY,EAAE,MAAM,EACpB,KAAK,SAAM,GACV,gBAAgB,CAOlB;AA+DD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,cAAc,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,QAAQ,EAAE,OAAO,GAAG,QAAQ,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,CAwChH;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,cAAc,EAAE,KAAK,EAAE,eAAe,GAAG,gBAAgB,CA6EzF"}
1
+ {"version":3,"file":"timeline.d.ts","sourceRoot":"","sources":["../src/timeline.ts"],"names":[],"mappings":"AAAA,OAAO,EAQL,KAAK,SAAS,EACd,KAAK,OAAO,EAEZ,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,WAAW,EAEhB,KAAK,gBAAgB,EACrB,KAAK,UAAU,EAMf,KAAK,QAAQ,EACb,KAAK,IAAI,EACT,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACtB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,KAAK,EAAE,SAAS,EAAY,MAAM,iBAAiB,CAAC;AAE3D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuDG;AAEH,oFAAoF;AACpF,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;CACxC;AAmID;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAC1B,GAAG,EAAE,cAAc,EACnB,MAAM,EAAE,SAAS,EACjB,IAAI,CAAC,EAAE,QAAQ,GACd,IAAI,CAAC,aAAa,CAAC,CAKrB;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,WAAW,CACzB,GAAG,EAAE,cAAc,EACnB,MAAM,EAAE,SAAS,EACjB,IAAI,CAAC,EAAE,QAAQ,GACd,IAAI,CAAC,YAAY,CAAC,CAKpB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,aAAc,SAAQ,QAAQ;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AA4ED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,cAAc,EACnB,IAAI,CAAC,EAAE,aAAa,GACnB,IAAI,CAAC,kBAAkB,CAAC,CAS1B;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,cAAc,EACnB,IAAI,CAAC,EAAE,aAAa,GACnB,IAAI,CAAC,iBAAiB,CAAC,CAazB;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,cAAc,EACnB,OAAO,EAAE,OAAO,EAChB,QAAQ,SAAK,GACZ,UAAU,CAiEZ;AAkDD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,cAAc,EACnB,OAAO,EAAE,OAAO,EAChB,QAAQ,SAAK,GACZ,WAAW,CAoFb;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,cAAc,EACnB,YAAY,EAAE,MAAM,EACpB,KAAK,SAAM,GACV,gBAAgB,CAOlB;AA+DD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,cAAc,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,QAAQ,EAAE,OAAO,GAAG,QAAQ,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,CAwChH;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,cAAc,EAAE,KAAK,EAAE,eAAe,GAAG,gBAAgB,CA6EzF"}