@zq-silk/yui 0.6.13 → 0.6.14
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/README.md +34 -5
- package/dist/cli/commandCatalog.js +173 -57
- package/dist/cli/helpRenderer.js +3 -1
- package/dist/cli.js +99 -11
- package/dist/commands/configCommands.js +521 -171
- package/dist/commands/deliveryGuardPreflight.js +2 -2
- package/dist/commands/executionAuditCommands.js +56 -3
- package/dist/commands/projectCommands.js +504 -2
- package/dist/commands/releaseCommands.js +0 -1
- package/dist/commands/taskActor.js +17 -0
- package/dist/commands/taskBaseCommands.js +29 -0
- package/dist/commands/taskCommands.js +577 -126
- package/dist/commands/taskContextCommand.js +36 -2
- package/dist/commands/taskNextActionCommand.js +48 -3
- package/dist/commands/taskPublicationCommands.js +319 -0
- package/dist/commands/taskRoleRuntimeStatus.js +83 -59
- package/dist/commands/telemetryCommands.js +14 -13
- package/dist/config/yuiConfig.js +161 -8
- package/dist/context/sessionContextBudget.js +68 -0
- package/dist/context/wakeNotification.js +65 -0
- package/dist/controller/clientRuntime.js +2 -1
- package/dist/controller/ephemeralResourceReaper.js +2 -1
- package/dist/controller/fileSchedulerStoreAdapter.js +183 -16
- package/dist/controller/jobSupervisor.js +5 -4
- package/dist/controller/resourceCleanupLinux.js +6 -6
- package/dist/controller/resourceInventoryLinux.js +3 -3
- package/dist/controller/runtime.js +88 -10
- package/dist/controller/updateReconciliation.js +4 -3
- package/dist/doctor/doctor.js +26 -7
- package/dist/executor/agentConfigurationCatalog.js +18 -0
- package/dist/executor/fileRoleLaunchPlanner.js +3 -3
- package/dist/lifecycle/contextBudgetRollover.js +81 -0
- package/dist/lifecycle/exactRunTerminalization.js +11 -1
- package/dist/lifecycle/providerErrorClass.js +33 -12
- package/dist/observability/executionAudit.js +214 -6
- package/dist/output/table.js +18 -0
- package/dist/repository/gitWorkspace.js +92 -0
- package/dist/repository/project.js +218 -4
- package/dist/repository/taskBaseFreshness.js +318 -0
- package/dist/repository/taskWorkspacePreparer.js +16 -2
- package/dist/review/deltaRecheck.js +232 -0
- package/dist/review/reviewConfig.js +31 -0
- package/dist/review/reviewFindingLedger.js +5 -1
- package/dist/review/reviewRound.js +156 -1
- package/dist/run/providerRetry.js +21 -3
- package/dist/run/providerRetryConfig.js +13 -60
- package/dist/run/recoveryProjection.js +199 -0
- package/dist/runtime/builtinAgentDrivers.js +3 -0
- package/dist/runtime/builtinTranscriptUsage.js +76 -32
- package/dist/runtime/continuationManager.js +17 -0
- package/dist/runtime/index.js +2 -0
- package/dist/runtime/launchDiagnostics.js +154 -0
- package/dist/runtime/lifecycleReservation.js +13 -0
- package/dist/runtime/providerContinuation.js +38 -0
- package/dist/runtime/providerContinuationReconciliationService.js +1 -0
- package/dist/runtime/providerErrorCodes.js +278 -0
- package/dist/runtime/runtimeHealthPolicy.js +20 -0
- package/dist/runtime/runtimeObservation.js +1 -0
- package/dist/runtime/runtimeProjection.js +115 -23
- package/dist/runtime/tmuxAdapters.js +242 -48
- package/dist/scheduler/activeRoleRunDelivery.js +139 -3
- package/dist/scheduler/activeTaskProgress.js +4 -3
- package/dist/scheduler/leaderWakeupProcessor.js +105 -15
- package/dist/scheduler/roleRunLiveness.js +2 -1
- package/dist/scheduler/roleRunStall.js +3 -2
- package/dist/scheduler/taskWake.js +72 -0
- package/dist/scheduler/wakeReason.js +64 -0
- package/dist/scheduler/wakeupQueue.js +2 -1
- package/dist/setup/setupCommand.js +1 -1
- package/dist/storage/migration/productionRegistry.js +325 -1
- package/dist/storage/sqliteSchema.js +61 -2
- package/dist/storage/sqliteStore.js +129 -2
- package/dist/storage/storeRpc.js +1 -0
- package/dist/storage/taskStore.js +262 -5
- package/dist/storage/upgrade/recordVersions.js +6 -1
- package/dist/storage/upgrade/sqliteStateMigration.js +22 -2
- package/dist/task/completionReadiness.js +282 -0
- package/dist/task/publicationReference.js +123 -0
- package/dist/task/taskRecordReference.js +3 -1
- package/dist/telemetry/telemetryConfig.js +23 -18
- package/dist/telemetry/telemetryWiring.js +8 -8
- package/dist/tmux/tmuxManager.js +50 -9
- package/dist/web/assets/client/i18n.js +4 -0
- package/dist/web/assets/client/view.js +18 -0
- package/dist/web/webSnapshot.js +100 -10
- package/i18n/README.zh-CN.md +5 -5
- package/package.json +1 -1
- package/skills/yui-leader/SKILL.md +49 -10
- package/skills/yui-operator/SKILL.md +13 -3
- package/skills/yui-worker/SKILL.md +8 -0
|
@@ -5,6 +5,7 @@ import { isDeepStrictEqual } from "node:util";
|
|
|
5
5
|
import { validateConfiguredAgent } from "../agent/agent.js";
|
|
6
6
|
import { validateCapabilityGrant } from "../grant/capabilityGrant.js";
|
|
7
7
|
import { validateReleaseWorkflow } from "../release/releaseWorkflow.js";
|
|
8
|
+
import { publicationExternalKey, validatePublicationReference } from "../task/publicationReference.js";
|
|
8
9
|
import { reconciliationIntervalMilliseconds, resolveLeaderNextActionMode, resolveResourcesGcAutoQuarantine, resolveResourcesGcMode } from "../config/yuiConfig.js";
|
|
9
10
|
import { resolveTimeZone } from "../output/timePresentation.js";
|
|
10
11
|
import { mailboxBatches, consumePendingBatch, mailboxHasWork, mailboxTargetKey, pendingLane, validateWorkMailbox } from "../coordination/workMailbox.js";
|
|
@@ -16,6 +17,7 @@ import { compareRuntimeSessionCandidates, projectRuntimeSessionCandidate } from
|
|
|
16
17
|
import { FileSessionOwnerRegistry } from "../runtime/sessionOwnerRegistry.js";
|
|
17
18
|
import { validateReviewConfig } from "../review/reviewConfig.js";
|
|
18
19
|
import { validateReviewRound } from "../review/reviewRound.js";
|
|
20
|
+
import { reviewFindingLedgerMode } from "../review/reviewFindingLedger.js";
|
|
19
21
|
import { sameTaskFinalReviewContract } from "../review/taskFinalReviewContract.js";
|
|
20
22
|
import { assertProjectCatalog, validateProject } from "../repository/project.js";
|
|
21
23
|
import { generateHomeIdentity, validateHomeIdentity } from "../repository/homeIdentity.js";
|
|
@@ -27,6 +29,7 @@ import { CURRENT_DURABLE_JOB_SCHEMA_VERSION, validDurableJobTransition, validate
|
|
|
27
29
|
import { validateGlobalRole, validateTaskRole } from "../role/role.js";
|
|
28
30
|
import { CURRENT_LEADER_FAILURE_SCHEMA_VERSION } from "../scheduler/leaderFailure.js";
|
|
29
31
|
import { CURRENT_OPERATOR_NOTIFICATION_SCHEMA_VERSION } from "../scheduler/operatorNotification.js";
|
|
32
|
+
import { CURRENT_TASK_WAKE_SCHEMA_VERSION, validateTaskWake } from "../scheduler/taskWake.js";
|
|
30
33
|
import { validateTask } from "../task/task.js";
|
|
31
34
|
import { formatAgentRunReceiptId, TASK_RECORD_ID_PREFIXES, validateTaskRecordReference } from "../task/taskRecordReference.js";
|
|
32
35
|
import { workItemExecutionGroupById, validateWorkItem } from "../workItem/workItem.js";
|
|
@@ -51,7 +54,7 @@ export const CURRENT_ACTIVE_RUN_POINTER_SCHEMA_VERSION = 3;
|
|
|
51
54
|
* below, but are not independent record-axis families.
|
|
52
55
|
*/
|
|
53
56
|
export const CURRENT_CONFIGURED_AGENT_SCHEMA_VERSION = 2;
|
|
54
|
-
export const CURRENT_PROJECT_SCHEMA_VERSION =
|
|
57
|
+
export const CURRENT_PROJECT_SCHEMA_VERSION = 4;
|
|
55
58
|
export const CURRENT_AGENT_PROFILE_SCHEMA_VERSION = 2;
|
|
56
59
|
export const CURRENT_GLOBAL_ROLE_SCHEMA_VERSION = 3;
|
|
57
60
|
export const CURRENT_GLOBAL_ROLE_SESSION_SET_SCHEMA_VERSION = 3;
|
|
@@ -71,6 +74,7 @@ export const CURRENT_EVENT_SCHEMA_VERSION = 2;
|
|
|
71
74
|
export const CURRENT_CAPABILITY_GRANT_SCHEMA_VERSION = 1;
|
|
72
75
|
export const CURRENT_RELEASE_WORKFLOW_SCHEMA_VERSION = 1;
|
|
73
76
|
export const CURRENT_WORK_MAILBOX_SCHEMA_VERSION = 2;
|
|
77
|
+
export const CURRENT_PUBLICATION_REFERENCE_SCHEMA_VERSION = 1;
|
|
74
78
|
export const CURRENT_ROLE_AGENT_SESSION_SCHEMA_VERSION = 3;
|
|
75
79
|
export const CURRENT_PENDING_WAKEUP_SCHEMA_VERSION = 1;
|
|
76
80
|
const STORAGE_LOCK_DIRECTORY = ".state.lock";
|
|
@@ -104,7 +108,7 @@ export function executionLaneActiveRunKeyParts(key) {
|
|
|
104
108
|
}
|
|
105
109
|
}
|
|
106
110
|
/** The schema version of each persisted `state.json#/tasks/*` aggregate. */
|
|
107
|
-
export const CURRENT_STORED_TASK_SCHEMA_VERSION =
|
|
111
|
+
export const CURRENT_STORED_TASK_SCHEMA_VERSION = 17;
|
|
108
112
|
/**
|
|
109
113
|
* Persisted nested-record versions consumed by this store's strict parser.
|
|
110
114
|
* Keep these named at the storage boundary so the upgrade record-axis map can
|
|
@@ -406,7 +410,8 @@ export class FileTaskStore {
|
|
|
406
410
|
task: {
|
|
407
411
|
id: aggregate.task.id,
|
|
408
412
|
status: aggregate.task.status,
|
|
409
|
-
projectBindings: aggregate.task.projectBindings
|
|
413
|
+
projectBindings: aggregate.task.projectBindings,
|
|
414
|
+
requireIntegration: aggregate.task.requireIntegration
|
|
410
415
|
},
|
|
411
416
|
workItems: values(aggregate.workItems, "id"),
|
|
412
417
|
changeSets: values(aggregate.changeSets, "id"),
|
|
@@ -419,6 +424,31 @@ export class FileTaskStore {
|
|
|
419
424
|
leaderRuns: agentRuns.filter((run) => run.roleName === "leader")
|
|
420
425
|
};
|
|
421
426
|
}
|
|
427
|
+
readCompletionReadinessFacts(taskId) {
|
|
428
|
+
const base = this.readNextActionFacts(taskId);
|
|
429
|
+
if (base === null)
|
|
430
|
+
return null;
|
|
431
|
+
const aggregate = this.#state().tasks[taskId];
|
|
432
|
+
const ledgerMode = reviewFindingLedgerMode(this.#state().config);
|
|
433
|
+
// The file-rollback backend does not persist the finding ledger. Under
|
|
434
|
+
// `enforce` the completion gate must fail closed with the same bounded
|
|
435
|
+
// diagnosis as `listReviewFindings` instead of silently treating
|
|
436
|
+
// "unsupported" as "no open findings".
|
|
437
|
+
if (ledgerMode === "enforce") {
|
|
438
|
+
throw new StorageRecordError(`Review findings require the SQLite backend (yui.db); migrate this Home with \`yui update\` before using the finding ledger on Task ${taskId}.`);
|
|
439
|
+
}
|
|
440
|
+
return {
|
|
441
|
+
...base,
|
|
442
|
+
managedWorkspaces: values(aggregate.managedWorkspaces, (workspace) => managedWorkspaceKey(workspace.owner)),
|
|
443
|
+
durableJobs: values(aggregate.durableJobs, "id"),
|
|
444
|
+
integrationQueueEntries: values(aggregate.integrationQueue, "id"),
|
|
445
|
+
// The SQLite backend supplies real findings; the file backend never
|
|
446
|
+
// reaches this point under `enforce` (throw above).
|
|
447
|
+
reviewFindings: [],
|
|
448
|
+
reviewFindingLedgerMode: ledgerMode,
|
|
449
|
+
events: values(aggregate.events, "id")
|
|
450
|
+
};
|
|
451
|
+
}
|
|
422
452
|
getReviewConfig() {
|
|
423
453
|
return optional(this.#state().config.review);
|
|
424
454
|
}
|
|
@@ -1246,6 +1276,28 @@ export class FileTaskStore {
|
|
|
1246
1276
|
});
|
|
1247
1277
|
}
|
|
1248
1278
|
listEvents(taskId) { return values(this.#requireTask(taskId).events, "id"); }
|
|
1279
|
+
nextTaskWakeId(taskId) {
|
|
1280
|
+
return this.#nextTaskRecordId(taskId, "taskWake");
|
|
1281
|
+
}
|
|
1282
|
+
peekNextTaskWakeId(taskId) {
|
|
1283
|
+
return this.#peekTaskRecordId(taskId, "taskWake");
|
|
1284
|
+
}
|
|
1285
|
+
saveTaskWake(taskId, wake) {
|
|
1286
|
+
if (wake.taskId !== taskId) {
|
|
1287
|
+
throw new StorageRecordError(`Task wake belongs to another Task: ${wake.taskId}`);
|
|
1288
|
+
}
|
|
1289
|
+
this.#mutate((state) => {
|
|
1290
|
+
const aggregate = requireTaskFromState(state, taskId);
|
|
1291
|
+
observeTaskRecordId(aggregate, "taskWake", wake.id);
|
|
1292
|
+
aggregate.wakes[wake.id] = wake;
|
|
1293
|
+
});
|
|
1294
|
+
}
|
|
1295
|
+
getTaskWake(taskId, wakeId) {
|
|
1296
|
+
return this.#state().tasks[taskId]?.wakes[wakeId] ?? null;
|
|
1297
|
+
}
|
|
1298
|
+
listTaskWakes(taskId) {
|
|
1299
|
+
return values(this.#requireTask(taskId).wakes, "id");
|
|
1300
|
+
}
|
|
1249
1301
|
removeEvents(taskId, eventIds) {
|
|
1250
1302
|
if (eventIds.length === 0)
|
|
1251
1303
|
return 0;
|
|
@@ -1317,6 +1369,62 @@ export class FileTaskStore {
|
|
|
1317
1369
|
getReleaseWorkflow(taskId, workflowId) {
|
|
1318
1370
|
return this.#requireTask(taskId).releaseWorkflows[workflowId] ?? null;
|
|
1319
1371
|
}
|
|
1372
|
+
nextPublicationReferenceId(taskId) {
|
|
1373
|
+
return this.#nextTaskRecordId(taskId, "publicationReference");
|
|
1374
|
+
}
|
|
1375
|
+
savePublicationReference(taskId, reference) {
|
|
1376
|
+
const stored = storedPublicationReference(reference);
|
|
1377
|
+
if (stored.taskId !== taskId) {
|
|
1378
|
+
throw new StorageRecordError(`Publication reference belongs to another Task: ${stored.taskId}`);
|
|
1379
|
+
}
|
|
1380
|
+
this.#mutate((state) => {
|
|
1381
|
+
const aggregate = requireTaskFromState(state, taskId);
|
|
1382
|
+
const existing = aggregate.publicationReferences[stored.id];
|
|
1383
|
+
if (existing !== undefined) {
|
|
1384
|
+
if (!isDeepStrictEqual(existing, stored)) {
|
|
1385
|
+
throw new StorageRecordError(`Publication reference cannot be overwritten: ${taskId}/${stored.id}`);
|
|
1386
|
+
}
|
|
1387
|
+
}
|
|
1388
|
+
else {
|
|
1389
|
+
const key = publicationExternalKey(stored);
|
|
1390
|
+
const sameExternal = [];
|
|
1391
|
+
for (const [otherTaskId, otherAggregate] of Object.entries(state.tasks)) {
|
|
1392
|
+
for (const candidate of Object.values(otherAggregate.publicationReferences)) {
|
|
1393
|
+
if (publicationExternalKey(candidate) === key) {
|
|
1394
|
+
if (otherTaskId !== taskId) {
|
|
1395
|
+
throw new StorageRecordError(`Publication external identity already belongs to Task ${otherTaskId}: ${key}.`);
|
|
1396
|
+
}
|
|
1397
|
+
sameExternal.push(candidate);
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1401
|
+
if (sameExternal.length > 0) {
|
|
1402
|
+
const latest = latestPublicationReference(sameExternal);
|
|
1403
|
+
if (stored.supersedes !== latest.id) {
|
|
1404
|
+
throw new StorageRecordError(`Publication external identity conflicts with ${latest.id}; `
|
|
1405
|
+
+ `explicitly supersede that record: ${key}.`);
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1408
|
+
else if (stored.supersedes !== undefined) {
|
|
1409
|
+
throw new StorageRecordError(`Publication supersedes target has a different external identity: ${stored.supersedes}.`);
|
|
1410
|
+
}
|
|
1411
|
+
observeTaskRecordId(aggregate, "publicationReference", stored.id);
|
|
1412
|
+
}
|
|
1413
|
+
aggregate.publicationReferences[stored.id] = stored;
|
|
1414
|
+
});
|
|
1415
|
+
}
|
|
1416
|
+
listPublicationReferences(taskId) {
|
|
1417
|
+
return values(this.#requireTask(taskId).publicationReferences, "id");
|
|
1418
|
+
}
|
|
1419
|
+
getPublicationReference(taskId, referenceId) {
|
|
1420
|
+
return this.#requireTask(taskId).publicationReferences[referenceId] ?? null;
|
|
1421
|
+
}
|
|
1422
|
+
findPublicationReferenceByExternalKey(externalKey) {
|
|
1423
|
+
const matches = Object.values(this.#state().tasks)
|
|
1424
|
+
.flatMap((aggregate) => Object.values(aggregate.publicationReferences))
|
|
1425
|
+
.filter((reference) => publicationExternalKey(reference) === externalKey);
|
|
1426
|
+
return matches.length === 0 ? null : latestPublicationReference(matches);
|
|
1427
|
+
}
|
|
1320
1428
|
// -- Gate artifacts (Issue 08) ---------------------------------------------
|
|
1321
1429
|
// FileTaskStore delegates to the file-backed artifact namespace under
|
|
1322
1430
|
// `<home>/artifacts/gates/`. This is the transitional path for Homes that
|
|
@@ -1820,8 +1928,10 @@ function emptyStoredTask(task) {
|
|
|
1820
1928
|
decisions: {},
|
|
1821
1929
|
milestones: {},
|
|
1822
1930
|
events: {},
|
|
1931
|
+
wakes: {},
|
|
1823
1932
|
capabilityGrants: {},
|
|
1824
1933
|
releaseWorkflows: {},
|
|
1934
|
+
publicationReferences: {},
|
|
1825
1935
|
leaderFailure: null,
|
|
1826
1936
|
operatorNotification: null
|
|
1827
1937
|
};
|
|
@@ -1841,8 +1951,10 @@ function emptyTaskIdHighWaterMarks() {
|
|
|
1841
1951
|
decision: 0,
|
|
1842
1952
|
milestone: 0,
|
|
1843
1953
|
event: 0,
|
|
1954
|
+
taskWake: 0,
|
|
1844
1955
|
capabilityGrant: 0,
|
|
1845
|
-
releaseWorkflow: 0
|
|
1956
|
+
releaseWorkflow: 0,
|
|
1957
|
+
publicationReference: 0
|
|
1846
1958
|
};
|
|
1847
1959
|
}
|
|
1848
1960
|
function nextTaskRecordSequence(aggregate, taskId, kind) {
|
|
@@ -2033,8 +2145,10 @@ function parseStoredTask(value, taskId) {
|
|
|
2033
2145
|
"decisions",
|
|
2034
2146
|
"milestones",
|
|
2035
2147
|
"events",
|
|
2148
|
+
"wakes",
|
|
2036
2149
|
"capabilityGrants",
|
|
2037
2150
|
"releaseWorkflows",
|
|
2151
|
+
"publicationReferences",
|
|
2038
2152
|
"leaderFailure",
|
|
2039
2153
|
"operatorNotification"
|
|
2040
2154
|
], `Task aggregate ${taskId}`);
|
|
@@ -2190,6 +2304,14 @@ function parseStoredTask(value, taskId) {
|
|
|
2190
2304
|
}
|
|
2191
2305
|
return event;
|
|
2192
2306
|
}, "events");
|
|
2307
|
+
parseMap(aggregate.wakes, (record, key) => {
|
|
2308
|
+
const wake = identified(record, CURRENT_TASK_WAKE_SCHEMA_VERSION, "id", key, "Task wake");
|
|
2309
|
+
if (wake.taskId !== taskId) {
|
|
2310
|
+
throw new StorageRecordError(`Task wake belongs to another Task: ${wake.taskId}`);
|
|
2311
|
+
}
|
|
2312
|
+
validateTaskWake(wake);
|
|
2313
|
+
return wake;
|
|
2314
|
+
}, "wakes");
|
|
2193
2315
|
parseMap(aggregate.capabilityGrants, (record, key) => {
|
|
2194
2316
|
const grant = storedCapabilityGrant(record);
|
|
2195
2317
|
if (grant.id !== key) {
|
|
@@ -2210,6 +2332,16 @@ function parseStoredTask(value, taskId) {
|
|
|
2210
2332
|
}
|
|
2211
2333
|
return workflow;
|
|
2212
2334
|
}, "releaseWorkflows");
|
|
2335
|
+
parseMap(aggregate.publicationReferences, (record, key) => {
|
|
2336
|
+
const reference = storedPublicationReference(record);
|
|
2337
|
+
if (reference.id !== key) {
|
|
2338
|
+
throw new StorageRecordError(`Publication reference identity is inconsistent: ${key}.`);
|
|
2339
|
+
}
|
|
2340
|
+
if (reference.taskId !== taskId) {
|
|
2341
|
+
throw new StorageRecordError(`Publication reference belongs to another Task: ${reference.taskId}`);
|
|
2342
|
+
}
|
|
2343
|
+
return reference;
|
|
2344
|
+
}, "publicationReferences");
|
|
2213
2345
|
for (const [key, label] of [["leaderFailure", "Leader failure"], ["operatorNotification", "Operator notification"]]) {
|
|
2214
2346
|
const record = aggregate[key];
|
|
2215
2347
|
if (record !== null) {
|
|
@@ -2239,8 +2371,10 @@ function validateTaskIdHighWaterCoverage(aggregate, taskId) {
|
|
|
2239
2371
|
decision: aggregate.decisions,
|
|
2240
2372
|
milestone: aggregate.milestones,
|
|
2241
2373
|
event: aggregate.events,
|
|
2374
|
+
taskWake: aggregate.wakes,
|
|
2242
2375
|
capabilityGrant: aggregate.capabilityGrants,
|
|
2243
|
-
releaseWorkflow: aggregate.releaseWorkflows
|
|
2376
|
+
releaseWorkflow: aggregate.releaseWorkflows,
|
|
2377
|
+
publicationReference: aggregate.publicationReferences
|
|
2244
2378
|
};
|
|
2245
2379
|
for (const kind of Object.keys(TASK_RECORD_ID_PREFIXES)) {
|
|
2246
2380
|
const pattern = new RegExp(`^${TASK_RECORD_ID_PREFIXES[kind]}-(\\d+)$`);
|
|
@@ -2649,6 +2783,101 @@ export function storedReleaseWorkflow(value) {
|
|
|
2649
2783
|
throw new StorageRecordError(error instanceof Error ? error.message : String(error));
|
|
2650
2784
|
}
|
|
2651
2785
|
}
|
|
2786
|
+
export function storedPublicationReference(value) {
|
|
2787
|
+
const reference = versioned(value, CURRENT_PUBLICATION_REFERENCE_SCHEMA_VERSION, "Publication reference");
|
|
2788
|
+
const fields = [
|
|
2789
|
+
"schemaVersion", "id", "taskId", "projectId", "provider", "repository",
|
|
2790
|
+
"externalKind", "externalId", "state", "verification", "recordedBy",
|
|
2791
|
+
"source", "createdAt"
|
|
2792
|
+
];
|
|
2793
|
+
if (reference.externalUrl !== undefined)
|
|
2794
|
+
fields.push("externalUrl");
|
|
2795
|
+
if (reference.title !== undefined)
|
|
2796
|
+
fields.push("title");
|
|
2797
|
+
if (reference.sourceBranch !== undefined)
|
|
2798
|
+
fields.push("sourceBranch");
|
|
2799
|
+
if (reference.targetBranch !== undefined)
|
|
2800
|
+
fields.push("targetBranch");
|
|
2801
|
+
if (reference.localCommit !== undefined)
|
|
2802
|
+
fields.push("localCommit");
|
|
2803
|
+
if (reference.remoteCommit !== undefined)
|
|
2804
|
+
fields.push("remoteCommit");
|
|
2805
|
+
if (reference.evidence !== undefined)
|
|
2806
|
+
fields.push("evidence");
|
|
2807
|
+
if (reference.supersedes !== undefined)
|
|
2808
|
+
fields.push("supersedes");
|
|
2809
|
+
if (reference.mergedAt !== undefined)
|
|
2810
|
+
fields.push("mergedAt");
|
|
2811
|
+
exact(reference, fields, "Publication reference");
|
|
2812
|
+
requireRecordIdentity(reference.id, "Publication reference id");
|
|
2813
|
+
requireRecordIdentity(reference.taskId, "Publication reference Task id");
|
|
2814
|
+
validateTaskRecordReference({ taskId: reference.taskId, localId: reference.id }, "publicationReference");
|
|
2815
|
+
requireRecordIdentity(reference.projectId, "Publication reference Project id");
|
|
2816
|
+
requireNormalizedText(reference.provider, "Publication reference provider");
|
|
2817
|
+
requireNormalizedText(reference.repository, "Publication reference repository");
|
|
2818
|
+
requireNormalizedText(reference.externalKind, "Publication reference external kind");
|
|
2819
|
+
requireNormalizedText(reference.externalId, "Publication reference external id");
|
|
2820
|
+
if (reference.externalUrl !== undefined) {
|
|
2821
|
+
requireNormalizedText(reference.externalUrl, "Publication reference external URL");
|
|
2822
|
+
}
|
|
2823
|
+
if (reference.title !== undefined) {
|
|
2824
|
+
requireNormalizedText(reference.title, "Publication reference title");
|
|
2825
|
+
}
|
|
2826
|
+
if (reference.sourceBranch !== undefined) {
|
|
2827
|
+
requireNormalizedText(reference.sourceBranch, "Publication reference source branch");
|
|
2828
|
+
}
|
|
2829
|
+
if (reference.targetBranch !== undefined) {
|
|
2830
|
+
requireNormalizedText(reference.targetBranch, "Publication reference target branch");
|
|
2831
|
+
}
|
|
2832
|
+
if (reference.localCommit !== undefined) {
|
|
2833
|
+
requireNormalizedText(reference.localCommit, "Publication reference local commit");
|
|
2834
|
+
}
|
|
2835
|
+
if (reference.remoteCommit !== undefined) {
|
|
2836
|
+
requireNormalizedText(reference.remoteCommit, "Publication reference remote commit");
|
|
2837
|
+
}
|
|
2838
|
+
requireNormalizedText(reference.state, "Publication reference state");
|
|
2839
|
+
requireNormalizedText(reference.verification, "Publication reference verification");
|
|
2840
|
+
if (reference.evidence !== undefined) {
|
|
2841
|
+
requireNormalizedText(reference.evidence, "Publication reference evidence");
|
|
2842
|
+
}
|
|
2843
|
+
if (reference.supersedes !== undefined) {
|
|
2844
|
+
requireNormalizedText(reference.supersedes, "Publication reference supersedes id");
|
|
2845
|
+
}
|
|
2846
|
+
requireNormalizedText(reference.recordedBy, "Publication reference recordedBy");
|
|
2847
|
+
requireNormalizedText(reference.source, "Publication reference source");
|
|
2848
|
+
if (reference.mergedAt !== undefined) {
|
|
2849
|
+
requireTimestamp(reference.mergedAt, "Publication reference mergedAt");
|
|
2850
|
+
}
|
|
2851
|
+
requireTimestamp(reference.createdAt, "Publication reference createdAt");
|
|
2852
|
+
try {
|
|
2853
|
+
return validatePublicationReference(reference);
|
|
2854
|
+
}
|
|
2855
|
+
catch (error) {
|
|
2856
|
+
throw new StorageRecordError(error instanceof Error ? error.message : String(error));
|
|
2857
|
+
}
|
|
2858
|
+
}
|
|
2859
|
+
function latestPublicationReference(references) {
|
|
2860
|
+
const byId = new Map(references.map((reference) => [reference.id, reference]));
|
|
2861
|
+
const superseded = new Set(references
|
|
2862
|
+
.map((reference) => reference.supersedes)
|
|
2863
|
+
.filter((id) => id !== undefined));
|
|
2864
|
+
const roots = references.filter((reference) => !superseded.has(reference.id));
|
|
2865
|
+
const latest = roots.length === 1 ? roots[0] : [...byId.values()].sort((left, right) => (right.id.localeCompare(left.id, undefined, { numeric: true })))[0];
|
|
2866
|
+
let current = latest;
|
|
2867
|
+
const seen = new Set();
|
|
2868
|
+
while (current.supersedes !== undefined) {
|
|
2869
|
+
if (seen.has(current.id)) {
|
|
2870
|
+
throw new StorageRecordError(`Publication supersession cycle at ${current.id}.`);
|
|
2871
|
+
}
|
|
2872
|
+
seen.add(current.id);
|
|
2873
|
+
const previous = byId.get(current.supersedes);
|
|
2874
|
+
if (previous === undefined) {
|
|
2875
|
+
throw new StorageRecordError(`Publication supersession target not found: ${current.id}/${current.supersedes}.`);
|
|
2876
|
+
}
|
|
2877
|
+
current = previous;
|
|
2878
|
+
}
|
|
2879
|
+
return latest;
|
|
2880
|
+
}
|
|
2652
2881
|
function storedReleaseWorkflowSource(source) {
|
|
2653
2882
|
const value = object(source, "Release workflow source");
|
|
2654
2883
|
const sourceFields = ["repository", "commit"];
|
|
@@ -3097,10 +3326,38 @@ function validateCanonicalTaskReferences(state, aggregate) {
|
|
|
3097
3326
|
}
|
|
3098
3327
|
}
|
|
3099
3328
|
}
|
|
3329
|
+
for (const reference of Object.values(aggregate.publicationReferences)) {
|
|
3330
|
+
if (!boundProjects.has(reference.projectId)) {
|
|
3331
|
+
throw new StorageRecordError(`Publication reference Project does not match Task: ${reference.id}.`);
|
|
3332
|
+
}
|
|
3333
|
+
if (reference.supersedes !== undefined) {
|
|
3334
|
+
const target = aggregate.publicationReferences[reference.supersedes];
|
|
3335
|
+
if (target === undefined) {
|
|
3336
|
+
throw new StorageRecordError(`Publication reference supersedes target not found: ${reference.id}/${reference.supersedes}.`);
|
|
3337
|
+
}
|
|
3338
|
+
if (publicationExternalKey(target) !== publicationExternalKey(reference)) {
|
|
3339
|
+
throw new StorageRecordError(`Publication reference supersedes a different external identity: ${reference.id}/${reference.supersedes}.`);
|
|
3340
|
+
}
|
|
3341
|
+
}
|
|
3342
|
+
}
|
|
3343
|
+
assertPublicationExternalIdentityUniqueness(state);
|
|
3100
3344
|
for (const workspace of Object.values(aggregate.managedWorkspaces)) {
|
|
3101
3345
|
assertManagedWorkspaceReferences(aggregate, workspace, "Managed workspace");
|
|
3102
3346
|
}
|
|
3103
3347
|
}
|
|
3348
|
+
function assertPublicationExternalIdentityUniqueness(state) {
|
|
3349
|
+
const owners = new Map();
|
|
3350
|
+
for (const aggregate of Object.values(state.tasks)) {
|
|
3351
|
+
for (const reference of Object.values(aggregate.publicationReferences)) {
|
|
3352
|
+
const key = publicationExternalKey(reference);
|
|
3353
|
+
const owner = owners.get(key);
|
|
3354
|
+
if (owner !== undefined && owner !== aggregate.task.id) {
|
|
3355
|
+
throw new StorageRecordError(`Publication external identity belongs to multiple Tasks: ${key}.`);
|
|
3356
|
+
}
|
|
3357
|
+
owners.set(key, aggregate.task.id);
|
|
3358
|
+
}
|
|
3359
|
+
}
|
|
3360
|
+
}
|
|
3104
3361
|
/**
|
|
3105
3362
|
* Enforce the owner-specific scope at the storage boundary. The map key and
|
|
3106
3363
|
* foreign-record checks prevent dangling identities; these checks prevent a
|
|
@@ -16,9 +16,10 @@
|
|
|
16
16
|
* transform in the production migration graph.
|
|
17
17
|
*/
|
|
18
18
|
import { CURRENT_AGGREGATE_SCHEMA_VERSION, CURRENT_STORAGE_LAYOUT_VERSION } from "../storageVersions.js";
|
|
19
|
-
import { CURRENT_AGENT_RUN_SCHEMA_VERSION, CURRENT_ACTIVE_RUN_POINTER_SCHEMA_VERSION, CURRENT_AGENT_PROFILE_SCHEMA_VERSION, CURRENT_CAPABILITY_GRANT_SCHEMA_VERSION, CURRENT_CONFIG_SCHEMA_VERSION, CURRENT_CONFIGURED_AGENT_SCHEMA_VERSION, CURRENT_CHANGE_SET_SCHEMA_VERSION, CURRENT_DECISION_SCHEMA_VERSION, CURRENT_EVENT_SCHEMA_VERSION, CURRENT_GLOBAL_ROLE_SCHEMA_VERSION, CURRENT_GLOBAL_ROLE_SESSION_SET_SCHEMA_VERSION, CURRENT_INPUT_REQUEST_SCHEMA_VERSION, CURRENT_INTEGRATION_ATTEMPT_SCHEMA_VERSION, CURRENT_INTEGRATION_QUEUE_SCHEMA_VERSION, CURRENT_MANAGED_WORKSPACE_SCHEMA_VERSION, CURRENT_MESSAGE_SCHEMA_VERSION, CURRENT_MILESTONE_SCHEMA_VERSION, CURRENT_PROJECT_SCHEMA_VERSION, CURRENT_RELEASE_WORKFLOW_SCHEMA_VERSION, CURRENT_REVIEW_ROUND_SCHEMA_VERSION, CURRENT_STORED_TASK_SCHEMA_VERSION, CURRENT_TASK_BRIEF_SCHEMA_VERSION, CURRENT_TASK_ROLE_SCHEMA_VERSION, CURRENT_TASK_ROLE_SESSION_SET_SCHEMA_VERSION, CURRENT_TASK_SCHEMA_VERSION, CURRENT_WORK_ITEM_SCHEMA_VERSION, CURRENT_WORK_MAILBOX_SCHEMA_VERSION } from "../taskStore.js";
|
|
19
|
+
import { CURRENT_AGENT_RUN_SCHEMA_VERSION, CURRENT_ACTIVE_RUN_POINTER_SCHEMA_VERSION, CURRENT_AGENT_PROFILE_SCHEMA_VERSION, CURRENT_CAPABILITY_GRANT_SCHEMA_VERSION, CURRENT_CONFIG_SCHEMA_VERSION, CURRENT_CONFIGURED_AGENT_SCHEMA_VERSION, CURRENT_CHANGE_SET_SCHEMA_VERSION, CURRENT_DECISION_SCHEMA_VERSION, CURRENT_EVENT_SCHEMA_VERSION, CURRENT_GLOBAL_ROLE_SCHEMA_VERSION, CURRENT_GLOBAL_ROLE_SESSION_SET_SCHEMA_VERSION, CURRENT_INPUT_REQUEST_SCHEMA_VERSION, CURRENT_INTEGRATION_ATTEMPT_SCHEMA_VERSION, CURRENT_INTEGRATION_QUEUE_SCHEMA_VERSION, CURRENT_MANAGED_WORKSPACE_SCHEMA_VERSION, CURRENT_MESSAGE_SCHEMA_VERSION, CURRENT_MILESTONE_SCHEMA_VERSION, CURRENT_PUBLICATION_REFERENCE_SCHEMA_VERSION, CURRENT_PROJECT_SCHEMA_VERSION, CURRENT_RELEASE_WORKFLOW_SCHEMA_VERSION, CURRENT_REVIEW_ROUND_SCHEMA_VERSION, CURRENT_STORED_TASK_SCHEMA_VERSION, CURRENT_TASK_BRIEF_SCHEMA_VERSION, CURRENT_TASK_ROLE_SCHEMA_VERSION, CURRENT_TASK_ROLE_SESSION_SET_SCHEMA_VERSION, CURRENT_TASK_SCHEMA_VERSION, CURRENT_WORK_ITEM_SCHEMA_VERSION, CURRENT_WORK_MAILBOX_SCHEMA_VERSION } from "../taskStore.js";
|
|
20
20
|
import { CURRENT_LEADER_FAILURE_SCHEMA_VERSION } from "../../scheduler/leaderFailure.js";
|
|
21
21
|
import { CURRENT_OPERATOR_NOTIFICATION_SCHEMA_VERSION } from "../../scheduler/operatorNotification.js";
|
|
22
|
+
import { CURRENT_TASK_WAKE_SCHEMA_VERSION } from "../../scheduler/taskWake.js";
|
|
22
23
|
import { CURRENT_DURABLE_JOB_SCHEMA_VERSION } from "../../job/durableJob.js";
|
|
23
24
|
function descriptor(version, path) {
|
|
24
25
|
return Object.freeze({ version, path });
|
|
@@ -55,8 +56,10 @@ const EXPECTED_DIRECT_RECORD_LOCATORS = Object.freeze({
|
|
|
55
56
|
decision: "state.json#/tasks/*/decisions",
|
|
56
57
|
milestone: "state.json#/tasks/*/milestones",
|
|
57
58
|
event: "state.json#/tasks/*/events",
|
|
59
|
+
taskWake: "state.json#/tasks/*/wakes",
|
|
58
60
|
capabilityGrant: "state.json#/tasks/*/capabilityGrants",
|
|
59
61
|
releaseWorkflow: "state.json#/tasks/*/releaseWorkflows",
|
|
62
|
+
publicationReference: "state.json#/tasks/*/publicationReferences",
|
|
60
63
|
leaderFailure: "state.json#/tasks/*/leaderFailure",
|
|
61
64
|
operatorNotification: "state.json#/tasks/*/operatorNotification",
|
|
62
65
|
workMailbox: "state.json#/mailboxes"
|
|
@@ -108,8 +111,10 @@ function getCurrentRecordDescriptors() {
|
|
|
108
111
|
decision: descriptor(CURRENT_DECISION_SCHEMA_VERSION, "state.json#/tasks/*/decisions"),
|
|
109
112
|
milestone: descriptor(CURRENT_MILESTONE_SCHEMA_VERSION, "state.json#/tasks/*/milestones"),
|
|
110
113
|
event: descriptor(CURRENT_EVENT_SCHEMA_VERSION, "state.json#/tasks/*/events"),
|
|
114
|
+
taskWake: descriptor(CURRENT_TASK_WAKE_SCHEMA_VERSION, "state.json#/tasks/*/wakes"),
|
|
111
115
|
capabilityGrant: descriptor(CURRENT_CAPABILITY_GRANT_SCHEMA_VERSION, "state.json#/tasks/*/capabilityGrants"),
|
|
112
116
|
releaseWorkflow: descriptor(CURRENT_RELEASE_WORKFLOW_SCHEMA_VERSION, "state.json#/tasks/*/releaseWorkflows"),
|
|
117
|
+
publicationReference: descriptor(CURRENT_PUBLICATION_REFERENCE_SCHEMA_VERSION, "state.json#/tasks/*/publicationReferences"),
|
|
113
118
|
leaderFailure: descriptor(CURRENT_LEADER_FAILURE_SCHEMA_VERSION, "state.json#/tasks/*/leaderFailure"),
|
|
114
119
|
operatorNotification: descriptor(CURRENT_OPERATOR_NOTIFICATION_SCHEMA_VERSION, "state.json#/tasks/*/operatorNotification"),
|
|
115
120
|
workMailbox: descriptor(CURRENT_WORK_MAILBOX_SCHEMA_VERSION, "state.json#/mailboxes")
|
|
@@ -189,11 +189,13 @@ function asStoredTask(value) {
|
|
|
189
189
|
decisions: asObjectMap(record.decisions),
|
|
190
190
|
milestones: asObjectMap(record.milestones),
|
|
191
191
|
events: asObjectMap(record.events),
|
|
192
|
+
wakes: asObjectMap(record.wakes),
|
|
192
193
|
leaderFailure: asNullableObject(record.leaderFailure),
|
|
193
194
|
operatorNotification: asNullableObject(record.operatorNotification),
|
|
194
195
|
idHighWaterMarks: asObject(record.idHighWaterMarks),
|
|
195
196
|
capabilityGrants: asObjectMap(record.capabilityGrants),
|
|
196
|
-
releaseWorkflows: asObjectMap(record.releaseWorkflows)
|
|
197
|
+
releaseWorkflows: asObjectMap(record.releaseWorkflows),
|
|
198
|
+
publicationReferences: asObjectMap(record.publicationReferences)
|
|
197
199
|
};
|
|
198
200
|
}
|
|
199
201
|
function tasksOf(state) {
|
|
@@ -335,6 +337,9 @@ export function populateSqliteFromState(home, state, databaseFilename) {
|
|
|
335
337
|
for (const event of Object.values(stored.events)) {
|
|
336
338
|
store.saveEvent(taskId, event);
|
|
337
339
|
}
|
|
340
|
+
for (const wake of Object.values(stored.wakes)) {
|
|
341
|
+
store.saveTaskWake(taskId, wake);
|
|
342
|
+
}
|
|
338
343
|
if (stored.leaderFailure !== null) {
|
|
339
344
|
store.saveLeaderFailure(stored.leaderFailure);
|
|
340
345
|
}
|
|
@@ -354,6 +359,9 @@ export function populateSqliteFromState(home, state, databaseFilename) {
|
|
|
354
359
|
for (const workflow of Object.values(stored.releaseWorkflows)) {
|
|
355
360
|
store.saveReleaseWorkflow(taskId, workflow);
|
|
356
361
|
}
|
|
362
|
+
for (const reference of Object.values(stored.publicationReferences)) {
|
|
363
|
+
store.savePublicationReference(taskId, reference);
|
|
364
|
+
}
|
|
357
365
|
}
|
|
358
366
|
// Work mailboxes.
|
|
359
367
|
for (const mailbox of Object.values(asObjectMap(state.mailboxes))) {
|
|
@@ -456,10 +464,12 @@ export function computeStateFamilyChecksums(state) {
|
|
|
456
464
|
const decisions = [];
|
|
457
465
|
const milestones = [];
|
|
458
466
|
const events = [];
|
|
467
|
+
const wakes = [];
|
|
459
468
|
const leaderFailures = [];
|
|
460
469
|
const operatorNotifications = [];
|
|
461
470
|
const capabilityGrants = [];
|
|
462
471
|
const releaseWorkflows = [];
|
|
472
|
+
const publicationReferences = [];
|
|
463
473
|
for (const stored of Object.values(tasks)) {
|
|
464
474
|
taskRecords.push(stored.task);
|
|
465
475
|
if (stored.brief !== null)
|
|
@@ -492,12 +502,14 @@ export function computeStateFamilyChecksums(state) {
|
|
|
492
502
|
decisions.push(...Object.values(stored.decisions));
|
|
493
503
|
milestones.push(...Object.values(stored.milestones));
|
|
494
504
|
events.push(...Object.values(stored.events));
|
|
505
|
+
wakes.push(...Object.values(stored.wakes));
|
|
495
506
|
if (stored.leaderFailure !== null)
|
|
496
507
|
leaderFailures.push(stored.leaderFailure);
|
|
497
508
|
if (stored.operatorNotification !== null)
|
|
498
509
|
operatorNotifications.push(stored.operatorNotification);
|
|
499
510
|
capabilityGrants.push(...Object.values(stored.capabilityGrants));
|
|
500
511
|
releaseWorkflows.push(...Object.values(stored.releaseWorkflows));
|
|
512
|
+
publicationReferences.push(...Object.values(stored.publicationReferences));
|
|
501
513
|
}
|
|
502
514
|
checksums.task = hashRecords(taskRecords);
|
|
503
515
|
checksums.taskBrief = hashRecords(briefs);
|
|
@@ -518,10 +530,12 @@ export function computeStateFamilyChecksums(state) {
|
|
|
518
530
|
checksums.decision = hashRecords(decisions);
|
|
519
531
|
checksums.milestone = hashRecords(milestones);
|
|
520
532
|
checksums.event = hashRecords(events);
|
|
533
|
+
checksums.taskWake = hashRecords(wakes);
|
|
521
534
|
checksums.leaderFailure = hashRecords(leaderFailures);
|
|
522
535
|
checksums.operatorNotification = hashRecords(operatorNotifications);
|
|
523
536
|
checksums.capabilityGrant = hashRecords(capabilityGrants);
|
|
524
537
|
checksums.releaseWorkflow = hashRecords(releaseWorkflows);
|
|
538
|
+
checksums.publicationReference = hashRecords(publicationReferences);
|
|
525
539
|
checksums.workMailbox = hashRecords(Object.values(asObjectMap(state.mailboxes)));
|
|
526
540
|
return checksums;
|
|
527
541
|
}
|
|
@@ -609,10 +623,12 @@ export function computeDbFamilyChecksums(home, databaseFilename) {
|
|
|
609
623
|
checksums.decision = hashPayloadTable(db, "SELECT payload FROM decisions");
|
|
610
624
|
checksums.milestone = hashPayloadTable(db, "SELECT payload FROM milestones");
|
|
611
625
|
checksums.event = hashPayloadTable(db, "SELECT payload FROM events");
|
|
626
|
+
checksums.taskWake = hashPayloadTable(db, "SELECT payload FROM task_wakes");
|
|
612
627
|
checksums.leaderFailure = hashPayloadTable(db, "SELECT payload FROM task_projections WHERE kind = 'leader-failure' AND payload IS NOT NULL");
|
|
613
628
|
checksums.operatorNotification = hashPayloadTable(db, "SELECT payload FROM task_projections WHERE kind = 'operator-notification' AND payload IS NOT NULL");
|
|
614
629
|
checksums.capabilityGrant = hashPayloadTable(db, "SELECT payload FROM capability_grants");
|
|
615
630
|
checksums.releaseWorkflow = hashPayloadTable(db, "SELECT payload FROM release_workflows");
|
|
631
|
+
checksums.publicationReference = hashPayloadTable(db, "SELECT payload FROM publication_references");
|
|
616
632
|
// Mailboxes are reconstructed from typed columns (no payload column).
|
|
617
633
|
const mailboxRows = readWorkMailboxRows(db);
|
|
618
634
|
checksums.workMailbox = hashRecords(mailboxRows.map(rowToMailbox));
|
|
@@ -730,11 +746,13 @@ export function readStateFromSqlite(home) {
|
|
|
730
746
|
decisions: {},
|
|
731
747
|
milestones: {},
|
|
732
748
|
events: {},
|
|
749
|
+
wakes: {},
|
|
733
750
|
leaderFailure: null,
|
|
734
751
|
operatorNotification: null,
|
|
735
752
|
idHighWaterMarks: {},
|
|
736
753
|
capabilityGrants: {},
|
|
737
|
-
releaseWorkflows: {}
|
|
754
|
+
releaseWorkflows: {},
|
|
755
|
+
publicationReferences: {}
|
|
738
756
|
};
|
|
739
757
|
}
|
|
740
758
|
// Per-task record families, keyed by their state.json map keys.
|
|
@@ -753,8 +771,10 @@ export function readStateFromSqlite(home) {
|
|
|
753
771
|
loadTaskPayloadMap(db, "decisions", tasks, "decisions", (record) => record.id);
|
|
754
772
|
loadTaskPayloadMap(db, "milestones", tasks, "milestones", (record) => record.id);
|
|
755
773
|
loadTaskPayloadMap(db, "events", tasks, "events", (record) => record.id);
|
|
774
|
+
loadTaskPayloadMap(db, "task_wakes", tasks, "wakes", (record) => record.id);
|
|
756
775
|
loadTaskPayloadMap(db, "capability_grants", tasks, "capabilityGrants", (record) => record.id);
|
|
757
776
|
loadTaskPayloadMap(db, "release_workflows", tasks, "releaseWorkflows", (record) => record.id);
|
|
777
|
+
loadTaskPayloadMap(db, "publication_references", tasks, "publicationReferences", (record) => record.id);
|
|
758
778
|
// Job caller key hashes: keyed by `${roleName}\0${agentId}`.
|
|
759
779
|
const callerHashRows = db.prepare("SELECT task_id, role_name, agent_id, hash FROM job_caller_key_hashes").all();
|
|
760
780
|
for (const row of callerHashRows) {
|