@substrat-run/kernel 0.132.1 → 0.134.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 +180 -0
- package/dist/attachment-extractor.d.ts.map +1 -0
- package/dist/attachment-extractor.js +230 -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/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 +8 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/job-run.d.ts +8 -2
- package/dist/job-run.d.ts.map +1 -1
- package/dist/job-run.js +16 -4
- package/dist/job-run.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/scope-host.d.ts +94 -1
- package/dist/scope-host.d.ts.map +1 -1
- package/dist/scope-host.js +75 -1
- package/dist/scope-host.js.map +1 -1
- package/dist/scope-tuple-seat.d.ts +7 -2
- package/dist/scope-tuple-seat.d.ts.map +1 -1
- package/dist/scope-tuple-seat.js +14 -5
- package/dist/scope-tuple-seat.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 +157 -22
- package/dist/subject-redaction.d.ts.map +1 -1
- package/dist/subject-redaction.js +250 -26
- package/dist/subject-redaction.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
|
*
|
|
@@ -218,7 +257,7 @@ export declare const REDACTED_JOB_NOTE = "redacted by subject erasure (#37) \u20
|
|
|
218
257
|
* handed the tombstone AS its input — a step's memo is returned to the handler without
|
|
219
258
|
* running anything — and walk on from nonsense. `failed` is what the run now is.
|
|
220
259
|
*/
|
|
221
|
-
export declare const CANCELLED_JOB_NOTE = "stopped by subject erasure (#37) \u2014 this run held
|
|
260
|
+
export declare const CANCELLED_JOB_NOTE = "stopped by subject erasure (#37) \u2014 this run held an erased subject's data, so it cannot resume from it";
|
|
222
261
|
/**
|
|
223
262
|
* How the job-run half talks to a scope database — one shape both adapters can satisfy
|
|
224
263
|
* in a line (`db.prepare(sql)` / `this.sql.exec(sql, …)`), so the reads, the predicate
|
|
@@ -228,21 +267,11 @@ export type RedactionSql = (sql: string, params: readonly (string | number | nul
|
|
|
228
267
|
/**
|
|
229
268
|
* The job-run half of an erasure (#1632), shared by both adapters.
|
|
230
269
|
*
|
|
231
|
-
*
|
|
232
|
-
*
|
|
233
|
-
*
|
|
234
|
-
*
|
|
235
|
-
*
|
|
236
|
-
* copy is redacted exactly when the erasure redacts the event it copies. The candidate
|
|
237
|
-
* reads use `instr` over the text, as the intent read does; `intentPayloadCarriesSubject`
|
|
238
|
-
* decides.
|
|
239
|
-
*
|
|
240
|
-
* **What it therefore does NOT reach** is external output naming the person with no
|
|
241
|
-
* classified envelope around it — a step that returns a provider's contact record, a
|
|
242
|
-
* `last_error` quoting a name. There is nothing in such a row that says whose it is, and a
|
|
243
|
-
* substring match on the id would both erase on coincidence and miss the name itself.
|
|
244
|
-
* kernel-design.md §13.1 limit 8 states it; a declared subject on the run is the open
|
|
245
|
-
* design that would close it (#1632).
|
|
270
|
+
* A declared `subject_id` identifies the whole run: all payload, cursor, step output,
|
|
271
|
+
* and error text is redacted, even when it contains no classified event envelope.
|
|
272
|
+
* Legacy and unclassified runs retain #1600's embedded-envelope predicate. Free text
|
|
273
|
+
* without either link remains unreachable; matching a name or id substring is not a
|
|
274
|
+
* reliable declaration of whose data a run handles.
|
|
246
275
|
*
|
|
247
276
|
* Per column, for a matching run: `payload` and `cursor` become the tombstone where THEY
|
|
248
277
|
* match (the payload is `NOT NULL`, the cursor may be `NULL` and stays so), `last_error`
|
|
@@ -270,4 +299,110 @@ export declare const JOB_STEP_REDACTION_SQL = "UPDATE _substrat_job_steps\n
|
|
|
270
299
|
* redacted-note, at (ended_at), at (updated_at), id.
|
|
271
300
|
*/
|
|
272
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;
|
|
273
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":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAIH;;;;;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;IAChB;;;;OAIG;IACH,kBAAkB,EAAE,MAAM,CAAC;IAC3B;;;;;OAKG;IACH,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED;;;;;GAKG;AACH,MAAM,MAAM,4BAA4B,GAAG,IAAI,CAC7C,sBAAsB,EACtB,SAAS,GAAG,oBAAoB,GAAG,WAAW,CAC/C,GAAG;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAWzB;;;;;;;;;;;;GAYG;AACH,wBAAgB,6BAA6B,CAAC,SAAS,EAAE,MAAM,GAAG;IAChE,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAKA;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;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAW1D;AAkBD;;;;;;;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,CAqE7F;AAWD;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,sGAEF,CAAC;AAElC;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,+dAQlB,CAAC;AAIjB;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,gHACwE,CAAC;AAE3G;;;;;;;;;;;;;GAaG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAiBjG;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,CAIhF;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,YAAY,EACjB,SAAS,EAAE,MAAM,EACjB,EAAE,EAAE,MAAM,GACT,IAAI,CAAC,sBAAsB,EAAE,oBAAoB,GAAG,WAAW,CAAC,CAIlE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,4BAA4B,CAAC,GAAG,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CA6BvF;AAID;;;GAGG;AACH,wBAAgB,4BAA4B,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAEnF;AAED,sGAAsG;AACtG,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAKvE;AAED,qGAAqG;AACrG,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED;;;;;;;;;GASG;AACH,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,UAAU,CAAC;AAEvD,oFAAoF;AACpF,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,kBAAkB,CAE9E;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,iCAAiC,q2BAWkB,CAAC;AAEjE;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,YAAY,EAAE,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAyC7F"}
|
|
@@ -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);
|
|
@@ -262,25 +271,15 @@ export const REDACTED_JOB_NOTE = 'redacted by subject erasure (#37) — what thi
|
|
|
262
271
|
* handed the tombstone AS its input — a step's memo is returned to the handler without
|
|
263
272
|
* running anything — and walk on from nonsense. `failed` is what the run now is.
|
|
264
273
|
*/
|
|
265
|
-
export const CANCELLED_JOB_NOTE = 'stopped by subject erasure (#37) — this run held
|
|
274
|
+
export const CANCELLED_JOB_NOTE = 'stopped by subject erasure (#37) — this run held an erased subject\'s data, so it cannot resume from it';
|
|
266
275
|
/**
|
|
267
276
|
* The job-run half of an erasure (#1632), shared by both adapters.
|
|
268
277
|
*
|
|
269
|
-
*
|
|
270
|
-
*
|
|
271
|
-
*
|
|
272
|
-
*
|
|
273
|
-
*
|
|
274
|
-
* copy is redacted exactly when the erasure redacts the event it copies. The candidate
|
|
275
|
-
* reads use `instr` over the text, as the intent read does; `intentPayloadCarriesSubject`
|
|
276
|
-
* decides.
|
|
277
|
-
*
|
|
278
|
-
* **What it therefore does NOT reach** is external output naming the person with no
|
|
279
|
-
* classified envelope around it — a step that returns a provider's contact record, a
|
|
280
|
-
* `last_error` quoting a name. There is nothing in such a row that says whose it is, and a
|
|
281
|
-
* substring match on the id would both erase on coincidence and miss the name itself.
|
|
282
|
-
* kernel-design.md §13.1 limit 8 states it; a declared subject on the run is the open
|
|
283
|
-
* design that would close it (#1632).
|
|
278
|
+
* A declared `subject_id` identifies the whole run: all payload, cursor, step output,
|
|
279
|
+
* and error text is redacted, even when it contains no classified event envelope.
|
|
280
|
+
* Legacy and unclassified runs retain #1600's embedded-envelope predicate. Free text
|
|
281
|
+
* without either link remains unreachable; matching a name or id substring is not a
|
|
282
|
+
* reliable declaration of whose data a run handles.
|
|
284
283
|
*
|
|
285
284
|
* Per column, for a matching run: `payload` and `cursor` become the tombstone where THEY
|
|
286
285
|
* match (the payload is `NOT NULL`, the cursor may be `NULL` and stays so), `last_error`
|
|
@@ -292,10 +291,29 @@ export const CANCELLED_JOB_NOTE = 'stopped by subject erasure (#37) — this run
|
|
|
292
291
|
* Returns the number of distinct runs touched.
|
|
293
292
|
*/
|
|
294
293
|
export function redactSubjectJobRuns(sql, subjectId, at) {
|
|
295
|
-
|
|
296
|
-
const needle = JSON.stringify(subjectId).slice(1, -1);
|
|
294
|
+
const needle = subjectNeedle(subjectId);
|
|
297
295
|
const tombstone = redactedIntentPayload(subjectId, at);
|
|
298
296
|
const runs = new Set();
|
|
297
|
+
const hits = new Map();
|
|
298
|
+
const declared = sql('SELECT id, payload, cursor, status, last_error FROM _substrat_job_runs WHERE subject_id = ?', [subjectId]);
|
|
299
|
+
for (const r of declared) {
|
|
300
|
+
// Older envelope-only erasure may have tombstoned just the payload. Verify every
|
|
301
|
+
// owned field before calling this complete; a terminal note is not a receipt.
|
|
302
|
+
if (r.status !== 'running' && isRedactedPayloadText(r.payload, subjectId) &&
|
|
303
|
+
(r.cursor === null || isRedactedPayloadText(r.cursor, subjectId)) &&
|
|
304
|
+
(r.last_error === CANCELLED_JOB_NOTE || r.last_error === REDACTED_JOB_NOTE)) {
|
|
305
|
+
const memos = sql('SELECT result, last_error FROM _substrat_job_steps WHERE run_id = ?', [r.id]);
|
|
306
|
+
if (memos.every((memo) => (memo.result === null || isRedactedPayloadText(memo.result, subjectId)) &&
|
|
307
|
+
(memo.last_error === null || memo.last_error === REDACTED_JOB_NOTE)))
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
sql(`UPDATE _substrat_job_steps
|
|
311
|
+
SET result = CASE WHEN result IS NULL THEN NULL ELSE ? END,
|
|
312
|
+
last_error = CASE WHEN last_error IS NULL THEN NULL ELSE ? END
|
|
313
|
+
WHERE run_id = ?`, [tombstone, REDACTED_JOB_NOTE, r.id]);
|
|
314
|
+
hits.set(r.id, { payload: true, cursor: r.cursor !== null });
|
|
315
|
+
runs.add(r.id);
|
|
316
|
+
}
|
|
299
317
|
const steps = sql('SELECT run_id, step, result FROM _substrat_job_steps WHERE instr(result, ?) > 0', [needle]);
|
|
300
318
|
for (const s of steps) {
|
|
301
319
|
if (!intentPayloadCarriesSubject(s.result, subjectId))
|
|
@@ -305,11 +323,10 @@ export function redactSubjectJobRuns(sql, subjectId, at) {
|
|
|
305
323
|
}
|
|
306
324
|
const candidates = sql(`SELECT id, payload, cursor FROM _substrat_job_runs
|
|
307
325
|
WHERE instr(payload, ?) > 0 OR instr(cursor, ?) > 0`, [needle, needle]);
|
|
308
|
-
const hits = new Map();
|
|
309
326
|
for (const r of candidates) {
|
|
310
327
|
const payload = intentPayloadCarriesSubject(r.payload, subjectId);
|
|
311
328
|
const cursor = r.cursor !== null && intentPayloadCarriesSubject(r.cursor, subjectId);
|
|
312
|
-
if (payload || cursor)
|
|
329
|
+
if ((payload || cursor) && !hits.has(r.id))
|
|
313
330
|
hits.set(r.id, { payload, cursor });
|
|
314
331
|
}
|
|
315
332
|
// A run reached only through a step is still rewritten: its note and its status are
|
|
@@ -333,6 +350,17 @@ export function redactSubjectJobRuns(sql, subjectId, at) {
|
|
|
333
350
|
}
|
|
334
351
|
return runs.size;
|
|
335
352
|
}
|
|
353
|
+
/** Recognise a previous complete payload tombstone without relying on its timestamp. */
|
|
354
|
+
function isRedactedPayloadText(text, subjectId) {
|
|
355
|
+
try {
|
|
356
|
+
const parsed = JSON.parse(text);
|
|
357
|
+
return isRedactedPayload(parsed) &&
|
|
358
|
+
parsed[REDACTED_INTENT_MARKER]['subjectId'] === subjectId;
|
|
359
|
+
}
|
|
360
|
+
catch {
|
|
361
|
+
return false;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
336
364
|
/**
|
|
337
365
|
* One matched step: its result becomes the tombstone, its error the note.
|
|
338
366
|
*
|
|
@@ -359,4 +387,200 @@ export const JOB_RUN_REDACTION_SQL = `UPDATE _substrat_job_runs
|
|
|
359
387
|
updated_at = ?,
|
|
360
388
|
status = CASE WHEN status = 'running' THEN 'failed' ELSE status END
|
|
361
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
|
+
}
|
|
362
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@substrat-run/kernel",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.134.0",
|
|
4
4
|
"description": "Substrat kernel contracts and services — pure TypeScript, no platform imports (D-14)",
|
|
5
5
|
"license": "AGPL-3.0-only",
|
|
6
6
|
"repository": {
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"dist"
|
|
23
23
|
],
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@substrat-run/contracts": "^0.
|
|
25
|
+
"@substrat-run/contracts": "^0.134.0"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"@types/node": "^22.20.4",
|