@rulvar/plan 1.35.0 → 1.37.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -503,7 +503,16 @@ declare function rebasePlanRevision(request: PlanReviseRequest, context: RebaseC
503
503
  //#region src/guards.d.ts
504
504
  /** RevisionGuards configuration. */
505
505
  interface RevisionGuardsOptions {
506
- /** Default 'finish-with-partial'; the chain is non-HITL and terminating. */
506
+ /**
507
+ * Default 'finish-with-partial'; the chain is non-HITL and
508
+ * terminating. 'reject-revision' and 'finish-with-partial' freeze the
509
+ * plan and steer the orchestrator to finish with the partial result
510
+ * (run outcome 'ok'). 'fail-run' closes the run as a FAILURE: after
511
+ * the journaled guard verdict the PlanRunner terminates the
512
+ * orchestration with FailRunError (code 'fail_run', data.source
513
+ * 'plan_guards', data.verdictRef), no further model turn is consulted,
514
+ * and resume rolls the same failure forward from the verdict entry.
515
+ */
507
516
  fallback?: "reject-revision" | "finish-with-partial" | "fail-run";
508
517
  /** Default 3 consecutive fully-dropped revisions. */
509
518
  droppedRevisionLimit?: number;
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { AdmissionRejectedError, BudgetExhaustedError, CURRENT_HASH_VERSION, ConfigError, DedupIndex, InMemoryStore, LEGACY_LTID_PREFIX, LEGACY_SIGNATURE_INPUTS, LineageIndex, PlanInvariantError, ROOT_ACCOUNT, ReplayPlanHashMismatch, TerminationAccount, approachSigCoarse, buildTerminationInitValue, canonicalIsolationTag, canonicalizeLadder, checkpointRefFor, countsAgainstLimit, createEngine, defineWorkflow, deriverV2, evaluateReuse, foldTermination, kMaxOf, knowledgeHash, ladderLengthOf, ladderRungChoice, makeOrchestratorWorkflow, nodeLinkKey, normalizeApproachTag, orchestrate, planNodeScope, profileRegistrySnapshotHash, tool, validateTerminationLimits } from "@rulvar/core";
1
+ import { AdmissionRejectedError, BudgetExhaustedError, CURRENT_HASH_VERSION, ConfigError, DedupIndex, FailRunError, InMemoryStore, LEGACY_LTID_PREFIX, LEGACY_SIGNATURE_INPUTS, LineageIndex, PlanInvariantError, ROOT_ACCOUNT, ReplayPlanHashMismatch, TerminationAccount, approachSigCoarse, buildTerminationInitValue, canonicalIsolationTag, canonicalizeLadder, checkpointRefFor, countsAgainstLimit, createEngine, defineWorkflow, deriverV2, evaluateReuse, foldTermination, kMaxOf, knowledgeHash, ladderLengthOf, ladderRungChoice, makeOrchestratorWorkflow, nodeLinkKey, normalizeApproachTag, orchestrate, planNodeScope, profileRegistrySnapshotHash, tool, validateTerminationLimits } from "@rulvar/core";
2
2
  //#region src/plan-state.ts
3
3
  /**
4
4
  * Plan scope substrate (M7-T01): TaskPlan as engine-owned typed data, the
@@ -2029,6 +2029,26 @@ function planRunner(options) {
2029
2029
  guard: verdict.guard,
2030
2030
  ...verdict.approachSigCoarse === void 0 ? {} : { approachSigCoarse: verdict.approachSigCoarse }
2031
2031
  });
2032
+ /**
2033
+ * The engaged 'fail-run' fallback closes the run as a typed failure
2034
+ * (v1.35.0 review P2-1: the verdict used to journal the fallback and
2035
+ * then behave exactly like finish-with-partial). The journaled verdict
2036
+ * is the decision; terminate() aborts the loop and the orchestrate
2037
+ * settle boundary rethrows the failure, so a crash after the verdict
2038
+ * rolls the SAME outcome forward from the journal on resume, with no
2039
+ * second decision and no model call.
2040
+ */
2041
+ let failRunSignalled = false;
2042
+ const enforceEngagedFailRun = () => {
2043
+ if (failRunSignalled || guards.state.engaged !== "fail-run") return;
2044
+ failRunSignalled = true;
2045
+ const verdictEntry = io.snapshot().find((entry) => entry.scope === planScope && entry.kind === "decision" && entry.value?.decisionType === "guard-verdict" && entry.value.fallback === "fail-run");
2046
+ const guardName = (verdictEntry?.value)?.guard;
2047
+ io.terminate?.(new FailRunError(`revision guards engaged (${guardName ?? "guard"}) with fallback 'fail-run': the plan is closed for adaptation and the run fails instead of finishing with the partial result`, { data: {
2048
+ source: "plan_guards",
2049
+ ...verdictEntry === void 0 ? {} : { verdictRef: verdictEntry.seq }
2050
+ } }));
2051
+ };
2032
2052
  /** Guard verdict state is a pure fold of journaled verdicts (M7-T06). */
2033
2053
  const absorbGuardVerdicts = () => {
2034
2054
  for (const entry of io.snapshot()) {
@@ -2040,6 +2060,7 @@ function planRunner(options) {
2040
2060
  }
2041
2061
  guardCursor = entry.seq;
2042
2062
  }
2063
+ enforceEngagedFailRun();
2043
2064
  };
2044
2065
  /**
2045
2066
  * Appends fold-fired verdicts strictly BEFORE their effects; a
@@ -2065,6 +2086,7 @@ function planRunner(options) {
2065
2086
  limit: verdict.oscillationCount ?? 0
2066
2087
  });
2067
2088
  }
2089
+ enforceEngagedFailRun();
2068
2090
  };
2069
2091
  /** The coarse approach signature of a spec (mirrors admission's inputs). */
2070
2092
  const coarseOf = (spec) => approachSigCoarse({
@@ -3340,7 +3362,13 @@ function planRunner(options) {
3340
3362
  await io.flush();
3341
3363
  absorbPlan();
3342
3364
  absorbGuardVerdicts();
3343
- if (guards.revisionsRejected) throw new ConfigError(`revision guards engaged (${guards.state.engaged ?? "unknown"}): the plan is closed for adaptation; call finish with the partial result`);
3365
+ if (guards.revisionsRejected) {
3366
+ if (guards.state.engaged === "fail-run") {
3367
+ enforceEngagedFailRun();
3368
+ throw new FailRunError("revision guards engaged with fallback 'fail-run': the plan is closed and the run fails instead of finishing with the partial result", { data: { source: "plan_guards" } });
3369
+ }
3370
+ throw new ConfigError(`revision guards engaged (${guards.state.engaged ?? "unknown"}): the plan is closed for adaptation; call finish with the partial result`);
3371
+ }
3344
3372
  if (vocabulary !== void 0) {
3345
3373
  for (const op of request.ops) if (op.op === "add_task") {
3346
3374
  const tag = op.approach ?? op.spec.approach;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rulvar/plan",
3
- "version": "1.35.0",
3
+ "version": "1.37.0",
4
4
  "description": "Rulvar adaptive orchestration extension: PlanRunner, RunLedger, escalation extensions, ModelLadder configuration.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -22,13 +22,13 @@
22
22
  "access": "public"
23
23
  },
24
24
  "dependencies": {
25
- "@rulvar/core": "1.35.0"
25
+ "@rulvar/core": "1.37.0"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@types/node": "^22.20.0",
29
29
  "tsdown": "^0.22.3",
30
30
  "typescript": "~6.0.3",
31
- "@rulvar/store-sqlite": "1.35.0"
31
+ "@rulvar/store-sqlite": "1.37.0"
32
32
  },
33
33
  "repository": {
34
34
  "type": "git",