@sema-agent/server 7.148.0 → 7.149.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/MIGRATION.md +429 -0
- package/README.md +16 -1
- package/README.zh-CN.md +4 -0
- package/USAGE.md +89 -55
- package/dist/adoption/wire.d.ts +3 -3
- package/dist/approval-card.d.ts +32 -32
- package/dist/approval-leg-origin.d.ts +33 -0
- package/dist/approval-leg-origin.js +4 -0
- package/dist/auth-bridge.d.ts +9 -1
- package/dist/auth-bridge.js +4 -4
- package/dist/auth-keys.d.ts +10 -1
- package/dist/auth-keys.js +8 -0
- package/dist/boot/execution-env.js +10 -11
- package/dist/boot/execution-lane.d.ts +6 -4
- package/dist/boot/execution-lane.js +3 -1
- package/dist/boot/org-delivery.d.ts +3 -2
- package/dist/boot/resolve-spec.js +6 -4
- package/dist/boot/runner-deps.js +3 -1
- package/dist/boot/stage-01-config.d.ts +1 -0
- package/dist/boot/stage-01-config.js +4 -3
- package/dist/boot/stage-02-web-admin-pull.d.ts +1 -0
- package/dist/boot/stage-02-web-admin-pull.js +10 -2
- package/dist/boot/stage-03-store-backend.d.ts +1 -0
- package/dist/boot/stage-03-store-backend.js +2 -2
- package/dist/boot/stage-04-stores.d.ts +1 -0
- package/dist/boot/stage-05-execution-env.d.ts +1 -0
- package/dist/boot/stage-06-runners.d.ts +2 -1
- package/dist/boot/stage-07-capability-layer.d.ts +2 -1
- package/dist/boot/stage-08-reapers.d.ts +2 -1
- package/dist/boot/stage-09-leader.d.ts +2 -1
- package/dist/boot/stage-10-http-server.d.ts +2 -1
- package/dist/boot/stores.d.ts +3 -0
- package/dist/boot/stores.js +22 -19
- package/dist/capabilities/tool-defer.d.ts +1 -1
- package/dist/capability-facts.d.ts +5 -4
- package/dist/capability-facts.js +3 -14
- package/dist/card-settle-stored-scope.d.ts +56 -0
- package/dist/card-settle-stored-scope.js +27 -0
- package/dist/card-void.d.ts +7 -12
- package/dist/card-void.js +2 -7
- package/dist/config-catalog.d.ts +12 -0
- package/dist/config-catalog.js +36 -32
- package/dist/config-invariants.d.ts +5 -4
- package/dist/config-invariants.js +4 -4
- package/dist/config-types.d.ts +37 -5
- package/dist/config.d.ts +6 -5
- package/dist/config.js +35 -24
- package/dist/context-window-notice.d.ts +31 -0
- package/dist/context-window-notice.js +28 -0
- package/dist/deployment-shape.d.ts +20 -11
- package/dist/deployment-shape.js +1 -0
- package/dist/env-name-allowlist-knobs.d.ts +6 -5
- package/dist/env-name-allowlist-knobs.js +5 -0
- package/dist/execution-lane-caps.d.ts +20 -5
- package/dist/execution-lane-caps.js +18 -4
- package/dist/hooks/command-spawn.d.ts +7 -2
- package/dist/hooks/command-spawn.js +13 -6
- package/dist/hooks/hook-runner.d.ts +5 -0
- package/dist/hooks/hook-runner.js +11 -7
- package/dist/http/admission.js +3 -3
- package/dist/http/approval-sweeps.js +3 -2
- package/dist/http/claim-heartbeat.d.ts +3 -3
- package/dist/http/claim-heartbeat.js +3 -3
- package/dist/http/claimed-run.d.ts +16 -9
- package/dist/http/claimed-run.js +8 -0
- package/dist/http/dispatch.js +5 -3
- package/dist/http/durable-run-leg.d.ts +8 -1
- package/dist/http/durable-run-leg.js +30 -11
- package/dist/http/execution-context.d.ts +115 -14
- package/dist/http/execution-context.js +130 -40
- package/dist/http/owner-access.d.ts +3 -2
- package/dist/http/owner-access.js +2 -3
- package/dist/http/principal-gate.d.ts +18 -11
- package/dist/http/principal-gate.js +3 -1
- package/dist/http/resume-ctx-read.d.ts +14 -3
- package/dist/http/resume-ctx-read.js +8 -2
- package/dist/http/resume-legs.d.ts +35 -3
- package/dist/http/resume-legs.js +244 -92
- package/dist/http/route-ctx.d.ts +6 -0
- package/dist/http/routes/a2a-serve.js +2 -0
- package/dist/http/routes/approvals-assistant.js +3 -2
- package/dist/http/routes/capabilities.js +1 -1
- package/dist/http/routes/diagnostics.d.ts +3 -1
- package/dist/http/routes/diagnostics.js +30 -5
- package/dist/http/routes/principal-inbox.d.ts +3 -1
- package/dist/http/routes/principal-inbox.js +3 -2
- package/dist/http/routes/runs.js +10 -7
- package/dist/http/routes/session-sync.d.ts +24 -5
- package/dist/http/routes/session-sync.js +46 -34
- package/dist/http/routes/sessions-list.d.ts +1 -1
- package/dist/http/routes/tasks.js +127 -93
- package/dist/http/server.d.ts +4 -5
- package/dist/http/server.js +30 -5
- package/dist/http/submit-ctx.d.ts +1 -0
- package/dist/http/submit-ctx.js +2 -3
- package/dist/index.d.ts +3 -1
- package/dist/index.js +1 -0
- package/dist/leg-facts.d.ts +7 -2
- package/dist/leg-facts.js +1 -0
- package/dist/local-store-declaration.d.ts +54 -0
- package/dist/local-store-declaration.js +59 -0
- package/dist/mcp-assertion-header.d.ts +1 -1
- package/dist/mcp-assertion-header.js +1 -1
- package/dist/memory-project-layer.js +1 -1
- package/dist/memory-scope.d.ts +4 -4
- package/dist/memory-scope.js +4 -4
- package/dist/memory-sync-client.js +2 -2
- package/dist/model-context-window.d.ts +50 -11
- package/dist/model-context-window.js +20 -1
- package/dist/model-entry-refusal.d.ts +5 -4
- package/dist/model-entry-refusal.js +17 -3
- package/dist/model-reach-scope.d.ts +2 -1
- package/dist/observability/fail-open.d.ts +14 -2
- package/dist/observability/fail-open.js +14 -2
- package/dist/observability/metrics.js +1 -1
- package/dist/observability/run-terminal.js +1 -0
- package/dist/observability/secret-env-scrub.d.ts +1 -1
- package/dist/observability/secret-env-scrub.js +1 -1
- package/dist/org-delivery-gate.d.ts +31 -6
- package/dist/org-delivery-gate.js +7 -4
- package/dist/owner-faces.d.ts +3 -2
- package/dist/park-row-commit.d.ts +67 -0
- package/dist/park-row-commit.js +76 -0
- package/dist/parked-decide.d.ts +9 -7
- package/dist/parked-decide.js +25 -6
- package/dist/peer-directory.d.ts +1 -1
- package/dist/plugins/adoption-log-sql.d.ts +3 -3
- package/dist/plugins/adoption-log-sql.js +19 -19
- package/dist/plugins/approval-ask-store-sql.d.ts +1 -1
- package/dist/plugins/approval-ask-store-sql.js +3 -5
- package/dist/plugins/approval-exemption-skill-cutoff.d.ts +64 -0
- package/dist/plugins/approval-exemption-skill-cutoff.js +122 -0
- package/dist/plugins/approval-exemption-skill-m46.d.ts +0 -6
- package/dist/plugins/approval-exemption-skill-m46.js +6 -10
- package/dist/plugins/approval-exemption-store.d.ts +26 -1
- package/dist/plugins/approval-exemption-store.js +28 -19
- package/dist/plugins/ensure-schema-lock-policy.d.ts +36 -3
- package/dist/plugins/ensure-schema-lock-policy.js +75 -9
- package/dist/plugins/file-run-store.d.ts +22 -9
- package/dist/plugins/file-run-store.js +50 -22
- package/dist/plugins/local-checkpoint-store.d.ts +4 -0
- package/dist/plugins/local-checkpoint-store.js +2 -1
- package/dist/plugins/local-data-root-admission.d.ts +52 -0
- package/dist/plugins/local-data-root-admission.js +100 -0
- package/dist/plugins/local-engine-high-water.d.ts +28 -7
- package/dist/plugins/local-engine-high-water.js +27 -22
- package/dist/plugins/local-session-store.d.ts +134 -49
- package/dist/plugins/local-session-store.js +149 -108
- package/dist/plugins/memory-run-store.d.ts +14 -9
- package/dist/plugins/memory-run-store.js +47 -21
- package/dist/plugins/one-time-migration-marker.d.ts +19 -3
- package/dist/plugins/one-time-migration-marker.js +7 -1
- package/dist/plugins/one-time-migrations.d.ts +46 -20
- package/dist/plugins/one-time-migrations.js +102 -79
- package/dist/plugins/org-delivery-quota-store.d.ts +34 -11
- package/dist/plugins/org-delivery-quota-store.js +29 -14
- package/dist/plugins/permission-rule-store-sql.d.ts +1 -1
- package/dist/plugins/permission-rule-store-sql.js +5 -9
- package/dist/plugins/pg-pool.d.ts +1 -1
- package/dist/plugins/pg-pool.js +10 -12
- package/dist/plugins/remote-env-device.d.ts +3 -2
- package/dist/plugins/remote-env-e2b.d.ts +1 -7
- package/dist/plugins/remote-env-e2b.js +10 -7
- package/dist/plugins/remote-env-host.d.ts +50 -9
- package/dist/plugins/remote-env-host.js +77 -20
- package/dist/plugins/remote-env-k8s.js +4 -2
- package/dist/plugins/remote-env-local-docker.d.ts +6 -3
- package/dist/plugins/remote-env-local-docker.js +8 -23
- package/dist/plugins/run-store-sql.d.ts +26 -7
- package/dist/plugins/run-store-sql.js +44 -16
- package/dist/plugins/scenario-prefix-switch-m42.d.ts +3 -1
- package/dist/plugins/scenario-prefix-switch-m42.js +4 -3
- package/dist/plugins/schema-consistency.d.ts +89 -5
- package/dist/plugins/schema-consistency.js +176 -7
- package/dist/plugins/schema-drift-sentence.d.ts +6 -5
- package/dist/plugins/schema-drift-sentence.js +13 -5
- package/dist/plugins/session-placement.d.ts +5 -4
- package/dist/plugins/shell-sentinel-owner-m48.d.ts +22 -0
- package/dist/plugins/shell-sentinel-owner-m48.js +6 -0
- package/dist/plugins/stop-then-start-sentence.d.ts +16 -0
- package/dist/plugins/stop-then-start-sentence.js +7 -0
- package/dist/plugins/store-backend.d.ts +22 -8
- package/dist/plugins/store-backend.js +58 -24
- package/dist/plugins/store-contracts.d.ts +33 -3
- package/dist/plugins/store-contracts.js +16 -0
- package/dist/plugins/tidb-pool.d.ts +11 -6
- package/dist/plugins/tidb-pool.js +18 -12
- package/dist/plugins/workspace-custody.d.ts +44 -0
- package/dist/plugins/workspace-custody.js +47 -0
- package/dist/project-identity.d.ts +8 -7
- package/dist/project-identity.js +40 -17
- package/dist/project-layer-key.d.ts +13 -2
- package/dist/project-layer-key.js +9 -1
- package/dist/read-deny-floor-notice.d.ts +36 -0
- package/dist/read-deny-floor-notice.js +40 -0
- package/dist/{plain-string-record.d.ts → request-declaration-disposition.d.ts} +9 -23
- package/dist/request-declaration-disposition.js +39 -0
- package/dist/run-cancel-card.d.ts +28 -0
- package/dist/run-cancel-card.js +19 -0
- package/dist/run-cancel-context.d.ts +10 -0
- package/dist/run-cancel-context.js +1 -0
- package/dist/run-local.js +28 -13
- package/dist/runs.d.ts +31 -7
- package/dist/runs.js +34 -16
- package/dist/security.d.ts +2 -2
- package/dist/server-secret-env.d.ts +34 -20
- package/dist/server-secret-env.js +61 -18
- package/dist/session-agent.d.ts +3 -2
- package/dist/session-children-retire.d.ts +6 -3
- package/dist/session-children-retire.js +2 -5
- package/dist/session-workspace.d.ts +3 -3
- package/dist/store-admission.d.ts +33 -0
- package/dist/store-admission.js +49 -0
- package/dist/store-posture.d.ts +5 -0
- package/dist/store-posture.js +18 -1
- package/dist/stores-sql/checkpoint-store-sql.d.ts +1 -1
- package/dist/stores-sql/checkpoint-store-sql.js +3 -5
- package/dist/stores-sql/file-history-store-sql.d.ts +1 -1
- package/dist/stores-sql/file-history-store-sql.js +3 -5
- package/dist/stores-sql/tool-result-store-sql.d.ts +1 -1
- package/dist/stores-sql/tool-result-store-sql.js +4 -6
- package/dist/task-a2a.d.ts +3 -8
- package/dist/task-a2a.js +25 -27
- package/dist/task-cwd.d.ts +23 -7
- package/dist/task-cwd.js +3 -0
- package/dist/task-mcp.d.ts +3 -3
- package/dist/task-mcp.js +1 -1
- package/dist/task-settings.js +1 -0
- package/dist/terminal.d.ts +2 -0
- package/dist/terminal.js +21 -6
- package/dist/tool-approval.d.ts +44 -36
- package/dist/tool-approval.js +66 -47
- package/dist/trace/engine-notice-wire.d.ts +24 -21
- package/dist/trace/engine-notice-wire.js +7 -3
- package/dist/trace/ledger-sink.d.ts +3 -1
- package/dist/trace/project.d.ts +4 -2
- package/dist/trace/project.js +8 -7
- package/dist/trace/redact.d.ts +12 -0
- package/dist/trace/redact.js +5 -1
- package/dist/trace/self-minted-wire.d.ts +131 -52
- package/dist/trace/self-minted-wire.js +71 -39
- package/dist/web-admin-client/apply-effective.js +22 -9
- package/docs/error-text-lexicon.json +317 -0
- package/package.json +3 -1
- package/scripts/embed-minimal.mjs +183 -0
- package/wire-changes/server@7.149.0.json +372 -0
- package/dist/plain-string-record.js +0 -70
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { recordEnsureStatements } from "./schema-ensure-legs.js";
|
|
2
2
|
import { readLiveColumns } from "./schema-live-columns.js";
|
|
3
3
|
import { SCHEMA_MISMATCH_WAYS_OUT } from "./schema-drift-sentence.js";
|
|
4
|
-
import { SCHEMA_MISMATCH_ERROR_CODE, StoreBootRefusalError } from "./store-contracts.js";
|
|
4
|
+
import { SCHEMA_MISMATCH_ERROR_CODE, SchemaMismatchRefusedError, StoreBootRefusalError } from "./store-contracts.js";
|
|
5
|
+
import { stopThenStartAction } from "./stop-then-start-sentence.js";
|
|
5
6
|
const QUOTES = new Set(["'", '"', "`"]);
|
|
6
7
|
function stripComments(sql) {
|
|
7
8
|
let out = "";
|
|
@@ -263,6 +264,117 @@ export function diffSchema(expected, live) {
|
|
|
263
264
|
}
|
|
264
265
|
return out;
|
|
265
266
|
}
|
|
267
|
+
function claimedColumnsOf(change) {
|
|
268
|
+
switch (change.kind) {
|
|
269
|
+
case "drop":
|
|
270
|
+
return change.columns;
|
|
271
|
+
case "rename":
|
|
272
|
+
return [...change.from, change.to];
|
|
273
|
+
case "add":
|
|
274
|
+
return [change.column];
|
|
275
|
+
case "rebuild":
|
|
276
|
+
return undefined;
|
|
277
|
+
default: {
|
|
278
|
+
const unhandled = change;
|
|
279
|
+
throw new Error(`unknown pending shape change ${JSON.stringify(unhandled)}`);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
const WHOLE_TABLE = "*";
|
|
284
|
+
function assertSingleOwnerPerShape(sources) {
|
|
285
|
+
const owners = new Map();
|
|
286
|
+
for (const s of sources) {
|
|
287
|
+
for (const change of s.shapeChanges ?? []) {
|
|
288
|
+
const table = owners.get(change.table) ?? new Map();
|
|
289
|
+
owners.set(change.table, table);
|
|
290
|
+
const columns = claimedColumnsOf(change);
|
|
291
|
+
const clashes = columns === undefined ? [...table.values()] : [table.get(WHOLE_TABLE), ...columns.map((c) => table.get(c))];
|
|
292
|
+
const clash = clashes.find((id) => id !== undefined && id !== s.id);
|
|
293
|
+
if (clash !== undefined)
|
|
294
|
+
throw new Error(`pending shape: table ${change.table} is changed by both ${clash} and ${s.id} on the same ${columns === undefined ? "table" : "column"} — one shape change has one migration`);
|
|
295
|
+
for (const c of columns ?? [WHOLE_TABLE])
|
|
296
|
+
table.set(c, s.id);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
function renamedColumn(dialect, old, declared) {
|
|
301
|
+
switch (dialect) {
|
|
302
|
+
case "mysql":
|
|
303
|
+
return declared();
|
|
304
|
+
case "pg":
|
|
305
|
+
return old;
|
|
306
|
+
default: {
|
|
307
|
+
const unhandled = dialect;
|
|
308
|
+
throw new Error(`unknown SQL dialect ${String(unhandled)}`);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
export function projectPendingShape(expected, live, sources, dialect) {
|
|
313
|
+
assertSingleOwnerPerShape(sources);
|
|
314
|
+
const out = new Map([...live].map(([t, cols]) => [t, new Map(cols)]));
|
|
315
|
+
const declaredNullable = (table, column) => {
|
|
316
|
+
const col = expected.get(table)?.columns.find((c) => c.name === column);
|
|
317
|
+
if (col === undefined)
|
|
318
|
+
throw new Error(`pending shape: ${table}.${column} is not declared by this build's schema — a migration can only bring a column the build declares`);
|
|
319
|
+
return { nullable: !declaresNotNull(col) };
|
|
320
|
+
};
|
|
321
|
+
const applied = new Set();
|
|
322
|
+
for (const s of sources) {
|
|
323
|
+
for (const change of s.shapeChanges ?? []) {
|
|
324
|
+
const before = live.get(change.table);
|
|
325
|
+
const after = out.get(change.table);
|
|
326
|
+
if (before === undefined || after === undefined)
|
|
327
|
+
continue;
|
|
328
|
+
switch (change.kind) {
|
|
329
|
+
case "drop": {
|
|
330
|
+
const present = change.columns.filter((c) => before.has(c));
|
|
331
|
+
for (const c of present)
|
|
332
|
+
after.delete(c);
|
|
333
|
+
if (present.length > 0)
|
|
334
|
+
applied.add(s.id);
|
|
335
|
+
break;
|
|
336
|
+
}
|
|
337
|
+
case "rename": {
|
|
338
|
+
const present = change.from.filter((c) => before.has(c));
|
|
339
|
+
if (before.has(change.to) || present.length !== 1)
|
|
340
|
+
break;
|
|
341
|
+
const [from] = present;
|
|
342
|
+
after.set(change.to, renamedColumn(dialect, before.get(from), () => declaredNullable(change.table, change.to)));
|
|
343
|
+
after.delete(from);
|
|
344
|
+
applied.add(s.id);
|
|
345
|
+
break;
|
|
346
|
+
}
|
|
347
|
+
case "add": {
|
|
348
|
+
if (before.has(change.column))
|
|
349
|
+
break;
|
|
350
|
+
const gate = change.whilePresent;
|
|
351
|
+
if (gate !== undefined && !gate.anyOf.some((c) => live.get(gate.table)?.has(c) === true))
|
|
352
|
+
break;
|
|
353
|
+
after.set(change.column, declaredNullable(change.table, change.column));
|
|
354
|
+
applied.add(s.id);
|
|
355
|
+
break;
|
|
356
|
+
}
|
|
357
|
+
case "rebuild": {
|
|
358
|
+
if (!before.has(change.whilePresent))
|
|
359
|
+
break;
|
|
360
|
+
const shape = expected.get(change.table);
|
|
361
|
+
if (shape === undefined)
|
|
362
|
+
throw new Error(`pending shape: ${change.table} is rebuilt by ${s.id} but this build declares no such table`);
|
|
363
|
+
if (shape.columns.some((c) => !change.supplies.includes(c.name) && !before.has(c.name)))
|
|
364
|
+
break;
|
|
365
|
+
out.set(change.table, new Map(shape.columns.map((c) => [c.name, { nullable: !declaresNotNull(c) }])));
|
|
366
|
+
applied.add(s.id);
|
|
367
|
+
break;
|
|
368
|
+
}
|
|
369
|
+
default: {
|
|
370
|
+
const unhandled = change;
|
|
371
|
+
throw new Error(`unknown pending shape change ${JSON.stringify(unhandled)}`);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
return { projected: out, appliedBy: sources.filter((s) => applied.has(s.id)).map((s) => s.id) };
|
|
377
|
+
}
|
|
266
378
|
function tightenLines(dialect, table, c) {
|
|
267
379
|
switch (dialect) {
|
|
268
380
|
case "pg":
|
|
@@ -337,34 +449,91 @@ export function describeMismatchedTables(dialect, mismatches) {
|
|
|
337
449
|
lines.push("", ...SCHEMA_MISMATCH_WAYS_OUT);
|
|
338
450
|
return lines;
|
|
339
451
|
}
|
|
340
|
-
|
|
452
|
+
function needsStatements(mismatches) {
|
|
453
|
+
return mismatches.some((m) => m.missing.length > 0 || m.tightened.length > 0);
|
|
454
|
+
}
|
|
455
|
+
export async function describeUpgradeChecklist(mismatches) {
|
|
456
|
+
if (!needsStatements(mismatches))
|
|
457
|
+
return [];
|
|
458
|
+
const { stopThenStartMigrations } = await import("./one-time-migrations.js");
|
|
459
|
+
const stops = stopThenStartMigrations();
|
|
460
|
+
const steps = [["Run every statement printed below, each recipe in the order it is printed (a printed comment line marks a value only you can choose) — all tables at once, before anything else (this build never alters a database for you)."]];
|
|
461
|
+
if (stops.length > 0) {
|
|
462
|
+
steps.push([
|
|
463
|
+
"Stop-then-start one-time migrations: this build runs them itself on its first boot (no statement from you), and each refuses to start — writing nothing — while any run on this database has",
|
|
464
|
+
"heartbeated within REAP_RUN_STALE_SEC. A database that has already been through one of them is not asked again.",
|
|
465
|
+
...stops.map((m) => ` - ${m.id}: ${m.reason}`),
|
|
466
|
+
stopThenStartAction(),
|
|
467
|
+
]);
|
|
468
|
+
}
|
|
469
|
+
steps.push(["Start this version; the one-time migrations above (if any are still owed) run on that boot."]);
|
|
470
|
+
return [
|
|
471
|
+
"Upgrade checklist — everything this build needs from you on this database, in this order (one start lists all of it; do not fix one table and retry):",
|
|
472
|
+
...steps.flatMap((lines, i) => lines.map((l, k) => (k === 0 ? ` ${i + 1}. ${l}` : ` ${l}`))),
|
|
473
|
+
];
|
|
474
|
+
}
|
|
475
|
+
export function describeSchemaMismatch(dialect, mismatches, checklist = []) {
|
|
341
476
|
const lines = [
|
|
342
477
|
`${SCHEMA_MISMATCH_ERROR_CODE}: the ${dialect === "pg" ? "PostgreSQL" : "MySQL-protocol"} database does not match this build's schema — refusing to start.`,
|
|
343
478
|
"Schema policy: the code is the single source of truth, and the column check that produced this refusal never alters a database —",
|
|
344
479
|
"so a drifted database is a deployment-order problem, not something the process may quietly work around.",
|
|
345
480
|
"",
|
|
481
|
+
...(checklist.length > 0 ? [...checklist, ""] : []),
|
|
346
482
|
...describeMismatchedTables(dialect, mismatches),
|
|
347
483
|
];
|
|
348
484
|
return lines.join("\n");
|
|
349
485
|
}
|
|
350
|
-
export async function
|
|
486
|
+
export async function statementBearing(expected, live, dialect) {
|
|
487
|
+
const { ONE_TIME_MIGRATIONS } = await import("./one-time-migrations.js");
|
|
488
|
+
return diffSchema(expected, projectPendingShape(expected, live, ONE_TIME_MIGRATIONS, dialect).projected)
|
|
489
|
+
.map((m) => ({ ...m, ghost: [] }))
|
|
490
|
+
.filter((m) => m.missing.length > 0 || m.tightened.length > 0);
|
|
491
|
+
}
|
|
492
|
+
export async function describeUpgradeBody(dialect, mismatches) {
|
|
493
|
+
const checklist = await describeUpgradeChecklist(mismatches);
|
|
494
|
+
return [...(checklist.length > 0 ? [...checklist, ""] : []), ...describeMismatchedTables(dialect, mismatches)];
|
|
495
|
+
}
|
|
496
|
+
export const DRIFT_TAIL_DEADLINE_MS = 10_000;
|
|
497
|
+
export async function describeUpgradeDriftTail(read, dialect, deadlineMs = DRIFT_TAIL_DEADLINE_MS) {
|
|
498
|
+
let mismatches;
|
|
499
|
+
let timer;
|
|
500
|
+
try {
|
|
501
|
+
const work = (async () => statementBearing(await expectedTableShapes(dialect), await readLiveColumns(read, dialect), dialect))();
|
|
502
|
+
work.catch(() => undefined);
|
|
503
|
+
const expired = new Promise((_, reject) => {
|
|
504
|
+
timer = setTimeout(() => reject(new Error(`no answer within ${deadlineMs} ms`)), deadlineMs);
|
|
505
|
+
timer.unref?.();
|
|
506
|
+
});
|
|
507
|
+
mismatches = await Promise.race([work, expired]);
|
|
508
|
+
}
|
|
509
|
+
catch (err) {
|
|
510
|
+
return `\n\nThe column check could not be read here (${err instanceof Error ? err.message : String(err)}), so any ALTER this database still owes is not listed in this refusal — the column check at boot lists them.`;
|
|
511
|
+
}
|
|
512
|
+
finally {
|
|
513
|
+
clearTimeout(timer);
|
|
514
|
+
}
|
|
515
|
+
if (mismatches.length === 0)
|
|
516
|
+
return "";
|
|
517
|
+
return `\n\nThis database also does not match this build's schema — the statements below are the ones the column check prints at boot:\n${(await describeUpgradeBody(dialect, mismatches)).join("\n")}`;
|
|
518
|
+
}
|
|
519
|
+
export async function assertSchemaMatchesCode(read, dialect, pending) {
|
|
351
520
|
const expected = await expectedTableShapes(dialect);
|
|
352
521
|
let live;
|
|
353
522
|
try {
|
|
354
523
|
live = await readLiveColumns(read, dialect);
|
|
355
524
|
}
|
|
356
525
|
catch (err) {
|
|
357
|
-
throw new
|
|
526
|
+
throw new SchemaMismatchRefusedError(`${SCHEMA_MISMATCH_ERROR_CODE}: could not read information_schema.columns to verify the ${dialect} schema — refusing to start ` +
|
|
358
527
|
`(an unverifiable schema is treated as a mismatch, not as a pass): ${err instanceof Error ? err.message : String(err)}`, { cause: err });
|
|
359
528
|
}
|
|
360
529
|
if (live.size === 0) {
|
|
361
|
-
throw new
|
|
530
|
+
throw new SchemaMismatchRefusedError(`${SCHEMA_MISMATCH_ERROR_CODE}: information_schema.columns returned no rows anywhere on this ${dialect} connection's schema path — refusing to start. ` +
|
|
362
531
|
`Either the connection points at an empty/foreign schema, or the account cannot see its own catalog; both make the ` +
|
|
363
532
|
`"database matches the code" check unprovable, and an unprovable protective check never passes.`);
|
|
364
533
|
}
|
|
365
|
-
const mismatches = diffSchema(expected, live);
|
|
534
|
+
const mismatches = diffSchema(expected, projectPendingShape(expected, live, pending, dialect).projected);
|
|
366
535
|
if (mismatches.length > 0)
|
|
367
|
-
throw new
|
|
536
|
+
throw new SchemaMismatchRefusedError(describeSchemaMismatch(dialect, mismatches, await describeUpgradeChecklist(mismatches)));
|
|
368
537
|
}
|
|
369
538
|
const RETIRED_SNAPSHOT_TABLE = "snapshot_manifest";
|
|
370
539
|
const RETIRED_STEER_SEAT = { table: "checkpoint", column: "pending_steer" };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { SqlDialect } from "./sql-driver.js";
|
|
2
|
+
import { SchemaMismatchRefusedError } from "./store-contracts.js";
|
|
2
3
|
/** 「库比构建旧」那一条出路的两个可变件:旧在哪(括注)、部署者要自己做的那件事。其余字一个不变。 */
|
|
3
4
|
export interface OlderWayOut {
|
|
4
5
|
/** 括注:库旧在哪(例:`missing columns`)。 */
|
|
@@ -20,11 +21,11 @@ export declare const SCHEMA_MISMATCH_WAYS_OUT: readonly string[];
|
|
|
20
21
|
export type ProbeQuery = (sql: string) => Promise<{
|
|
21
22
|
rows: Record<string, unknown>[];
|
|
22
23
|
}>;
|
|
24
|
+
/** 单表探针的拒启(缺列、键宽不够)的出口:`body` 是码之后的整句,码在这里领头 —— 各探针不自己拼码。 */
|
|
25
|
+
export declare function schemaMismatchRefusal(body: string): SchemaMismatchRefusedError;
|
|
23
26
|
/**
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* 读不出库的列册(权限 / 超时)或对账看不到探针点名的表有缺列(探针与建表语句互相矛盾)⇒ **响亮**地说「ALTER 没能打印」及原因,
|
|
27
|
-
* 出路仍是同一份闭集(旧一条改成「按建表语句自己加」)—— 绝不退回销毁性指路,也不悄悄吞掉这一段。
|
|
27
|
+
* 单表探针抓到可证缺列后的**整条拒启**(唯一铸点;`throw await probedMissingColumnRefusal(…)`):探针自己的首句 `lead`(这张表缺什么、缺了会在哪里坏;不带码、不带换行收尾)
|
|
28
|
+
* + 底层驱动错误 `underlying`(运维要看见是哪条探针读撞的)+ {@link describeProbedTableDrift} 的逐表段与闭集出路,码领头({@link schemaMismatchRefusal})。
|
|
28
29
|
*/
|
|
29
|
-
export declare function
|
|
30
|
+
export declare function probedMissingColumnRefusal(query: ProbeQuery, dialect: SqlDialect, tables: readonly string[], lead: string, underlying: unknown): Promise<SchemaMismatchRefusedError>;
|
|
30
31
|
//# sourceMappingURL=schema-drift-sentence.d.ts.map
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { readLiveColumns } from "./schema-live-columns.js";
|
|
2
|
+
import { SCHEMA_MISMATCH_ERROR_CODE, SchemaMismatchRefusedError } from "./store-contracts.js";
|
|
2
3
|
export function schemaWaysOut(older) {
|
|
3
4
|
return [
|
|
4
5
|
" Ways out (these three and no others):",
|
|
@@ -11,16 +12,23 @@ export const SCHEMA_MISMATCH_WAYS_OUT = schemaWaysOut({
|
|
|
11
12
|
when: "missing columns, or columns that allow NULL where this build declares NOT NULL",
|
|
12
13
|
action: "run the statements printed above yourself (where a column needs a value this build cannot choose for rows already in the table, the printed comment says so and that value is yours; this refusal stays until every printed statement has taken effect)",
|
|
13
14
|
});
|
|
14
|
-
export
|
|
15
|
+
export function schemaMismatchRefusal(body) {
|
|
16
|
+
return new SchemaMismatchRefusedError(`${SCHEMA_MISMATCH_ERROR_CODE}: ${body}`);
|
|
17
|
+
}
|
|
18
|
+
export async function probedMissingColumnRefusal(query, dialect, tables, lead, underlying) {
|
|
19
|
+
return schemaMismatchRefusal(`${lead}\n` +
|
|
20
|
+
`Underlying probe error: ${underlying instanceof Error ? underlying.message : String(underlying)}\n\n` +
|
|
21
|
+
(await describeProbedTableDrift(query, dialect, tables)));
|
|
22
|
+
}
|
|
23
|
+
async function describeProbedTableDrift(query, dialect, tables) {
|
|
15
24
|
const d = dialect === "pg" ? "pg" : "mysql";
|
|
16
25
|
const read = async (sql) => (await query(sql)).rows;
|
|
17
26
|
let why;
|
|
18
27
|
try {
|
|
19
28
|
const sc = await import("./schema-consistency.js");
|
|
20
|
-
const diff = sc.
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
return sc.describeMismatchedTables(d, missingOnly).join("\n");
|
|
29
|
+
const diff = await sc.statementBearing(await sc.expectedTableShapes(d), await readLiveColumns(read, d), d);
|
|
30
|
+
if (diff.some((m) => tables.includes(m.table) && m.missing.length > 0))
|
|
31
|
+
return (await sc.describeUpgradeBody(d, diff)).join("\n");
|
|
24
32
|
why = "this build's table definitions list no column that the database lacks on that table, so the probe and the definitions disagree";
|
|
25
33
|
}
|
|
26
34
|
catch (err) {
|
|
@@ -37,8 +37,9 @@ import { type PlacedSessionRow, type SessionPlacement, type SessionPlacementReco
|
|
|
37
37
|
import type { ForkPlacement } from "./session-fork.js";
|
|
38
38
|
/**
|
|
39
39
|
* 三只持久会话店(SQL 两孪生 + local 后端)的**会话耐久声明**(core `SessionStore.durability`:未 placed 的会话活不活过进程重启)——
|
|
40
|
-
*
|
|
41
|
-
*
|
|
40
|
+
* **单源**:两孪生类上的顶层 `durability` 与委派分区的 {@link SESSION_PLACEMENTS} 引用的都是这一只常量;local 后端交给两半店(会话店顶层、
|
|
41
|
+
* 检查点店)的声明由 `local-store-declaration.ts` 的读者定,它的「店型的设计声明」一臂就是这一只常量(运维声明易失 / 店落在调用方自己那块易失盘上 ⇒ `process-local`)。
|
|
42
|
+
* 源码里不再有第二份 `"durable"` 字面(`test/session-store-durability-declaration.test.ts` 的 AST 钉)。
|
|
42
43
|
*
|
|
43
44
|
* 为什么必须声明:core 的静态装配对**缺席**折 `"process-local"`(它不能替没表态的店猜),接线清单 `session.store` 与起服自检读的就是它 ——
|
|
44
45
|
* 不声明 ⇒ 一个真持久的 SQL 部署读成「重启即丢」,没有任何一处报错。依据同下面分区声明那一段:两孪生的会话史落在 `session_meta` + `session_event` 两张真表,
|
|
@@ -47,8 +48,8 @@ import type { ForkPlacement } from "./session-fork.js";
|
|
|
47
48
|
*/
|
|
48
49
|
export declare const SESSION_DURABILITY: "durable";
|
|
49
50
|
/**
|
|
50
|
-
*
|
|
51
|
-
*
|
|
51
|
+
* 两支 SQL 孪生的 placement **声明**(core `SessionStore.placements`,类上的字段)。local 后端装配 `LocalSessionStore` 时交进去的分区声明与它同形,
|
|
52
|
+
* 耐久取 local 店的那一份声明(`local-store-declaration.ts`;设计声明一臂与这里同值,与 core `FileStorageBackend` 对同一种文件 repo 的声明同)。
|
|
52
53
|
*
|
|
53
54
|
* 🔴 声明制,不是鸭子类型:core 的铸造门判「row store ∧ session 店声明」,不声明的店**不收** placed
|
|
54
55
|
* 语义(合法降级:placement 参数被忽略,会话就是普通会话)。所以这一格只有在上面六条义务**全部**在
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { SqlDialect } from "./sql-driver.js";
|
|
1
2
|
/**
|
|
2
3
|
* 一次性迁移 **M48** 的唯一属主(窗、删法与删后谁接住:窗口见 `plugins/one-time-migrations.ts` 登记表;随 M48 删整个文件)。
|
|
3
4
|
*
|
|
@@ -13,8 +14,29 @@
|
|
|
13
14
|
* 改写面 = 曾放那一格的读面读属主的那几处:SQL `session_meta` / `task_run` / `leader_run` 的 `owner` 列;local 会话元数据边档那一格的 `owner`、
|
|
14
15
|
* `FileRunStore` 的 run 行 `owner`(local 没有 leader run 店)。不改的(如实):规则行(存在哨兵键下的规则此前也不对无主体任务生效,改键 = 放宽,不做)、
|
|
15
16
|
* 收件箱条目 / 问账行 / 检查点 scope(这些读面从没放过那一格)。
|
|
17
|
+
*
|
|
18
|
+
* **有身份边界的部署不改写,但不零信号**:部署形读数取自**起服的那一个进程**的配置,而改写落在整只库 / 数据根上、不可逆 ⇒ 同一只库 / 根被身份配置不同的进程打开
|
|
19
|
+
* (`run-local` 不带服务凭据 / 桥、嵌入方先于验签器装配的起服序列、连着共享库的临时进程)时,一样身份键都不带的那个进程先起,会替有边界的服务进程把行改成无主(边界是任一身份来源在的并 —— 改写只在一样都没有时发生)。
|
|
20
|
+
* 有边界的进程自己只看见「零改写」,不数一数就不知道库里还留着多少行 ⇒ 那一臂对**同一批改写面**用**同一个比较**数一遍(不写,不改),读数 {@link ShellSentinelOwnerRowsRetained}
|
|
21
|
+
* 逐面列非零的计数,起服日志一行 warn(`shell_sentinel_rows_retained`)。比较只有一份:SQL 的 {@link shellSentinelOwnerWhereM48}(改写的 `UPDATE` 与计数的 `SELECT COUNT(*)` 共用),
|
|
22
|
+
* local 的 {@link isShellSentinelOwnerM48}(会话元数据格与 run 行的改写和计数共用)。
|
|
16
23
|
*/
|
|
17
24
|
export declare const SHELL_SENTINEL_OWNER_M48 = "anon:shell-live";
|
|
18
25
|
/** SQL 腿改写 `owner` 列的表(曾放那一格的读面读属主的表;local 腿的对应面见文件头)。 */
|
|
19
26
|
export declare const SHELL_SENTINEL_OWNER_TABLES_M48: readonly ["session_meta", "task_run", "leader_run"];
|
|
27
|
+
/** 改写面的词(留存读数与日志的逐面计数键):SQL = 表名;local 腿借同一组词 —— `session_meta` = 会话元数据格、`task_run` = run 行(local 没有 leader run 店 ⇒ 不出 `leader_run`)。 */
|
|
28
|
+
export type ShellSentinelOwnerSurfaceM48 = (typeof SHELL_SENTINEL_OWNER_TABLES_M48)[number];
|
|
29
|
+
/** 留存读数的一只:有身份边界的部署上,这一面还留着多少行哨兵属主(只列非零的面)。 */
|
|
30
|
+
export interface ShellSentinelOwnerRowsRetained {
|
|
31
|
+
readonly surface: ShellSentinelOwnerSurfaceM48;
|
|
32
|
+
readonly rows: number;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* SQL 腿「这一行是哨兵属主」的比较(**唯一一份**;改写的 `UPDATE … SET owner = NULL WHERE <此>` 与留存计数的 `SELECT COUNT(*) … WHERE <此>` 共用,绑定参数同为 {@link SHELL_SENTINEL_OWNER_M48})。
|
|
36
|
+
* 值**逐字节**比:MySQL 协议的 `utf8mb4_bin` 是 PAD SPACE(`'a' = 'a '`),普通等值会把只差尾空格的另一位属主(合法主体名)也当哨兵 ——
|
|
37
|
+
* 与 M17 / M18 的 CAS 同一写法 `CAST(… AS BINARY)`;PG `text` 等值本就逐字节。
|
|
38
|
+
*/
|
|
39
|
+
export declare function shellSentinelOwnerWhereM48(dialect: SqlDialect): string;
|
|
40
|
+
/** local 腿「这一行 / 格的属主是哨兵」的比较(**唯一一份**;会话元数据格与 run 行的改写、留存计数共用 —— 严格相等,与 SQL 腿的逐字节比同义)。 */
|
|
41
|
+
export declare function isShellSentinelOwnerM48(owner: string | null | undefined): boolean;
|
|
20
42
|
//# sourceMappingURL=shell-sentinel-owner-m48.d.ts.map
|
|
@@ -1,3 +1,9 @@
|
|
|
1
1
|
export const SHELL_SENTINEL_OWNER_M48 = "anon:shell-live";
|
|
2
2
|
export const SHELL_SENTINEL_OWNER_TABLES_M48 = ["session_meta", "task_run", "leader_run"];
|
|
3
|
+
export function shellSentinelOwnerWhereM48(dialect) {
|
|
4
|
+
return dialect === "mysql" ? "CAST(owner AS BINARY) = CAST(? AS BINARY)" : "owner = $1";
|
|
5
|
+
}
|
|
6
|
+
export function isShellSentinelOwnerM48(owner) {
|
|
7
|
+
return owner === SHELL_SENTINEL_OWNER_M48;
|
|
8
|
+
}
|
|
3
9
|
//# sourceMappingURL=shell-sentinel-owner-m48.js.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 「停-迁-起」那一段的**唯一属主**。
|
|
3
|
+
*
|
|
4
|
+
* 一次性迁移里有几条(登记表 `stopThenStart` 一格点名的)改的是更早版本的副本还会继续写的形:改完之后它再写一笔,这一笔读不出 / 丢掉。它们没有运行期开关,
|
|
5
|
+
* 起服时由守卫判 —— 判活窗内(`REAP_RUN_STALE_SEC`,收割器判 run 持有者还活着的同一个窗)库里还有 `running` run 在心跳 ⇒ 拒启、一字节不写。
|
|
6
|
+
* 四只守卫(M40 · M41 · M42 · M51)的拒句和起服列册对账的升级清单**说同一件事**:先停光更早版本的副本、等满判活窗、再起本版。
|
|
7
|
+
* 这件事的句子只在这里写一遍;各守卫只讲「为什么这一条要停」,不各抄一份动作段。
|
|
8
|
+
*
|
|
9
|
+
* 叶子模块:零 import(守卫所在的一次性迁移文件、M42 的拒句文件与列册对账都静态 import 它,不成环)。
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* 动作段:停光 → 等窗 → 再起。`after` = 全停之后可以再起的最早时刻(守卫读到的最新心跳 + 判活窗,人读形);
|
|
13
|
+
* 缺席 ⇒ 读不到具体心跳(列册对账的清单:此刻没有守卫在判),只说「等满判活窗」。
|
|
14
|
+
*/
|
|
15
|
+
export declare function stopThenStartAction(after?: string): string;
|
|
16
|
+
//# sourceMappingURL=stop-then-start-sentence.d.ts.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export function stopThenStartAction(after) {
|
|
2
|
+
return ("Stop every replica of the earlier version, then start this version (stop, migrate, start — this release cannot be rolled across replicas of both versions). " +
|
|
3
|
+
(after === undefined
|
|
4
|
+
? "Wait out the heartbeat window (REAP_RUN_STALE_SEC) after the last replica stops, then start this version."
|
|
5
|
+
: `If every replica is already stopped, those are the runs they left behind: start this version again after ${after}`));
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=stop-then-start-sentence.js.map
|
|
@@ -9,6 +9,7 @@ import { type RunStallWiring } from "./store-contracts.js";
|
|
|
9
9
|
import { type StoreOpenLane } from "./store-open-refusal.js";
|
|
10
10
|
import { type OneTimeMigrationReport, type SqlOneTimeMigrationInput } from "./one-time-migrations.js";
|
|
11
11
|
import { LocalSessionStore } from "./local-session-store.js";
|
|
12
|
+
import { type LocalStoreDeclaration } from "../local-store-declaration.js";
|
|
12
13
|
import type { LocalSessionRows } from "./local-session-window.js";
|
|
13
14
|
import type { SessionHeadReader } from "./caching-session-store.js";
|
|
14
15
|
import { LocalCheckpointStore } from "./local-checkpoint-store.js";
|
|
@@ -41,9 +42,10 @@ import { type SqlTransactionHooks } from "../stores-sql/retention-store-sql.js";
|
|
|
41
42
|
import type { SessionEraser } from "../session-erase.js";
|
|
42
43
|
import { type RetentionDestructiveInput, type RetentionExecutor, type RetentionExecutorOptions } from "./retention-deployment.js";
|
|
43
44
|
import { type RetentionLaneStore } from "./retention-lane-store-sql.js";
|
|
45
|
+
import { type LocalDataRootAdmission } from "./local-data-root-admission.js";
|
|
44
46
|
import type { PermissionRuleStoreBundle } from "../rules-consent.js";
|
|
45
47
|
import { type SqlDriver } from "./sql-driver.js";
|
|
46
|
-
import { type StoreDegradedReason } from "../store-posture.js";
|
|
48
|
+
import { type StoreDegradedReason, type StoreDurability as MediumDurability } from "../store-posture.js";
|
|
47
49
|
/** boot 期的一条日志座(级别由**座位**决定,不由参数携带):`createStoreBackend` 的 `onWarn` / `onError`
|
|
48
50
|
* 两参与 `LocalBackend` 的同名字段共用此形。装配层把它们分别接到 `logger.warn` / `logger.error` 上。 */
|
|
49
51
|
export type BootLogSink = (msg: string, meta?: Record<string, unknown>) => void;
|
|
@@ -54,6 +56,10 @@ export type BootLogSink = (msg: string, meta?: Record<string, unknown>) => void;
|
|
|
54
56
|
export interface StoreBackendObservers {
|
|
55
57
|
readonly runStallVerdicts?: (landed: number) => void;
|
|
56
58
|
}
|
|
59
|
+
/** 开店时递进来的起服事实(只 local 腿读):数据根介质的判定(起服第 2 段的取证;缺席 = 这条入口没有起服证据 ⇒ 按 `unknown` 读 —— 判不出的介质不放宽 local 店的声明)。 */
|
|
60
|
+
export interface StoreOpenFacts {
|
|
61
|
+
readonly dataRootMedium?: MediumDurability;
|
|
62
|
+
}
|
|
57
63
|
/** run 店落死亡判决的两样:窗 = 后端持有的配置对象的 `runStaleSec`(热发布原地改写 ⇒ getter 读到热值;判活窗只有这一个来源)+ 计数座。 */
|
|
58
64
|
export declare function createRunStallWiring(config: Pick<ServiceConfig, "runStaleSec">, observers: StoreBackendObservers | undefined): RunStallWiring;
|
|
59
65
|
export type RunStore = TiDBRunStore | PgRunStore | FileRunStore;
|
|
@@ -426,6 +432,8 @@ export interface StoreBackend {
|
|
|
426
432
|
* 拒绝句不带盘上位置)的同时,路径进本 backend 的 `file_store_corrupt_read` 披露座(逐命中 warn)。修前 `boot/stores.ts` 在同一数据根上自己
|
|
427
433
|
* `new FileUsageWindowStore(root)` 第二只实例、不接座 ⇒ 坏值只拒不披露,运维找不到是哪只文件。SQL 后端省略(它们有自己的 usage-window 双方言店)。 */
|
|
428
434
|
fileUsageWindowStore?(): UsageWindowStore;
|
|
435
|
+
/** **local 后端专有**:构造时交给两半店(会话店顶层、检查点店)的那一份声明(唯一读者 `localStoreDeclarationOf`)—— 装配值从这里读回,不重算。SQL 后端省略。 */
|
|
436
|
+
localStoreDeclaration?(): LocalStoreDeclaration;
|
|
429
437
|
}
|
|
430
438
|
/**
|
|
431
439
|
* 托管留存执行器的**组合**:引擎座表那一半(`SqlRetentionStore`,事务属主)+ 部署那一半(hold / 审计 / 认领判 / 十三张部署表,
|
|
@@ -517,25 +525,31 @@ export interface LocalStoreBackend extends StoreBackend {
|
|
|
517
525
|
toolResult(): ToolResultStoreFull;
|
|
518
526
|
/** local 后端恒有(引擎 File 后端的用量窗账本;接口上可选的那一口在这里必在)。 */
|
|
519
527
|
fileUsageWindowStore(): UsageWindowStore;
|
|
528
|
+
/** local 后端恒有(构造时交给两半店的声明;接口上可选的那一口在这里必在)。 */
|
|
529
|
+
localStoreDeclaration(): LocalStoreDeclaration;
|
|
520
530
|
}
|
|
521
531
|
/** 引擎 File 后端上会话店之外、本仓没有自己一份口的店(run-local 的 Runner 接它们;工具结果 / 用量窗 / 会话规则走既有的 `toolResult()` / `fileUsageWindowStore()` / `sessionPolicy()` 口)。 */
|
|
522
532
|
export type LocalEngineFileStores = Pick<FileStorageBackend, "checkpointStore" | "backgroundAgentStore" | "mailboxStore" | "rosterStore">;
|
|
523
533
|
/** 打开 local 数据根的入口参数:哪条路在开(只决定拒句的措辞 —— 表头与「换根」半句)与三只 boot 期日志座(见 {@link createStoreBackend})。 */
|
|
524
534
|
export interface LocalBackendOpenOptions {
|
|
525
535
|
readonly lane: StoreOpenLane;
|
|
536
|
+
/** 这只根的数据根准入读数(必填;{@link admitLocalDataRoot} 铸,调用方在它对这只根的第一笔写之前取 —— 打开就是第一笔写的调用方当场取,见 {@link createStoreBackend})。 */
|
|
537
|
+
readonly admission: LocalDataRootAdmission;
|
|
526
538
|
readonly onWarn?: BootLogSink;
|
|
527
539
|
readonly onError?: BootLogSink;
|
|
528
540
|
readonly observers?: StoreBackendObservers;
|
|
541
|
+
/** 起服事实(数据根介质的判定;HTTP 服务递第 2 段的取证,缺席 ⇒ `unknown`)。 */
|
|
542
|
+
readonly facts?: StoreOpenFacts;
|
|
529
543
|
}
|
|
530
544
|
/**
|
|
531
545
|
* **local 后端打开数据根**(唯一的路 —— 本仓每一条打开 local 数据根的入口都经它:`createStoreBackend` 的 local 腿(HTTP 服务)与 run-local;一个数据根一只会话行店、一份装配):
|
|
532
|
-
*
|
|
546
|
+
* 数据根准入(调用方交来的读数 `opts.admission`,判已在本进程第一笔写之前做完)→ 取锁(引擎 File 后端:建根、锁文件、引擎自己的店目录与空账本)→
|
|
547
|
+
* **锁内一步**({@link holdLocalDataRootAdmission}:核物理数据根与准入那一次观察都没动 → 跳版臂记 / 销账 → 抬引擎版本高水位)→ 本仓的店。
|
|
533
548
|
* 打开之后的公开序列两条入口相同:`ensureSchema()`(起服对账)→ `runOneTimeMigrations()` → 才读会话。
|
|
534
|
-
*
|
|
535
|
-
*
|
|
536
|
-
*
|
|
537
|
-
*
|
|
538
|
-
* 残余(如实):引擎 `FileStorageBackend` 的构造把取锁与它自己的店放在同一步(建子目录、店目录锁、撕裂账本尾的收拢)—— 那几笔在判之前,本仓在两者之间没有座(要 core 给)。
|
|
549
|
+
* 抬住在这里而不是 `ensureSchema()` 里,因为围栏以**第一笔落盘**界定:本仓的店在构造里就会写(撕裂的问账日志留证 + 压实、撕裂的 run 认领挪开、会话收尾的活跃边档落盘),
|
|
550
|
+
* 抬必须先于它们(写到一半崩了,水位已是本构建)。所以这一段之后才有店,没有任何一只店先于它。
|
|
551
|
+
* 锁内一步拒(准入判过的输入在准入之后被另一只引擎动过 / 记账或抬写不进)或本仓的店构造时抛 ⇒ 交回一只 {@link RefusedLocalBackend}:只握着锁,`ensureSchema()` 交出那一只拒
|
|
552
|
+
* (公开序列在它该在的那一步拒,降级臂按拒的族判),`close()` 只放锁 —— 没有店、没有收尾写。
|
|
539
553
|
*/
|
|
540
554
|
export declare function openLocalBackend(config: ServiceConfig, opts: LocalBackendOpenOptions): LocalStoreBackend;
|
|
541
555
|
/** Build the durable-store backend for `config.dbBackend`. Does NOT connect (the pool connects lazily); the next
|
|
@@ -573,7 +587,7 @@ export declare function localBackendRootOf(config: Pick<ServiceConfig, "localDat
|
|
|
573
587
|
export declare function openStoreBackendWithFallback(config: ServiceConfig, logger: {
|
|
574
588
|
warn: (msg: string, meta?: Record<string, unknown>) => void;
|
|
575
589
|
error?: (msg: string, meta?: Record<string, unknown>) => void;
|
|
576
|
-
}, observers?: StoreBackendObservers): Promise<{
|
|
590
|
+
}, observers?: StoreBackendObservers, localAdmission?: LocalDataRootAdmission, facts?: StoreOpenFacts): Promise<{
|
|
577
591
|
backend: StoreBackend | undefined;
|
|
578
592
|
degradedReason: StoreDegradedReason | undefined;
|
|
579
593
|
}>;
|