@shapeshift-labs/frontier-swarm 0.5.22 → 0.5.24

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.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { createRunDashboardSnapshot, createRunEdgeEvent, createRunEvent, createRunNodeEvent, defineRunArtifact, defineRunAttempt, defineRunDecision, defineRunEvidence, defineRunLane, defineRunPatch, defineRunTask, defineRunVerification, linkRunNodes, replayRunEvents } from '@shapeshift-labs/frontier-run';
2
+ import { acquireSemanticLease, createSemanticLeaseState, defineSemanticLeaseScope, validateSemanticLeaseFence } from '@shapeshift-labs/frontier-lease';
2
3
  export const FRONTIER_SWARM_MANIFEST_KIND = 'frontier.swarm.manifest';
3
4
  export const FRONTIER_SWARM_MANIFEST_VERSION = 1;
4
5
  export const FRONTIER_SWARM_TASK_KIND = 'frontier.swarm.task';
@@ -2294,6 +2295,45 @@ export function createRunProjectionFromSwarmRunEvents(events, options = {}) {
2294
2295
  metadata: toJsonObject(options.metadata)
2295
2296
  });
2296
2297
  }
2298
+ export function createSwarmRunFromRunProjection(projection, options) {
2299
+ const plan = options.plan;
2300
+ const results = plan.jobs
2301
+ .map((job) => deriveSwarmResultFromRunProjection(projection, job))
2302
+ .filter((result) => !!result);
2303
+ const run = createSwarmRun({
2304
+ id: options.id ?? projection.run.id ?? plan.runId,
2305
+ plan,
2306
+ startedAt: options.startedAt ?? parseRunTimeMs(projection.run.createdAt, plan.createdAt),
2307
+ status: options.status ?? deriveSwarmRunStatusFromResults(plan.jobs, results),
2308
+ events: createSwarmEventsFromRunProjection(projection),
2309
+ results,
2310
+ metadata: mergeSwarmMetadata([
2311
+ projection.run.metadata,
2312
+ options.metadata,
2313
+ { source: 'frontier-run.projection', frontierRunId: projection.run.id }
2314
+ ])
2315
+ });
2316
+ const finishedAt = latestSwarmResultFinishedAt(run.results);
2317
+ return finishedAt === undefined ? run : { ...run, finishedAt };
2318
+ }
2319
+ export function createSwarmQueueOverlayFromRunProjection(projection, options) {
2320
+ const run = createSwarmRunFromRunProjection(projection, {
2321
+ plan: options.plan,
2322
+ id: projection.run.id,
2323
+ startedAt: parseRunTimeMs(projection.run.createdAt, options.plan.createdAt),
2324
+ metadata: options.metadata
2325
+ });
2326
+ return createSwarmQueueOverlay({
2327
+ id: options.id,
2328
+ runId: run.id,
2329
+ results: run.results,
2330
+ generatedAt: options.generatedAt,
2331
+ metadata: mergeSwarmMetadata([
2332
+ options.metadata,
2333
+ { source: 'frontier-run.projection', frontierRunId: projection.run.id }
2334
+ ])
2335
+ });
2336
+ }
2297
2337
  export function createRunDashboardFromSwarmRun(input, options = {}) {
2298
2338
  const events = isFrontierRunEventList(input) ? input : createRunEventsFromSwarmRun(input, options);
2299
2339
  return createRunDashboardSnapshot(createRunProjectionFromSwarmRunEvents(events, options));
@@ -4075,6 +4115,11 @@ export function createSwarmHierarchicalMergeQueue(input) {
4075
4115
  const admissionPressure = summarizeSwarmMergeAdmissionPressure(assignments);
4076
4116
  const orderedScopes = Array.from(scopes.values()).sort((left, right) => (mergeQueueScopeRank(left.kind) - mergeQueueScopeRank(right.kind)
4077
4117
  || left.id.localeCompare(right.id)));
4118
+ const semanticLeaseScopeMap = createSwarmSemanticLeaseScopeMap(orderedScopes, {
4119
+ rootScopeId,
4120
+ ...semanticLeaseScopeOptionsFromMetadata(input.metadata)
4121
+ });
4122
+ const scopesWithSemanticLeases = orderedScopes.map((scope) => attachSemanticLeaseScopeToMergeQueueScope(scope, semanticLeaseScopeMap));
4078
4123
  const queueId = input.id ?? 'swarm-hierarchical-merge-queue:' + stableHash([input.index.id, input.admission?.id, orderedScopes, assignments, promotions, generatedAt]);
4079
4124
  const linkedAssignments = assignments.map((assignment) => {
4080
4125
  if (!coordinatorAgentDrainActionIsTerminal(assignment.action))
@@ -4084,19 +4129,19 @@ export function createSwarmHierarchicalMergeQueue(input) {
4084
4129
  terminalDecisionId: hierarchicalQueueTerminalDecisionId(queueId, assignment),
4085
4130
  terminalDecisionQueueItemIds: [...assignment.queueItemIds]
4086
4131
  };
4087
- });
4132
+ }).map((assignment) => attachSemanticLeaseScopesToAssignment(assignment, semanticLeaseScopeMap));
4088
4133
  const leaseRecords = createHierarchicalQueueLeaseRecords({
4089
4134
  queueId,
4090
4135
  rootScopeId,
4091
4136
  generatedAt,
4092
- scopes: orderedScopes,
4137
+ scopes: scopesWithSemanticLeases,
4093
4138
  assignments: linkedAssignments,
4094
4139
  promotions,
4095
4140
  localLeader: input.localLeader,
4096
4141
  localLeaders: input.localLeaders
4097
4142
  });
4098
4143
  const byLeaseKey = groupJobIdsByMany(linkedAssignments, (assignment) => assignment.requiredLeaseKeys ?? [assignment.leaseKey]);
4099
- const scopeTree = createHierarchicalQueueScopeTree(orderedScopes, rootScopeId);
4144
+ const scopeTree = createHierarchicalQueueScopeTree(scopesWithSemanticLeases, rootScopeId);
4100
4145
  return {
4101
4146
  kind: FRONTIER_SWARM_HIERARCHICAL_MERGE_QUEUE_KIND,
4102
4147
  version: FRONTIER_SWARM_HIERARCHICAL_MERGE_QUEUE_VERSION,
@@ -4106,13 +4151,14 @@ export function createSwarmHierarchicalMergeQueue(input) {
4106
4151
  generatedAt,
4107
4152
  rootScopeId,
4108
4153
  scopeTree,
4109
- scopes: orderedScopes,
4154
+ scopes: scopesWithSemanticLeases,
4110
4155
  leaseRecords,
4111
4156
  assignments: linkedAssignments,
4112
4157
  promotions,
4113
4158
  byScope,
4114
4159
  byLeaseKey,
4115
4160
  byAction,
4161
+ semanticLeaseScopes: uniqueSemanticLeaseScopes(Array.from(semanticLeaseScopeMap.values())),
4116
4162
  summary: {
4117
4163
  scopeCount: orderedScopes.length,
4118
4164
  assignmentCount: linkedAssignments.length,
@@ -4142,6 +4188,7 @@ export function createSwarmCoordinatorAgentDrainWork(input) {
4142
4188
  title: scope.title,
4143
4189
  leaseScope: scope.leaseKey,
4144
4190
  leaseKey: scope.leaseKey,
4191
+ ...(scope.semanticLeaseScope ? { semanticLeaseScope: scope.semanticLeaseScope } : {}),
4145
4192
  ...(scope.parentId ? { parentQueueId: scope.parentId } : {}),
4146
4193
  ...(scope.lane ? { lane: scope.lane } : {}),
4147
4194
  changedPaths: [...scope.changedPaths],
@@ -4171,6 +4218,9 @@ export function createSwarmCoordinatorAgentDrainWork(input) {
4171
4218
  const requiredLeaseKeys = assignmentRequiredLeaseKeys.length
4172
4219
  ? [...assignmentRequiredLeaseKeys]
4173
4220
  : [leaseScope];
4221
+ const requiredSemanticLeaseScopes = requiredLeaseScopeIds
4222
+ .map((scopeId) => scopesById.get(scopeId)?.semanticLeaseScope)
4223
+ .filter((scope) => Boolean(scope));
4174
4224
  const decision = coordinatorAgentDrainDecisionForAction(assignment.action);
4175
4225
  const terminal = coordinatorAgentDrainActionIsTerminal(assignment.action);
4176
4226
  const parentQueueId = assignment.action === 'promote'
@@ -4207,6 +4257,7 @@ export function createSwarmCoordinatorAgentDrainWork(input) {
4207
4257
  conflictingJobIds: [...assignment.conflictingJobIds],
4208
4258
  requiredLeaseScopeIds,
4209
4259
  requiredLeaseKeys,
4260
+ ...(requiredSemanticLeaseScopes.length ? { requiredSemanticLeaseScopes } : {}),
4210
4261
  ...(assignment.retrySlices?.length ? { retrySlices: cloneMergeQueueRetrySlices(assignment.retrySlices) } : {}),
4211
4262
  ...(assignment.semanticSliceScopeIds?.length ? { semanticSliceScopeIds: [...assignment.semanticSliceScopeIds] } : {}),
4212
4263
  ...(assignment.semanticSliceLeaseKeys?.length ? { semanticSliceLeaseKeys: [...assignment.semanticSliceLeaseKeys] } : {}),
@@ -4231,6 +4282,7 @@ export function createSwarmCoordinatorAgentDrainWork(input) {
4231
4282
  reasons: [...assignment.reasons],
4232
4283
  requiredLeaseScopeIds: [...(assignment.requiredLeaseScopeIds ?? [])],
4233
4284
  requiredLeaseKeys: [...(assignment.requiredLeaseKeys ?? [])],
4285
+ ...(assignment.requiredSemanticLeaseScopes?.length ? { requiredSemanticLeaseScopes: assignment.requiredSemanticLeaseScopes.map(cloneSemanticLeaseScope) } : {}),
4234
4286
  ...(assignment.retrySlices?.length ? { retrySlices: cloneMergeQueueRetrySlices(assignment.retrySlices) } : {}),
4235
4287
  ...(assignment.semanticSliceScopeIds?.length ? { semanticSliceScopeIds: [...assignment.semanticSliceScopeIds] } : {}),
4236
4288
  ...(assignment.semanticSliceLeaseKeys?.length ? { semanticSliceLeaseKeys: [...assignment.semanticSliceLeaseKeys] } : {}),
@@ -4257,6 +4309,7 @@ export function createSwarmCoordinatorAgentDrainWork(input) {
4257
4309
  reasons: [...assignment.reasons],
4258
4310
  requiredLeaseScopeIds: [...(assignment.requiredLeaseScopeIds ?? [])],
4259
4311
  requiredLeaseKeys: [...(assignment.requiredLeaseKeys ?? [])],
4312
+ ...(assignment.requiredSemanticLeaseScopes?.length ? { requiredSemanticLeaseScopes: assignment.requiredSemanticLeaseScopes.map(cloneSemanticLeaseScope) } : {}),
4260
4313
  ...(assignment.metadata ? { metadata: cloneJsonValue(assignment.metadata) } : {})
4261
4314
  }));
4262
4315
  const activeAssignments = assignments.filter((assignment) => !coordinatorAgentDrainAssignmentIsTerminal(assignment));
@@ -4314,6 +4367,120 @@ export function createSwarmCoordinatorAgentDrainWork(input) {
4314
4367
  ...(toJsonObject(input.metadata) ? { metadata: toJsonObject(input.metadata) } : {})
4315
4368
  };
4316
4369
  }
4370
+ export function createSwarmSemanticLeaseScopeForMergeQueueScope(scope, input = {}) {
4371
+ const scopesById = new Map((input.scopes ?? []).map((entry) => [entry.id, entry]));
4372
+ const parentKeys = [];
4373
+ let parentId = scope.parentId;
4374
+ const visited = new Set([scope.id]);
4375
+ while (parentId && !visited.has(parentId)) {
4376
+ const parent = scopesById.get(parentId);
4377
+ if (!parent)
4378
+ break;
4379
+ parentKeys.push(parent.leaseKey);
4380
+ visited.add(parentId);
4381
+ parentId = parent.parentId;
4382
+ }
4383
+ const regionId = scope.changedRegions.length === 1 ? scope.changedRegions[0] : scope.id;
4384
+ const path = scope.changedPaths.length === 1 ? scope.changedPaths[0] : undefined;
4385
+ const metadata = mergeSwarmMetadata([
4386
+ scope.metadata,
4387
+ toJsonObject(input.metadata),
4388
+ {
4389
+ swarmQueueScopeId: scope.id,
4390
+ swarmQueueScopeKind: scope.kind,
4391
+ swarmLeaseKey: scope.leaseKey,
4392
+ changedPaths: scope.changedPaths,
4393
+ changedRegions: scope.changedRegions
4394
+ }
4395
+ ]);
4396
+ return defineSemanticLeaseScope({
4397
+ kind: semanticLeaseScopeKindForMergeQueueScope(scope),
4398
+ key: scope.leaseKey,
4399
+ repository: input.repository,
4400
+ packageId: input.packageId,
4401
+ lane: scope.lane,
4402
+ path,
4403
+ regionId,
4404
+ name: semanticLeaseScopeNameForMergeQueueScope(scope),
4405
+ parentKeys,
4406
+ metadata
4407
+ });
4408
+ }
4409
+ export function createSwarmSemanticLeaseScopesForMergeQueue(queue, input = {}) {
4410
+ const existing = queue.scopes
4411
+ .map((scope) => scope.semanticLeaseScope)
4412
+ .filter((scope) => Boolean(scope));
4413
+ if (existing.length)
4414
+ return uniqueSemanticLeaseScopes(existing);
4415
+ return uniqueSemanticLeaseScopes(queue.scopes.map((scope) => (createSwarmSemanticLeaseScopeForMergeQueueScope(scope, {
4416
+ ...input,
4417
+ rootScopeId: input.rootScopeId ?? queue.rootScopeId,
4418
+ scopes: queue.scopes
4419
+ }))));
4420
+ }
4421
+ export function createSwarmSemanticLeaseStateForMergeQueue(queue, input = {}) {
4422
+ const semanticLeaseScopes = createSwarmSemanticLeaseScopesForMergeQueue(queue, input);
4423
+ return createSemanticLeaseState({
4424
+ id: input.id ?? `frontier-swarm-merge-queue:${queue.id}`,
4425
+ defaultTtlMs: input.defaultTtlMs,
4426
+ metadata: mergeSwarmMetadata([
4427
+ toJsonObject(input.metadata),
4428
+ {
4429
+ swarmQueueId: queue.id,
4430
+ swarmMergeIndexId: queue.mergeIndexId,
4431
+ rootScopeId: queue.rootScopeId,
4432
+ semanticLeaseScopeCount: semanticLeaseScopes.length,
4433
+ generatedAt: input.now ?? queue.generatedAt
4434
+ }
4435
+ ])
4436
+ });
4437
+ }
4438
+ export function acquireSwarmCoordinatorSemanticLease(input) {
4439
+ const scopes = semanticLeaseScopesForCoordinatorAssignment(input.queue, input.assignment, input);
4440
+ const requiredLeaseScopeIds = coordinatorAssignmentRequiredLeaseScopeIds(input.assignment);
4441
+ const requiredLeaseKeys = coordinatorAssignmentRequiredLeaseKeys(input.assignment, scopes);
4442
+ const state = input.state ?? createSwarmSemanticLeaseStateForMergeQueue(input.queue, input);
4443
+ const acquireInput = {
4444
+ ownerId: input.ownerId,
4445
+ holderId: input.holderId,
4446
+ now: input.now,
4447
+ ttlMs: input.ttlMs,
4448
+ purpose: input.purpose ?? `frontier swarm coordinator apply: ${input.assignment.jobId}`,
4449
+ reason: input.reason,
4450
+ scopes,
4451
+ metadata: mergeSwarmMetadata([
4452
+ toJsonObject(input.metadata),
4453
+ {
4454
+ swarmQueueId: input.queue.id,
4455
+ swarmJobId: input.assignment.jobId,
4456
+ swarmTaskId: input.assignment.taskId,
4457
+ requiredLeaseScopeIds,
4458
+ requiredLeaseKeys
4459
+ }
4460
+ ])
4461
+ };
4462
+ const mutation = acquireSemanticLease(state, acquireInput);
4463
+ return {
4464
+ state: mutation.state,
4465
+ mutation,
4466
+ scopes,
4467
+ requiredLeaseScopeIds,
4468
+ requiredLeaseKeys,
4469
+ ...(mutation.lease ? { lease: mutation.lease } : {})
4470
+ };
4471
+ }
4472
+ export function validateSwarmCoordinatorSemanticLeaseFence(input) {
4473
+ const requiredScopes = input.requiredSemanticLeaseScopes?.length
4474
+ ? input.requiredSemanticLeaseScopes.map(cloneSemanticLeaseScope)
4475
+ : (input.assignment.requiredSemanticLeaseScopes ?? []).map(cloneSemanticLeaseScope);
4476
+ return validateSemanticLeaseFence(input.state, {
4477
+ leaseId: input.leaseId ?? input.lease?.id ?? '',
4478
+ token: input.token,
4479
+ fencingToken: input.fencingToken,
4480
+ now: input.now,
4481
+ scopes: requiredScopes.length ? requiredScopes : undefined
4482
+ });
4483
+ }
4317
4484
  export function summarizeSwarmCoordinatorAgentDrainWork(work) {
4318
4485
  const activeAssignments = work.assignments.filter((assignment) => !coordinatorAgentDrainAssignmentIsTerminal(assignment));
4319
4486
  const terminalAssignments = work.assignments.filter((assignment) => coordinatorAgentDrainAssignmentIsTerminal(assignment));
@@ -5888,6 +6055,154 @@ function ensureMergeQueueScope(scopes, input) {
5888
6055
  scopes.set(scope.id, scope);
5889
6056
  return scope;
5890
6057
  }
6058
+ function createSwarmSemanticLeaseScopeMap(scopes, input = {}) {
6059
+ const out = new Map();
6060
+ for (const scope of scopes) {
6061
+ out.set(scope.id, createSwarmSemanticLeaseScopeForMergeQueueScope(scope, { ...input, scopes }));
6062
+ }
6063
+ return out;
6064
+ }
6065
+ function attachSemanticLeaseScopeToMergeQueueScope(scope, semanticLeaseScopes) {
6066
+ const semanticLeaseScope = semanticLeaseScopes.get(scope.id);
6067
+ return {
6068
+ ...scope,
6069
+ ...(semanticLeaseScope ? { semanticLeaseScope: cloneSemanticLeaseScope(semanticLeaseScope) } : {})
6070
+ };
6071
+ }
6072
+ function attachSemanticLeaseScopesToAssignment(assignment, semanticLeaseScopes) {
6073
+ const requiredLeaseScopeIds = assignment.requiredLeaseScopeIds?.length ? assignment.requiredLeaseScopeIds : [assignment.scopeId];
6074
+ const requiredSemanticLeaseScopes = requiredLeaseScopeIds
6075
+ .map((scopeId) => semanticLeaseScopes.get(scopeId))
6076
+ .filter((scope) => Boolean(scope))
6077
+ .map(cloneSemanticLeaseScope);
6078
+ const retrySlices = assignment.retrySlices?.map((slice) => {
6079
+ const requiredScopeIds = slice.requiredLeaseScopeIds?.length ? slice.requiredLeaseScopeIds : [slice.scopeId];
6080
+ const requiredScopes = requiredScopeIds
6081
+ .map((scopeId) => semanticLeaseScopes.get(scopeId))
6082
+ .filter((scope) => Boolean(scope))
6083
+ .map(cloneSemanticLeaseScope);
6084
+ const semanticLeaseScope = semanticLeaseScopes.get(slice.scopeId);
6085
+ return {
6086
+ ...slice,
6087
+ ...(semanticLeaseScope ? { semanticLeaseScope: cloneSemanticLeaseScope(semanticLeaseScope) } : {}),
6088
+ ...(requiredScopes.length ? { requiredSemanticLeaseScopes: requiredScopes } : {})
6089
+ };
6090
+ });
6091
+ return {
6092
+ ...assignment,
6093
+ ...(requiredSemanticLeaseScopes.length ? { requiredSemanticLeaseScopes } : {}),
6094
+ ...(retrySlices?.length ? { retrySlices } : {})
6095
+ };
6096
+ }
6097
+ function semanticLeaseScopesForCoordinatorAssignment(queue, assignment, input = {}) {
6098
+ if (assignment.requiredSemanticLeaseScopes?.length) {
6099
+ return uniqueSemanticLeaseScopes(assignment.requiredSemanticLeaseScopes.map(cloneSemanticLeaseScope));
6100
+ }
6101
+ const queueScopes = new Map(queue.scopes.map((scope) => [scope.id, scope]));
6102
+ const semanticByKey = new Map(createSwarmSemanticLeaseScopesForMergeQueue(queue, input).map((scope) => [scope.key, scope]));
6103
+ const fromIds = coordinatorAssignmentRequiredLeaseScopeIds(assignment)
6104
+ .map((scopeId) => queueScopes.get(scopeId)?.semanticLeaseScope)
6105
+ .filter((scope) => Boolean(scope));
6106
+ if (fromIds.length)
6107
+ return uniqueSemanticLeaseScopes(fromIds);
6108
+ const fromKeys = coordinatorAssignmentRequiredLeaseKeys(assignment, [])
6109
+ .map((key) => semanticByKey.get(key))
6110
+ .filter((scope) => Boolean(scope));
6111
+ if (fromKeys.length)
6112
+ return uniqueSemanticLeaseScopes(fromKeys);
6113
+ const fallbackKey = 'leaseScope' in assignment ? assignment.leaseScope : assignment.leaseKey;
6114
+ return [defineSemanticLeaseScope({
6115
+ kind: 'custom',
6116
+ key: fallbackKey,
6117
+ repository: input.repository,
6118
+ packageId: input.packageId,
6119
+ metadata: mergeSwarmMetadata([
6120
+ toJsonObject(input.metadata),
6121
+ {
6122
+ swarmQueueId: queue.id,
6123
+ swarmJobId: assignment.jobId,
6124
+ fallbackLeaseKey: fallbackKey
6125
+ }
6126
+ ])
6127
+ })];
6128
+ }
6129
+ function coordinatorAssignmentRequiredLeaseScopeIds(assignment) {
6130
+ const explicit = assignment.requiredLeaseScopeIds ?? [];
6131
+ if (explicit.length)
6132
+ return uniqueStrings(explicit);
6133
+ return uniqueStrings(['queueId' in assignment ? assignment.queueId : assignment.scopeId]);
6134
+ }
6135
+ function coordinatorAssignmentRequiredLeaseKeys(assignment, scopes) {
6136
+ const explicit = assignment.requiredLeaseKeys ?? [];
6137
+ if (explicit.length)
6138
+ return uniqueStrings(explicit);
6139
+ if (scopes.length)
6140
+ return uniqueStrings(scopes.map((scope) => scope.key));
6141
+ return uniqueStrings(['leaseScope' in assignment ? assignment.leaseScope : assignment.leaseKey]);
6142
+ }
6143
+ function semanticLeaseScopeOptionsFromMetadata(metadata) {
6144
+ const object = toJsonObject(metadata);
6145
+ if (!object)
6146
+ return {};
6147
+ return {
6148
+ ...(typeof object.repository === 'string' ? { repository: object.repository } : {}),
6149
+ ...(typeof object.packageId === 'string' ? { packageId: object.packageId } : {})
6150
+ };
6151
+ }
6152
+ function semanticLeaseScopeKindForMergeQueueScope(scope) {
6153
+ if (scope.kind === 'root')
6154
+ return 'repository';
6155
+ if (scope.kind === 'path')
6156
+ return 'path';
6157
+ if (scope.kind === 'lane')
6158
+ return 'lane';
6159
+ if (scope.kind === 'semantic-region' || scope.kind === 'semantic')
6160
+ return semanticLeaseScopeKindForRegion(scope.changedRegions[0]);
6161
+ if (scope.kind === 'package')
6162
+ return 'package';
6163
+ return 'custom';
6164
+ }
6165
+ function semanticLeaseScopeKindForRegion(region) {
6166
+ if (!region)
6167
+ return 'semantic-region';
6168
+ const normalized = region.toLowerCase();
6169
+ if (normalized.includes(FRONTIER_SWARM_SEMANTIC_OWNERSHIP_EXPORT_STABLE_KEY_KIND) || normalized.includes('named-export') || normalized.includes('default-export'))
6170
+ return 'export';
6171
+ if (normalized.includes(FRONTIER_SWARM_SEMANTIC_OWNERSHIP_TYPE_STABLE_KEY_KIND) || normalized.includes('interface') || normalized.includes('type-alias'))
6172
+ return 'type';
6173
+ if (normalized.includes(FRONTIER_SWARM_SEMANTIC_OWNERSHIP_CLI_COMMAND_STABLE_KEY_KIND))
6174
+ return 'cli-command';
6175
+ if (normalized.includes(FRONTIER_SWARM_SEMANTIC_OWNERSHIP_DOCS_SECTION_STABLE_KEY_KIND))
6176
+ return 'docs-section';
6177
+ if (normalized.includes(FRONTIER_SWARM_SEMANTIC_OWNERSHIP_FIXTURE_FAMILY_STABLE_KEY_KIND))
6178
+ return 'test-fixture';
6179
+ if (normalized.includes(FRONTIER_SWARM_SEMANTIC_OWNERSHIP_TEST_CASE_STABLE_KEY_KIND))
6180
+ return 'test-fixture';
6181
+ if (normalized.includes('function'))
6182
+ return 'function';
6183
+ if (normalized.includes('class'))
6184
+ return 'class';
6185
+ if (normalized.includes('member'))
6186
+ return 'member';
6187
+ return 'semantic-region';
6188
+ }
6189
+ function semanticLeaseScopeNameForMergeQueueScope(scope) {
6190
+ const region = scope.changedRegions[0];
6191
+ if (region)
6192
+ return region.split(':').filter(Boolean).at(-1);
6193
+ if (scope.changedPaths.length === 1)
6194
+ return scope.changedPaths[0].split('/').at(-1);
6195
+ return scope.title || scope.id;
6196
+ }
6197
+ function uniqueSemanticLeaseScopes(scopes) {
6198
+ const out = new Map();
6199
+ for (const scope of scopes)
6200
+ out.set(scope.key, cloneSemanticLeaseScope(scope));
6201
+ return Array.from(out.values()).sort((left, right) => left.key.localeCompare(right.key));
6202
+ }
6203
+ function cloneSemanticLeaseScope(scope) {
6204
+ return cloneJsonValue(scope);
6205
+ }
5891
6206
  function mergeQueueRootLeaseKey(rootScopeId) {
5892
6207
  return `merge:root:${rootScopeId}`;
5893
6208
  }
@@ -6002,6 +6317,8 @@ function cloneMergeQueueRetrySlices(slices) {
6002
6317
  leaseKey: slice.leaseKey,
6003
6318
  ...(slice.requiredLeaseScopeIds?.length ? { requiredLeaseScopeIds: [...slice.requiredLeaseScopeIds] } : {}),
6004
6319
  ...(slice.requiredLeaseKeys?.length ? { requiredLeaseKeys: [...slice.requiredLeaseKeys] } : {}),
6320
+ ...(slice.semanticLeaseScope ? { semanticLeaseScope: cloneSemanticLeaseScope(slice.semanticLeaseScope) } : {}),
6321
+ ...(slice.requiredSemanticLeaseScopes?.length ? { requiredSemanticLeaseScopes: slice.requiredSemanticLeaseScopes.map(cloneSemanticLeaseScope) } : {}),
6005
6322
  ...(slice.lane ? { lane: slice.lane } : {}),
6006
6323
  changedPaths: [...slice.changedPaths],
6007
6324
  changedRegions: [...slice.changedRegions],
@@ -6051,6 +6368,7 @@ function createHierarchicalQueueLeaseRecords(input) {
6051
6368
  ...(scope.lane ? { lane: scope.lane } : {}),
6052
6369
  title: scope.title,
6053
6370
  leaseKey: scope.leaseKey,
6371
+ ...(scope.semanticLeaseScope ? { semanticLeaseScope: cloneSemanticLeaseScope(scope.semanticLeaseScope) } : {}),
6054
6372
  ...(hierarchicalQueueLocalLeaderForScope(input, scope) ? { localLeader: hierarchicalQueueLocalLeaderForScope(input, scope) } : {}),
6055
6373
  promotion: {
6056
6374
  state: promotionState,
@@ -10173,6 +10491,258 @@ function swarmRunEventTime(options, fallback) {
10173
10491
  const value = options.now ?? fallback;
10174
10492
  return new Date(Number.isFinite(value) ? value : Date.now()).toISOString();
10175
10493
  }
10494
+ function createSwarmEventsFromRunProjection(projection) {
10495
+ return projection.events.map((event) => ({
10496
+ id: `frontier-run:${event.id}`,
10497
+ type: event.type,
10498
+ runId: projection.run.id,
10499
+ at: parseRunTimeMs(event.time, Date.now()),
10500
+ message: event.type,
10501
+ data: event.payload,
10502
+ metadata: pruneUndefinedJsonObject({
10503
+ source: 'frontier-run.event',
10504
+ eventId: event.id,
10505
+ actorId: event.actorId,
10506
+ actorSeq: event.actorSeq,
10507
+ parents: event.parents
10508
+ })
10509
+ }));
10510
+ }
10511
+ function deriveSwarmResultFromRunProjection(projection, job) {
10512
+ const graph = projection.run.graph;
10513
+ const nodes = Object.values(graph.nodes);
10514
+ const edges = Object.values(graph.edges);
10515
+ const attempt = nodes.find((node) => node.kind === 'attempt' && runNodeMatchesJob(node, job));
10516
+ const attemptId = attempt?.id ?? swarmRunAttemptNodeId(job.id);
10517
+ const patchNodes = nodes.filter((node) => node.kind === 'patch' && runNodeMatchesJob(node, job));
10518
+ const patchIds = new Set(patchNodes.map((node) => node.id));
10519
+ const verificationNodeIds = new Set(edges
10520
+ .filter((edge) => edge.from === attemptId && edge.type === 'verified-by')
10521
+ .map((edge) => edge.to));
10522
+ const verificationNodes = nodes.filter((node) => (node.kind === 'verification'
10523
+ && (runNodeMatchesJob(node, job) || verificationNodeIds.has(node.id))));
10524
+ const decisionNodes = nodes.filter((node) => (node.kind === 'decision'
10525
+ && (runNodeMatchesJob(node, job) || runDecisionSubjectsJob(node, job, patchIds))));
10526
+ const evidenceNodes = nodes.filter((node) => (node.kind === 'evidence'
10527
+ && (runNodeMatchesJob(node, job) || runEvidenceLinkedToJob(node, attemptId, patchIds, edges))));
10528
+ const hasProjectionResult = !!attempt || patchNodes.length > 0 || verificationNodes.length > 0 || evidenceNodes.length > 0 || decisionNodes.length > 0;
10529
+ if (!hasProjectionResult)
10530
+ return undefined;
10531
+ const attemptMetadata = attempt ? runNodeMetadata(attempt) : undefined;
10532
+ const patchMetadata = patchNodes.map(runNodeMetadata);
10533
+ const decisionMetadata = decisionNodes.map(runNodeMetadata);
10534
+ const mergedMetadata = mergeSwarmMetadata([
10535
+ attemptMetadata,
10536
+ ...patchMetadata,
10537
+ ...decisionMetadata,
10538
+ { source: 'frontier-run.projection', frontierRunId: projection.run.id }
10539
+ ]);
10540
+ const changedPaths = uniqueStrings(patchNodes.flatMap((node) => node.kind === 'patch' ? node.changedPaths : []));
10541
+ const changedRegions = uniqueStrings(patchMetadata.flatMap((metadata) => jsonStringArray(metadata?.changedRegions)));
10542
+ const ownershipViolations = uniqueStrings(patchMetadata.flatMap((metadata) => jsonStringArray(metadata?.ownershipViolations)));
10543
+ const evidencePaths = deriveRunEvidencePaths(nodes, edges, attemptId, patchIds, evidenceNodes);
10544
+ const patchPath = deriveRunPatchPath(nodes, edges, patchNodes);
10545
+ const status = deriveSwarmResultStatusFromRunAttempt(attempt, verificationNodes, patchNodes);
10546
+ const error = status === 'failed' || status === 'blocked'
10547
+ ? (runMetadataString(attemptMetadata, 'reason') ?? (attempt?.kind === 'attempt' ? attempt.reason : undefined))
10548
+ : undefined;
10549
+ const startedAt = attempt?.kind === 'attempt' ? parseOptionalRunTimeMs(attempt.startedAt) : undefined;
10550
+ const finishedAt = attempt?.kind === 'attempt' ? parseOptionalRunTimeMs(attempt.endedAt) : undefined;
10551
+ return {
10552
+ jobId: job.id,
10553
+ status,
10554
+ mergeReadiness: readSwarmMergeReadiness(attemptMetadata, patchMetadata, decisionMetadata),
10555
+ ...(startedAt !== undefined ? { startedAt } : {}),
10556
+ ...(finishedAt !== undefined ? { finishedAt } : {}),
10557
+ ...(runMetadataNumber(attemptMetadata, 'exitCode') !== undefined ? { exitCode: runMetadataNumber(attemptMetadata, 'exitCode') } : {}),
10558
+ ...(runMetadataString(attemptMetadata, 'signal') ? { signal: runMetadataString(attemptMetadata, 'signal') } : {}),
10559
+ changedPaths,
10560
+ changedRegions,
10561
+ ownershipViolations,
10562
+ evidencePaths,
10563
+ ...(patchPath ? { patchPath } : {}),
10564
+ queueItemIds: uniqueStrings([
10565
+ ...jsonStringArray(attemptMetadata?.queueItemIds),
10566
+ ...patchMetadata.flatMap((metadata) => jsonStringArray(metadata?.queueItemIds)),
10567
+ ...decisionMetadata.flatMap((metadata) => jsonStringArray(metadata?.queueItemIds))
10568
+ ]),
10569
+ riskLevel: readSwarmRiskLevel(attemptMetadata, patchMetadata),
10570
+ mergeDisposition: readSwarmMergeDisposition(attemptMetadata, patchMetadata, decisionMetadata),
10571
+ verification: verificationNodes.map((node) => runVerificationNodeToSwarmResult(node)),
10572
+ ...(attemptMetadata?.semanticImport !== undefined ? { semanticImport: cloneJsonValue(attemptMetadata.semanticImport) } : {}),
10573
+ ...(patchNodes[0]?.kind === 'patch' && patchNodes[0].summary ? { lastMessage: patchNodes[0].summary } : {}),
10574
+ ...(error ? { error } : {}),
10575
+ ...(mergedMetadata ? { metadata: mergedMetadata } : {})
10576
+ };
10577
+ }
10578
+ function runNodeMatchesJob(node, job) {
10579
+ const metadata = runNodeMetadata(node);
10580
+ const metadataJobId = runMetadataString(metadata, 'jobId');
10581
+ if (metadataJobId === job.id)
10582
+ return true;
10583
+ if (node.kind === 'attempt' && node.taskId === swarmRunTaskNodeId(job.taskId))
10584
+ return true;
10585
+ if (node.kind === 'task' && node.id === swarmRunTaskNodeId(job.taskId))
10586
+ return true;
10587
+ if ((node.kind === 'attempt' || node.kind === 'patch') && stripRunNodePrefix(node.id, node.kind) === job.id)
10588
+ return true;
10589
+ return false;
10590
+ }
10591
+ function runDecisionSubjectsJob(node, job, patchIds) {
10592
+ if (node.kind !== 'decision')
10593
+ return false;
10594
+ const taskId = swarmRunTaskNodeId(job.taskId);
10595
+ return node.subjectIds.some((subjectId) => subjectId === taskId || patchIds.has(subjectId));
10596
+ }
10597
+ function runEvidenceLinkedToJob(node, attemptId, patchIds, edges) {
10598
+ if (node.kind !== 'evidence')
10599
+ return false;
10600
+ return edges.some((edge) => edge.to === node.id && (edge.from === attemptId || patchIds.has(edge.from)));
10601
+ }
10602
+ function deriveRunEvidencePaths(nodes, edges, attemptId, patchIds, evidenceNodes) {
10603
+ const artifacts = new Map(nodes
10604
+ .filter((node) => node.kind === 'artifact')
10605
+ .map((node) => [node.id, node]));
10606
+ const subjectIds = new Set([attemptId, ...patchIds]);
10607
+ const linkedArtifactIds = edges
10608
+ .filter((edge) => edge.type === 'produces-artifact' && subjectIds.has(edge.from))
10609
+ .map((edge) => edge.to);
10610
+ return uniqueStrings([
10611
+ ...evidenceNodes.flatMap((node) => node.kind === 'evidence' ? (node.artifactIds ?? []) : [])
10612
+ .map((artifactId) => runArtifactPath(artifacts.get(artifactId)))
10613
+ .filter((file) => !!file),
10614
+ ...linkedArtifactIds
10615
+ .map((artifactId) => artifacts.get(artifactId))
10616
+ .filter((node) => !!node && node.kind === 'artifact' && node.artifactType !== 'patch')
10617
+ .map(runArtifactPath)
10618
+ .filter((file) => !!file)
10619
+ ]);
10620
+ }
10621
+ function deriveRunPatchPath(nodes, edges, patchNodes) {
10622
+ const artifacts = new Map(nodes
10623
+ .filter((node) => node.kind === 'artifact')
10624
+ .map((node) => [node.id, node]));
10625
+ for (const patch of patchNodes) {
10626
+ if (patch.kind !== 'patch')
10627
+ continue;
10628
+ const metadataPatchPath = runMetadataString(runNodeMetadata(patch), 'patchPath');
10629
+ if (metadataPatchPath)
10630
+ return metadataPatchPath;
10631
+ if (patch.artifactId) {
10632
+ const artifactPath = runArtifactPath(artifacts.get(patch.artifactId));
10633
+ if (artifactPath)
10634
+ return artifactPath;
10635
+ }
10636
+ const attached = edges
10637
+ .filter((edge) => edge.from === patch.id && edge.type === 'produces-artifact')
10638
+ .map((edge) => artifacts.get(edge.to))
10639
+ .find((node) => node?.kind === 'artifact' && node.artifactType === 'patch');
10640
+ const attachedPath = runArtifactPath(attached);
10641
+ if (attachedPath)
10642
+ return attachedPath;
10643
+ }
10644
+ return undefined;
10645
+ }
10646
+ function runVerificationNodeToSwarmResult(node) {
10647
+ if (node.kind !== 'verification')
10648
+ return { name: node.id };
10649
+ const metadata = runNodeMetadata(node);
10650
+ const command = node.command ? [node.command, ...(node.args ?? [])] : [];
10651
+ return {
10652
+ name: node.title ?? node.id,
10653
+ command,
10654
+ ...(command.length ? { commandLine: command.join(' ') } : {}),
10655
+ ...(node.cwd ? { cwd: node.cwd } : {}),
10656
+ ...(node.exitCode !== undefined ? { status: node.exitCode } : { status: node.status === 'passed' ? 0 : node.status === 'failed' ? 1 : undefined }),
10657
+ ...(runMetadataNumber(metadata, 'durationMs') !== undefined ? { durationMs: runMetadataNumber(metadata, 'durationMs') } : {}),
10658
+ stdoutTail: jsonStringArray(metadata?.stdoutTail),
10659
+ stderrTail: jsonStringArray(metadata?.stderrTail),
10660
+ required: node.required ?? true,
10661
+ ...(runMetadataString(metadata, 'category') ? { category: runMetadataString(metadata, 'category') } : {}),
10662
+ ...(metadata ? { metadata } : {})
10663
+ };
10664
+ }
10665
+ function deriveSwarmResultStatusFromRunAttempt(attempt, verificationNodes, patchNodes) {
10666
+ if (attempt?.kind === 'attempt') {
10667
+ if (attempt.status === 'completed')
10668
+ return 'completed';
10669
+ if (attempt.status === 'running')
10670
+ return 'running';
10671
+ if (attempt.status === 'queued')
10672
+ return 'scheduled';
10673
+ if (attempt.status === 'cancelled' || attempt.status === 'timed-out' || attempt.status === 'failed')
10674
+ return 'failed';
10675
+ }
10676
+ if (verificationNodes.some((node) => node.kind === 'verification' && node.required !== false && node.status === 'failed'))
10677
+ return 'failed';
10678
+ if (patchNodes.length > 0 || verificationNodes.length > 0)
10679
+ return 'completed';
10680
+ return 'planned';
10681
+ }
10682
+ function deriveSwarmRunStatusFromResults(jobs, results) {
10683
+ if (results.length === 0)
10684
+ return 'planned';
10685
+ if (results.some((result) => result.status === 'failed'))
10686
+ return 'failed';
10687
+ if (results.some((result) => result.status === 'blocked'))
10688
+ return 'blocked';
10689
+ if (results.some((result) => result.status === 'running'))
10690
+ return 'running';
10691
+ if (results.length >= jobs.length && results.every((result) => result.status === 'completed' || result.status === 'verified'))
10692
+ return 'completed';
10693
+ return 'running';
10694
+ }
10695
+ function latestSwarmResultFinishedAt(results) {
10696
+ const finishedAt = results
10697
+ .map((result) => result.finishedAt)
10698
+ .filter((value) => value !== undefined);
10699
+ return finishedAt.length ? Math.max(...finishedAt) : undefined;
10700
+ }
10701
+ function readSwarmMergeReadiness(attemptMetadata, patchMetadata, decisionMetadata) {
10702
+ return readFirstMetadataString('mergeReadiness', [attemptMetadata, ...patchMetadata, ...decisionMetadata]);
10703
+ }
10704
+ function readSwarmMergeDisposition(attemptMetadata, patchMetadata, decisionMetadata) {
10705
+ return readFirstMetadataString('mergeDisposition', [attemptMetadata])
10706
+ ?? readFirstMetadataString('disposition', [...patchMetadata, ...decisionMetadata]);
10707
+ }
10708
+ function readSwarmRiskLevel(attemptMetadata, patchMetadata) {
10709
+ return readFirstMetadataString('riskLevel', [attemptMetadata, ...patchMetadata]);
10710
+ }
10711
+ function readFirstMetadataString(key, metadata) {
10712
+ for (const entry of metadata) {
10713
+ const value = runMetadataString(entry, key);
10714
+ if (value)
10715
+ return value;
10716
+ }
10717
+ return undefined;
10718
+ }
10719
+ function runNodeMetadata(node) {
10720
+ return toJsonObject(node.metadata);
10721
+ }
10722
+ function runMetadataString(metadata, key) {
10723
+ const value = metadata?.[key];
10724
+ return typeof value === 'string' && value ? value : undefined;
10725
+ }
10726
+ function runMetadataNumber(metadata, key) {
10727
+ const value = metadata?.[key];
10728
+ return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
10729
+ }
10730
+ function runArtifactPath(node) {
10731
+ if (!node || node.kind !== 'artifact')
10732
+ return undefined;
10733
+ return node.path ?? node.uri ?? node.title;
10734
+ }
10735
+ function stripRunNodePrefix(id, prefix) {
10736
+ return id.startsWith(`${prefix}:`) ? id.slice(prefix.length + 1) : undefined;
10737
+ }
10738
+ function parseRunTimeMs(value, fallback) {
10739
+ const parsed = value ? Date.parse(value) : NaN;
10740
+ return Number.isFinite(parsed) ? parsed : fallback;
10741
+ }
10742
+ function parseOptionalRunTimeMs(value) {
10743
+ const parsed = value ? Date.parse(value) : NaN;
10744
+ return Number.isFinite(parsed) ? parsed : undefined;
10745
+ }
10176
10746
  function isFrontierRunEventList(input) {
10177
10747
  return Array.isArray(input);
10178
10748
  }