@optique/core 1.3.0-dev.2433 → 1.3.0-dev.2434

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.
@@ -89,6 +89,14 @@ function filterSchedulableRuntimeNodes(nodes, preCompleted) {
89
89
  * failure. Returns `undefined` on success.
90
90
  */
91
91
  /**
92
+ * Nodes a `conditional()` pre-expanded from a committed branch so a
93
+ * `branchError` wrap can ride on the nested barrier nodes. They are
94
+ * expanded descendants despite appearing in a scheduling call's direct
95
+ * node list, so {@link scheduleEffectfulSourceCompletions} must not
96
+ * treat them as reusable or collected.
97
+ */
98
+ const preExpandedBranchNodes = /* @__PURE__ */ new WeakSet();
99
+ /**
92
100
  * Expands runtime nodes through nested constructs for effectful source
93
101
  * scheduling and demand detection.
94
102
  *
@@ -317,13 +325,18 @@ function computeBarrierDependenciesFromNodes(nodes) {
317
325
  * Computes a resolved barrier's concrete dependencies from the selected
318
326
  * branch's expanded runtime nodes: the completion dependencies its
319
327
  * active consumers read, minus the sources the branch actively
320
- * provides, and the active provides themselves. Unlike the
321
- * synchronous estimate, promise-shaped state extractions are awaited,
322
- * so an asynchronously validating bound value counts as active.
328
+ * provides, the active provides themselves, and the selection's demand
329
+ * edges. Unlike the synchronous estimate, promise-shaped state
330
+ * extractions are awaited, so an asynchronously validating bound value
331
+ * counts as active. A nested barrier whose demand activation is
332
+ * `"after-resolution"` contributes only its ordering aggregate: its
333
+ * demand edges stay behind its own confirmation boundary and are
334
+ * promoted by its own resolution within the nested scheduling pass.
323
335
  */
324
336
  async function computeActiveBarrierDependencies(nodes) {
325
337
  const active = /* @__PURE__ */ new Set();
326
338
  const ordering = /* @__PURE__ */ new Set();
339
+ const demandEdges = [];
327
340
  for (const node of nodes) {
328
341
  const metadata = node.parser.dependencyMetadata;
329
342
  const source = metadata?.source;
@@ -341,14 +354,24 @@ async function computeActiveBarrierDependencies(nodes) {
341
354
  for (const id of node.guaranteedProvidesSourceIds ?? []) active.add(id);
342
355
  if (completion != null) {
343
356
  const inactive = source?.extractSourceValue != null ? extracted?.success === true : require_dependency_runtime.hasInactiveCompletion(node);
344
- if (!inactive) for (const id of completion.dependencyIds) ordering.add(id);
357
+ if (!inactive) {
358
+ for (const id of completion.dependencyIds) ordering.add(id);
359
+ if (source != null) demandEdges.push({
360
+ consumerSourceId: source.sourceId,
361
+ dependencyIds: completion.dependencyIds
362
+ });
363
+ }
345
364
  }
346
365
  const nested = node.barrierCompletionDependencies;
347
- if (nested != null) for (const id of nested.orderingDependencyIds) ordering.add(id);
366
+ if (nested != null) {
367
+ for (const id of nested.orderingDependencyIds) ordering.add(id);
368
+ if (node.barrierDemandActivation !== "after-resolution" || node.barrierResolutionState === "resolved") demandEdges.push(...nested.demandEdges);
369
+ }
348
370
  }
349
371
  return {
350
372
  orderingDependencyIds: [...ordering].filter((id) => !active.has(id)),
351
- activeProvidesSourceIds: active
373
+ activeProvidesSourceIds: active,
374
+ demandEdges
352
375
  };
353
376
  }
354
377
  function isDeferredCompletionResult(result) {
@@ -395,13 +418,15 @@ async function scheduleEffectfulSourceCompletions(nodes, state, runtime, exec, p
395
418
  success: false,
396
419
  error: preCompletedFailure
397
420
  };
398
- const direct = new Set(nodes);
421
+ const direct = new Set(nodes.filter((node) => !preExpandedBranchNodes.has(node)));
399
422
  const collected = /* @__PURE__ */ new Set();
400
423
  const expandedNodes = [];
401
424
  for (const node of nodes) {
402
425
  const optedIn = node.parser[require_dependency_runtime.sourceCollectionExpansionKey] === true;
426
+ const preExpanded = preExpandedBranchNodes.has(node);
403
427
  for (const expandedNode of expandEffectfulRuntimeNodes([node])) {
404
428
  expandedNodes.push(expandedNode);
429
+ if (preExpanded) continue;
405
430
  if (optedIn || expandedNode === node) collected.add(expandedNode);
406
431
  }
407
432
  }
@@ -6610,6 +6635,47 @@ function conditional(discriminator, branches, defaultBranch, options) {
6610
6635
  };
6611
6636
  const preparedKeyPrefix = `c${++conditionalInstanceCounter}|`;
6612
6637
  const preparedKeyFor = (parentPath) => preparedKeyPrefix + require_dependency_runtime.serializeSchedulingPath(parentPath ?? []);
6638
+ const branchMismatchFailure = (resolvedValue, speculativeKey) => {
6639
+ const resolvedKey = typeof resolvedValue === "string" ? resolvedValue : "<unknown>";
6640
+ return {
6641
+ success: false,
6642
+ error: options?.errors?.branchMismatch ? options.errors.branchMismatch(resolvedKey, speculativeKey) : require_message.message`Branch mismatch: tokens for ${speculativeKey} were consumed, but the discriminator resolved to ${resolvedKey}.`
6643
+ };
6644
+ };
6645
+ const wrapCachedBarrierFailure = (session, failure, branchKey) => {
6646
+ const branchError = options?.errors?.branchError;
6647
+ if (branchKey == null || branchError == null) return failure;
6648
+ const wrapped = {
6649
+ success: false,
6650
+ error: branchError(branchKey, failure.error)
6651
+ };
6652
+ return require_dependency_runtime.replaceCachedBarrierFailure(session, failure, wrapped) ? wrapped : failure;
6653
+ };
6654
+ const wrapBranchBarrierNodes = (nodes, branchKey) => {
6655
+ const branchError = options?.errors?.branchError;
6656
+ if (branchKey == null || branchError == null) return nodes;
6657
+ return nodes.map((node) => {
6658
+ const resolveBarrier = node.resolveBarrier;
6659
+ const prepare = node.prepare;
6660
+ if (resolveBarrier == null && prepare == null) return node;
6661
+ return {
6662
+ ...node,
6663
+ ...resolveBarrier == null ? {} : { resolveBarrier: async (ctx) => {
6664
+ const result = await resolveBarrier(ctx);
6665
+ if (result != null && "success" in result) return {
6666
+ success: false,
6667
+ error: branchError(branchKey, result.error)
6668
+ };
6669
+ return result;
6670
+ } },
6671
+ ...prepare == null ? {} : { prepare: async (ctx) => {
6672
+ const failure = await prepare(ctx);
6673
+ if (failure == null) return void 0;
6674
+ return wrapCachedBarrierFailure(ctx.exec?.effectfulCompletionSession, failure, branchKey);
6675
+ } }
6676
+ };
6677
+ });
6678
+ };
6613
6679
  const { branchProvidedSourceIds, branchGuaranteedIntersection, mergedBarrierDependencies, barrierDependenciesByKey } = (() => {
6614
6680
  const provided = /* @__PURE__ */ new Set();
6615
6681
  const byParser = /* @__PURE__ */ new Map();
@@ -6678,11 +6744,19 @@ function conditional(discriminator, branches, defaultBranch, options) {
6678
6744
  const selected = conditionalState.selectedBranch;
6679
6745
  if (selected !== void 0 && conditionalState.speculative !== true) {
6680
6746
  const branchParser = selected.kind === "default" ? defaultBranch : branches[selected.key];
6681
- if (branchParser != null) nodes.push({
6682
- path: [...parentPath ?? [], "_branch"],
6683
- parser: branchParser,
6684
- state: require_annotation_state.getWrappedChildState(conditionalState, conditionalState.branchState, branchParser)
6685
- });
6747
+ if (branchParser != null) {
6748
+ const branchNode = {
6749
+ path: [...parentPath ?? [], "_branch"],
6750
+ parser: branchParser,
6751
+ state: require_annotation_state.getWrappedChildState(conditionalState, conditionalState.branchState, branchParser)
6752
+ };
6753
+ const branchKey = selected.kind === "branch" ? selected.key : void 0;
6754
+ if (branchKey != null && options?.errors?.branchError != null) for (const expanded of wrapBranchBarrierNodes(expandEffectfulRuntimeNodes([branchNode]), branchKey)) {
6755
+ preExpandedBranchNodes.add(expanded);
6756
+ nodes.push(expanded);
6757
+ }
6758
+ else nodes.push(branchNode);
6759
+ }
6686
6760
  return nodes;
6687
6761
  }
6688
6762
  const discriminatorSource = discriminator.dependencyMetadata?.source;
@@ -6733,14 +6807,17 @@ function conditional(discriminator, branches, defaultBranch, options) {
6733
6807
  providesSourceIds: branchProvidedSourceIds,
6734
6808
  ...speculativeEstimate != null && speculativeEstimate.guaranteedProvides.size > 0 ? { guaranteedProvidesSourceIds: speculativeEstimate.guaranteedProvides } : {},
6735
6809
  ...speculativeBarrierDependencies != null ? { barrierCompletionDependencies: speculativeBarrierDependencies } : {},
6810
+ barrierDemandActivation: "after-resolution",
6736
6811
  resolveBarrier: async (ctx) => {
6737
6812
  const session = ctx.exec?.effectfulCompletionSession;
6738
6813
  if (session == null) return void 0;
6739
6814
  const result = cell.result ?? session.completedByPath.get(discriminatorPathKey);
6740
6815
  if (result == null || isDeferredCompletionResult(result) || result.success !== true) return void 0;
6741
- if (String(result.value) !== speculativeKey || branches[speculativeKey] == null) return {
6816
+ if (String(result.value) !== speculativeKey) return branchMismatchFailure(result.value, speculativeKey);
6817
+ if (branches[speculativeKey] == null) return {
6742
6818
  orderingDependencyIds: [],
6743
- activeProvidesSourceIds: /* @__PURE__ */ new Set()
6819
+ activeProvidesSourceIds: /* @__PURE__ */ new Set(),
6820
+ demandEdges: []
6744
6821
  };
6745
6822
  return await computeActiveBarrierDependencies(expandGuessedBranchNodes());
6746
6823
  },
@@ -6751,7 +6828,9 @@ function conditional(discriminator, branches, defaultBranch, options) {
6751
6828
  if (result == null || isDeferredCompletionResult(result) || result.success !== true) return void 0;
6752
6829
  if (String(result.value) !== speculativeKey) return void 0;
6753
6830
  if (branches[speculativeKey] == null) return void 0;
6754
- return await ctx.schedule(expandGuessedBranchNodes());
6831
+ const failure = await ctx.schedule(expandGuessedBranchNodes());
6832
+ if (failure == null) return void 0;
6833
+ return wrapCachedBarrierFailure(session, failure, speculativeKey);
6755
6834
  }
6756
6835
  });
6757
6836
  return nodes;
@@ -6819,19 +6898,23 @@ function conditional(discriminator, branches, defaultBranch, options) {
6819
6898
  providesSourceIds: branchProvidedSourceIds,
6820
6899
  ...branchGuaranteedIntersection.size > 0 ? { guaranteedProvidesSourceIds: branchGuaranteedIntersection } : {},
6821
6900
  ...mergedBarrierDependencies != null ? { barrierCompletionDependencies: mergedBarrierDependencies } : {},
6901
+ barrierDemandActivation: "after-resolution",
6822
6902
  resolveBarrier: async (ctx) => {
6823
6903
  const prepared = await resolvePreparedSelection(ctx);
6824
6904
  if (prepared == null) return void 0;
6825
6905
  if (prepared.branchParser == null) return {
6826
6906
  orderingDependencyIds: [],
6827
- activeProvidesSourceIds: /* @__PURE__ */ new Set()
6907
+ activeProvidesSourceIds: /* @__PURE__ */ new Set(),
6908
+ demandEdges: []
6828
6909
  };
6829
6910
  return await computeActiveBarrierDependencies(expandPreparedBranchNodes(prepared));
6830
6911
  },
6831
6912
  prepare: async (ctx) => {
6832
6913
  const prepared = await resolvePreparedSelection(ctx);
6833
6914
  if (prepared?.branchParser == null) return void 0;
6834
- return await ctx.schedule(expandPreparedBranchNodes(prepared));
6915
+ const failure = await ctx.schedule(expandPreparedBranchNodes(prepared));
6916
+ if (failure == null) return void 0;
6917
+ return wrapCachedBarrierFailure(ctx.exec?.effectfulCompletionSession, failure, prepared.branchKey);
6835
6918
  }
6836
6919
  });
6837
6920
  return nodes;
@@ -6979,14 +7062,7 @@ function conditional(discriminator, branches, defaultBranch, options) {
6979
7062
  else if (wasSpeculative) return completedDiscriminator;
6980
7063
  else discriminatorValue = state.selectedBranch.key;
6981
7064
  }
6982
- if (wasSpeculative && state.selectedBranch.kind === "branch" && discriminatorValue !== state.selectedBranch.key) {
6983
- const speculativeKey = state.selectedBranch.key;
6984
- const resolvedKey = typeof discriminatorValue === "string" ? discriminatorValue : "<unknown>";
6985
- return {
6986
- success: false,
6987
- error: options?.errors?.branchMismatch ? options.errors.branchMismatch(resolvedKey, speculativeKey) : require_message.message`Branch mismatch: tokens for ${speculativeKey} were consumed, but the discriminator resolved to ${resolvedKey}.`
6988
- };
6989
- }
7065
+ if (wasSpeculative && state.selectedBranch.kind === "branch" && discriminatorValue !== state.selectedBranch.key) return branchMismatchFailure(discriminatorValue, state.selectedBranch.key);
6990
7066
  const resolvedBranchState = require_annotation_state.getWrappedChildState(state, await require_dependency_runtime.resolveStateWithRuntimeAsync(state.branchState, runtime), branchParser);
6991
7067
  const branchResult = unwrapCompleteResult(await branchParser.complete(resolvedBranchState, require_execution_context.withChildExecPath(completionExec, "_branch")));
6992
7068
  if (!branchResult.success) {
@@ -5,7 +5,7 @@ import { extractArgumentMetavars, extractCommandNames, extractOptionNames, isDoc
5
5
  import { deduplicateDocFragments } from "./doc.js";
6
6
  import { dispatchByMode, dispatchIterableByMode } from "./internal/mode-dispatch.js";
7
7
  import { createDependencySourceState, dependencyId, isDependencySourceState, isPendingDependencySourceState, isWrappedDependencySource, wrappedDependencySourceMarker } from "./internal/dependency.js";
8
- import { buildRuntimeNodesFromArray, buildRuntimeNodesFromPairs, collectExplicitSourceValues, collectExplicitSourceValuesAsync, collectSourcesFromState, completeEffectfulSourcesAsync, createDependencyRuntimeContext, effectfulSchedulingNodesKey, exclusiveSourceScopeKey, fillMissingSourceDefaults, fillMissingSourceDefaultsAsync, guaranteedStaticSourceIdsKey, hasInactiveCompletion, resolveDerivedSourceValues, resolveDerivedSourceValuesAsync, resolveStateWithRuntime, resolveStateWithRuntimeAsync, serializeSchedulingPath, sourceCollectionExpansionKey, staticSourceScopeKey } from "./dependency-runtime.js";
8
+ import { buildRuntimeNodesFromArray, buildRuntimeNodesFromPairs, collectExplicitSourceValues, collectExplicitSourceValuesAsync, collectSourcesFromState, completeEffectfulSourcesAsync, createDependencyRuntimeContext, effectfulSchedulingNodesKey, exclusiveSourceScopeKey, fillMissingSourceDefaults, fillMissingSourceDefaultsAsync, guaranteedStaticSourceIdsKey, hasInactiveCompletion, replaceCachedBarrierFailure, resolveDerivedSourceValues, resolveDerivedSourceValuesAsync, resolveStateWithRuntime, resolveStateWithRuntimeAsync, serializeSchedulingPath, sourceCollectionExpansionKey, staticSourceScopeKey } from "./dependency-runtime.js";
9
9
  import { defineInheritedAnnotationParser, defineParseLanes, getOwnParseLanes, getParserSuggestRuntimeNodes, unmatchedNonCliDependencySourceStateMarker } from "./internal/parser.js";
10
10
  import { annotationViewTargets, getWrappedChildParseState, getWrappedChildState, reconcileObjectChildState, unwrapAnnotationView } from "./annotation-state.js";
11
11
  import { allowDuplicateLeadingCommandNamesKey } from "./internal/command-alias.js";
@@ -89,6 +89,14 @@ function filterSchedulableRuntimeNodes(nodes, preCompleted) {
89
89
  * failure. Returns `undefined` on success.
90
90
  */
91
91
  /**
92
+ * Nodes a `conditional()` pre-expanded from a committed branch so a
93
+ * `branchError` wrap can ride on the nested barrier nodes. They are
94
+ * expanded descendants despite appearing in a scheduling call's direct
95
+ * node list, so {@link scheduleEffectfulSourceCompletions} must not
96
+ * treat them as reusable or collected.
97
+ */
98
+ const preExpandedBranchNodes = /* @__PURE__ */ new WeakSet();
99
+ /**
92
100
  * Expands runtime nodes through nested constructs for effectful source
93
101
  * scheduling and demand detection.
94
102
  *
@@ -317,13 +325,18 @@ function computeBarrierDependenciesFromNodes(nodes) {
317
325
  * Computes a resolved barrier's concrete dependencies from the selected
318
326
  * branch's expanded runtime nodes: the completion dependencies its
319
327
  * active consumers read, minus the sources the branch actively
320
- * provides, and the active provides themselves. Unlike the
321
- * synchronous estimate, promise-shaped state extractions are awaited,
322
- * so an asynchronously validating bound value counts as active.
328
+ * provides, the active provides themselves, and the selection's demand
329
+ * edges. Unlike the synchronous estimate, promise-shaped state
330
+ * extractions are awaited, so an asynchronously validating bound value
331
+ * counts as active. A nested barrier whose demand activation is
332
+ * `"after-resolution"` contributes only its ordering aggregate: its
333
+ * demand edges stay behind its own confirmation boundary and are
334
+ * promoted by its own resolution within the nested scheduling pass.
323
335
  */
324
336
  async function computeActiveBarrierDependencies(nodes) {
325
337
  const active = /* @__PURE__ */ new Set();
326
338
  const ordering = /* @__PURE__ */ new Set();
339
+ const demandEdges = [];
327
340
  for (const node of nodes) {
328
341
  const metadata = node.parser.dependencyMetadata;
329
342
  const source = metadata?.source;
@@ -341,14 +354,24 @@ async function computeActiveBarrierDependencies(nodes) {
341
354
  for (const id of node.guaranteedProvidesSourceIds ?? []) active.add(id);
342
355
  if (completion != null) {
343
356
  const inactive = source?.extractSourceValue != null ? extracted?.success === true : hasInactiveCompletion(node);
344
- if (!inactive) for (const id of completion.dependencyIds) ordering.add(id);
357
+ if (!inactive) {
358
+ for (const id of completion.dependencyIds) ordering.add(id);
359
+ if (source != null) demandEdges.push({
360
+ consumerSourceId: source.sourceId,
361
+ dependencyIds: completion.dependencyIds
362
+ });
363
+ }
345
364
  }
346
365
  const nested = node.barrierCompletionDependencies;
347
- if (nested != null) for (const id of nested.orderingDependencyIds) ordering.add(id);
366
+ if (nested != null) {
367
+ for (const id of nested.orderingDependencyIds) ordering.add(id);
368
+ if (node.barrierDemandActivation !== "after-resolution" || node.barrierResolutionState === "resolved") demandEdges.push(...nested.demandEdges);
369
+ }
348
370
  }
349
371
  return {
350
372
  orderingDependencyIds: [...ordering].filter((id) => !active.has(id)),
351
- activeProvidesSourceIds: active
373
+ activeProvidesSourceIds: active,
374
+ demandEdges
352
375
  };
353
376
  }
354
377
  function isDeferredCompletionResult(result) {
@@ -395,13 +418,15 @@ async function scheduleEffectfulSourceCompletions(nodes, state, runtime, exec, p
395
418
  success: false,
396
419
  error: preCompletedFailure
397
420
  };
398
- const direct = new Set(nodes);
421
+ const direct = new Set(nodes.filter((node) => !preExpandedBranchNodes.has(node)));
399
422
  const collected = /* @__PURE__ */ new Set();
400
423
  const expandedNodes = [];
401
424
  for (const node of nodes) {
402
425
  const optedIn = node.parser[sourceCollectionExpansionKey] === true;
426
+ const preExpanded = preExpandedBranchNodes.has(node);
403
427
  for (const expandedNode of expandEffectfulRuntimeNodes([node])) {
404
428
  expandedNodes.push(expandedNode);
429
+ if (preExpanded) continue;
405
430
  if (optedIn || expandedNode === node) collected.add(expandedNode);
406
431
  }
407
432
  }
@@ -6610,6 +6635,47 @@ function conditional(discriminator, branches, defaultBranch, options) {
6610
6635
  };
6611
6636
  const preparedKeyPrefix = `c${++conditionalInstanceCounter}|`;
6612
6637
  const preparedKeyFor = (parentPath) => preparedKeyPrefix + serializeSchedulingPath(parentPath ?? []);
6638
+ const branchMismatchFailure = (resolvedValue, speculativeKey) => {
6639
+ const resolvedKey = typeof resolvedValue === "string" ? resolvedValue : "<unknown>";
6640
+ return {
6641
+ success: false,
6642
+ error: options?.errors?.branchMismatch ? options.errors.branchMismatch(resolvedKey, speculativeKey) : message`Branch mismatch: tokens for ${speculativeKey} were consumed, but the discriminator resolved to ${resolvedKey}.`
6643
+ };
6644
+ };
6645
+ const wrapCachedBarrierFailure = (session, failure, branchKey) => {
6646
+ const branchError = options?.errors?.branchError;
6647
+ if (branchKey == null || branchError == null) return failure;
6648
+ const wrapped = {
6649
+ success: false,
6650
+ error: branchError(branchKey, failure.error)
6651
+ };
6652
+ return replaceCachedBarrierFailure(session, failure, wrapped) ? wrapped : failure;
6653
+ };
6654
+ const wrapBranchBarrierNodes = (nodes, branchKey) => {
6655
+ const branchError = options?.errors?.branchError;
6656
+ if (branchKey == null || branchError == null) return nodes;
6657
+ return nodes.map((node) => {
6658
+ const resolveBarrier = node.resolveBarrier;
6659
+ const prepare = node.prepare;
6660
+ if (resolveBarrier == null && prepare == null) return node;
6661
+ return {
6662
+ ...node,
6663
+ ...resolveBarrier == null ? {} : { resolveBarrier: async (ctx) => {
6664
+ const result = await resolveBarrier(ctx);
6665
+ if (result != null && "success" in result) return {
6666
+ success: false,
6667
+ error: branchError(branchKey, result.error)
6668
+ };
6669
+ return result;
6670
+ } },
6671
+ ...prepare == null ? {} : { prepare: async (ctx) => {
6672
+ const failure = await prepare(ctx);
6673
+ if (failure == null) return void 0;
6674
+ return wrapCachedBarrierFailure(ctx.exec?.effectfulCompletionSession, failure, branchKey);
6675
+ } }
6676
+ };
6677
+ });
6678
+ };
6613
6679
  const { branchProvidedSourceIds, branchGuaranteedIntersection, mergedBarrierDependencies, barrierDependenciesByKey } = (() => {
6614
6680
  const provided = /* @__PURE__ */ new Set();
6615
6681
  const byParser = /* @__PURE__ */ new Map();
@@ -6678,11 +6744,19 @@ function conditional(discriminator, branches, defaultBranch, options) {
6678
6744
  const selected = conditionalState.selectedBranch;
6679
6745
  if (selected !== void 0 && conditionalState.speculative !== true) {
6680
6746
  const branchParser = selected.kind === "default" ? defaultBranch : branches[selected.key];
6681
- if (branchParser != null) nodes.push({
6682
- path: [...parentPath ?? [], "_branch"],
6683
- parser: branchParser,
6684
- state: getWrappedChildState(conditionalState, conditionalState.branchState, branchParser)
6685
- });
6747
+ if (branchParser != null) {
6748
+ const branchNode = {
6749
+ path: [...parentPath ?? [], "_branch"],
6750
+ parser: branchParser,
6751
+ state: getWrappedChildState(conditionalState, conditionalState.branchState, branchParser)
6752
+ };
6753
+ const branchKey = selected.kind === "branch" ? selected.key : void 0;
6754
+ if (branchKey != null && options?.errors?.branchError != null) for (const expanded of wrapBranchBarrierNodes(expandEffectfulRuntimeNodes([branchNode]), branchKey)) {
6755
+ preExpandedBranchNodes.add(expanded);
6756
+ nodes.push(expanded);
6757
+ }
6758
+ else nodes.push(branchNode);
6759
+ }
6686
6760
  return nodes;
6687
6761
  }
6688
6762
  const discriminatorSource = discriminator.dependencyMetadata?.source;
@@ -6733,14 +6807,17 @@ function conditional(discriminator, branches, defaultBranch, options) {
6733
6807
  providesSourceIds: branchProvidedSourceIds,
6734
6808
  ...speculativeEstimate != null && speculativeEstimate.guaranteedProvides.size > 0 ? { guaranteedProvidesSourceIds: speculativeEstimate.guaranteedProvides } : {},
6735
6809
  ...speculativeBarrierDependencies != null ? { barrierCompletionDependencies: speculativeBarrierDependencies } : {},
6810
+ barrierDemandActivation: "after-resolution",
6736
6811
  resolveBarrier: async (ctx) => {
6737
6812
  const session = ctx.exec?.effectfulCompletionSession;
6738
6813
  if (session == null) return void 0;
6739
6814
  const result = cell.result ?? session.completedByPath.get(discriminatorPathKey);
6740
6815
  if (result == null || isDeferredCompletionResult(result) || result.success !== true) return void 0;
6741
- if (String(result.value) !== speculativeKey || branches[speculativeKey] == null) return {
6816
+ if (String(result.value) !== speculativeKey) return branchMismatchFailure(result.value, speculativeKey);
6817
+ if (branches[speculativeKey] == null) return {
6742
6818
  orderingDependencyIds: [],
6743
- activeProvidesSourceIds: /* @__PURE__ */ new Set()
6819
+ activeProvidesSourceIds: /* @__PURE__ */ new Set(),
6820
+ demandEdges: []
6744
6821
  };
6745
6822
  return await computeActiveBarrierDependencies(expandGuessedBranchNodes());
6746
6823
  },
@@ -6751,7 +6828,9 @@ function conditional(discriminator, branches, defaultBranch, options) {
6751
6828
  if (result == null || isDeferredCompletionResult(result) || result.success !== true) return void 0;
6752
6829
  if (String(result.value) !== speculativeKey) return void 0;
6753
6830
  if (branches[speculativeKey] == null) return void 0;
6754
- return await ctx.schedule(expandGuessedBranchNodes());
6831
+ const failure = await ctx.schedule(expandGuessedBranchNodes());
6832
+ if (failure == null) return void 0;
6833
+ return wrapCachedBarrierFailure(session, failure, speculativeKey);
6755
6834
  }
6756
6835
  });
6757
6836
  return nodes;
@@ -6819,19 +6898,23 @@ function conditional(discriminator, branches, defaultBranch, options) {
6819
6898
  providesSourceIds: branchProvidedSourceIds,
6820
6899
  ...branchGuaranteedIntersection.size > 0 ? { guaranteedProvidesSourceIds: branchGuaranteedIntersection } : {},
6821
6900
  ...mergedBarrierDependencies != null ? { barrierCompletionDependencies: mergedBarrierDependencies } : {},
6901
+ barrierDemandActivation: "after-resolution",
6822
6902
  resolveBarrier: async (ctx) => {
6823
6903
  const prepared = await resolvePreparedSelection(ctx);
6824
6904
  if (prepared == null) return void 0;
6825
6905
  if (prepared.branchParser == null) return {
6826
6906
  orderingDependencyIds: [],
6827
- activeProvidesSourceIds: /* @__PURE__ */ new Set()
6907
+ activeProvidesSourceIds: /* @__PURE__ */ new Set(),
6908
+ demandEdges: []
6828
6909
  };
6829
6910
  return await computeActiveBarrierDependencies(expandPreparedBranchNodes(prepared));
6830
6911
  },
6831
6912
  prepare: async (ctx) => {
6832
6913
  const prepared = await resolvePreparedSelection(ctx);
6833
6914
  if (prepared?.branchParser == null) return void 0;
6834
- return await ctx.schedule(expandPreparedBranchNodes(prepared));
6915
+ const failure = await ctx.schedule(expandPreparedBranchNodes(prepared));
6916
+ if (failure == null) return void 0;
6917
+ return wrapCachedBarrierFailure(ctx.exec?.effectfulCompletionSession, failure, prepared.branchKey);
6835
6918
  }
6836
6919
  });
6837
6920
  return nodes;
@@ -6979,14 +7062,7 @@ function conditional(discriminator, branches, defaultBranch, options) {
6979
7062
  else if (wasSpeculative) return completedDiscriminator;
6980
7063
  else discriminatorValue = state.selectedBranch.key;
6981
7064
  }
6982
- if (wasSpeculative && state.selectedBranch.kind === "branch" && discriminatorValue !== state.selectedBranch.key) {
6983
- const speculativeKey = state.selectedBranch.key;
6984
- const resolvedKey = typeof discriminatorValue === "string" ? discriminatorValue : "<unknown>";
6985
- return {
6986
- success: false,
6987
- error: options?.errors?.branchMismatch ? options.errors.branchMismatch(resolvedKey, speculativeKey) : message`Branch mismatch: tokens for ${speculativeKey} were consumed, but the discriminator resolved to ${resolvedKey}.`
6988
- };
6989
- }
7065
+ if (wasSpeculative && state.selectedBranch.kind === "branch" && discriminatorValue !== state.selectedBranch.key) return branchMismatchFailure(discriminatorValue, state.selectedBranch.key);
6990
7066
  const resolvedBranchState = getWrappedChildState(state, await resolveStateWithRuntimeAsync(state.branchState, runtime), branchParser);
6991
7067
  const branchResult = unwrapCompleteResult(await branchParser.complete(resolvedBranchState, withChildExecPath(completionExec, "_branch")));
6992
7068
  if (!branchResult.success) {
@@ -1151,6 +1151,133 @@ function collectDeferredDemand(state, demanded, visited) {
1151
1151
  for (const key of Reflect.ownKeys(state)) collectDeferredDemand(state[key], demanded, visited);
1152
1152
  }
1153
1153
  /**
1154
+ * Runs the monotonic demand fixed point over the given nodes' metadata,
1155
+ * adding to the session's demanded set until nothing changes:
1156
+ *
1157
+ * - a demanded derived source demands its dependency IDs;
1158
+ * - a demanded source whose effectful completion consumes other
1159
+ * dependency values (a prompt with a derived configuration) demands
1160
+ * those prerequisites, unless this occurrence is already satisfied;
1161
+ * - a barrier's demand edges mirror the flat completion rule for the
1162
+ * consumers hidden behind it—only when a branch consumer's own source
1163
+ * is demanded do its completion prerequisites become demanded—but a
1164
+ * barrier whose {@link RuntimeNode.barrierDemandActivation} is
1165
+ * `"after-resolution"` contributes its edges only once it has
1166
+ * resolved, so an unselected branch's prerequisites are never
1167
+ * demanded on the strength of a static estimate;
1168
+ * - when a source a barrier can provide is demanded, the barrier's
1169
+ * control dependency (its discriminator source) becomes demanded.
1170
+ *
1171
+ * One barrier's branches can provide another barrier's discriminator
1172
+ * source, and the chain must propagate regardless of declaration order.
1173
+ * Each iteration adds at least one demanded ID, so the loop terminates.
1174
+ * The scheduler re-runs this after a gated barrier resolves, passing
1175
+ * the pass's metadata universe with resolved replacement nodes swapped
1176
+ * in, so promotion chains through already-visited metadata as well.
1177
+ */
1178
+ function propagateDemand(universe, session) {
1179
+ let demandAdded = true;
1180
+ while (demandAdded) {
1181
+ demandAdded = false;
1182
+ for (const node of universe) {
1183
+ const metadata = node.parser.dependencyMetadata;
1184
+ if (metadata?.source != null && metadata.derived != null && session.demanded.has(metadata.source.sourceId)) for (const dependencySourceId of metadata.derived.dependencyIds) {
1185
+ if (session.demanded.has(dependencySourceId)) continue;
1186
+ session.demanded.add(dependencySourceId);
1187
+ demandAdded = true;
1188
+ }
1189
+ if (metadata?.source != null && metadata.completion != null && session.demanded.has(metadata.source.sourceId) && !hasInactiveCompletion(node)) for (const dependencySourceId of metadata.completion.dependencyIds) {
1190
+ if (session.demanded.has(dependencySourceId)) continue;
1191
+ session.demanded.add(dependencySourceId);
1192
+ demandAdded = true;
1193
+ }
1194
+ if (node.barrierCompletionDependencies != null && (node.barrierDemandActivation !== "after-resolution" || node.barrierResolutionState === "resolved")) for (const edge of node.barrierCompletionDependencies.demandEdges) {
1195
+ if (!session.demanded.has(edge.consumerSourceId)) continue;
1196
+ for (const dependencySourceId of edge.dependencyIds) {
1197
+ if (session.demanded.has(dependencySourceId)) continue;
1198
+ session.demanded.add(dependencySourceId);
1199
+ demandAdded = true;
1200
+ }
1201
+ }
1202
+ if (node.requiresSourceId == null || node.providesSourceIds == null) continue;
1203
+ if (session.demanded.has(node.requiresSourceId)) continue;
1204
+ for (const provided of node.providesSourceIds) if (session.demanded.has(provided)) {
1205
+ session.demanded.add(node.requiresSourceId);
1206
+ demandAdded = true;
1207
+ break;
1208
+ }
1209
+ }
1210
+ }
1211
+ }
1212
+ const barrierFailureDescription = "optique.barrierFailure";
1213
+ /**
1214
+ * Replaces a barrier failure cached in the run-scoped session with a
1215
+ * wrapped version of the same failure, identified by object identity.
1216
+ * A construct that decorates a nested barrier failure on its way out—a
1217
+ * `conditional()` applying its `branchError` hook—uses this so later
1218
+ * passes sharing the session (the eager fallback after a failed seed
1219
+ * pass) surface the wrapped error rather than the raw one.
1220
+ *
1221
+ * @param session The run-scoped effectful completion session.
1222
+ * @param original The failure exactly as the scheduling pass returned
1223
+ * it.
1224
+ * @param replacement The decorated failure to cache in its place.
1225
+ * @returns Whether a cached barrier failure was found and replaced;
1226
+ * `false` means the failure did not come from a barrier resolution
1227
+ * and should propagate untouched.
1228
+ * @internal
1229
+ * @since 1.3.0
1230
+ */
1231
+ function replaceCachedBarrierFailure(session, original, replacement) {
1232
+ if (session == null) return false;
1233
+ let replaced = false;
1234
+ for (const [key, value] of session.results) if (key.description === barrierFailureDescription && value === original) {
1235
+ session.results.set(key, replacement);
1236
+ replaced = true;
1237
+ }
1238
+ return replaced;
1239
+ }
1240
+ /**
1241
+ * Whether the node is a scheduling barrier whose demand edges are gated
1242
+ * on resolution and whose resolution has not happened yet. While any
1243
+ * such barrier is pending in a demand-only pass, the scheduler parks
1244
+ * not-yet-demanded effectful nodes instead of letting them defer, so a
1245
+ * later resolution can still demand them into their dependency slot.
1246
+ */
1247
+ function isGatedUnresolvedBarrier(node) {
1248
+ return node.resolveBarrier != null && node.barrierDemandActivation === "after-resolution" && node.barrierResolutionState == null;
1249
+ }
1250
+ /**
1251
+ * Collects the nodes a demand-only pass must not visit yet while a
1252
+ * gated barrier is unresolved: every effectful source node whose own
1253
+ * source is not demanded (its completion would defer irrevocably for
1254
+ * this pass, yet a barrier's resolution may still demand it), plus
1255
+ * every node reachable from a parked node along hard (non-advisory)
1256
+ * dependency edges, so a dependent—a derived replay, a barrier whose
1257
+ * control dependency is a parked discriminator—never runs ahead of a
1258
+ * parked provider. The scheduling loop's all-blocked fallback keeps
1259
+ * the pass progressing even when this parks every pending node.
1260
+ */
1261
+ function collectParkedNodes(pending, session) {
1262
+ const parked = /* @__PURE__ */ new Set();
1263
+ for (const node of pending) {
1264
+ const source = node.parser.dependencyMetadata?.source;
1265
+ if (source?.completeSource != null && !session.demanded.has(source.sourceId)) parked.add(node);
1266
+ }
1267
+ if (parked.size === 0) return parked;
1268
+ const graph = buildDependencyGraph(pending);
1269
+ const queue = [...parked];
1270
+ while (queue.length > 0) {
1271
+ const provider = queue.pop();
1272
+ for (const [consumer, advisoryOnly] of graph.outgoing.get(provider) ?? []) {
1273
+ if (advisoryOnly || parked.has(consumer)) continue;
1274
+ parked.add(consumer);
1275
+ queue.push(consumer);
1276
+ }
1277
+ }
1278
+ return parked;
1279
+ }
1280
+ /**
1154
1281
  * Runs effectful source completions (e.g., interactive prompts) serially
1155
1282
  * in declaration order for source nodes whose value is not yet registered.
1156
1283
  *
@@ -1207,38 +1334,7 @@ async function completeEffectfulSourcesAsync(nodes, state, runtime, exec, option
1207
1334
  const demandNodes = options?.demandNodes ?? nodes;
1208
1335
  const demanded = collectDemandedDependencyIds(demandNodes, state, exec.trace);
1209
1336
  for (const id of demanded) session.demanded.add(id);
1210
- let demandAdded = true;
1211
- while (demandAdded) {
1212
- demandAdded = false;
1213
- for (const node of nodes) {
1214
- const metadata = node.parser.dependencyMetadata;
1215
- if (metadata?.source != null && metadata.derived != null && session.demanded.has(metadata.source.sourceId)) for (const dependencySourceId of metadata.derived.dependencyIds) {
1216
- if (session.demanded.has(dependencySourceId)) continue;
1217
- session.demanded.add(dependencySourceId);
1218
- demandAdded = true;
1219
- }
1220
- if (metadata?.source != null && metadata.completion != null && session.demanded.has(metadata.source.sourceId) && !hasInactiveCompletion(node)) for (const dependencySourceId of metadata.completion.dependencyIds) {
1221
- if (session.demanded.has(dependencySourceId)) continue;
1222
- session.demanded.add(dependencySourceId);
1223
- demandAdded = true;
1224
- }
1225
- if (node.barrierCompletionDependencies != null) for (const edge of node.barrierCompletionDependencies.demandEdges) {
1226
- if (!session.demanded.has(edge.consumerSourceId)) continue;
1227
- for (const dependencySourceId of edge.dependencyIds) {
1228
- if (session.demanded.has(dependencySourceId)) continue;
1229
- session.demanded.add(dependencySourceId);
1230
- demandAdded = true;
1231
- }
1232
- }
1233
- if (node.requiresSourceId == null || node.providesSourceIds == null) continue;
1234
- if (session.demanded.has(node.requiresSourceId)) continue;
1235
- for (const provided of node.providesSourceIds) if (session.demanded.has(provided)) {
1236
- session.demanded.add(node.requiresSourceId);
1237
- demandAdded = true;
1238
- break;
1239
- }
1240
- }
1241
- }
1337
+ propagateDemand(nodes, session);
1242
1338
  }
1243
1339
  if (session != null) {
1244
1340
  for (const result of session.results.values()) if (!result.success) return {
@@ -1259,12 +1355,17 @@ async function completeEffectfulSourcesAsync(nodes, state, runtime, exec, option
1259
1355
  }).then((result) => result.success ? void 0 : result)
1260
1356
  };
1261
1357
  const pending = [...nodes];
1358
+ const metadataUniverse = [...nodes];
1262
1359
  const providesId = (node, id) => node.parser.dependencyMetadata?.source?.sourceId === id || node.providesSourceIds?.has(id) === true;
1360
+ const demandSession = session?.policy === "demand-only" ? session : void 0;
1263
1361
  const resolveBarrierAt = async (index) => {
1264
1362
  const candidate = pending[index];
1265
1363
  const resolution = await candidate.resolveBarrier(barrierContext);
1266
- if (resolution != null && "success" in resolution) return resolution;
1267
- pending[index] = resolution == null ? {
1364
+ if (resolution != null && "success" in resolution) {
1365
+ session?.results.set(Symbol(barrierFailureDescription), resolution);
1366
+ return resolution;
1367
+ }
1368
+ const replacement = resolution == null ? {
1268
1369
  ...candidate,
1269
1370
  barrierResolutionState: "unresolvable"
1270
1371
  } : {
@@ -1273,22 +1374,44 @@ async function completeEffectfulSourcesAsync(nodes, state, runtime, exec, option
1273
1374
  providesSourceIds: resolution.activeProvidesSourceIds,
1274
1375
  barrierCompletionDependencies: {
1275
1376
  orderingDependencyIds: resolution.orderingDependencyIds,
1276
- demandEdges: []
1377
+ demandEdges: resolution.demandEdges
1277
1378
  }
1278
1379
  };
1380
+ pending[index] = replacement;
1381
+ const universeIndex = metadataUniverse.indexOf(candidate);
1382
+ if (universeIndex >= 0) metadataUniverse[universeIndex] = replacement;
1383
+ if (resolution != null && demandSession != null) propagateDemand(metadataUniverse, demandSession);
1279
1384
  return void 0;
1280
1385
  };
1281
1386
  while (pending.length > 0) {
1387
+ const parkingActive = demandSession != null && pending.some(isGatedUnresolvedBarrier);
1282
1388
  for (let i = 0; i < pending.length; i++) {
1283
1389
  const candidate = pending[i];
1284
1390
  if (candidate.resolveBarrier == null || candidate.barrierResolutionState != null) continue;
1285
1391
  const requires = candidate.requiresSourceId;
1286
1392
  if (requires == null) continue;
1393
+ if (parkingActive && demandSession != null && !demandSession.demanded.has(requires)) continue;
1287
1394
  if (pending.some((other) => other !== candidate && providesId(other, requires))) continue;
1288
1395
  const failure = await resolveBarrierAt(i);
1289
1396
  if (failure != null) return failure;
1290
1397
  }
1291
- const node = orderDependencyNodes(pending)[0];
1398
+ const ordered = orderDependencyNodes(pending);
1399
+ let node = ordered[0];
1400
+ const parkingStillActive = demandSession != null && pending.some(isGatedUnresolvedBarrier);
1401
+ if (parkingStillActive && demandSession != null) {
1402
+ const parked = collectParkedNodes(pending, demandSession);
1403
+ const isSkippedBarrier = (candidate) => candidate.resolveBarrier != null && candidate.barrierResolutionState == null && candidate.requiresSourceId != null && !demandSession.demanded.has(candidate.requiresSourceId);
1404
+ const selectable = ordered.find((candidate) => !parked.has(candidate) && !isSkippedBarrier(candidate));
1405
+ if (selectable != null) node = selectable;
1406
+ else {
1407
+ const stalled = ordered.find((candidate) => candidate.resolveBarrier != null && candidate.barrierResolutionState == null);
1408
+ if (stalled != null) {
1409
+ const failure = await resolveBarrierAt(pending.indexOf(stalled));
1410
+ if (failure != null) return failure;
1411
+ continue;
1412
+ }
1413
+ }
1414
+ }
1292
1415
  if (node.resolveBarrier != null && node.barrierResolutionState == null) {
1293
1416
  const failure = await resolveBarrierAt(pending.indexOf(node));
1294
1417
  if (failure != null) return failure;
@@ -1703,6 +1826,7 @@ exports.hasInactiveCompletion = hasInactiveCompletion;
1703
1826
  exports.includeSourceFailureChain = includeSourceFailureChain;
1704
1827
  exports.orderDependencyNodes = orderDependencyNodes;
1705
1828
  exports.recordDerivedRawInput = recordDerivedRawInput;
1829
+ exports.replaceCachedBarrierFailure = replaceCachedBarrierFailure;
1706
1830
  exports.replayDerivedParser = replayDerivedParser;
1707
1831
  exports.replayDerivedParserAsync = replayDerivedParserAsync;
1708
1832
  exports.resolveDerivedSourceValues = resolveDerivedSourceValues;
@@ -3,7 +3,7 @@ import { DependencyRegistryLike } from "./registry-types.cjs";
3
3
  import { ValueParserResult } from "./valueparser.cjs";
4
4
  import { ParserDependencyMetadata } from "./dependency-metadata.cjs";
5
5
  import { InputTrace } from "./input-trace.cjs";
6
- import { ExecutionContext } from "./internal/parser.cjs";
6
+ import { EffectfulCompletionSession, ExecutionContext } from "./internal/parser.cjs";
7
7
 
8
8
  //#region src/dependency-runtime.d.ts
9
9
 
@@ -220,6 +220,22 @@ interface RuntimeNode {
220
220
  * @since 1.3.0
221
221
  */
222
222
  readonly barrierCompletionDependencies?: BarrierCompletionDependencies;
223
+ /**
224
+ * When `"after-resolution"`, the demand edges in
225
+ * {@link RuntimeNode.barrierCompletionDependencies} join demand
226
+ * propagation only once {@link RuntimeNode.resolveBarrier} has
227
+ * replaced the static estimate with the resolved selection's actual
228
+ * edges. Until then the demand-only pass parks not-yet-demanded
229
+ * effectful nodes instead of letting them defer, so a prerequisite
230
+ * demanded only by an unselected branch never runs, while one the
231
+ * resolved selection reads still completes in its dependency slot.
232
+ * A barrier the pass marks `"unresolvable"` never activates its
233
+ * edges within that pass. Ordering and control edges are unaffected.
234
+ * Default: `"immediate"`.
235
+ *
236
+ * @since 1.3.0
237
+ */
238
+ readonly barrierDemandActivation?: "immediate" | "after-resolution";
223
239
  }
224
240
  /**
225
241
  * An exact demand edge inside a scheduling barrier's subtree: when the
@@ -285,6 +301,19 @@ interface BarrierResolution {
285
301
  * sibling consumer no longer waits for a merely possible provider.
286
302
  */
287
303
  readonly activeProvidesSourceIds: ReadonlySet<symbol>;
304
+ /**
305
+ * The demand edges of the resolved selection: empty when the
306
+ * selection was rejected or has no completion consumers. A
307
+ * demand-only pass applies them once the barrier resolves, so a
308
+ * prerequisite is demanded only for a selection that actually reads
309
+ * it. Edges belonging to a nested barrier whose own demand
310
+ * activation is `"after-resolution"` and which is still unresolved
311
+ * must not appear here; the nested barrier promotes them itself
312
+ * within its own scheduling pass.
313
+ *
314
+ * @since 1.3.0
315
+ */
316
+ readonly demandEdges: readonly BarrierCompletionDemandEdge[];
288
317
  }
289
318
  /**
290
319
  * Options for resolving matched derived source values.
@@ -723,6 +752,31 @@ interface CompleteEffectfulSourcesOptions {
723
752
  */
724
753
  readonly includeStructural?: boolean;
725
754
  }
755
+ /**
756
+ * Replaces a barrier failure cached in the run-scoped session with a
757
+ * wrapped version of the same failure, identified by object identity.
758
+ * A construct that decorates a nested barrier failure on its way out—a
759
+ * `conditional()` applying its `branchError` hook—uses this so later
760
+ * passes sharing the session (the eager fallback after a failed seed
761
+ * pass) surface the wrapped error rather than the raw one.
762
+ *
763
+ * @param session The run-scoped effectful completion session.
764
+ * @param original The failure exactly as the scheduling pass returned
765
+ * it.
766
+ * @param replacement The decorated failure to cache in its place.
767
+ * @returns Whether a cached barrier failure was found and replaced;
768
+ * `false` means the failure did not come from a barrier resolution
769
+ * and should propagate untouched.
770
+ * @internal
771
+ * @since 1.3.0
772
+ */
773
+ declare function replaceCachedBarrierFailure(session: EffectfulCompletionSession | undefined, original: {
774
+ readonly success: false;
775
+ readonly error: Message;
776
+ }, replacement: {
777
+ readonly success: false;
778
+ readonly error: Message;
779
+ }): boolean;
726
780
  /**
727
781
  * Runs effectful source completions (e.g., interactive prompts) serially
728
782
  * in declaration order for source nodes whose value is not yet registered.
@@ -858,4 +912,4 @@ declare function buildRuntimeNodesFromArray(parsers: ReadonlyArray<{
858
912
  readonly initialState?: unknown;
859
913
  }>, stateArray: readonly unknown[], parentPath?: readonly PropertyKey[]): readonly RuntimeNode[];
860
914
  //#endregion
861
- export { BarrierCompletionDemandEdge, BarrierCompletionDependencies, BarrierResolution, CompleteEffectfulSourcesOptions, DependencyRequest, DependencyResolution, DependencyRuntimeContext, EffectfulSchedulingNodesFn, EffectfulSourceCompletion, EffectfulSourceCompletionResult, ReplayKey, ResolveDerivedSourceValuesOptions, RuntimeNode, SchedulingBarrierContext, SourceDefaultFailure, buildRuntimeNodesFromArray, buildRuntimeNodesFromPairs, collectDemandedDependencyIds, collectExplicitSourceValues, collectExplicitSourceValuesAsync, collectSourcesFromState, completeEffectfulSourcesAsync, createDependencyFingerprint, createDependencyRuntimeContext, createReplayKey, defineForwardedEffectfulSchedulingNodes, derivedRawInputKey, effectfulSchedulingNodesKey, exclusiveSourceScopeKey, extractRawInputFromState, fillMissingSourceDefaults, fillMissingSourceDefaultsAsync, guaranteedStaticSourceIdsKey, hasInactiveCompletion, includeSourceFailureChain, orderDependencyNodes, recordDerivedRawInput, replayDerivedParser, replayDerivedParserAsync, resolveDerivedSourceValues, resolveDerivedSourceValuesAsync, resolveStateWithRuntime, resolveStateWithRuntimeAsync, serializeSchedulingPath, sourceCollectionExpansionKey, staticSourceScopeKey };
915
+ export { BarrierCompletionDemandEdge, BarrierCompletionDependencies, BarrierResolution, CompleteEffectfulSourcesOptions, DependencyRequest, DependencyResolution, DependencyRuntimeContext, EffectfulSchedulingNodesFn, EffectfulSourceCompletion, EffectfulSourceCompletionResult, ReplayKey, ResolveDerivedSourceValuesOptions, RuntimeNode, SchedulingBarrierContext, SourceDefaultFailure, buildRuntimeNodesFromArray, buildRuntimeNodesFromPairs, collectDemandedDependencyIds, collectExplicitSourceValues, collectExplicitSourceValuesAsync, collectSourcesFromState, completeEffectfulSourcesAsync, createDependencyFingerprint, createDependencyRuntimeContext, createReplayKey, defineForwardedEffectfulSchedulingNodes, derivedRawInputKey, effectfulSchedulingNodesKey, exclusiveSourceScopeKey, extractRawInputFromState, fillMissingSourceDefaults, fillMissingSourceDefaultsAsync, guaranteedStaticSourceIdsKey, hasInactiveCompletion, includeSourceFailureChain, orderDependencyNodes, recordDerivedRawInput, replaceCachedBarrierFailure, replayDerivedParser, replayDerivedParserAsync, resolveDerivedSourceValues, resolveDerivedSourceValuesAsync, resolveStateWithRuntime, resolveStateWithRuntimeAsync, serializeSchedulingPath, sourceCollectionExpansionKey, staticSourceScopeKey };
@@ -3,7 +3,7 @@ import { DependencyRegistryLike } from "./registry-types.js";
3
3
  import { ValueParserResult } from "./valueparser.js";
4
4
  import { ParserDependencyMetadata } from "./dependency-metadata.js";
5
5
  import { InputTrace } from "./input-trace.js";
6
- import { ExecutionContext } from "./internal/parser.js";
6
+ import { EffectfulCompletionSession, ExecutionContext } from "./internal/parser.js";
7
7
 
8
8
  //#region src/dependency-runtime.d.ts
9
9
 
@@ -220,6 +220,22 @@ interface RuntimeNode {
220
220
  * @since 1.3.0
221
221
  */
222
222
  readonly barrierCompletionDependencies?: BarrierCompletionDependencies;
223
+ /**
224
+ * When `"after-resolution"`, the demand edges in
225
+ * {@link RuntimeNode.barrierCompletionDependencies} join demand
226
+ * propagation only once {@link RuntimeNode.resolveBarrier} has
227
+ * replaced the static estimate with the resolved selection's actual
228
+ * edges. Until then the demand-only pass parks not-yet-demanded
229
+ * effectful nodes instead of letting them defer, so a prerequisite
230
+ * demanded only by an unselected branch never runs, while one the
231
+ * resolved selection reads still completes in its dependency slot.
232
+ * A barrier the pass marks `"unresolvable"` never activates its
233
+ * edges within that pass. Ordering and control edges are unaffected.
234
+ * Default: `"immediate"`.
235
+ *
236
+ * @since 1.3.0
237
+ */
238
+ readonly barrierDemandActivation?: "immediate" | "after-resolution";
223
239
  }
224
240
  /**
225
241
  * An exact demand edge inside a scheduling barrier's subtree: when the
@@ -285,6 +301,19 @@ interface BarrierResolution {
285
301
  * sibling consumer no longer waits for a merely possible provider.
286
302
  */
287
303
  readonly activeProvidesSourceIds: ReadonlySet<symbol>;
304
+ /**
305
+ * The demand edges of the resolved selection: empty when the
306
+ * selection was rejected or has no completion consumers. A
307
+ * demand-only pass applies them once the barrier resolves, so a
308
+ * prerequisite is demanded only for a selection that actually reads
309
+ * it. Edges belonging to a nested barrier whose own demand
310
+ * activation is `"after-resolution"` and which is still unresolved
311
+ * must not appear here; the nested barrier promotes them itself
312
+ * within its own scheduling pass.
313
+ *
314
+ * @since 1.3.0
315
+ */
316
+ readonly demandEdges: readonly BarrierCompletionDemandEdge[];
288
317
  }
289
318
  /**
290
319
  * Options for resolving matched derived source values.
@@ -723,6 +752,31 @@ interface CompleteEffectfulSourcesOptions {
723
752
  */
724
753
  readonly includeStructural?: boolean;
725
754
  }
755
+ /**
756
+ * Replaces a barrier failure cached in the run-scoped session with a
757
+ * wrapped version of the same failure, identified by object identity.
758
+ * A construct that decorates a nested barrier failure on its way out—a
759
+ * `conditional()` applying its `branchError` hook—uses this so later
760
+ * passes sharing the session (the eager fallback after a failed seed
761
+ * pass) surface the wrapped error rather than the raw one.
762
+ *
763
+ * @param session The run-scoped effectful completion session.
764
+ * @param original The failure exactly as the scheduling pass returned
765
+ * it.
766
+ * @param replacement The decorated failure to cache in its place.
767
+ * @returns Whether a cached barrier failure was found and replaced;
768
+ * `false` means the failure did not come from a barrier resolution
769
+ * and should propagate untouched.
770
+ * @internal
771
+ * @since 1.3.0
772
+ */
773
+ declare function replaceCachedBarrierFailure(session: EffectfulCompletionSession | undefined, original: {
774
+ readonly success: false;
775
+ readonly error: Message;
776
+ }, replacement: {
777
+ readonly success: false;
778
+ readonly error: Message;
779
+ }): boolean;
726
780
  /**
727
781
  * Runs effectful source completions (e.g., interactive prompts) serially
728
782
  * in declaration order for source nodes whose value is not yet registered.
@@ -858,4 +912,4 @@ declare function buildRuntimeNodesFromArray(parsers: ReadonlyArray<{
858
912
  readonly initialState?: unknown;
859
913
  }>, stateArray: readonly unknown[], parentPath?: readonly PropertyKey[]): readonly RuntimeNode[];
860
914
  //#endregion
861
- export { BarrierCompletionDemandEdge, BarrierCompletionDependencies, BarrierResolution, CompleteEffectfulSourcesOptions, DependencyRequest, DependencyResolution, DependencyRuntimeContext, EffectfulSchedulingNodesFn, EffectfulSourceCompletion, EffectfulSourceCompletionResult, ReplayKey, ResolveDerivedSourceValuesOptions, RuntimeNode, SchedulingBarrierContext, SourceDefaultFailure, buildRuntimeNodesFromArray, buildRuntimeNodesFromPairs, collectDemandedDependencyIds, collectExplicitSourceValues, collectExplicitSourceValuesAsync, collectSourcesFromState, completeEffectfulSourcesAsync, createDependencyFingerprint, createDependencyRuntimeContext, createReplayKey, defineForwardedEffectfulSchedulingNodes, derivedRawInputKey, effectfulSchedulingNodesKey, exclusiveSourceScopeKey, extractRawInputFromState, fillMissingSourceDefaults, fillMissingSourceDefaultsAsync, guaranteedStaticSourceIdsKey, hasInactiveCompletion, includeSourceFailureChain, orderDependencyNodes, recordDerivedRawInput, replayDerivedParser, replayDerivedParserAsync, resolveDerivedSourceValues, resolveDerivedSourceValuesAsync, resolveStateWithRuntime, resolveStateWithRuntimeAsync, serializeSchedulingPath, sourceCollectionExpansionKey, staticSourceScopeKey };
915
+ export { BarrierCompletionDemandEdge, BarrierCompletionDependencies, BarrierResolution, CompleteEffectfulSourcesOptions, DependencyRequest, DependencyResolution, DependencyRuntimeContext, EffectfulSchedulingNodesFn, EffectfulSourceCompletion, EffectfulSourceCompletionResult, ReplayKey, ResolveDerivedSourceValuesOptions, RuntimeNode, SchedulingBarrierContext, SourceDefaultFailure, buildRuntimeNodesFromArray, buildRuntimeNodesFromPairs, collectDemandedDependencyIds, collectExplicitSourceValues, collectExplicitSourceValuesAsync, collectSourcesFromState, completeEffectfulSourcesAsync, createDependencyFingerprint, createDependencyRuntimeContext, createReplayKey, defineForwardedEffectfulSchedulingNodes, derivedRawInputKey, effectfulSchedulingNodesKey, exclusiveSourceScopeKey, extractRawInputFromState, fillMissingSourceDefaults, fillMissingSourceDefaultsAsync, guaranteedStaticSourceIdsKey, hasInactiveCompletion, includeSourceFailureChain, orderDependencyNodes, recordDerivedRawInput, replaceCachedBarrierFailure, replayDerivedParser, replayDerivedParserAsync, resolveDerivedSourceValues, resolveDerivedSourceValuesAsync, resolveStateWithRuntime, resolveStateWithRuntimeAsync, serializeSchedulingPath, sourceCollectionExpansionKey, staticSourceScopeKey };
@@ -1151,6 +1151,133 @@ function collectDeferredDemand(state, demanded, visited) {
1151
1151
  for (const key of Reflect.ownKeys(state)) collectDeferredDemand(state[key], demanded, visited);
1152
1152
  }
1153
1153
  /**
1154
+ * Runs the monotonic demand fixed point over the given nodes' metadata,
1155
+ * adding to the session's demanded set until nothing changes:
1156
+ *
1157
+ * - a demanded derived source demands its dependency IDs;
1158
+ * - a demanded source whose effectful completion consumes other
1159
+ * dependency values (a prompt with a derived configuration) demands
1160
+ * those prerequisites, unless this occurrence is already satisfied;
1161
+ * - a barrier's demand edges mirror the flat completion rule for the
1162
+ * consumers hidden behind it—only when a branch consumer's own source
1163
+ * is demanded do its completion prerequisites become demanded—but a
1164
+ * barrier whose {@link RuntimeNode.barrierDemandActivation} is
1165
+ * `"after-resolution"` contributes its edges only once it has
1166
+ * resolved, so an unselected branch's prerequisites are never
1167
+ * demanded on the strength of a static estimate;
1168
+ * - when a source a barrier can provide is demanded, the barrier's
1169
+ * control dependency (its discriminator source) becomes demanded.
1170
+ *
1171
+ * One barrier's branches can provide another barrier's discriminator
1172
+ * source, and the chain must propagate regardless of declaration order.
1173
+ * Each iteration adds at least one demanded ID, so the loop terminates.
1174
+ * The scheduler re-runs this after a gated barrier resolves, passing
1175
+ * the pass's metadata universe with resolved replacement nodes swapped
1176
+ * in, so promotion chains through already-visited metadata as well.
1177
+ */
1178
+ function propagateDemand(universe, session) {
1179
+ let demandAdded = true;
1180
+ while (demandAdded) {
1181
+ demandAdded = false;
1182
+ for (const node of universe) {
1183
+ const metadata = node.parser.dependencyMetadata;
1184
+ if (metadata?.source != null && metadata.derived != null && session.demanded.has(metadata.source.sourceId)) for (const dependencySourceId of metadata.derived.dependencyIds) {
1185
+ if (session.demanded.has(dependencySourceId)) continue;
1186
+ session.demanded.add(dependencySourceId);
1187
+ demandAdded = true;
1188
+ }
1189
+ if (metadata?.source != null && metadata.completion != null && session.demanded.has(metadata.source.sourceId) && !hasInactiveCompletion(node)) for (const dependencySourceId of metadata.completion.dependencyIds) {
1190
+ if (session.demanded.has(dependencySourceId)) continue;
1191
+ session.demanded.add(dependencySourceId);
1192
+ demandAdded = true;
1193
+ }
1194
+ if (node.barrierCompletionDependencies != null && (node.barrierDemandActivation !== "after-resolution" || node.barrierResolutionState === "resolved")) for (const edge of node.barrierCompletionDependencies.demandEdges) {
1195
+ if (!session.demanded.has(edge.consumerSourceId)) continue;
1196
+ for (const dependencySourceId of edge.dependencyIds) {
1197
+ if (session.demanded.has(dependencySourceId)) continue;
1198
+ session.demanded.add(dependencySourceId);
1199
+ demandAdded = true;
1200
+ }
1201
+ }
1202
+ if (node.requiresSourceId == null || node.providesSourceIds == null) continue;
1203
+ if (session.demanded.has(node.requiresSourceId)) continue;
1204
+ for (const provided of node.providesSourceIds) if (session.demanded.has(provided)) {
1205
+ session.demanded.add(node.requiresSourceId);
1206
+ demandAdded = true;
1207
+ break;
1208
+ }
1209
+ }
1210
+ }
1211
+ }
1212
+ const barrierFailureDescription = "optique.barrierFailure";
1213
+ /**
1214
+ * Replaces a barrier failure cached in the run-scoped session with a
1215
+ * wrapped version of the same failure, identified by object identity.
1216
+ * A construct that decorates a nested barrier failure on its way out—a
1217
+ * `conditional()` applying its `branchError` hook—uses this so later
1218
+ * passes sharing the session (the eager fallback after a failed seed
1219
+ * pass) surface the wrapped error rather than the raw one.
1220
+ *
1221
+ * @param session The run-scoped effectful completion session.
1222
+ * @param original The failure exactly as the scheduling pass returned
1223
+ * it.
1224
+ * @param replacement The decorated failure to cache in its place.
1225
+ * @returns Whether a cached barrier failure was found and replaced;
1226
+ * `false` means the failure did not come from a barrier resolution
1227
+ * and should propagate untouched.
1228
+ * @internal
1229
+ * @since 1.3.0
1230
+ */
1231
+ function replaceCachedBarrierFailure(session, original, replacement) {
1232
+ if (session == null) return false;
1233
+ let replaced = false;
1234
+ for (const [key, value] of session.results) if (key.description === barrierFailureDescription && value === original) {
1235
+ session.results.set(key, replacement);
1236
+ replaced = true;
1237
+ }
1238
+ return replaced;
1239
+ }
1240
+ /**
1241
+ * Whether the node is a scheduling barrier whose demand edges are gated
1242
+ * on resolution and whose resolution has not happened yet. While any
1243
+ * such barrier is pending in a demand-only pass, the scheduler parks
1244
+ * not-yet-demanded effectful nodes instead of letting them defer, so a
1245
+ * later resolution can still demand them into their dependency slot.
1246
+ */
1247
+ function isGatedUnresolvedBarrier(node) {
1248
+ return node.resolveBarrier != null && node.barrierDemandActivation === "after-resolution" && node.barrierResolutionState == null;
1249
+ }
1250
+ /**
1251
+ * Collects the nodes a demand-only pass must not visit yet while a
1252
+ * gated barrier is unresolved: every effectful source node whose own
1253
+ * source is not demanded (its completion would defer irrevocably for
1254
+ * this pass, yet a barrier's resolution may still demand it), plus
1255
+ * every node reachable from a parked node along hard (non-advisory)
1256
+ * dependency edges, so a dependent—a derived replay, a barrier whose
1257
+ * control dependency is a parked discriminator—never runs ahead of a
1258
+ * parked provider. The scheduling loop's all-blocked fallback keeps
1259
+ * the pass progressing even when this parks every pending node.
1260
+ */
1261
+ function collectParkedNodes(pending, session) {
1262
+ const parked = /* @__PURE__ */ new Set();
1263
+ for (const node of pending) {
1264
+ const source = node.parser.dependencyMetadata?.source;
1265
+ if (source?.completeSource != null && !session.demanded.has(source.sourceId)) parked.add(node);
1266
+ }
1267
+ if (parked.size === 0) return parked;
1268
+ const graph = buildDependencyGraph(pending);
1269
+ const queue = [...parked];
1270
+ while (queue.length > 0) {
1271
+ const provider = queue.pop();
1272
+ for (const [consumer, advisoryOnly] of graph.outgoing.get(provider) ?? []) {
1273
+ if (advisoryOnly || parked.has(consumer)) continue;
1274
+ parked.add(consumer);
1275
+ queue.push(consumer);
1276
+ }
1277
+ }
1278
+ return parked;
1279
+ }
1280
+ /**
1154
1281
  * Runs effectful source completions (e.g., interactive prompts) serially
1155
1282
  * in declaration order for source nodes whose value is not yet registered.
1156
1283
  *
@@ -1207,38 +1334,7 @@ async function completeEffectfulSourcesAsync(nodes, state, runtime, exec, option
1207
1334
  const demandNodes = options?.demandNodes ?? nodes;
1208
1335
  const demanded = collectDemandedDependencyIds(demandNodes, state, exec.trace);
1209
1336
  for (const id of demanded) session.demanded.add(id);
1210
- let demandAdded = true;
1211
- while (demandAdded) {
1212
- demandAdded = false;
1213
- for (const node of nodes) {
1214
- const metadata = node.parser.dependencyMetadata;
1215
- if (metadata?.source != null && metadata.derived != null && session.demanded.has(metadata.source.sourceId)) for (const dependencySourceId of metadata.derived.dependencyIds) {
1216
- if (session.demanded.has(dependencySourceId)) continue;
1217
- session.demanded.add(dependencySourceId);
1218
- demandAdded = true;
1219
- }
1220
- if (metadata?.source != null && metadata.completion != null && session.demanded.has(metadata.source.sourceId) && !hasInactiveCompletion(node)) for (const dependencySourceId of metadata.completion.dependencyIds) {
1221
- if (session.demanded.has(dependencySourceId)) continue;
1222
- session.demanded.add(dependencySourceId);
1223
- demandAdded = true;
1224
- }
1225
- if (node.barrierCompletionDependencies != null) for (const edge of node.barrierCompletionDependencies.demandEdges) {
1226
- if (!session.demanded.has(edge.consumerSourceId)) continue;
1227
- for (const dependencySourceId of edge.dependencyIds) {
1228
- if (session.demanded.has(dependencySourceId)) continue;
1229
- session.demanded.add(dependencySourceId);
1230
- demandAdded = true;
1231
- }
1232
- }
1233
- if (node.requiresSourceId == null || node.providesSourceIds == null) continue;
1234
- if (session.demanded.has(node.requiresSourceId)) continue;
1235
- for (const provided of node.providesSourceIds) if (session.demanded.has(provided)) {
1236
- session.demanded.add(node.requiresSourceId);
1237
- demandAdded = true;
1238
- break;
1239
- }
1240
- }
1241
- }
1337
+ propagateDemand(nodes, session);
1242
1338
  }
1243
1339
  if (session != null) {
1244
1340
  for (const result of session.results.values()) if (!result.success) return {
@@ -1259,12 +1355,17 @@ async function completeEffectfulSourcesAsync(nodes, state, runtime, exec, option
1259
1355
  }).then((result) => result.success ? void 0 : result)
1260
1356
  };
1261
1357
  const pending = [...nodes];
1358
+ const metadataUniverse = [...nodes];
1262
1359
  const providesId = (node, id) => node.parser.dependencyMetadata?.source?.sourceId === id || node.providesSourceIds?.has(id) === true;
1360
+ const demandSession = session?.policy === "demand-only" ? session : void 0;
1263
1361
  const resolveBarrierAt = async (index) => {
1264
1362
  const candidate = pending[index];
1265
1363
  const resolution = await candidate.resolveBarrier(barrierContext);
1266
- if (resolution != null && "success" in resolution) return resolution;
1267
- pending[index] = resolution == null ? {
1364
+ if (resolution != null && "success" in resolution) {
1365
+ session?.results.set(Symbol(barrierFailureDescription), resolution);
1366
+ return resolution;
1367
+ }
1368
+ const replacement = resolution == null ? {
1268
1369
  ...candidate,
1269
1370
  barrierResolutionState: "unresolvable"
1270
1371
  } : {
@@ -1273,22 +1374,44 @@ async function completeEffectfulSourcesAsync(nodes, state, runtime, exec, option
1273
1374
  providesSourceIds: resolution.activeProvidesSourceIds,
1274
1375
  barrierCompletionDependencies: {
1275
1376
  orderingDependencyIds: resolution.orderingDependencyIds,
1276
- demandEdges: []
1377
+ demandEdges: resolution.demandEdges
1277
1378
  }
1278
1379
  };
1380
+ pending[index] = replacement;
1381
+ const universeIndex = metadataUniverse.indexOf(candidate);
1382
+ if (universeIndex >= 0) metadataUniverse[universeIndex] = replacement;
1383
+ if (resolution != null && demandSession != null) propagateDemand(metadataUniverse, demandSession);
1279
1384
  return void 0;
1280
1385
  };
1281
1386
  while (pending.length > 0) {
1387
+ const parkingActive = demandSession != null && pending.some(isGatedUnresolvedBarrier);
1282
1388
  for (let i = 0; i < pending.length; i++) {
1283
1389
  const candidate = pending[i];
1284
1390
  if (candidate.resolveBarrier == null || candidate.barrierResolutionState != null) continue;
1285
1391
  const requires = candidate.requiresSourceId;
1286
1392
  if (requires == null) continue;
1393
+ if (parkingActive && demandSession != null && !demandSession.demanded.has(requires)) continue;
1287
1394
  if (pending.some((other) => other !== candidate && providesId(other, requires))) continue;
1288
1395
  const failure = await resolveBarrierAt(i);
1289
1396
  if (failure != null) return failure;
1290
1397
  }
1291
- const node = orderDependencyNodes(pending)[0];
1398
+ const ordered = orderDependencyNodes(pending);
1399
+ let node = ordered[0];
1400
+ const parkingStillActive = demandSession != null && pending.some(isGatedUnresolvedBarrier);
1401
+ if (parkingStillActive && demandSession != null) {
1402
+ const parked = collectParkedNodes(pending, demandSession);
1403
+ const isSkippedBarrier = (candidate) => candidate.resolveBarrier != null && candidate.barrierResolutionState == null && candidate.requiresSourceId != null && !demandSession.demanded.has(candidate.requiresSourceId);
1404
+ const selectable = ordered.find((candidate) => !parked.has(candidate) && !isSkippedBarrier(candidate));
1405
+ if (selectable != null) node = selectable;
1406
+ else {
1407
+ const stalled = ordered.find((candidate) => candidate.resolveBarrier != null && candidate.barrierResolutionState == null);
1408
+ if (stalled != null) {
1409
+ const failure = await resolveBarrierAt(pending.indexOf(stalled));
1410
+ if (failure != null) return failure;
1411
+ continue;
1412
+ }
1413
+ }
1414
+ }
1292
1415
  if (node.resolveBarrier != null && node.barrierResolutionState == null) {
1293
1416
  const failure = await resolveBarrierAt(pending.indexOf(node));
1294
1417
  if (failure != null) return failure;
@@ -1681,4 +1804,4 @@ function getDefaultDependencySnapshotInner(state, visited) {
1681
1804
  }
1682
1805
 
1683
1806
  //#endregion
1684
- export { buildRuntimeNodesFromArray, buildRuntimeNodesFromPairs, collectDemandedDependencyIds, collectExplicitSourceValues, collectExplicitSourceValuesAsync, collectSourcesFromState, completeEffectfulSourcesAsync, createDependencyFingerprint, createDependencyRuntimeContext, createReplayKey, defineForwardedEffectfulSchedulingNodes, derivedRawInputKey, effectfulSchedulingNodesKey, exclusiveSourceScopeKey, extractRawInputFromState, fillMissingSourceDefaults, fillMissingSourceDefaultsAsync, guaranteedStaticSourceIdsKey, hasInactiveCompletion, includeSourceFailureChain, orderDependencyNodes, recordDerivedRawInput, replayDerivedParser, replayDerivedParserAsync, resolveDerivedSourceValues, resolveDerivedSourceValuesAsync, resolveStateWithRuntime, resolveStateWithRuntimeAsync, serializeSchedulingPath, sourceCollectionExpansionKey, staticSourceScopeKey };
1807
+ export { buildRuntimeNodesFromArray, buildRuntimeNodesFromPairs, collectDemandedDependencyIds, collectExplicitSourceValues, collectExplicitSourceValuesAsync, collectSourcesFromState, completeEffectfulSourcesAsync, createDependencyFingerprint, createDependencyRuntimeContext, createReplayKey, defineForwardedEffectfulSchedulingNodes, derivedRawInputKey, effectfulSchedulingNodesKey, exclusiveSourceScopeKey, extractRawInputFromState, fillMissingSourceDefaults, fillMissingSourceDefaultsAsync, guaranteedStaticSourceIdsKey, hasInactiveCompletion, includeSourceFailureChain, orderDependencyNodes, recordDerivedRawInput, replaceCachedBarrierFailure, replayDerivedParser, replayDerivedParserAsync, resolveDerivedSourceValues, resolveDerivedSourceValuesAsync, resolveStateWithRuntime, resolveStateWithRuntimeAsync, serializeSchedulingPath, sourceCollectionExpansionKey, staticSourceScopeKey };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optique/core",
3
- "version": "1.3.0-dev.2433",
3
+ "version": "1.3.0-dev.2434",
4
4
  "description": "Type-safe combinatorial command-line interface parser",
5
5
  "keywords": [
6
6
  "CLI",
@@ -221,7 +221,7 @@
221
221
  },
222
222
  "sideEffects": false,
223
223
  "devDependencies": {
224
- "@optique/env": "1.3.0-dev.2433+82919fcb",
224
+ "@optique/env": "1.3.0-dev.2434+6eaf6d6e",
225
225
  "@types/node": "^24.0.0",
226
226
  "fast-check": "^4.7.0",
227
227
  "tsdown": "^0.13.0",