@lsctech/polaris 0.5.11 → 0.5.13

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.
Files changed (41) hide show
  1. package/dist/autoresearch/proposal.js +61 -0
  2. package/dist/autoresearch/score.js +124 -0
  3. package/dist/cli/adopt-canon.js +22 -8
  4. package/dist/cli/index.js +4 -0
  5. package/dist/cli/qc.js +97 -0
  6. package/dist/config/validator.js +16 -6
  7. package/dist/finalize/artifact-policy.js +12 -3
  8. package/dist/finalize/index.js +36 -21
  9. package/dist/finalize/run-report.js +189 -19
  10. package/dist/finalize/steps/05-generate-report.js +5 -1
  11. package/dist/finalize/steps/12-archive.js +6 -0
  12. package/dist/loop/adapters/terminal-cli.js +159 -25
  13. package/dist/loop/body-parser.js +73 -6
  14. package/dist/loop/continue.js +22 -4
  15. package/dist/loop/dispatch.js +103 -68
  16. package/dist/loop/orphan-recovery.js +2 -1
  17. package/dist/loop/parent.js +50 -15
  18. package/dist/loop/router/engine.js +1 -0
  19. package/dist/loop/run-bootstrap.js +3 -1
  20. package/dist/loop/run-preflight.js +4 -1
  21. package/dist/loop/worker-packet.js +81 -2
  22. package/dist/map/inference.js +4 -1
  23. package/dist/medic/routing-signals.js +60 -0
  24. package/dist/medic/run-health-consult.js +5 -4
  25. package/dist/medic/treatment-packets.js +5 -1
  26. package/dist/qc/policy.js +2 -0
  27. package/dist/qc/providers/coderabbit.js +140 -10
  28. package/dist/qc/repair-loop.js +147 -1
  29. package/dist/qc/repair-packets.js +16 -3
  30. package/dist/qc/routing.js +6 -0
  31. package/dist/qc/types.js +3 -0
  32. package/dist/run-health/index.js +12 -0
  33. package/dist/skill-packet/generator.js +234 -3
  34. package/dist/smartdocs-engine/canon-check.js +5 -5
  35. package/dist/smartdocs-engine/index.js +54 -0
  36. package/dist/smartdocs-engine/seed-instructions.js +159 -4
  37. package/dist/smartdocs-engine/validate-instructions.js +46 -4
  38. package/dist/tracker/local-graph.js +106 -3
  39. package/dist/workspace/POLARIS.md +4 -0
  40. package/dist/workspace/SUMMARY.md +56 -0
  41. package/package.json +1 -1
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveTelemetryFilePath = resolveTelemetryFilePath;
3
4
  exports.runLoopContinue = runLoopContinue;
4
5
  const node_path_1 = require("node:path");
5
6
  const node_fs_1 = require("node:fs");
@@ -214,7 +215,7 @@ function appendTelemetryEvent(telemetryFile, event) {
214
215
  }
215
216
  function resolveTelemetryFilePath(state, repoRoot) {
216
217
  const artifactDir = state.artifact_dir ?? (0, node_path_1.join)(repoRoot, ".taskchain_artifacts", "polaris-run");
217
- return (0, node_path_1.join)(artifactDir, "runs", state.run_id, "telemetry.jsonl");
218
+ return (0, node_path_1.resolve)(repoRoot, artifactDir, "runs", state.run_id, "telemetry.jsonl");
218
219
  }
219
220
  function hasValidationEvidence(validation) {
220
221
  if (validation === undefined || validation === null)
@@ -280,12 +281,15 @@ function bridgeEvidenceToClusterState(repoRoot, clusterId, childId, commit, rawV
280
281
  : [...existing.child_states, { id: childId, status: "done", commit: commit || undefined }];
281
282
  // Evict any stale commit entry for this child before conditionally re-adding
282
283
  const { [childId]: _staleCommit, ...remainingCommits } = existing.commits;
284
+ const relativeResultFile = resultFile
285
+ ? (0, node_path_1.relative)(repoRoot, (0, node_path_1.isAbsolute)(resultFile) ? resultFile : (0, node_path_1.resolve)(repoRoot, resultFile))
286
+ : resultFile;
283
287
  const updated = {
284
288
  ...existing,
285
289
  state_generation: existing.state_generation + 1,
286
290
  child_states: updatedChildStates,
287
291
  commits: commit ? { ...remainingCommits, [childId]: commit } : remainingCommits,
288
- result_pointers: resultFile ? { ...existing.result_pointers, [childId]: resultFile } : existing.result_pointers,
292
+ result_pointers: relativeResultFile ? { ...existing.result_pointers, [childId]: relativeResultFile } : existing.result_pointers,
289
293
  validation_results: { ...existing.validation_results, [childId]: toValidationResult(rawValidation) },
290
294
  };
291
295
  (0, store_js_1.writeClusterStateSync)(clusterId, updated, repoRoot);
@@ -379,7 +383,7 @@ function runLoopContinue(options) {
379
383
  // If no dispatch was recorded (dispatch_epoch === continue_epoch),
380
384
  // reject immediately and do NOT mutate any state.
381
385
  const artifactDirForTelemetry = state.artifact_dir ?? (0, node_path_1.join)(repoRoot, ".taskchain_artifacts", "polaris-run");
382
- const telemetryFileForCheck = (0, node_path_1.join)(artifactDirForTelemetry, "runs", state.run_id, "telemetry.jsonl");
386
+ const telemetryFileForCheck = (0, node_path_1.resolve)(repoRoot, artifactDirForTelemetry, "runs", state.run_id, "telemetry.jsonl");
383
387
  try {
384
388
  (0, dispatch_boundary_js_1.assertContinueRequiresDispatch)(state, telemetryFileForCheck);
385
389
  }
@@ -601,10 +605,24 @@ function runLoopContinue(options) {
601
605
  }
602
606
  // Step 1 (cont): Atomic write of updated current-state.json (open_children_meta pruned after bridge)
603
607
  const sha = (0, checkpoint_js_1.writeStateAtomic)(stateFile, updatedState);
608
+ // Also keep the canonical cluster state snapshot in sync so finalize and
609
+ // direct cluster-state reads see the same completed children.
610
+ const canonicalStatePath = (0, node_path_1.join)(repoRoot, ".polaris", "clusters", updatedState.cluster_id, "state.json");
611
+ if ((0, node_path_1.resolve)(stateFile) !== (0, node_path_1.resolve)(canonicalStatePath)) {
612
+ try {
613
+ (0, checkpoint_js_1.writeStateAtomic)(canonicalStatePath, updatedState);
614
+ }
615
+ catch (error) {
616
+ const msg = error instanceof Error ? error.message : String(error);
617
+ console.error(`Error: primary state for cluster ${updatedState.cluster_id} was persisted, but the canonical ` +
618
+ `cluster state snapshot at ${canonicalStatePath} failed to update and remains stale: ${msg}`);
619
+ process.exit(1);
620
+ }
621
+ }
604
622
  appendContinueLedgerEvents(repoRoot, updatedState, completedChild);
605
623
  // Step 2: Append JSONL checkpoint event
606
624
  const artifactDir = state.artifact_dir ?? (0, node_path_1.join)(repoRoot, ".taskchain_artifacts", "polaris-run");
607
- const telemetryFile = (0, node_path_1.join)(artifactDir, "runs", state.run_id, "telemetry.jsonl");
625
+ const telemetryFile = (0, node_path_1.resolve)(repoRoot, artifactDir, "runs", state.run_id, "telemetry.jsonl");
608
626
  (0, checkpoint_js_1.appendCheckpointEvent)(telemetryFile, {
609
627
  event: "loop-checkpoint",
610
628
  run_id: state.run_id,
@@ -139,6 +139,18 @@ function resolveProviderAndMode(options, role, config, routerContext) {
139
139
  },
140
140
  compatibilityMode: false,
141
141
  });
142
+ const workerPolicy = exec?.providerPolicy?.[role];
143
+ const noFallback = workerPolicy?.noFallback === true;
144
+ const fallbackEligible = !noFallback && decision.providersTried.length > 1;
145
+ const routingSummary = {
146
+ selected_provider: decision.selectedProvider ?? null,
147
+ selected_adapter: adapter,
148
+ selection_reason: decision.selectionReason,
149
+ effective_policy_order: decision.providersTried,
150
+ compatibility_mode: false,
151
+ registry_present: true,
152
+ fallback_eligible: fallbackEligible,
153
+ };
142
154
  return {
143
155
  provider: decision.selectedProvider,
144
156
  mode: decision.mode,
@@ -157,91 +169,108 @@ function resolveProviderAndMode(options, role, config, routerContext) {
157
169
  activeSlotsByProvider: routerContext?.activeSlotsByProvider,
158
170
  quotaAvailableByProvider: routerContext?.quotaAvailableByProvider,
159
171
  },
172
+ routingSummary,
160
173
  };
161
174
  }
162
175
  function resolveProviderAndModeLegacy(options, role, adapter, exec) {
163
- if (options.provider) {
164
- return {
165
- provider: options.provider,
166
- mode: "direct-worker",
167
- adapter,
168
- selectionReason: "cli-provider-override",
169
- overrideSource: "dispatch-flag",
170
- providersTried: [options.provider],
171
- };
172
- }
173
176
  const rolePolicy = exec?.providerPolicy?.[role];
174
177
  const roleProviders = rolePolicy?.providers ?? [];
178
+ const noFallback = rolePolicy?.noFallback === true;
175
179
  const rotation = exec?.rotation ?? [];
176
- if (roleProviders.length > 0) {
180
+ const configuredProviders = new Set(Object.keys(exec?.providers ?? {}));
181
+ let provider;
182
+ let selectionReason;
183
+ let overrideSource;
184
+ let fallbackFrom;
185
+ let fallbackReason;
186
+ let exhaustedReason;
187
+ let effectivePolicyOrder;
188
+ if (options.provider) {
189
+ provider = options.provider;
190
+ selectionReason = "cli-provider-override";
191
+ overrideSource = "dispatch-flag";
192
+ effectivePolicyOrder = [options.provider];
193
+ }
194
+ else if (roleProviders.length > 0) {
177
195
  // When a role policy is configured, filter the rotation to only include
178
196
  // providers that are allowed by the policy. This ensures that a provider
179
197
  // present in rotation but absent from the policy is never selected.
180
198
  const allowedByPolicy = new Set(roleProviders);
181
- const configuredProviders = new Set(Object.keys(exec?.providers ?? {}));
182
199
  const filteredRotation = rotation.filter((p) => allowedByPolicy.has(p));
200
+ const availablePolicyProviders = roleProviders.filter((p) => configuredProviders.has(p));
183
201
  if (filteredRotation.length > 0 && filteredRotation[0]) {
184
- return {
185
- provider: filteredRotation[0],
186
- mode: "direct-worker",
187
- adapter,
188
- selectionReason: "policy-filtered-rotation",
189
- providersTried: [filteredRotation[0]],
190
- };
202
+ provider = filteredRotation[0];
203
+ selectionReason = "policy-filtered-rotation";
204
+ effectivePolicyOrder = filteredRotation.slice();
205
+ // Surface remaining configured policy providers as fallback alternatives
206
+ for (const p of availablePolicyProviders) {
207
+ if (!effectivePolicyOrder.includes(p)) {
208
+ effectivePolicyOrder.push(p);
209
+ }
210
+ }
191
211
  }
192
- // No rotation entry is in the policy — fall back to first policy provider
193
- // that is actually configured. If none is configured, fail before mutation.
194
- const availablePolicyProviders = roleProviders.filter((p) => configuredProviders.has(p));
195
- if (availablePolicyProviders.length > 0 && availablePolicyProviders[0]) {
196
- return {
197
- provider: availablePolicyProviders[0],
198
- mode: "direct-worker",
199
- adapter,
200
- selectionReason: "role-policy",
201
- providersTried: [availablePolicyProviders[0]],
202
- };
212
+ else if (availablePolicyProviders.length > 0 && availablePolicyProviders[0]) {
213
+ provider = availablePolicyProviders[0];
214
+ selectionReason = "role-policy";
215
+ effectivePolicyOrder = availablePolicyProviders.slice();
216
+ }
217
+ else {
218
+ // No configured provider satisfies the policy — fail clearly before dispatch.
219
+ throw new Error(`provider dispatch forbidden: no configured provider satisfies the "${role}" role policy (policy=${roleProviders.join(",")})`);
203
220
  }
204
- // No configured provider satisfies the policy — fail clearly before dispatch.
205
- throw new Error(`provider dispatch forbidden: no configured provider satisfies the "${role}" role policy (policy=${roleProviders.join(",")})`);
206
221
  }
207
- const roleProvider = exec?.roles?.[role]?.provider;
208
- if (roleProvider) {
209
- return {
210
- provider: roleProvider,
211
- mode: "direct-worker",
212
- adapter,
213
- selectionReason: "role-config",
214
- providersTried: [roleProvider],
215
- };
222
+ else if (exec?.roles?.[role]?.provider) {
223
+ provider = exec.roles[role].provider;
224
+ selectionReason = "role-config";
225
+ effectivePolicyOrder = [provider];
226
+ // If a role policy exists for this role, include its other providers as alternatives
227
+ for (const p of roleProviders) {
228
+ if (p !== provider && !effectivePolicyOrder.includes(p)) {
229
+ effectivePolicyOrder.push(p);
230
+ }
231
+ }
216
232
  }
217
- if (rotation.length > 0 && rotation[0]) {
218
- return {
219
- provider: rotation[0],
220
- mode: "direct-worker",
221
- adapter,
222
- selectionReason: "config-rotation",
223
- providersTried: [rotation[0]],
224
- };
233
+ else if (rotation.length > 0 && rotation[0]) {
234
+ provider = rotation[0];
235
+ selectionReason = "config-rotation";
236
+ effectivePolicyOrder = rotation.slice();
225
237
  }
226
- const providers = Object.keys(exec?.providers ?? {});
227
- if (providers.length > 0 && providers[0]) {
228
- return {
229
- provider: providers[0],
230
- mode: "direct-worker",
231
- adapter,
232
- selectionReason: "config-first-provider",
233
- fallbackFrom: "rotation",
234
- fallbackReason: "rotation-empty",
235
- providersTried: [providers[0]],
236
- };
238
+ else {
239
+ const providers = Object.keys(exec?.providers ?? {});
240
+ if (providers.length > 0 && providers[0]) {
241
+ provider = providers[0];
242
+ selectionReason = "config-first-provider";
243
+ fallbackFrom = "rotation";
244
+ fallbackReason = "rotation-empty";
245
+ effectivePolicyOrder = providers.slice();
246
+ }
247
+ else {
248
+ selectionReason = "delegated-no-provider";
249
+ exhaustedReason = "no-configured-provider";
250
+ effectivePolicyOrder = [];
251
+ }
237
252
  }
253
+ const fallbackEligible = !noFallback && effectivePolicyOrder.length > 1;
254
+ const routingSummary = {
255
+ selected_provider: provider ?? null,
256
+ selected_adapter: adapter,
257
+ selection_reason: selectionReason,
258
+ effective_policy_order: effectivePolicyOrder,
259
+ compatibility_mode: true,
260
+ registry_present: false,
261
+ fallback_eligible: fallbackEligible,
262
+ };
238
263
  return {
239
- provider: undefined,
240
- mode: "delegated",
264
+ provider,
265
+ mode: provider ? "direct-worker" : "delegated",
241
266
  adapter,
242
- selectionReason: "delegated-no-provider",
243
- providersTried: [],
244
- exhaustedReason: "no-configured-provider",
267
+ selectionReason,
268
+ overrideSource,
269
+ fallbackFrom,
270
+ fallbackReason,
271
+ providersTried: provider ? [provider] : [],
272
+ exhaustedReason,
273
+ routingSummary,
245
274
  };
246
275
  }
247
276
  function fail(message) {
@@ -344,7 +373,7 @@ function appendTelemetry(telemetryFile, event) {
344
373
  }
345
374
  function resolveTelemetryFile(state, repoRoot) {
346
375
  const artifactDir = state.artifact_dir ?? (0, node_path_1.join)(repoRoot, ".taskchain_artifacts", "polaris-run");
347
- return (0, node_path_1.join)(artifactDir, "runs", state.run_id, "telemetry.jsonl");
376
+ return (0, node_path_1.resolve)(repoRoot, artifactDir, "runs", state.run_id, "telemetry.jsonl");
348
377
  }
349
378
  function canonicalPath(path) {
350
379
  try {
@@ -464,6 +493,7 @@ function emitProviderSelected(telemetryFile, dispatchId, runId, childId, decisio
464
493
  ...(decision.fallbackReason ? { fallback_reason: decision.fallbackReason } : {}),
465
494
  ...(decision.providersTried.length > 0 ? { providers_tried: decision.providersTried } : {}),
466
495
  ...(decision.exhaustedReason ? { router_exhausted_reason: decision.exhaustedReason } : {}),
496
+ ...(decision.routingSummary ? { routing_summary: decision.routingSummary } : {}),
467
497
  ...(decision.routerEvidence?.candidates?.length
468
498
  ? {
469
499
  router_candidates: decision.routerEvidence.candidates.map((candidate) => ({
@@ -484,6 +514,7 @@ function emitProviderSelected(telemetryFile, dispatchId, runId, childId, decisio
484
514
  active_slots: candidate.evidence.activeSlots,
485
515
  slot_limit: candidate.evidence.slotLimit,
486
516
  policy_matched: candidate.evidence.policyMatched,
517
+ fallback_eligible: candidate.evidence.fallbackEligible,
487
518
  },
488
519
  })),
489
520
  }
@@ -574,7 +605,7 @@ function assertProviderAllowedForRole(role, provider, policy, telemetryFile, dis
574
605
  /**
575
606
  * Create a dispatch record with all required evidence.
576
607
  */
577
- function createDispatchRecord(runId, clusterId, childId, packetPath, resultPath, roleContext, provider, providerSelectionReason, providerOverrideSource, providersTried) {
608
+ function createDispatchRecord(runId, clusterId, childId, packetPath, resultPath, roleContext, provider, providerSelectionReason, providerOverrideSource, providersTried, routingSummary) {
578
609
  const dispatchMode = determineDispatchMode(provider);
579
610
  const runtimeState = determineRuntimeState(dispatchMode);
580
611
  return {
@@ -588,6 +619,7 @@ function createDispatchRecord(runId, clusterId, childId, packetPath, resultPath,
588
619
  provider_selection_reason: providerSelectionReason,
589
620
  provider_override_source: providerOverrideSource,
590
621
  providers_tried: providersTried && providersTried.length > 0 ? providersTried : undefined,
622
+ routing_summary: routingSummary,
591
623
  dispatched_at: new Date().toISOString(),
592
624
  status: "dispatched",
593
625
  dispatch_mode: dispatchMode,
@@ -755,6 +787,7 @@ function ledgerLastCommit(state) {
755
787
  return state.last_commit && state.last_commit.length > 0 ? state.last_commit : null;
756
788
  }
757
789
  function appendDispatchLedgerEvent(repoRoot, state, childId) {
790
+ const routingSummary = state.open_children_meta?.[childId]?.dispatch_record?.routing_summary;
758
791
  new ledger_js_1.LedgerWriter((0, node_path_1.join)(repoRoot, ledger_js_1.DEFAULT_LEDGER_PATH)).append({
759
792
  schema_version: 1,
760
793
  event_id: (0, node_crypto_1.randomUUID)(),
@@ -772,6 +805,7 @@ function appendDispatchLedgerEvent(repoRoot, state, childId) {
772
805
  pr_url: null,
773
806
  timestamp: new Date().toISOString(),
774
807
  dispatch_epoch: state.dispatch_boundary?.dispatch_epoch ?? 0,
808
+ ...(routingSummary ? { routing_summary: routingSummary } : {}),
775
809
  });
776
810
  }
777
811
  function selectChild(state, requestedChild) {
@@ -1189,7 +1223,7 @@ function runLoopDispatch(options) {
1189
1223
  fail(`Failed to write packet artifact to ${packetPath}: ${errorMsg}`);
1190
1224
  }
1191
1225
  // Create dispatch record with all evidence
1192
- const dispatchRecord = createDispatchRecord(state.run_id, state.cluster_id, childId, relativePacketPath, relativeEffectiveResultPath, packet.role_context, resolvedProvider, providerDecision.selectionReason, providerDecision.overrideSource, providerDecision.providersTried);
1226
+ const dispatchRecord = createDispatchRecord(state.run_id, state.cluster_id, childId, relativePacketPath, relativeEffectiveResultPath, packet.role_context, resolvedProvider, providerDecision.selectionReason, providerDecision.overrideSource, providerDecision.providersTried, providerDecision.routingSummary);
1193
1227
  emitProviderFallbackAttempted(telemetryFile, dispatchRecord.dispatch_id, state.run_id, childId, providerDecision);
1194
1228
  emitProviderExhausted(telemetryFile, dispatchRecord.dispatch_id, state.run_id, childId, providerDecision);
1195
1229
  emitProviderSelected(telemetryFile, dispatchRecord.dispatch_id, state.run_id, childId, providerDecision);
@@ -1245,6 +1279,7 @@ function runLoopDispatch(options) {
1245
1279
  dispatch_mode: dispatchRecord.dispatch_mode,
1246
1280
  runtime_state: dispatchRecord.runtime_state,
1247
1281
  provider: dispatchRecord.provider ?? null,
1282
+ routing_summary: dispatchRecord.routing_summary ?? null,
1248
1283
  timestamp: new Date().toISOString(),
1249
1284
  });
1250
1285
  // ── Apply lifecycle transition for child-dispatch event ────────────────────
@@ -177,12 +177,13 @@ function resetForRedispatch(stateFile, state, childId) {
177
177
  if (!childMeta?.dispatch_record)
178
178
  return (0, node_crypto_1.randomUUID)();
179
179
  const newDispatchId = (0, node_crypto_1.randomUUID)();
180
- // Clear dispatch record but retain audit trail via telemetry
180
+ // Clear dispatch record and result_file to prevent stale artifact reads
181
181
  const updatedMeta = {
182
182
  ...state.open_children_meta,
183
183
  [childId]: {
184
184
  ...childMeta,
185
185
  dispatch_record: undefined,
186
+ result_file: undefined,
186
187
  },
187
188
  };
188
189
  // Reset active_child so a new dispatch can proceed
@@ -120,7 +120,7 @@ function appendTelemetry(telemetryFile, event) {
120
120
  }
121
121
  function resolveTelemetryFile(state, repoRoot) {
122
122
  const artifactDir = state.artifact_dir ?? (0, node_path_1.join)(repoRoot, ".taskchain_artifacts", "polaris-run");
123
- return (0, node_path_1.join)(artifactDir, "runs", state.run_id, "telemetry.jsonl");
123
+ return (0, node_path_1.resolve)(repoRoot, artifactDir, "runs", state.run_id, "telemetry.jsonl");
124
124
  }
125
125
  function estimateTokensFromBytes(bytes) {
126
126
  return Math.round(bytes / 4);
@@ -254,6 +254,7 @@ function appendChildCompletedLedgerEvent(repoRoot, state, completedChild, lastCo
254
254
  ...(completion?.providersTried?.length
255
255
  ? { providers_tried: completion.providersTried }
256
256
  : {}),
257
+ ...(completion?.routingSummary ? { routing_summary: completion.routingSummary } : {}),
257
258
  });
258
259
  }
259
260
  function appendClusterCompletedLedgerEvent(repoRoot, state) {
@@ -435,6 +436,7 @@ function buildParentDispatchRecord(args) {
435
436
  provider: args.provider,
436
437
  provider_selection_reason: args.providerSelectionReason,
437
438
  providers_tried: args.providersTried,
439
+ routing_summary: args.routingSummary,
438
440
  dispatched_at: args.dispatchedAt,
439
441
  status: "dispatched",
440
442
  dispatch_mode: "direct-worker",
@@ -557,15 +559,16 @@ async function syncClusterCompletion(args) {
557
559
  output: String(args.validationSummary),
558
560
  },
559
561
  };
562
+ const relativeResultFile = args.resultFile ? (0, node_path_1.relative)(args.repoRoot, args.resultFile) : args.resultFile;
560
563
  await (0, store_js_1.writeClusterState)(args.clusterId, {
561
564
  ...clusterState,
562
565
  state_generation: clusterState.state_generation + 1,
563
566
  child_states: childStates,
564
567
  claim_metadata: Object.fromEntries(Object.entries(clusterState.claim_metadata).filter(([childId]) => childId !== args.childId)),
565
- result_pointers: args.resultFile
568
+ result_pointers: relativeResultFile
566
569
  ? {
567
570
  ...clusterState.result_pointers,
568
- [args.childId]: args.resultFile,
571
+ [args.childId]: relativeResultFile,
569
572
  }
570
573
  : clusterState.result_pointers,
571
574
  validation_results: nextValidationResults,
@@ -594,6 +597,7 @@ async function syncClusterDispatch(args) {
594
597
  }
595
598
  : child)
596
599
  : [...clusterState.child_states, { id: args.childId, status: "dispatched" }];
600
+ const relativePacketPath = (0, node_path_1.relative)(args.repoRoot, args.packetPath);
597
601
  await (0, store_js_1.writeClusterState)(args.clusterId, {
598
602
  ...clusterState,
599
603
  state_generation: clusterState.state_generation + 1,
@@ -608,7 +612,7 @@ async function syncClusterDispatch(args) {
608
612
  },
609
613
  packet_pointers: {
610
614
  ...clusterState.packet_pointers,
611
- [args.childId]: args.packetPath,
615
+ [args.childId]: relativePacketPath,
612
616
  },
613
617
  }, args.repoRoot);
614
618
  return true;
@@ -681,6 +685,23 @@ async function runParentLoop(options) {
681
685
  if (!dryRun) {
682
686
  appendRunStartedLedgerEvent(repoRoot, state);
683
687
  }
688
+ // Keep the canonical cluster snapshot in sync with the taskchain state so
689
+ // `polaris status`, `polaris continue`, and `polaris finalize` always see
690
+ // the freshest state, even if the parent loop is interrupted before it
691
+ // reaches the final cluster-complete write.
692
+ const canonicalStatePath = (0, node_path_1.join)(repoRoot, ".polaris", "clusters", state.cluster_id, "state.json");
693
+ const writeStateAtomic = (filePath, stateToWrite) => {
694
+ (0, checkpoint_js_1.writeStateAtomic)(filePath, stateToWrite);
695
+ if ((0, node_path_1.resolve)(filePath) !== (0, node_path_1.resolve)(canonicalStatePath)) {
696
+ try {
697
+ (0, checkpoint_js_1.writeStateAtomic)(canonicalStatePath, stateToWrite);
698
+ }
699
+ catch (err) {
700
+ const msg = err instanceof Error ? err.message : String(err);
701
+ process.stderr.write(`[polaris] canonical cluster state snapshot at ${canonicalStatePath} failed to update and remains stale: ${msg}\n`);
702
+ }
703
+ }
704
+ };
684
705
  // Load config for adapter and provider resolution
685
706
  const config = (0, loader_js_1.loadConfig)(repoRoot);
686
707
  const legacyOrchestrationMode = state["orchestration_mode"];
@@ -692,10 +713,20 @@ async function runParentLoop(options) {
692
713
  let providerName;
693
714
  let providerSelectionReason;
694
715
  let providersTried;
716
+ let routingSummary;
695
717
  if (adapterName === "agent-subtask") {
696
718
  providerName = "agent-subtask";
697
719
  providerSelectionReason = "agent-subtask-adapter";
698
720
  providersTried = ["agent-subtask"];
721
+ routingSummary = {
722
+ selected_provider: "agent-subtask",
723
+ selected_adapter: "agent-subtask",
724
+ selection_reason: "agent-subtask-adapter",
725
+ effective_policy_order: ["agent-subtask"],
726
+ compatibility_mode: false,
727
+ registry_present: false,
728
+ fallback_eligible: false,
729
+ };
699
730
  }
700
731
  else {
701
732
  let evidence;
@@ -713,6 +744,7 @@ async function runParentLoop(options) {
713
744
  providerName = evidence.provider ?? "default";
714
745
  providerSelectionReason = evidence.selectionReason;
715
746
  providersTried = evidence.providersTried;
747
+ routingSummary = evidence.routingSummary;
716
748
  }
717
749
  const executionConfig = adapterName === "agent-subtask"
718
750
  ? { ...(config.execution ?? { providers: {} }), adapter: "agent-subtask" }
@@ -1038,11 +1070,11 @@ async function runParentLoop(options) {
1038
1070
  onStateUpdate: (loopState) => {
1039
1071
  // Persist loop state to the state file on each mutation.
1040
1072
  const stateWithLoop = { ...state, qc_repair_loop: loopState };
1041
- (0, checkpoint_js_1.writeStateAtomic)(stateFile, stateWithLoop);
1073
+ writeStateAtomic(stateFile, stateWithLoop);
1042
1074
  },
1043
1075
  });
1044
1076
  state = { ...state, qc_repair_loop: repairLoopResult.loop_state };
1045
- (0, checkpoint_js_1.writeStateAtomic)(stateFile, state);
1077
+ writeStateAtomic(stateFile, state);
1046
1078
  appendTelemetry(telemetryFile, {
1047
1079
  event: "qc-repair-loop-finished",
1048
1080
  run_id: state.run_id,
@@ -1164,8 +1196,7 @@ async function runParentLoop(options) {
1164
1196
  if (!dryRun) {
1165
1197
  logStatus(notificationFormat, "COMPLETE");
1166
1198
  const clusterCompleteState = { ...state, status: "cluster-complete" };
1167
- (0, checkpoint_js_1.writeStateAtomic)(stateFile, clusterCompleteState);
1168
- (0, checkpoint_js_1.writeStateAtomic)((0, node_path_1.join)(repoRoot, '.polaris', 'clusters', state.cluster_id, 'state.json'), clusterCompleteState);
1199
+ writeStateAtomic(stateFile, clusterCompleteState);
1169
1200
  appendTelemetry(telemetryFile, {
1170
1201
  event: "cluster-complete",
1171
1202
  run_id: state.run_id,
@@ -1225,7 +1256,7 @@ async function runParentLoop(options) {
1225
1256
  if (budgetCheck.status === 'exhausted') {
1226
1257
  // Write checkpoint before halting
1227
1258
  if (!dryRun) {
1228
- (0, checkpoint_js_1.writeStateAtomic)(stateFile, {
1259
+ writeStateAtomic(stateFile, {
1229
1260
  ...state,
1230
1261
  status: "budget-exhausted",
1231
1262
  step_cursor: "budget-check",
@@ -1489,6 +1520,7 @@ async function runParentLoop(options) {
1489
1520
  provider: providerName,
1490
1521
  providerSelectionReason,
1491
1522
  providersTried,
1523
+ routingSummary,
1492
1524
  workerId,
1493
1525
  dispatchedAt,
1494
1526
  });
@@ -1498,7 +1530,7 @@ async function runParentLoop(options) {
1498
1530
  step_cursor: "dispatch",
1499
1531
  dispatch_boundary: (0, dispatch_boundary_js_1.advanceDispatchEpoch)(state.dispatch_boundary, nextChild),
1500
1532
  };
1501
- (0, checkpoint_js_1.writeStateAtomic)(stateFile, stateWithDispatch);
1533
+ writeStateAtomic(stateFile, stateWithDispatch);
1502
1534
  state = stateWithDispatch;
1503
1535
  stateBeforeDispatch = stateWithDispatch;
1504
1536
  try {
@@ -1563,6 +1595,7 @@ async function runParentLoop(options) {
1563
1595
  dry_run: dryRun,
1564
1596
  selected_slot_claim: selectedSlotClaim ?? null,
1565
1597
  slot_claims: nextSlotClaims,
1598
+ routing_summary: routingSummary ?? null,
1566
1599
  timestamp: new Date().toISOString(),
1567
1600
  });
1568
1601
  emitBootstrapContextSize(telemetryFile, state.run_id, nextChild, stateFile, packet);
@@ -1600,7 +1633,7 @@ async function runParentLoop(options) {
1600
1633
  // No result file was written. Roll back dispatch state so the run is
1601
1634
  // cleanly resumable without manual `loop abort` intervention.
1602
1635
  if (dispatchResult.pre_dispatch_failure && !dryRun) {
1603
- (0, checkpoint_js_1.writeStateAtomic)(stateFile, statePreDispatch);
1636
+ writeStateAtomic(stateFile, statePreDispatch);
1604
1637
  appendTelemetry(telemetryFile, {
1605
1638
  event: "pre-dispatch-failure",
1606
1639
  run_id: state.run_id,
@@ -1751,7 +1784,7 @@ async function runParentLoop(options) {
1751
1784
  timestamp: new Date().toISOString(),
1752
1785
  });
1753
1786
  // Write checkpoint with blocker information
1754
- (0, checkpoint_js_1.writeStateAtomic)(stateFile, {
1787
+ writeStateAtomic(stateFile, {
1755
1788
  ...state,
1756
1789
  status: "blocked",
1757
1790
  step_cursor: "blocked",
@@ -2136,7 +2169,7 @@ async function runParentLoop(options) {
2136
2169
  childrenDispatched += 1;
2137
2170
  // Worker did not write its own completion — orchestrator fills the gap.
2138
2171
  if (!dryRun) {
2139
- (0, checkpoint_js_1.writeStateAtomic)(stateFile, state);
2172
+ writeStateAtomic(stateFile, state);
2140
2173
  }
2141
2174
  }
2142
2175
  else {
@@ -2152,7 +2185,7 @@ async function runParentLoop(options) {
2152
2185
  }, nextChild);
2153
2186
  childrenDispatched += 1;
2154
2187
  if (!dryRun) {
2155
- (0, checkpoint_js_1.writeStateAtomic)(stateFile, state);
2188
+ writeStateAtomic(stateFile, state);
2156
2189
  }
2157
2190
  }
2158
2191
  // Orchestrator checkpoint event — always emitted after a successful child.
@@ -2213,6 +2246,7 @@ async function runParentLoop(options) {
2213
2246
  model: modelUsed,
2214
2247
  router_selection_reason: dispatchRecord?.provider_selection_reason,
2215
2248
  providers_tried: dispatchRecord?.providers_tried,
2249
+ routing_summary: dispatchRecord?.routing_summary ?? null,
2216
2250
  timestamp: new Date().toISOString(),
2217
2251
  };
2218
2252
  if (elapsedSeconds !== undefined) {
@@ -2228,6 +2262,7 @@ async function runParentLoop(options) {
2228
2262
  completionStatus: workerStatus,
2229
2263
  routerSelectionReason: dispatchRecord?.provider_selection_reason,
2230
2264
  providersTried: dispatchRecord?.providers_tried,
2265
+ routingSummary: dispatchRecord?.routing_summary,
2231
2266
  });
2232
2267
  }
2233
2268
  if (orchestrationMode === 'supervised') {
@@ -2250,7 +2285,7 @@ async function runParentLoop(options) {
2250
2285
  if (postBudgetCheck.status === 'exhausted') {
2251
2286
  const nextPending = state.open_children[0] ?? null;
2252
2287
  if (!dryRun) {
2253
- (0, checkpoint_js_1.writeStateAtomic)(stateFile, {
2288
+ writeStateAtomic(stateFile, {
2254
2289
  ...state,
2255
2290
  status: "budget-exhausted",
2256
2291
  step_cursor: "budget-check",
@@ -188,6 +188,7 @@ function decideWorkerRoute(input) {
188
188
  activeSlots,
189
189
  slotLimit: providerSlotLimit ?? globalSlotLimit,
190
190
  policyMatched,
191
+ fallbackEligible: policy?.fallbackEligible,
191
192
  },
192
193
  });
193
194
  }
@@ -141,6 +141,8 @@ function runLoopBootstrapInit(options) {
141
141
  const runId = options.runId ?? deriveRunId(clusterId);
142
142
  const seal = createBootstrapSeal(runId, clusterId, openChildren);
143
143
  const deliveryBranch = branch ?? (0, git_custody_js_1.buildDeliveryBranchName)(clusterId);
144
+ const resolvedArtifactDir = (0, node_path_1.resolve)(repoRoot, artifactDir ?? (0, node_path_1.join)(repoRoot, ".taskchain_artifacts", "polaris-run"));
145
+ const artifactDirValue = (0, node_path_1.relative)(repoRoot, resolvedArtifactDir);
144
146
  const initialState = {
145
147
  schema_version: "1.0",
146
148
  run_id: runId,
@@ -159,7 +161,7 @@ function runLoopBootstrapInit(options) {
159
161
  },
160
162
  status: "running",
161
163
  next_open_child: openChildren[0] ?? null,
162
- artifact_dir: artifactDir ?? (0, node_path_1.join)(repoRoot, ".taskchain_artifacts", "polaris-run"),
164
+ artifact_dir: artifactDirValue,
163
165
  dispatch_boundary: (0, dispatch_boundary_js_2.initialDispatchBoundary)(),
164
166
  run_bootstrap_seal: seal,
165
167
  };
@@ -220,7 +220,10 @@ async function ensureClusterRunState(options) {
220
220
  }
221
221
  }
222
222
  }
223
- const { openChildren, openChildrenMeta } = buildBootstrapPlan(clusterId, await loadOrSyncGraph(clusterId, repoRoot), repoRoot);
223
+ const graph = await loadOrSyncGraph(clusterId, repoRoot);
224
+ const { openChildren, openChildrenMeta } = buildBootstrapPlan(clusterId, graph, repoRoot);
225
+ // Persist canonical child ordering and any body-derived ordering dependencies.
226
+ await graph.save(clusterId, repoRoot);
224
227
  await bootstrapHandler({
225
228
  clusterId,
226
229
  openChildren,