@substrat-run/adapter-sqlite 0.133.0 → 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/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { type BlobStoreHandle, type ImportBatch, type ImportResult, type Coverage, type PeerCoverage, type VerticalCaller, type CapabilityExchange, type ConnectionId, type ModuleId, type DomainEvent, type PlatformRequestId, type PlatformRequest, type PlatformRequestFilter, type PlatformRequestStatus, type PlatformRequestFailure, type ProjectedConnectionGrant, type PermissionKey, type PlatformActorId, type OnBehalfOf, type PrincipalId, type ScopeDump, type ScopeId, type ImpersonationSessionId, type TenantId, type TenantStoreHandle } from '@substrat-run/contracts';
2
- import { type ModuleLogSink, type FreshnessReport, type FreshnessRegistration, type BlobStoreProvisionInput, type ScopeAttachments, type ExecutorDeadLetter, type ExecutorDrainReport, type MigrateScopeOutcome, type MigrationFrontier, type ExecutorHandler, type ExecutorRetryPolicy, type ConnectorHandler, type ConnectorOptions, type Clock, type FetchLike, type SecretBox, type HostAdmin, type ModuleRegistration, type OperationHandler, type PermissionChecker, type ProvisionScopeInput, type ScheduleRegistration, type ScheduleRunReport, type ScopeHost, type ScopeStub, type ScopeStubOptions, type TenantRelationalStore, type TenantStoreProvisionInput, type JobDriveReport, type JobHandler, type JobRun, type JobRunFilter, type StartJobRunInput, type ConnectorCallRecorder } from '@substrat-run/kernel';
2
+ import { type ModuleLogSink, type FreshnessReport, type FreshnessRegistration, type BlobStoreProvisionInput, type ScopeAttachments, type ExecutorDeadLetter, type ExecutorDrainReport, type MigrateScopeOutcome, type MigrationFrontier, type ExecutorHandler, type ExecutorRetryPolicy, type ConnectorHandler, type ConnectorOptions, type Clock, type FetchLike, type SecretBox, type HostAdmin, type ModuleRegistration, type OperationHandler, type PermissionChecker, type ProvisionScopeInput, type ScheduleRegistration, type ScheduleRunReport, type ScopeHost, type ScopeStub, type ScopeStubOptions, type TenantRelationalStore, type TenantStoreProvisionInput, type AttachmentExtractor, type JobDriveReport, type JobHandler, type JobRun, type JobRunFilter, type StartJobRunInput, type ConnectorCallRecorder } from '@substrat-run/kernel';
3
3
  /**
4
4
  * A fault in the database itself (full, corrupt, I/O), as opposed to one statement failing.
5
5
  * The #1764 backfill logs and opens past a failed batch, but never past one of these.
@@ -16,6 +16,13 @@ export declare function isStorageFault(err: unknown): boolean;
16
16
  */
17
17
  export declare const DO_SCOPE_ONLY_SPINE_TABLES: ReadonlySet<string>;
18
18
  export interface SqliteScopeHostOptions {
19
+ /**
20
+ * The parsers attachment text is extracted with (#1575, K-43) — `defaultAttachmentExtractors()`
21
+ * from `@substrat-run/attachment-extractors`, or a list of the deployment's own. The kernel
22
+ * and this adapter parse no file format; omitted, every upload records `unsupported`, with
23
+ * that reason, which is a valid configuration rather than a broken one.
24
+ */
25
+ attachmentExtractors?: readonly AttachmentExtractor[];
19
26
  /** Directory holding one SQLite file per scope plus the directory database. */
20
27
  dir: string;
21
28
  /** Defaults to the built-in tuple checker (deny-by-default on empty tuples). */
@@ -178,6 +185,8 @@ export declare class SqliteScopeHost implements ScopeHost {
178
185
  private readonly onBehalfOf;
179
186
  private readonly systemPrincipal;
180
187
  private readonly secretBox;
188
+ /** The parsers attachment text is extracted with (K-43); the host's own, never imported here. */
189
+ private readonly attachmentExtractors;
181
190
  private readonly fetchImpl;
182
191
  private readonly connectorCalls;
183
192
  private readonly clock;
@@ -523,6 +532,12 @@ export declare class SqliteScopeHost implements ScopeHost {
523
532
  * no path by which this can deadlock against itself.
524
533
  */
525
534
  private jobStore;
535
+ /**
536
+ * The extraction job's adapter half (#1575): the record and the bytes with no permission
537
+ * gate — extraction is the kernel's own derivation, and the person-facing gate is at
538
+ * search — and the outcome written in a turn of its own, like every job store write.
539
+ */
540
+ private attachmentTextHandler;
526
541
  startJobRun(tenantId: TenantId, scopeId: ScopeId, input: StartJobRunInput): Promise<JobRun>;
527
542
  runDueJobs(tenantId: TenantId, scopeId: ScopeId, options?: {
528
543
  maxPasses?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAeL,KAAK,eAAe,EAcpB,KAAK,WAAW,EAEhB,KAAK,YAAY,EAuBjB,KAAK,QAAQ,EACb,KAAK,YAAY,EAIjB,KAAK,cAAc,EAwCnB,KAAK,kBAAkB,EAMvB,KAAK,YAAY,EAGjB,KAAK,QAAQ,EAeb,KAAK,WAAW,EAIhB,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAI3B,KAAK,wBAAwB,EAW7B,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,UAAU,EACf,KAAK,WAAW,EAehB,KAAK,SAAS,EAEd,KAAK,OAAO,EAYZ,KAAK,sBAAsB,EAG3B,KAAK,QAAQ,EAGb,KAAK,iBAAiB,EAevB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAoBL,KAAK,aAAa,EAoBlB,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAc1B,KAAK,uBAAuB,EAG5B,KAAK,gBAAgB,EAGrB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,mBAAmB,EA0FxB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,KAAK,EACV,KAAK,SAAS,EACd,KAAK,SAAS,EAEd,KAAK,SAAS,EACd,KAAK,kBAAkB,EAEvB,KAAK,gBAAgB,EAErB,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EAExB,KAAK,oBAAoB,EACzB,KAAK,iBAAiB,EAGtB,KAAK,SAAS,EACd,KAAK,SAAS,EACd,KAAK,gBAAgB,EAGrB,KAAK,qBAAqB,EAC1B,KAAK,yBAAyB,EA2D9B,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,MAAM,EACX,KAAK,YAAY,EAMjB,KAAK,gBAAgB,EAmCrB,KAAK,qBAAqB,EAE3B,MAAM,sBAAsB,CAAC;AAM9B;;;GAGG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAGpD;AAgBD;;;;;;;;GAQG;AACH,eAAO,MAAM,0BAA0B,EAAE,WAAW,CAAC,MAAM,CAQzD,CAAC;AAuHH,MAAM,WAAW,sBAAsB;IACrC,+EAA+E;IAC/E,GAAG,EAAE,MAAM,CAAC;IACZ,gFAAgF;IAChF,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAC5B;;;;OAIG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB;;;;;;;OAOG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,qBAAqB,CAAC;IACvC;;;;;;;;;;;;;;OAcG;IACH,KAAK,CAAC,EAAE,KAAK,CAAC;IACd;;;OAGG;IACH,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAksBD,qBAAa,eAAgB,YAAW,SAAS;IAC/C,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAC1B;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,KAAK,CAAC;IAC3B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoB;IAC5C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAoB;IAC9C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmC;IAC1D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAmC;IAC9D,qGAAqG;IACrG,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAmC;IAC3D;;+EAE2E;IAC3E,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAwC;IACvE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAuD;IAClF,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuC;IAC/D,oFAAoF;IACpF,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA+B;IAC7D,gFAAgF;IAChF,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsC;IAC7D,gFAAgF;IAChF,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAkE;IAC7F,2EAA2E;IAC3E,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA6B;IACvD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAkC;IAC5D,8EAA8E;IAC9E,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAsC;IAClE,4FAA4F;IAC5F,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAoC;IAC9D,8FAA8F;IAC9F,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAoE;IACtG,uEAAuE;IACvE,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAA6B;IAClE;;;;;OAKG;IACH,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAyD;IACxF;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAyD;IAC9F;;;;;OAKG;IACH,OAAO,CAAC,QAAQ,CAAC,0BAA0B,CAAqB;IAChE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAqC;IAC3D,kFAAkF;IAClF,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAyC;IACnE;;;;;OAKG;IACH,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA2E;IAChG;;;;;OAKG;IACH,OAAO,CAAC,QAAQ,CAAuB;IACvC;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA2B;IACtD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA0C;IAC1E,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IACtC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IACtC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAwB;IACvD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAQ;IAC9B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAgB;IAC1C,6FAA6F;IAC7F,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgB;IAOxC,YAAY,OAAO,EAAE,sBAAsB,EAyB1C;IAED;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,OAAO,CAAC,oBAAoB;IAqjB5B;;;;OAIG;IACH,OAAO,CAAC,oBAAoB;IAU5B;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,qBAAqB;IAS7B;;;;;;OAMG;IACH,OAAO,CAAC,sBAAsB;IAY9B,gBAAgB,CACd,EAAE,EAAE,MAAM,EACV,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,eAAe,EACxB,KAAK,CAAC,EAAE,mBAAmB,GAC1B,IAAI,CAQN;IAED,iBAAiB,CACf,EAAE,EAAE,MAAM,EACV,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,gBAAgB,EACzB,OAAO,CAAC,EAAE,gBAAgB,GACzB,IAAI,CASN;IAED;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,gBAAgB;IAiGxB,cAAc,CAAC,YAAY,EAAE,kBAAkB,GAAG,IAAI,CAuMrD;IAED,eAAe,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAIzE;IAEK,cAAc,CAAC,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAwHtF;IAED;;;;;;;;;;OAUG;IACH,OAAO,CAAC,sBAAsB;IA6CxB,oBAAoB,CACxB,KAAK,EAAE,eAAe,EACtB,KAAK,EAAE,yBAAyB,GAC/B,OAAO,CAAC,iBAAiB,CAAC,CAwD5B;IAED,eAAe,CAAC,MAAM,EAAE,iBAAiB,GAAG,qBAAqB,CAoBhE;IAED,sFAAsF;IACtF,OAAO,CAAC,aAAa;IAUf,kBAAkB,CACtB,KAAK,EAAE,eAAe,EACtB,KAAK,EAAE,uBAAuB,GAC7B,OAAO,CAAC,eAAe,CAAC,CA0C1B;IAED;;mFAE+E;IAC/E,OAAO,CAAC,SAAS;IAoDjB;;;wEAGoE;IACpE,OAAO,CAAC,eAAe;IAuBjB,WAAW,CACf,SAAS,EAAE,WAAW,EACtB,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,gBAAgB,CAAC,CAU3B;IAEK,oBAAoB,CACxB,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,IAAI,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAC,CAczC;IAED;;;;;;OAMG;IACH,OAAO,CAAC,gBAAgB;IA2QlB,WAAW,CACf,KAAK,EAAE,eAAe,EACtB,KAAK,EAAE,mBAAmB,EAC1B,IAAI,EAAE,SAAS,GACd,OAAO,CAAC,IAAI,CAAC,CAqBf;IAED,oFAAoF;YACtE,QAAQ;IA4HhB,YAAY,CAChB,KAAK,EAAE,eAAe,EACtB,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,SAAS,EACf,IAAI,CAAC,EAAE;QAAE,aAAa,CAAC,EAAE,OAAO,CAAA;KAAE,GACjC,OAAO,CAAC,IAAI,CAAC,CAsBf;IAEK,aAAa,CACjB,KAAK,EAAE,eAAe,EACtB,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,OAAO,EAChB,IAAI,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAC3C,OAAO,CAAC,OAAO,CAAC,CAwBlB;IAEK,cAAc,CAAC,KAAK,EAAE,eAAe,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CA6BhG;IAEK,QAAQ,CACZ,SAAS,EAAE,WAAW,EACtB,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC,SAAS,CAAC,CA2CpB;IAED;;;;;;;;;;;;;OAaG;IACG,iBAAiB,CAAC,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,SAAS,CAAC,CA4BxF;IAEK,uBAAuB,CAC3B,YAAY,EAAE,YAAY,EAC1B,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,gBAAgB,CAAC,CA2B3B;IAED,mFAAmF;IACnF,OAAO,CAAC,iBAAiB;IAOzB;;;;;;;OAOG;IACG,oBAAoB,CACxB,OAAO,EAAE,sBAAsB,EAC/B,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC,SAAS,CAAC,CAiBpB;IAEK,cAAc,CAClB,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,SAAS,CAAC,CAoBpB;IAED;;;;;;;;OAQG;YACW,WAAW;IA8BzB;;;;OAIG;YACW,WAAW;IAUzB,uEAAuE;IACvE,OAAO,CAAC,aAAa;IAgBf,aAAa,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CAkHjG;IAED;;;OAGG;IACH,OAAO,CAAC,cAAc;IAWtB;;;;OAIG;IACH,OAAO,CAAC,UAAU;IA2BlB,yGAAyG;IACzG,OAAO,CAAC,cAAc;IAMtB,4FAA4F;IAC5F,OAAO,CAAC,mBAAmB;IAgB3B;;;;;OAKG;YACW,eAAe;IAyB7B;;;;;OAKG;IACG,kBAAkB,CACtB,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAA;KAAE,GACpC,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CA0CpC;IAED;;;;;OAKG;IACG,kBAAkB,CACtB,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC,SAAS,CAAC,CAOpB;IAED;;;;;OAKG;IACG,wBAAwB,CAC5B,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,gBAAgB,CAAC,CAW3B;IAED,uFAAuF;IACvF,OAAO,CAAC,gBAAgB;IAIxB;;;;OAIG;IACG,gBAAgB,CACpB,MAAM,EAAE,cAAc,EACtB,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC,SAAS,CAAC,CAIpB;IAED;;;;;OAKG;IACG,UAAU,CACd,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,SAAS,aAAa,EAAE,GACpC,OAAO,CAAC,YAAY,EAAE,CAAC,CAQzB;IAED;;;OAGG;IACG,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAIhH;IAEK,sBAAsB,CAC1B,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,WAAW,EACnB,QAAQ,EAAE,WAAW,EACrB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,QAAQ,CAAC,CAcnB;IAED;;;;;OAKG;YACW,eAAe;IAa7B,kGAAkG;IAClG,iBAAiB,IAAI;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,EAAE,CAE3E;IAED,mBAAmB,IAAI,oBAAoB,EAAE,CAQ5C;IAED,mBAAmB,IAAI,qBAAqB,EAAE,CAQ7C;IAED;;;;;;;;;;;;;;;OAeG;IACG,cAAc,CAClB,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,eAAe,CAAC,CA+E1B;IAGK,eAAe,CACnB,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,iBAAiB,CAAC,CA8G5B;IAED,sGAAsG;IACtG,OAAO,CAAC,SAAS;IAsUjB;;;;;;;;;OASG;IACH,OAAO,CAAC,cAAc;IAgBtB,qFAAqF;IACrF,OAAO,CAAC,SAAS;YAKH,SAAS;IAqBjB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAG3B;IAOD;;;;;;;;;;;;;;;;;;;;OAoBG;YACW,iBAAiB;IAgF/B;;;;;;;OAOG;IACH,OAAO,CAAC,sBAAsB;IAmDxB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAOjF;IAED,WAAW,CACT,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,UAAU,EACnB,KAAK,CAAC,EAAE,mBAAmB,GAC1B,IAAI,CAIN;IAED;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,OAAO,CAAC,QAAQ;IAuGV,WAAW,CACf,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,gBAAgB,GACtB,OAAO,CAAC,MAAM,CAAC,CAIjB;IAEK,UAAU,CACd,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAC/C,OAAO,CAAC,cAAc,CAAC,CAWzB;IAEK,OAAO,CACX,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,OAAO,EAChB,MAAM,CAAC,EAAE,YAAY,GACpB,OAAO,CAAC,MAAM,EAAE,CAAC,CAInB;IAEK,iBAAiB,CACrB,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,gBAAgB,EACzB,KAAK,EAAE,WAAW,EAClB,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAC/B,OAAO,CAAC,IAAI,CAAC,CAgBf;IAED;;;;;;;OAOG;IACG,uBAAuB,CAC3B,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,wBAAwB,EAAE,CAAC,CAiCrC;IAED,iBAAiB,IAAI,iBAAiB,CAIrC;IAED;;;;;;;;OAQG;IACG,YAAY,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,mBAAmB,CAAC,CA6CrF;IAEK,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC,CA6B7F;IAEK,oBAAoB,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAW3F;IAEK,0BAA0B,CAC9B,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,OAAO,EAChB,MAAM,CAAC,EAAE,qBAAqB,GAC7B,OAAO,CAAC,eAAe,EAAE,CAAC,CAO5B;IAEK,qBAAqB,CACzB,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,OAAO,EAChB,EAAE,EAAE,iBAAiB,EACrB,OAAO,EAAE;QACP,MAAM,EAAE,qBAAqB,CAAC;QAC9B,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC1B,OAAO,CAAC,EAAE,sBAAsB,GAAG,IAAI,CAAC;KACzC,GACA,OAAO,CAAC,IAAI,CAAC,CA4Bf;YAEa,QAAQ;IAyFtB;;;;OAIG;IACH;;;OAGG;IACH,OAAO,CAAC,aAAa;IAuBrB,OAAO,CAAC,YAAY;IAmDpB;;;;;;OAMG;IACH;;;;;;OAMG;IACH,mFAAmF;IACnF,OAAO,CAAC,gBAAgB;IA4CxB,OAAO,CAAC,YAAY;IA0BpB;;;;;OAKG;IACH,OAAO,CAAC,WAAW;IASnB;;;;OAIG;IACH,OAAO,CAAC,cAAc;IAiDtB;;;;;;;;;OASG;YACW,gBAAgB;IA0D9B;;;;;;;;;OASG;YACW,eAAe;IAiB7B,gFAAgF;IAChF,OAAO,CAAC,aAAa;IAQrB,OAAO,CAAC,WAAW;IA6BnB,OAAO,CAAC,sBAAsB;IAe9B,4FAA4F;IAC5F,OAAO,CAAC,gBAAgB;IAYxB,sFAAsF;IACtF,UAAU,CAAC,UAAU,EAAE,UAAU,GAAG,IAAI,CAEvC;IAED,OAAO,CAAC,UAAU;IAusIlB;;;;;;;;;OASG;IACH;;;;OAIG;IACH,OAAO,CAAC,YAAY;IASpB;;;;;OAKG;IACH,OAAO,CAAC,uBAAuB;IAc/B;;;;;;;;;;;;;;;;OAgBG;IACH,OAAO,CAAC,iBAAiB;IAIzB;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,iBAAiB;IA0BzB;;;;;;OAMG;IACH,OAAO,CAAC,4BAA4B;IA2BpC;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,yBAAyB;IAWjC,OAAO,CAAC,sBAAsB;IA8H9B,OAAO,CAAC,SAAS;IAejB;;;;OAIG;IACH,OAAO,CAAC,gBAAgB;YA4eV,sBAAsB;IAkEpC;;;;;;;;;OASG;IACH,OAAO,CAAC,oBAAoB;IAyB5B;;;;;OAKG;IACH;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,oBAAoB;IAU5B;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,oBAAoB;IAa5B,OAAO,CAAC,UAAU;IAKlB;;;;;;;;;;;;;;;OAeG;IACH,OAAO,CAAC,cAAc;IAKtB;;;;;OAKG;IACH,OAAO,CAAC,MAAM;IAuBd;;;OAGG;IACH,OAAO,CAAC,YAAY;IAUpB;;;;;;;OAOG;IACH,OAAO,CAAC,kBAAkB;IAgF1B,OAAO,CAAC,OAAO;CA6ChB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@ import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync
2
2
  import { dirname, join } from 'node:path';
3
3
  import Database from 'better-sqlite3';
4
4
  import { accessLogEntry, adminLogEntry, delegatedReadParams, opsFailureEntry, opsFailureFingerprint, issueEntry, FRESHNESS_HEARTBEAT_MINUTES, sweepRunEntry, modelUsageEntry, ATTACHMENT_ADDED, ATTACHMENT_REMOVED, attachmentRecord, createTenantInput, domainEvent, domainEventInput, exportReadInput, importBatch, importCursorMove, exportsOfManifestJson, importsOfManifestJson, entitlementGrant, entitlementGrantInput, eventId, meterReading, platformRequestInput, platformRequestId, MAX_PENDING_PLATFORM_REQUESTS, identityLink, identityPool, instant, connection, capabilityGrant, connectionGrant, connectionGrantRecord, connectionSecret, systemGrant, systemSwitch, systemSwitchRecord, peerSwitch, verticalCaller, verticalSlug as verticalSlugOf, subjectRef, requestFingerprint, createConnectionInput, projectedConnectionGrant, projectedConnectionKey, moduleManifest, createOrgInput, promotionAcknowledgement, bindAcknowledgement, bindHostnameInput, channelHistoryEntry, hostnameBinding, publishVersionInput, AUTO_ADMISSION_NOTE, routeTarget, registerVerticalInput, vertical as verticalSchema, verticalChannel, verticalVersion, objectRef, entityObjectRef, assertModuleEmittableType, assertKernelAuthoredType, grantRefFromProof, org as orgSchema, orgMembership, principalId, resolvedIdentity, identityMembership, roleDefinition, scope as scopeSchema, tenant as tenantSchema, tenantRole, subjectShredReceipt, SCOPE_TABLE_PAGE_DEFAULT, SCOPE_TABLE_PAGE_MAX, SCOPE_QUERY_ROW_MAX, verticalServingState, callsOfManifestJson, outboundOfManifestJson, listLimitOf, substratError, assertReplayableDump, delegatedReadRecord, ownerTransferAudit, redrainEventsInput, REDRAIN_BATCH, } from '@substrat-run/contracts';
5
- import { actorOf, asPrincipal, assertAllowed, assertNoSecret, assertPermissionKey, CAPABILITY_DDL, CAPABILITY_EXCHANGE_OPERATION, capabilityAttachmentWriteRefused, capabilityTokenHash, createCapabilityVerbs, createEntityEdgeVerbs, exchangeCapability as exchangeCapabilitySecret, guardSecrets, mintBecomeCapability, plausibleSessionToken, redactSecrets, redactSecretText, moduleLog, consoleLogSink, resolveCapabilitySession, revokeCapabilityAsPlatform, assertReadOnlyQuery, attachmentBlobKey, entitlementDenial, foldMeterReading, guardSpine, guardSqlLimits, DO_SQL_LIMITS, tooManyResultColumns, tooManyTableColumns, parseValidationRecords, resolveScopeRecord, ulid, ISSUE_RETENTION_DAYS, OPS_FAILURE_RETENTION_DAYS, SWEEP_RUN_RETENTION_DAYS, SWEEP_RUNS_INTENT_INDEX, sweepRunsIntentHasKind, MODEL_USAGE_RETENTION_DAYS, foldModelUsage, backoffAt, platformRequestHistoryQuery, platformRequestOf, PLATFORM_REQUEST_COLUMNS, PLATFORM_REQUEST_REDACTION_SQL, platformRequestRedactionParams, platformRequestRedactionQuery, intentPayloadCarriesSubject, redactSubjectJobRuns, JOB_RUN_PATCH_SQL, JOB_STEP_RECORD_SQL, DELIVERY_ERROR_REDACTION_SQL, REDACTED_DELIVERY_NOTE, seatScopeTuple, switchSystemSchedules, admitPeer, collectPeers, peerSeats, resolveVerticalInstanceFrom, switchPeer, peerGrantsStatus, systemGrantsStatus, systemScheduleState, systemSwitchedOff, systemSwitchedOffMessage, tenantSystemSwitchedOffMessage, SYSTEM_SWITCHES_BACKFILL_SQL, SYSTEM_SWITCHES_DDL, forgetSystemSwitchesOf, listSystemSwitchRecords, recordSystemSwitchedOff, recordSystemSwitchedOn, restoreSystemSwitchRecord, scopesSwitchedOffFor, switchedOffModulesOf, inUnitMovesToAudit, staleCarryRevertRow, staleCarryReverts, systemSwitchRecordsOf, systemSwitchesTableExists, withRecorded, VERSION_MIGRATIONS_DDL, splitManifestMigrations, splitVersionMigrationsBatch, versionMigrationsOf, writeVersionMigrations, denialListQuery, denialSummaryQuery, denialTotalsQuery, DENIAL_WINDOW_QUERY, mapDenialRow, mapDenialSummaryBuckets, IMPERSONATION_COLUMNS, IMPERSONATION_DDL, ImpersonationRefused, assertImpersonationWrites, assertModuleEnqueueableKind, assertSessionUsable, impersonationByIdQuery, impersonationListQuery, impersonationRowValues, impersonationStampOf, mapImpersonationRow, newImpersonationSession, resolveRetryPolicy, isSecretBoxConfigured, unconfiguredSecretBox, createSubjectKeys, generateSealingKeyPair, noSealingKeyMessage, openSealed, sealTo, ConnectionSealingKeyUnavailableError, PermissionDenied, createAtomic, NotSearchable, NotListable, listIndexMigrations, listIndexPlans, listQuery, cursorOf, moduleMigrations, isSearchIndexTable, searchIndexDdl, searchIndexMigrations, searchIndexPlans, searchLimit, searchMatchExpression, searchQuery, entityVersionQuery, entityVersionOf, assertIfMatch, OUTBOX_ENTITY_INDEX, SCHEDULE_STATE_DDL, SCHEDULE_STATE_REBUILD, scheduleStateHasKind, VERTICAL_EVENTS_DDL, EXPORT_HOPS_SQL, IMPORT_CURSORS_SQL, IMPORT_CURSOR_OF_SQL, OUTBOX_MARK_SQL, emittedSinceQuery, emittedReportOf, EMITTED_REPORT_CAP, exportedSinceQuery, IMPORT_CURSOR_ADVANCE_SQL, IMPORT_RECORD_SQL, moveImportCursor, importCursorSourceOf, exportBreaksOf, exportBreakRefusal, bindExportBreaksOf, bindExportBreakRefusal, CrossVerticalRegistry, exportReadPlan, exportReadQuery, planExportBatch, withheldNote, JOB_RUN_DDL, jobRunListLimit, jobRunOf, runDueJobRuns, startJobRun, IDEMPOTENCY_DDL, REFUSALS_DDL, refusalInsert, refusedTransitionOf, assertIdempotencyKey, idempotencyLookupQuery, idempotencyPruneStatement, idempotencyRecordStatement, idempotencyOptedOutMessage, replayFor, globalFetch, createUlid, facetEvents, readHistory, walkEventCause, walkEventEffects, assertRedrainWindow, readInvocation, readDeadLetters, readLifecycleFlow, domainEventOf, readUndrainedOutbox, undrainedEventsOf, connectorCallRecord, noopConnectorCallRecorder, recordConnectorCall, settleConnectionUse, unknownRoleError, } from '@substrat-run/kernel';
5
+ import { actorOf, asPrincipal, assertAllowed, assertNoSecret, assertPermissionKey, CAPABILITY_DDL, CAPABILITY_EXCHANGE_OPERATION, capabilityAttachmentWriteRefused, capabilityTokenHash, createCapabilityVerbs, createEntityEdgeVerbs, exchangeCapability as exchangeCapabilitySecret, guardSecrets, mintBecomeCapability, plausibleSessionToken, redactSecrets, redactSecretText, moduleLog, consoleLogSink, resolveCapabilitySession, revokeCapabilityAsPlatform, assertReadOnlyQuery, attachmentBlobKey, attachmentSha256, entitlementDenial, foldMeterReading, guardSpine, guardSqlLimits, DO_SQL_LIMITS, tooManyResultColumns, tooManyTableColumns, parseValidationRecords, resolveScopeRecord, ulid, ISSUE_RETENTION_DAYS, telemetryRetentionStatements, assertRowLimit, assertRowOffset, OPS_FAILURE_RETENTION_DAYS, SWEEP_RUN_RETENTION_DAYS, SWEEP_RUNS_INTENT_INDEX, sweepRunsIntentHasKind, MODEL_USAGE_RETENTION_DAYS, foldModelUsage, backoffAt, platformRequestHistoryQuery, platformRequestOf, PLATFORM_REQUEST_COLUMNS, PLATFORM_REQUEST_REDACTION_SQL, platformRequestRedactionParams, platformRequestRedactionQuery, intentPayloadCarriesSubject, redactSubjectJobRuns, redactSubjectScopeText, redactSubjectDirectoryText, ISSUE_EXEMPLAR_OWNER_BACKFILL_SQL, issueExemplarOwner, JOB_RUN_PATCH_SQL, JOB_STEP_RECORD_SQL, DELIVERY_ERROR_REDACTION_SQL, REDACTED_DELIVERY_NOTE, seatScopeTuple, switchSystemSchedules, admitPeer, collectPeers, peerSeats, resolveVerticalInstanceFrom, switchPeer, peerGrantsStatus, systemGrantsStatus, systemScheduleState, systemSwitchedOff, systemSwitchedOffMessage, tenantSystemSwitchedOffMessage, SYSTEM_SWITCHES_BACKFILL_SQL, SYSTEM_SWITCHES_DDL, forgetSystemSwitchesOf, listSystemSwitchRecords, recordSystemSwitchedOff, recordSystemSwitchedOn, restoreSystemSwitchRecord, scopesSwitchedOffFor, switchedOffModulesOf, inUnitMovesToAudit, staleCarryRevertRow, staleCarryReverts, systemSwitchRecordsOf, systemSwitchesTableExists, withRecorded, VERSION_MIGRATIONS_DDL, splitManifestMigrations, splitVersionMigrationsBatch, versionMigrationsOf, writeVersionMigrations, denialListQuery, denialSummaryQuery, denialTotalsQuery, DENIAL_WINDOW_QUERY, mapDenialRow, mapDenialSummaryBuckets, IMPERSONATION_COLUMNS, IMPERSONATION_DDL, ImpersonationRefused, assertImpersonationWrites, assertModuleEnqueueableKind, assertSessionUsable, impersonationByIdQuery, impersonationListQuery, impersonationRowValues, impersonationStampOf, mapImpersonationRow, newImpersonationSession, resolveRetryPolicy, isSecretBoxConfigured, unconfiguredSecretBox, createSubjectKeys, generateSealingKeyPair, noSealingKeyMessage, openSealed, sealTo, ConnectionSealingKeyUnavailableError, PermissionDenied, createAtomic, NotSearchable, NotListable, listIndexMigrations, listIndexPlans, listQuery, cursorOf, moduleMigrations, isSearchIndexTable, searchIndexDdl, searchIndexMigrations, searchIndexPlans, searchLimit, searchMatchExpression, searchQuery, ATTACHMENT_TEXT_DDL, assertAttachmentExtractors, assertJobRegistrable, attachmentRecordOfRow, attachmentTextJob, enqueueAttachmentText, isAttachmentTextRun, reconcileAttachmentText, recordAttachmentText, searchAttachments, entityVersionQuery, entityVersionOf, assertIfMatch, OUTBOX_ENTITY_INDEX, SCHEDULE_STATE_DDL, SCHEDULE_STATE_REBUILD, scheduleStateHasKind, VERTICAL_EVENTS_DDL, EXPORT_HOPS_SQL, IMPORT_CURSORS_SQL, IMPORT_CURSOR_OF_SQL, OUTBOX_MARK_SQL, emittedSinceQuery, emittedReportOf, EMITTED_REPORT_CAP, exportedSinceQuery, IMPORT_CURSOR_ADVANCE_SQL, IMPORT_RECORD_SQL, moveImportCursor, importCursorSourceOf, exportBreaksOf, exportBreakRefusal, bindExportBreaksOf, bindExportBreakRefusal, CrossVerticalRegistry, exportReadPlan, exportReadQuery, planExportBatch, withheldNote, JOB_RUN_DDL, jobRunListLimit, jobRunOf, runDueJobRuns, startJobRun, IDEMPOTENCY_DDL, REFUSALS_DDL, refusalInsert, refusedTransitionOf, assertIdempotencyKey, idempotencyLookupQuery, idempotencyPruneStatement, idempotencyRecordStatement, idempotencyOptedOutMessage, replayFor, globalFetch, createUlid, facetEvents, readHistory, walkEventCause, walkEventEffects, assertRedrainWindow, readInvocation, readDeadLetters, readLifecycleFlow, domainEventOf, readUndrainedOutbox, undrainedEventsOf, connectorCallRecord, noopConnectorCallRecorder, recordConnectorCall, settleConnectionUse, unknownRoleError, } from '@substrat-run/kernel';
6
6
  import { attributedHost } from '@substrat-run/kernel';
7
7
  import { LEGACY_SCOPE_ROWS_BACKFILL, assertNoSpineReference, assertSpineTablesBuilt, dumpRowsInsert, isSpineTable, loadDirectoryDump, repointScopeGrants, spineColumnAdditions } from '@substrat-run/kernel';
8
8
  import { ScopeActor } from './actor.js';
@@ -295,6 +295,9 @@ const KERNEL_DDL = `
295
295
  );
296
296
  CREATE INDEX IF NOT EXISTS _substrat_attachments_entity
297
297
  ON _substrat_attachments (entity_type, entity_id);
298
+ -- #1575: attachment text and its FTS5 index, shared from @substrat-run/kernel. After
299
+ -- _substrat_attachments, whose delete trigger it adds.
300
+ ${ATTACHMENT_TEXT_DDL}
298
301
  -- #901: an entity's version is the ULID of the last event about it, so
299
302
  -- MAX(id) per (entity_type, entity_id) is the read. The id column sits last so
300
303
  -- SQLite walks to the end of the matched range instead of aggregating over it.
@@ -366,7 +369,7 @@ function keysetTail(where, params, key, page, defaultOrder = 'asc') {
366
369
  let tail = ` ORDER BY ${key} ${order}`;
367
370
  if (page?.limit !== undefined) {
368
371
  tail += ' LIMIT ?';
369
- params.push(page.limit);
372
+ params.push(assertRowLimit('limit', page.limit));
370
373
  }
371
374
  return tail;
372
375
  }
@@ -560,6 +563,8 @@ export class SqliteScopeHost {
560
563
  onBehalfOf = null;
561
564
  systemPrincipal = principalId.parse(ulid());
562
565
  secretBox;
566
+ /** The parsers attachment text is extracted with (K-43); the host's own, never imported here. */
567
+ attachmentExtractors;
563
568
  fetchImpl;
564
569
  connectorCalls;
565
570
  clock;
@@ -573,6 +578,8 @@ export class SqliteScopeHost {
573
578
  // process-wide `ulid()` that every other id here still uses.
574
579
  constructor(options) {
575
580
  this.secretBox = options.secretBox ?? unconfiguredSecretBox;
581
+ assertAttachmentExtractors(options.attachmentExtractors ?? []);
582
+ this.attachmentExtractors = options.attachmentExtractors ?? [];
576
583
  this.fetchImpl = options.fetch ?? globalFetch;
577
584
  this.connectorCalls = options.connectorCalls ?? noopConnectorCallRecorder;
578
585
  this.clock = options.clock ?? (() => instant.parse(new Date().toISOString()));
@@ -1113,6 +1120,12 @@ export class SqliteScopeHost {
1113
1120
  first_seen TEXT NOT NULL,
1114
1121
  last_seen TEXT NOT NULL,
1115
1122
  last_message TEXT NOT NULL,
1123
+ -- #1632: whose ops failure last_message was copied from, written in the same
1124
+ -- statement as the message: last_owner_kind is 'tenant' (last_tenant_id names it) or
1125
+ -- 'platform' (the platform's own row; last_tenant_id NULL). NULL kind = unknown, an
1126
+ -- issue from before the columns that no retained row attributes.
1127
+ last_tenant_id TEXT,
1128
+ last_owner_kind TEXT,
1116
1129
  last_vertical TEXT,
1117
1130
  last_version TEXT,
1118
1131
  resolved_version TEXT,
@@ -1919,21 +1932,6 @@ export class SqliteScopeHost {
1919
1932
  }
1920
1933
  return gate;
1921
1934
  };
1922
- const rowToRecord = (row) => attachmentRecord.parse({
1923
- id: row.id,
1924
- entity: { entityType: row.entity_type, entityId: row.entity_id },
1925
- filename: row.filename,
1926
- contentType: row.content_type,
1927
- size: row.size,
1928
- sha256: row.sha256,
1929
- visibility: row.visibility,
1930
- createdBy: row.created_by,
1931
- createdAt: row.created_at,
1932
- });
1933
- const sha256Hex = async (body) => {
1934
- const digest = await globalThis.crypto.subtle.digest('SHA-256', body);
1935
- return [...new Uint8Array(digest)].map((b) => b.toString(16).padStart(2, '0')).join('');
1936
- };
1937
1935
  // One attachment mutation/read = one serialized scope task, transactional exactly
1938
1936
  // like an operation invoke (including K-35 denial recording and prompt dispatch of
1939
1937
  // the events it emitted).
@@ -2011,7 +2009,7 @@ export class SqliteScopeHost {
2011
2009
  filename: input.filename,
2012
2010
  contentType: input.contentType,
2013
2011
  size: input.body.byteLength,
2014
- sha256: await sha256Hex(input.body),
2012
+ sha256: await attachmentSha256(input.body),
2015
2013
  visibility: input.visibility,
2016
2014
  createdBy: creator.id,
2017
2015
  createdAt: new Date().toISOString(),
@@ -2036,6 +2034,9 @@ export class SqliteScopeHost {
2036
2034
  piiClass: 'none',
2037
2035
  payload: { attachment: record },
2038
2036
  });
2037
+ // #1575: queue its text extraction in the same transaction — a `pending` row
2038
+ // and a job run. Nothing is extracted here, so nothing here can fail the upload.
2039
+ enqueueAttachmentText(spineSql(rt.db), record.id, ulid(), this.clock());
2039
2040
  return record;
2040
2041
  });
2041
2042
  }
@@ -2054,7 +2055,7 @@ export class SqliteScopeHost {
2054
2055
  .prepare(`SELECT * FROM _substrat_attachments WHERE entity_type = ? AND entity_id = ?
2055
2056
  ORDER BY id DESC`)
2056
2057
  .all(entity.entityType, entity.entityId);
2057
- return rows.map(rowToRecord);
2058
+ return rows.map(attachmentRecordOfRow);
2058
2059
  }),
2059
2060
  open: async (attachmentId) => {
2060
2061
  const record = await guarded('attachments.open', async (ctx) => {
@@ -2065,11 +2066,11 @@ export class SqliteScopeHost {
2065
2066
  return null;
2066
2067
  if (opts.admitByEvent !== undefined) {
2067
2068
  admitByDelivery(rt, opts.admitByEvent, row);
2068
- return rowToRecord(row);
2069
+ return attachmentRecordOfRow(row);
2069
2070
  }
2070
2071
  const gate = targetGate(row.entity_type);
2071
2072
  assertAllowed(await ctx.check(gate.read, { entityType: row.entity_type, entityId: row.entity_id }));
2072
- return rowToRecord(row);
2073
+ return attachmentRecordOfRow(row);
2073
2074
  });
2074
2075
  if (!record)
2075
2076
  return null;
@@ -2078,7 +2079,7 @@ export class SqliteScopeHost {
2078
2079
  throw new Error(`attachment ${record.id}: bytes missing from the blob store — the metadata row ` +
2079
2080
  `survived something the object did not (rewind/reap); see the #473 integrity notes`);
2080
2081
  }
2081
- if ((await sha256Hex(obj.body)) !== record.sha256) {
2082
+ if ((await attachmentSha256(obj.body)) !== record.sha256) {
2082
2083
  throw new Error(`attachment ${record.id}: bytes do not match the recorded sha256`);
2083
2084
  }
2084
2085
  return { record, body: obj.body, contentType: obj.contentType ?? record.contentType };
@@ -2098,7 +2099,7 @@ export class SqliteScopeHost {
2098
2099
  const gate = targetGate(row.entity_type);
2099
2100
  assertAllowed(await ctx.check(gate.write, { entityType: row.entity_type, entityId: row.entity_id }));
2100
2101
  rt.db.prepare('DELETE FROM _substrat_attachments WHERE id = ?').run(attachmentId);
2101
- const record = rowToRecord(row);
2102
+ const record = attachmentRecordOfRow(row);
2102
2103
  kernelEmit(ctx, {
2103
2104
  type: ATTACHMENT_REMOVED,
2104
2105
  schemaVersion: 1,
@@ -2114,6 +2115,18 @@ export class SqliteScopeHost {
2114
2115
  await store.delete(attachmentBlobKey(rt.scopeId, removed.id)).catch(() => { });
2115
2116
  return removed;
2116
2117
  },
2118
+ // #1575: extracted text, gated per hit by the check `open` makes, before the limit.
2119
+ search: async (term, options) => {
2120
+ if (opts.admitByEvent !== undefined) {
2121
+ // The delivery-admitted surface reads the ONE attachment its delivery names; a
2122
+ // search would reach past it. Nothing builds this surface for anything but `open`.
2123
+ throw new Error('attachments.search is not available on a delivery-scoped surface');
2124
+ }
2125
+ // The term is judged before the turn: a refusal costs no queue slot.
2126
+ searchMatchExpression(term, 'prefix');
2127
+ // Authorized first, as this surface's subject, then matched over readable owners only.
2128
+ return guarded('attachments.search', (ctx) => searchAttachments(spineSql(rt.db), { targets: this.attachmentTargets, check: (permission, entity) => ctx.check(permission, entity) }, term, searchLimit(options?.limit)));
2129
+ },
2117
2130
  };
2118
2131
  }
2119
2132
  async importScope(actor, input, dump) {
@@ -2224,6 +2237,10 @@ export class SqliteScopeHost {
2224
2237
  if (present.has(plan.table))
2225
2238
  db.exec(searchIndexDdl(plan));
2226
2239
  }
2240
+ // #1575: attachment text is not in a dump, so a load left it as it was. Drop the
2241
+ // text of attachments the dump did not bring back, and queue extraction for those
2242
+ // it brought back without text — the bytes decide what that run finds.
2243
+ reconcileAttachmentText(spineSql(db), ulid, this.clock());
2227
2244
  // Re-point scope-level grants at the scope they now live in. They are written as
2228
2245
  // `object = scope:<scopeId>`, so a fork, a restore into a different scope, or #286's
2229
2246
  // migration onto a stable script name all land rows naming a scope that is not this
@@ -3571,6 +3588,8 @@ export class SqliteScopeHost {
3571
3588
  return rt.actor.enqueue(() => this.dispatchExecutors(rt, null));
3572
3589
  }
3573
3590
  registerJob(moduleId, name, handler, retry) {
3591
+ // #1575: the kernel's own jobs are dispatched before this registry is read.
3592
+ assertJobRegistrable(moduleId, name);
3574
3593
  const key = `${moduleId}/${name}`;
3575
3594
  if (this.jobs.has(key))
3576
3595
  throw new Error(`job '${key}' is already registered`);
@@ -3674,6 +3693,27 @@ export class SqliteScopeHost {
3674
3693
  }),
3675
3694
  };
3676
3695
  }
3696
+ /**
3697
+ * The extraction job's adapter half (#1575): the record and the bytes with no permission
3698
+ * gate — extraction is the kernel's own derivation, and the person-facing gate is at
3699
+ * search — and the outcome written in a turn of its own, like every job store write.
3700
+ */
3701
+ attachmentTextHandler(rt) {
3702
+ return attachmentTextJob({
3703
+ record: (attachmentId) => rt.actor.enqueue(() => {
3704
+ const row = rt.db.prepare('SELECT * FROM _substrat_attachments WHERE id = ?').get(attachmentId);
3705
+ return row ? attachmentRecordOfRow(row) : null;
3706
+ }),
3707
+ bytes: async (record) => {
3708
+ const scope = this.directory.prepare('SELECT vertical FROM scopes WHERE scope_id = ?').get(rt.scopeId);
3709
+ const store = this.attachmentStore(rt.tenantId, scope?.vertical ?? null);
3710
+ return (await store.get(attachmentBlobKey(rt.scopeId, record.id)))?.body ?? null;
3711
+ },
3712
+ write: (attachmentId, outcome) => rt.actor.enqueue(() => recordAttachmentText(spineSql(rt.db), attachmentId, outcome, this.clock())),
3713
+ },
3714
+ // K-43: the host's parsers, handed in — this adapter imports none.
3715
+ this.attachmentExtractors);
3716
+ }
3677
3717
  async startJobRun(tenantId, scopeId, input) {
3678
3718
  const rt = this.runtime(tenantId, scopeId);
3679
3719
  await this.applyPendingMigrations(rt);
@@ -3682,9 +3722,12 @@ export class SqliteScopeHost {
3682
3722
  async runDueJobs(tenantId, scopeId, options) {
3683
3723
  const rt = this.runtime(tenantId, scopeId);
3684
3724
  await this.applyPendingMigrations(rt);
3725
+ // #1575: the kernel's extraction job is this host's own, bound to this scope — no
3726
+ // deployment registers it, and none can shadow it.
3727
+ const attachmentText = { handler: this.attachmentTextHandler(rt) };
3685
3728
  return runDueJobRuns({
3686
3729
  store: this.jobStore(rt),
3687
- handlerFor: (run) => this.jobs.get(`${run.module_id}/${run.job}`),
3730
+ handlerFor: (run) => isAttachmentTextRun(run) ? attachmentText : this.jobs.get(`${run.module_id}/${run.job}`),
3688
3731
  now: this.clock,
3689
3732
  openScope: (run) => this.getSystemScope(run.module_id, tenantId, scopeId),
3690
3733
  maxPasses: options?.maxPasses,
@@ -4060,7 +4103,7 @@ export class SqliteScopeHost {
4060
4103
  ` ORDER BY id ${order}`;
4061
4104
  if (filter?.limit !== undefined) {
4062
4105
  sql += ' LIMIT ?';
4063
- params.push(filter.limit);
4106
+ params.push(assertRowLimit('limit', filter.limit));
4064
4107
  }
4065
4108
  const rows = this.directory.prepare(sql).all(...params);
4066
4109
  return rows.map((r) => modelUsageEntryOf(r));
@@ -4415,7 +4458,7 @@ export class SqliteScopeHost {
4415
4458
  // private vertical self-admit, and what lets a LISTED vertical's builder keep
4416
4459
  // previewing their own new code (issue #509 ask (d)).
4417
4460
  if (v.admission !== 'admitted' && scope.kind !== 'preview') {
4418
- throw new Error(`version ${versionId} is ${v.admission}, not admitted — it cannot be bound to a scope`);
4461
+ throw substratError('conflict', `version ${versionId} is ${v.admission}, not admitted — it cannot be bound to a scope`);
4419
4462
  }
4420
4463
  return { v, scope };
4421
4464
  };
@@ -4828,7 +4871,7 @@ export class SqliteScopeHost {
4828
4871
  ` ORDER BY tenant_id ${order}, role_key ${order}`;
4829
4872
  if (filter?.limit !== undefined) {
4830
4873
  sql += ' LIMIT ?';
4831
- params.push(filter.limit);
4874
+ params.push(assertRowLimit('limit', filter.limit));
4832
4875
  }
4833
4876
  const rows = this.directory.prepare(sql).all(...params);
4834
4877
  // Parsed, not cast: `permissions` is a JSON blob in a TEXT column, so the
@@ -5287,7 +5330,7 @@ export class SqliteScopeHost {
5287
5330
  return;
5288
5331
  }
5289
5332
  if (existing.ownerTenant !== parsed.ownerTenant) {
5290
- throw new Error(`vertical '${parsed.slug}' is owned by ${existing.ownerTenant ?? 'the platform'}, not ${parsed.ownerTenant ?? 'the platform'}`);
5333
+ throw substratError('conflict', `vertical '${parsed.slug}' is owned by ${existing.ownerTenant ?? 'the platform'}, not ${parsed.ownerTenant ?? 'the platform'}`);
5291
5334
  }
5292
5335
  throw new Error(`vertical '${parsed.slug}' is already registered as ${existing.source}`);
5293
5336
  }
@@ -5368,7 +5411,7 @@ export class SqliteScopeHost {
5368
5411
  .get(slug);
5369
5412
  const prodVersion = prod ? readVersion(prod.version_id) : undefined;
5370
5413
  if (prodVersion?.admissionNote === AUTO_ADMISSION_NOTE) {
5371
- throw new Error(`vertical '${slug}' prod version ${prodVersion.id} is auto-admitted (private self-serve) — ` +
5414
+ throw substratError('conflict', `vertical '${slug}' prod version ${prodVersion.id} is auto-admitted (private self-serve) — ` +
5372
5415
  `a staff admit must vouch for it before listing`);
5373
5416
  }
5374
5417
  }
@@ -5510,7 +5553,7 @@ export class SqliteScopeHost {
5510
5553
  throw new Error(`version ${versionId} belongs to '${incoming.verticalSlug}'`);
5511
5554
  }
5512
5555
  if (incoming.admission !== 'admitted') {
5513
- throw new Error(`version ${versionId} is ${incoming.admission}, not admitted — it cannot be promoted`);
5556
+ throw substratError('conflict', `version ${versionId} is ${incoming.admission}, not admitted — it cannot be promoted`);
5514
5557
  }
5515
5558
  const current = this.directory
5516
5559
  .prepare('SELECT version_id FROM vertical_channels WHERE vertical_slug = ? AND channel = ?')
@@ -5786,7 +5829,7 @@ export class SqliteScopeHost {
5786
5829
  // The kernel's read, shared with the DO: the envelope and the columns lifted beside
5787
5830
  // it (#1242, #1237) are decoded once, and a row that will not decode is stepped over
5788
5831
  // rather than stalling the scope on it (#1636).
5789
- const read = readUndrainedOutbox((offset, count) => page.all(count, offset), Math.min(Math.max(limit ?? 200, 1), 1000));
5832
+ const read = readUndrainedOutbox((offset, count) => page.all(count, offset), Math.min(assertRowLimit('limit', limit ?? 200), 1000));
5790
5833
  this.recordAccess(actor, 'readUndrainedEvents', { tenantId, scopeId }, { limit }, read.events.length);
5791
5834
  return undrainedEventsOf(read);
5792
5835
  },
@@ -6305,8 +6348,10 @@ export class SqliteScopeHost {
6305
6348
  const known = new Set(db.prepare(`SELECT name FROM sqlite_master WHERE type = 'table'`).all().map((r) => r.name));
6306
6349
  if (!known.has(input.table))
6307
6350
  throw new Error(`unknown table '${input.table}'`);
6308
- const limit = Math.min(Math.max(1, input.limit ?? SCOPE_TABLE_PAGE_DEFAULT), SCOPE_TABLE_PAGE_MAX);
6309
- const offset = Math.max(0, input.offset ?? 0);
6351
+ // The ceiling clamps; a bound SQLite would misread (NaN, non-finite, fractional,
6352
+ // negative) is refused instead of reaching LIMIT / OFFSET (#1632).
6353
+ const limit = Math.min(assertRowLimit('limit', input.limit ?? SCOPE_TABLE_PAGE_DEFAULT), SCOPE_TABLE_PAGE_MAX);
6354
+ const offset = assertRowOffset('offset', input.offset ?? 0);
6310
6355
  const stmt = db.prepare(`SELECT * FROM "${input.table}" LIMIT ? OFFSET ?`).raw(true);
6311
6356
  const rows = stmt.all(limit, offset).map((row) => row.map(cellToJson));
6312
6357
  const columns = stmt.columns().map((c) => c.name);
@@ -6580,7 +6625,8 @@ export class SqliteScopeHost {
6580
6625
  // Both scope-side redactions in ONE turn on the scope actor (#1678): issued while an
6581
6626
  // invoke held its transaction open, they joined it, and its rollback put the
6582
6627
  // person's PII back after this verb had destroyed the key and receipted the erasure.
6583
- const { redacted, intentsRedacted, jobRunsRedacted } = await this.runtime(tenantId, scopeId).actor.turn(() => ({
6628
+ const scopeSql = redactionSqlOf(db);
6629
+ const { redacted, intentsRedacted, jobRunsRedacted, text } = await this.runtime(tenantId, scopeId).actor.turn(() => ({
6584
6630
  redacted: db
6585
6631
  .prepare(`UPDATE _substrat_outbox SET payload = NULL
6586
6632
  WHERE subject_id = ? AND pii_class != 'none' AND payload IS NOT NULL`)
@@ -6599,14 +6645,16 @@ export class SqliteScopeHost {
6599
6645
  .run(REDACTED_DELIVERY_NOTE, REDACTED_DELIVERY_NOTE, subjectId),
6600
6646
  // The job-run tables (#1632): a run, its cursor or a step's memo can hold a copy
6601
6647
  // of the same event. The kernel's walk, so the DO runs the identical SQL.
6602
- jobRunsRedacted: redactSubjectJobRuns((sql, params) => {
6603
- const stmt = db.prepare(sql);
6604
- if (stmt.reader)
6605
- return stmt.all(...params);
6606
- stmt.run(...params);
6607
- return [];
6608
- }, subjectId, at),
6648
+ jobRunsRedacted: redactSubjectJobRuns(scopeSql, subjectId, at),
6649
+ // The free-text copies (#1632), and the tombstoned intents the directory half
6650
+ // follows. Last, so those ids include every intent tombstoned above.
6651
+ text: redactSubjectScopeText(scopeSql, subjectId, at),
6609
6652
  }));
6653
+ const { idempotencyResults, intentIds } = text;
6654
+ // The directory's failure text (#1632) — a drain failure quoting one of those
6655
+ // intents, an issue's exemplar, a sweep record's error. Before the key, for the
6656
+ // ordering reason above.
6657
+ redactSubjectDirectoryText(redactionSqlOf(this.directory), { tenantId, scopeId, subjectId, intentIds });
6610
6658
  const { existed } = await this.subjectKeysFor(tenantId, scopeId).destroy(subjectId, at);
6611
6659
  const receipt = subjectShredReceipt.parse({
6612
6660
  subjectId,
@@ -6622,7 +6670,7 @@ export class SqliteScopeHost {
6622
6670
  this.recordAdmin(actor, 'shredSubject', { tenantId, scopeId }, null, receipt);
6623
6671
  // BOTH counts: the access log's number is "how much evidence this destroyed", and
6624
6672
  // an intent payload is a whole event's worth of it.
6625
- this.recordAccess(actor, 'shredSubject', { tenantId, scopeId }, { subjectId }, redacted.changes + intentsRedacted + jobRunsRedacted);
6673
+ this.recordAccess(actor, 'shredSubject', { tenantId, scopeId }, { subjectId }, redacted.changes + intentsRedacted + jobRunsRedacted + idempotencyResults);
6626
6674
  return receipt;
6627
6675
  },
6628
6676
  // -- impersonation (K-42, #868) ----------------------------------------
@@ -7248,6 +7296,7 @@ export class SqliteScopeHost {
7248
7296
  return info.changes;
7249
7297
  },
7250
7298
  pruneAccessLog: async (actor, limit) => {
7299
+ assertRowLimit('limit', limit);
7251
7300
  // ONLY drained rows. Age alone is not a licence to delete evidence.
7252
7301
  const info = this.directory
7253
7302
  .prepare(`DELETE FROM _substrat_access_log WHERE id IN (
@@ -7305,7 +7354,7 @@ export class SqliteScopeHost {
7305
7354
  ` ORDER BY id ${order}`;
7306
7355
  if (filter?.limit !== undefined) {
7307
7356
  sql += ' LIMIT ?';
7308
- params.push(filter.limit);
7357
+ params.push(assertRowLimit('limit', filter.limit));
7309
7358
  }
7310
7359
  const rows = this.directory.prepare(sql).all(...params);
7311
7360
  // Reading the audit trail is itself audited. Who examined the record of
@@ -7347,17 +7396,19 @@ export class SqliteScopeHost {
7347
7396
  // resolved issue; an ignored one stays ignored — that is what ignoring means.
7348
7397
  this.directory
7349
7398
  .prepare(`INSERT INTO _substrat_issues
7350
- (fingerprint, operation, stage, origin, code, status, seen_count, first_seen, last_seen, last_message, last_vertical, last_version, resolved_version, resolved_at)
7351
- VALUES (?, ?, ?, ?, ?, 'new', 1, ?, ?, ?, ?, ?, NULL, NULL)
7399
+ (fingerprint, operation, stage, origin, code, status, seen_count, first_seen, last_seen, last_message, last_tenant_id, last_owner_kind, last_vertical, last_version, resolved_version, resolved_at)
7400
+ VALUES (?, ?, ?, ?, ?, 'new', 1, ?, ?, ?, ?, ?, ?, ?, NULL, NULL)
7352
7401
  ON CONFLICT (fingerprint) DO UPDATE SET
7353
7402
  seen_count = seen_count + 1,
7354
7403
  last_seen = excluded.last_seen,
7355
7404
  last_message = excluded.last_message,
7405
+ last_tenant_id = excluded.last_tenant_id,
7406
+ last_owner_kind = excluded.last_owner_kind,
7356
7407
  last_vertical = COALESCE(excluded.last_vertical, last_vertical),
7357
7408
  last_version = COALESCE(excluded.last_version, last_version),
7358
7409
  origin = COALESCE(excluded.origin, origin),
7359
7410
  status = CASE WHEN status = 'resolved' THEN 'regressed' ELSE status END`)
7360
- .run(fingerprint, entry.operation, entry.stage ?? null, entry.origin ?? null, entry.code ?? null, at, at, entry.message.slice(0, 2000), entry.vertical ?? null, entry.version ?? null);
7411
+ .run(fingerprint, entry.operation, entry.stage ?? null, entry.origin ?? null, entry.code ?? null, at, at, entry.message.slice(0, 2000), entry.tenantId ?? null, issueExemplarOwner(entry.tenantId ?? null), entry.vertical ?? null, entry.version ?? null);
7361
7412
  const issueHorizon = new Date(Date.now() - ISSUE_RETENTION_DAYS * 86_400_000).toISOString();
7362
7413
  this.directory.prepare('DELETE FROM _substrat_issues WHERE last_seen < ?').run(issueHorizon);
7363
7414
  },
@@ -7416,7 +7467,7 @@ export class SqliteScopeHost {
7416
7467
  ` ORDER BY id ${order}`;
7417
7468
  if (filter?.limit !== undefined) {
7418
7469
  sql += ' LIMIT ?';
7419
- params.push(filter.limit);
7470
+ params.push(assertRowLimit('limit', filter.limit));
7420
7471
  }
7421
7472
  const rows = this.directory.prepare(sql).all(...params);
7422
7473
  // Rows can name tenants and scopes, so reading them is recorded like the
@@ -7490,7 +7541,7 @@ export class SqliteScopeHost {
7490
7541
  ` ORDER BY id ${order}`;
7491
7542
  if (filter?.limit !== undefined) {
7492
7543
  sql += ' LIMIT ?';
7493
- params.push(filter.limit);
7544
+ params.push(assertRowLimit('limit', filter.limit));
7494
7545
  }
7495
7546
  const rows = this.directory.prepare(sql).all(...params);
7496
7547
  // Rows can name tenants and scopes, so reading them is recorded (K-24).
@@ -7514,6 +7565,15 @@ export class SqliteScopeHost {
7514
7565
  at: r.at,
7515
7566
  }));
7516
7567
  },
7568
+ pruneTelemetry: async (_actor, limit) => {
7569
+ // A negative LIMIT is no limit at all to SQLite (#1632): refused before any statement.
7570
+ assertRowLimit('limit', limit);
7571
+ const pruned = { opsFailures: 0, issues: 0, sweepRuns: 0 };
7572
+ for (const { table, sql, params } of telemetryRetentionStatements(Date.now(), limit)) {
7573
+ pruned[table] = this.directory.prepare(sql).all(...params).length;
7574
+ }
7575
+ return pruned;
7576
+ },
7517
7577
  listIssues: async (actor, filter) => {
7518
7578
  const where = [];
7519
7579
  const params = [];
@@ -7534,7 +7594,7 @@ export class SqliteScopeHost {
7534
7594
  const sql = 'SELECT * FROM _substrat_issues' +
7535
7595
  (where.length ? ` WHERE ${where.join(' AND ')}` : '') +
7536
7596
  ' ORDER BY last_seen DESC, fingerprint LIMIT ?';
7537
- params.push(filter?.limit ?? 100);
7597
+ params.push(assertRowLimit('limit', filter?.limit ?? 100));
7538
7598
  const rows = this.directory.prepare(sql).all(...params);
7539
7599
  // Issues aggregate fleet-wide failures; the read is recorded like the rows' own (K-24).
7540
7600
  this.recordAccess(actor, 'listIssues', {}, filter, rows.length);
@@ -7603,8 +7663,10 @@ export class SqliteScopeHost {
7603
7663
  // Without case, as SQLite resolves a column name: a restore may have added this column
7604
7664
  // already, untyped and spelled as a newer kernel's dump spelled it (#1883).
7605
7665
  const existing = db.prepare(`PRAGMA table_info(${table})`).all().some((c) => c.name.toLowerCase() === column.toLowerCase());
7606
- if (!existing)
7607
- db.exec(`ALTER TABLE ${table} ADD COLUMN ${ddl}`);
7666
+ if (existing)
7667
+ return false;
7668
+ db.exec(`ALTER TABLE ${table} ADD COLUMN ${ddl}`);
7669
+ return true;
7608
7670
  }
7609
7671
  /**
7610
7672
  * #1288: `_substrat_schedule_state`, rebuilt with `kind` in its key on a scope db
@@ -7810,6 +7872,15 @@ export class SqliteScopeHost {
7810
7872
  // #1236: the regression's version pair, on a directory whose issues table predates it.
7811
7873
  this.ensureColumn(this.directory, '_substrat_issues', 'last_version', 'last_version TEXT');
7812
7874
  this.ensureColumn(this.directory, '_substrat_issues', 'resolved_version', 'resolved_version TEXT');
7875
+ // #1632: whose exemplar `last_message` is. Backfilled once, as the columns arrive, from
7876
+ // the retained ops-failure rows that prove it; every other row stays unknown. The columns
7877
+ // and the backfill commit together because this whole pass is `ensureDirectorySchema`'s
7878
+ // one transaction: the backfill's gate is "this call added the column", so a column
7879
+ // committed ahead of a backfill that then failed would read as migrated for good.
7880
+ this.ensureColumn(this.directory, '_substrat_issues', 'last_tenant_id', 'last_tenant_id TEXT');
7881
+ if (this.ensureColumn(this.directory, '_substrat_issues', 'last_owner_kind', 'last_owner_kind TEXT')) {
7882
+ this.directory.exec(ISSUE_EXEMPLAR_OWNER_BACKFILL_SQL);
7883
+ }
7813
7884
  this.directory.exec('CREATE INDEX IF NOT EXISTS _substrat_ops_failures_fingerprint ON _substrat_ops_failures (fingerprint, id)');
7814
7885
  // #1232: the drained batch's dedupe key, on a directory created before it. The
7815
7886
  // unique index rides here too — created after the column exists on every path.
@@ -8619,6 +8690,16 @@ function cellToJson(v) {
8619
8690
  return null;
8620
8691
  return v;
8621
8692
  }
8693
+ /** The kernel's erasure walks over one SQLite connection — a read returns its rows, a write none. */
8694
+ function redactionSqlOf(db) {
8695
+ return (sql, params) => {
8696
+ const stmt = db.prepare(sql);
8697
+ if (stmt.reader)
8698
+ return stmt.all(...params);
8699
+ stmt.run(...params);
8700
+ return [];
8701
+ };
8702
+ }
8622
8703
  /**
8623
8704
  * The connection module code holds. `guardSpine` is what makes "never write
8624
8705
  * `_substrat_*`" a mechanism rather than a lint rule (#954) — the kernel's own