@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.
- package/dist/attachment-extractor.d.ts +188 -0
- package/dist/attachment-extractor.d.ts.map +1 -0
- package/dist/attachment-extractor.js +243 -0
- package/dist/attachment-extractor.js.map +1 -0
- package/dist/attachment-text.d.ts +283 -0
- package/dist/attachment-text.d.ts.map +1 -0
- package/dist/attachment-text.js +497 -0
- package/dist/attachment-text.js.map +1 -0
- package/dist/capability.d.ts +34 -1
- package/dist/capability.d.ts.map +1 -1
- package/dist/capability.js +62 -16
- package/dist/capability.js.map +1 -1
- package/dist/idempotency.d.ts +4 -3
- package/dist/idempotency.d.ts.map +1 -1
- package/dist/idempotency.js +15 -7
- package/dist/idempotency.js.map +1 -1
- package/dist/index.d.ts +12 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -4
- package/dist/index.js.map +1 -1
- package/dist/job-run.d.ts.map +1 -1
- package/dist/job-run.js +3 -2
- package/dist/job-run.js.map +1 -1
- package/dist/lifecycle-flow.d.ts +6 -1
- package/dist/lifecycle-flow.d.ts.map +1 -1
- package/dist/lifecycle-flow.js +1 -1
- package/dist/lifecycle-flow.js.map +1 -1
- package/dist/list-index.d.ts +2 -1
- package/dist/list-index.d.ts.map +1 -1
- package/dist/list-index.js +9 -0
- package/dist/list-index.js.map +1 -1
- package/dist/platform-sweep.d.ts +9 -21
- package/dist/platform-sweep.d.ts.map +1 -1
- package/dist/platform-sweep.js +30 -1
- package/dist/platform-sweep.js.map +1 -1
- package/dist/refusal-query.d.ts +42 -0
- package/dist/refusal-query.d.ts.map +1 -0
- package/dist/refusal-query.js +79 -0
- package/dist/refusal-query.js.map +1 -0
- package/dist/scope-host.d.ts +167 -2
- package/dist/scope-host.d.ts.map +1 -1
- package/dist/scope-host.js +120 -1
- package/dist/scope-host.js.map +1 -1
- package/dist/search-index.d.ts +7 -0
- package/dist/search-index.d.ts.map +1 -1
- package/dist/search-index.js +7 -0
- package/dist/search-index.js.map +1 -1
- package/dist/subject-redaction.d.ts +151 -6
- package/dist/subject-redaction.d.ts.map +1 -1
- package/dist/subject-redaction.js +212 -8
- package/dist/subject-redaction.js.map +1 -1
- package/dist/timeline.d.ts +65 -1
- package/dist/timeline.d.ts.map +1 -1
- package/dist/timeline.js +136 -1
- package/dist/timeline.js.map +1 -1
- 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.
|
|
30
|
-
*
|
|
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
|
|
125
|
-
* because that host never looked at the job tables
|
|
126
|
-
*
|
|
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
|
|
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.
|
|
30
|
-
*
|
|
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
|
-
|
|
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
|
-
|
|
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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"}
|
package/dist/timeline.d.ts
CHANGED
|
@@ -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?"
|
package/dist/timeline.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timeline.d.ts","sourceRoot":"","sources":["../src/timeline.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
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"}
|