@sellable/mcp 0.1.751 → 0.1.753

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.
@@ -78,6 +78,12 @@ const REFILL_DONE_REASONS = new Set([
78
78
  "abandoned_stale_checkpoint",
79
79
  "signal_search_provider_unavailable",
80
80
  "exact_action_complete",
81
+ // fix(112ay): the fence opened, the fresh plan's head had already drifted
82
+ // away from the pinned action, and NOTHING executed. The pinned edge was
83
+ // never attempted, so this terminal must not read as a completion — the
84
+ // coordinator records no claim and the edge stays selectable when the
85
+ // planner exposes it as head again.
86
+ "exact_action_superseded",
81
87
  ]);
82
88
  // fix(110-20d): a resumed scheduler wait must be mortal. Terminalize a stale
83
89
  // checkpoint once the persisted wait entry has aged past this multiple of the
@@ -2105,6 +2111,10 @@ const INHERITED_ATTEMPT_LEDGER_KEYS = [
2105
2111
  "drySourcePrepAttempts",
2106
2112
  "approvalCohortAttempts",
2107
2113
  "erroredCellRepairAttempts",
2114
+ // fix(112aw): mirrors WORKSPACE_ATTEMPT_LEDGER_KEYS — census fingerprints of
2115
+ // confirmed completeness-claim releases must survive the fence inherit or a
2116
+ // continuation would re-authorize the same release and reopen the livelock.
2117
+ "confirmedClaimReleaseAttempts",
2108
2118
  ];
2109
2119
  function inheritAttemptLedgers(base, incoming) {
2110
2120
  if (!incoming)
@@ -2632,11 +2642,26 @@ async function gatePlan(input, deps, ctx) {
2632
2642
  // preflight/fence. Continuing inside this run misattributes later blockers
2633
2643
  // to the original target (for example, a Signal outage reported against a
2634
2644
  // scheduler action) and is the root of cross-action retry loops.
2635
- return completeTerminal(input, deps, ctx, "exact_action_complete", {
2645
+ //
2646
+ // fix(112ay): head drift BEFORE anything executed is not a completion. Run
2647
+ // 5 (Dotwork td7-28): the sweep fence opened, the in-fence dated capacity
2648
+ // read blocked pending a credit refresh, the fresh head became
2649
+ // approve_messages, and this branch stamped exact_action_complete on a
2650
+ // sweep that NEVER RAN — the coordinator hardened that into a confirmed
2651
+ // claim while a directly-dispatched dated sweep placed 18 cells
2652
+ // immediately. Only a fence that actually executed its pinned (or
2653
+ // sanctioned in-fence) action may claim completion; an unexecuted pin
2654
+ // terminals exact_action_superseded, which records NO claim.
2655
+ const fenceExecutedPinnedAction = Boolean(executedAction);
2656
+ return completeTerminal(input, deps, ctx, fenceExecutedPinnedAction
2657
+ ? "exact_action_complete"
2658
+ : "exact_action_superseded", {
2636
2659
  expectedActionKey,
2637
2660
  nextActionKey,
2638
2661
  nextActionType: stringValue(action.type),
2639
- guidance: "The pinned exact action is no longer the planner head. Return to the workspace coordinator and preflight the fresh action behind a new fence.",
2662
+ guidance: fenceExecutedPinnedAction
2663
+ ? "The pinned exact action is no longer the planner head. Return to the workspace coordinator and preflight the fresh action behind a new fence."
2664
+ : "The pinned exact action was superseded before this fence executed anything. No completion is claimed; return to the workspace coordinator and preflight the fresh head behind a new fence.",
2640
2665
  plan,
2641
2666
  });
2642
2667
  }
@@ -253,6 +253,10 @@ const WORKSPACE_ATTEMPT_LEDGER_KEYS = [
253
253
  "drySourcePrepAttempts",
254
254
  "approvalCohortAttempts",
255
255
  "erroredCellRepairAttempts",
256
+ // fix(112aw): census fingerprints at which a CONFIRMED completeness claim was
257
+ // released. Stripping this would re-authorize a confirmed release on every
258
+ // coordinator call and reopen the 112as livelock.
259
+ "confirmedClaimReleaseAttempts",
256
260
  ];
257
261
  // A fenced exact run records its bounded attempt receipts on ITS OWN
258
262
  // runState; the workspace loop replans from workspaceRunState. Without this
@@ -1499,12 +1503,17 @@ async function selectWorkspaceExactTarget(input, workspacePlanOverride, options
1499
1503
  // opening is barred for those targets (in the selection loop below).
1500
1504
  const completeDeferredTargets = blockedExactTargets.filter((blocked) => blocked.blocker === "complete" ||
1501
1505
  blocked.blocker === "capped_by_scheduler");
1502
- const waiveCompleteClaims = options.waiveCompleteClaims === true;
1506
+ const waiveCompleteClaims = options.waiveCompleteClaims === true ||
1507
+ options.waiveCompleteClaims === "include_confirmed";
1508
+ const waiveConfirmedClaims = options.waiveCompleteClaims === "include_confirmed";
1503
1509
  const prefilterBlockedTargets = blockedExactTargets.filter((blocked) => blocked.blocker !== "complete" &&
1504
1510
  blocked.blocker !== "capped_by_scheduler" &&
1505
1511
  // fix(112as): on the bounded release pass, a self-issued
1506
1512
  // exact_action_complete claim no longer bars its own edge.
1507
- !(waiveCompleteClaims && blocked.blocker === "exact_action_complete"));
1513
+ !(waiveCompleteClaims && blocked.blocker === "exact_action_complete") &&
1514
+ // fix(112aw): a census-authorized release also waives CONFIRMED claims.
1515
+ !(waiveConfirmedClaims &&
1516
+ blocked.blocker === EXACT_ACTION_COMPLETE_CONFIRMED_BLOCKER));
1508
1517
  const seenTargetKeys = new Set();
1509
1518
  // fix(112ak): every refusal is recorded so a non-empty-census terminal can
1510
1519
  // name the concrete per-lane blocker instead of reporting a bare dead end.
@@ -1544,16 +1553,61 @@ async function selectWorkspaceExactTarget(input, workspacePlanOverride, options
1544
1553
  return null;
1545
1554
  if (coordinatorExcludedEdges.length === 0)
1546
1555
  return null;
1547
- if (!coordinatorExcludedEdges.every((edge) => edge.blocker === "exact_action_complete")) {
1556
+ if (!coordinatorExcludedEdges.every((edge) => edge.blocker === EXACT_ACTION_COMPLETE_BLOCKER ||
1557
+ edge.blocker === EXACT_ACTION_COMPLETE_CONFIRMED_BLOCKER)) {
1548
1558
  return null;
1549
1559
  }
1550
1560
  const census = workspaceGapBearingActionableSupply(workspacePlan);
1551
1561
  if (census.actionableRows <= 0 && !census.frontierHasMoreRows) {
1552
1562
  return null;
1553
1563
  }
1554
- const released = await selectWorkspaceExactTarget(input, workspacePlan, {
1564
+ // fix(112aw): a CONFIRMED claim is a bounded batch receipt, not proof the
1565
+ // edge is done — prepare/approve run in bounded cohorts, so a 50-send day
1566
+ // legitimately needs the SAME edge many times (Dotwork td7-28 run 1:
1567
+ // approve_messages + prepare_messages hardened to confirmed after two
1568
+ // productive batches, then refused the remaining 40-send fill against a
1569
+ // census of 6 approval candidates). Release confirmed claims too, but
1570
+ // only when the gap-bearing census MOVED since the last confirmed
1571
+ // release: a productive batch always changes the census (rows advance
1572
+ // stages), while a dispatch that moved nothing leaves it identical and
1573
+ // the claim stands. That keeps the 112as-b livelock kill, re-keyed on
1574
+ // progress instead of receipt count.
1575
+ const hasConfirmedClaims = coordinatorExcludedEdges.some((edge) => edge.blocker === EXACT_ACTION_COMPLETE_CONFIRMED_BLOCKER);
1576
+ let releaseInput = input;
1577
+ if (hasConfirmedClaims) {
1578
+ const fingerprint = [
1579
+ census.approvalFrontier,
1580
+ census.generateFrontier,
1581
+ census.enrichFrontier,
1582
+ census.rubricFrontier,
1583
+ census.frontierHasMoreRows ? 1 : 0,
1584
+ ].join(":");
1585
+ const priorReleases = Array.isArray(workspaceRunState?.confirmedClaimReleaseAttempts)
1586
+ ? workspaceRunState.confirmedClaimReleaseAttempts
1587
+ : [];
1588
+ if (priorReleases.some((entry) => stringValue(recordValue(entry)?.fingerprint) === fingerprint)) {
1589
+ return null;
1590
+ }
1591
+ releaseInput = {
1592
+ ...input,
1593
+ workspaceRunState: {
1594
+ ...(workspaceRunState ?? {
1595
+ version: 1,
1596
+ senderCursors: [],
1597
+ laneCooldowns: [],
1598
+ passRates: [],
1599
+ coordinatorBlockedExactTargets: [],
1600
+ }),
1601
+ confirmedClaimReleaseAttempts: [
1602
+ ...priorReleases.filter((entry) => Boolean(recordValue(entry))),
1603
+ { fingerprint, decidedAt: new Date().toISOString() },
1604
+ ],
1605
+ },
1606
+ };
1607
+ }
1608
+ const released = await selectWorkspaceExactTarget(releaseInput, workspacePlan, {
1555
1609
  ...options,
1556
- waiveCompleteClaims: true,
1610
+ waiveCompleteClaims: hasConfirmedClaims ? "include_confirmed" : true,
1557
1611
  seedExcludedEdges: [...coordinatorExcludedEdges],
1558
1612
  });
1559
1613
  // The release may only ADD a dispatch. If it fails to bind an edge, fall
@@ -1846,6 +1900,11 @@ async function selectWorkspaceExactTarget(input, workspacePlanOverride, options
1846
1900
  blocked.blocker === "exact_action_complete") {
1847
1901
  return false;
1848
1902
  }
1903
+ // fix(112aw): mirror the confirmed-claim waiver after the exact rebind.
1904
+ if (waiveConfirmedClaims &&
1905
+ blocked.blocker === EXACT_ACTION_COMPLETE_CONFIRMED_BLOCKER) {
1906
+ return false;
1907
+ }
1849
1908
  recordExcludedEdge(exactSelectedTarget, blocked, "post_rebind");
1850
1909
  return true;
1851
1910
  })) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sellable/mcp",
3
- "version": "0.1.751",
3
+ "version": "0.1.753",
4
4
  "type": "module",
5
5
  "description": "Sellable MCP server for Claude Code, Codex, and Hermes campaign workflows",
6
6
  "main": "dist/index.js",