@sellable/mcp 0.1.747 → 0.1.749

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.
@@ -688,6 +688,7 @@ type WorkspaceCoordinatorWaitAction = {
688
688
  senderId: string | null;
689
689
  reason: string | null;
690
690
  };
691
+ declare function clearCompleteDefersForCampaign(runState: Record<string, unknown> | undefined, campaignId: string | null, preserveActionKey?: string | null): Record<string, unknown> | undefined;
691
692
  export declare function approvedPacketComparison(input: RefillSendsCommandInput, targetPlan: unknown): {
692
693
  changed: boolean;
693
694
  expectedTargetShapeRevision: string | null;
@@ -728,6 +729,10 @@ type RefillSenderSelectorMiss = {
728
729
  displayName: string;
729
730
  }>;
730
731
  };
732
+ export declare const refillSendsDeferInternals: {
733
+ clearCompleteDefersForCampaign: typeof clearCompleteDefersForCampaign;
734
+ SUPPLY_INVALIDATED_DEFER_BLOCKERS: Set<string>;
735
+ };
731
736
  export declare function executeRefillSendsCommand(input?: RefillSendsCommandInput): Promise<import("./workspace-context.js").WorkspaceRequiredResult | {
732
737
  ok: boolean;
733
738
  code: string;
@@ -918,7 +918,32 @@ const WORKSPACE_SUPPLY_ACTION_FAMILIES = new Set([
918
918
  "broaden_provider_search",
919
919
  "refresh_sender_post_engagers",
920
920
  ]);
921
- function clearCompleteDefersForCampaign(runState, campaignId) {
921
+ // fix(112ar): the blocker vocabulary the ledger WRITES and the one this cleaner
922
+ // MATCHED had drifted apart. `workspaceExactDeferredBlocker` records
923
+ // "exact_action_complete" (see deferWorkspaceExactTarget), but the filter only
924
+ // recognised "complete"/"capped_by_scheduler" -- so the clear never fired for
925
+ // the blocker that actually gets written, and a satisfied-before-supply defer
926
+ // became a STANDING claim for the rest of the session.
927
+ //
928
+ // Amplify 7-30: three exposed edges (run_scheduler_sweep, approve_messages,
929
+ // prepare_messages) were all held at "exact_action_complete" while the same
930
+ // payload reported 18 ready and 12 rows still to prepare. Every edge that could
931
+ // have filled the day was suppressed, and the run terminaled
932
+ // `actionable_supply_not_queued` -- an owner-invariant breach produced by a
933
+ // stale proof, not by absent supply.
934
+ //
935
+ // Same shape as 112c: a bounded ATTEMPT must not harden into a standing claim.
936
+ const SUPPLY_INVALIDATED_DEFER_BLOCKERS = new Set([
937
+ "complete",
938
+ "capped_by_scheduler",
939
+ "exact_action_complete",
940
+ ]);
941
+ function clearCompleteDefersForCampaign(runState, campaignId,
942
+ // fix(112ar): the action that JUST landed keeps its own defer. Clearing it
943
+ // would re-expose the edge we just completed and invite a duplicate copy /
944
+ // approve. Only the OTHER campaign edges held on a now-stale completeness
945
+ // proof are released.
946
+ preserveActionKey) {
922
947
  if (!runState || !campaignId)
923
948
  return runState;
924
949
  const entries = Array.isArray(runState.coordinatorBlockedExactTargets)
@@ -929,7 +954,11 @@ function clearCompleteDefersForCampaign(runState, campaignId) {
929
954
  const kept = entries.filter((entry) => {
930
955
  const blocked = recordValue(entry);
931
956
  const blocker = stringValue(blocked?.blocker);
932
- if (blocker !== "complete" && blocker !== "capped_by_scheduler") {
957
+ if (!SUPPLY_INVALIDATED_DEFER_BLOCKERS.has(blocker ?? "")) {
958
+ return true;
959
+ }
960
+ if (preserveActionKey &&
961
+ stringValue(blocked?.actionKey) === preserveActionKey) {
933
962
  return true;
934
963
  }
935
964
  return stringValue(blocked?.campaignId) !== campaignId;
@@ -1441,12 +1470,18 @@ async function selectWorkspaceExactTarget(input, workspacePlanOverride, options
1441
1470
  // opening is barred for those targets (in the selection loop below).
1442
1471
  const completeDeferredTargets = blockedExactTargets.filter((blocked) => blocked.blocker === "complete" ||
1443
1472
  blocked.blocker === "capped_by_scheduler");
1473
+ const waiveCompleteClaims = options.waiveCompleteClaims === true;
1444
1474
  const prefilterBlockedTargets = blockedExactTargets.filter((blocked) => blocked.blocker !== "complete" &&
1445
- blocked.blocker !== "capped_by_scheduler");
1475
+ blocked.blocker !== "capped_by_scheduler" &&
1476
+ // fix(112as): on the bounded release pass, a self-issued
1477
+ // exact_action_complete claim no longer bars its own edge.
1478
+ !(waiveCompleteClaims && blocked.blocker === "exact_action_complete"));
1446
1479
  const seenTargetKeys = new Set();
1447
1480
  // fix(112ak): every refusal is recorded so a non-empty-census terminal can
1448
1481
  // name the concrete per-lane blocker instead of reporting a bare dead end.
1449
- const coordinatorExcludedEdges = [];
1482
+ const coordinatorExcludedEdges = [
1483
+ ...(options.seedExcludedEdges ?? []),
1484
+ ];
1450
1485
  const recordExcludedEdge = (candidate, blocked, stage) => {
1451
1486
  coordinatorExcludedEdges.push({
1452
1487
  campaignId: candidate.campaignId,
@@ -1458,6 +1493,46 @@ async function selectWorkspaceExactTarget(input, workspacePlanOverride, options
1458
1493
  stage,
1459
1494
  });
1460
1495
  };
1496
+ // fix(112as): a self-issued `exact_action_complete` claim is a BOUNDED
1497
+ // ATTEMPT, not a standing proof — the same principle as 112c.
1498
+ //
1499
+ // The claim is dropped at BOTH refusal points (prefilter and post_rebind),
1500
+ // and 112ar only clears it when a prepare/supply action LANDS on that
1501
+ // campaign. When every edge the planner exposed for the campaign is already
1502
+ // held by such a claim, nothing can land, so nothing ever clears it: a closed
1503
+ // loop that terminals `actionable_supply_not_queued` against visible supply
1504
+ // (Dotwork 2026-07-30/31: 100 enrichment candidates, approve_messages
1505
+ // refused at post_rebind on every run). 112ak made that terminal NAME the
1506
+ // refusal, which is honest but does not fill the day.
1507
+ //
1508
+ // So: if the ONLY reason we have no selection is our own completeness
1509
+ // claims, and the census still shows actionable supply, waive them and
1510
+ // re-select ONCE. Bounded by waiveCompleteClaims so it can never livelock,
1511
+ // and it reuses the SAME workspacePlan so no extra planner call is made and
1512
+ // the census stays consistent with the decision.
1513
+ const completeClaimReleaseRetry = async () => {
1514
+ if (waiveCompleteClaims)
1515
+ return null;
1516
+ if (coordinatorExcludedEdges.length === 0)
1517
+ return null;
1518
+ if (!coordinatorExcludedEdges.every((edge) => edge.blocker === "exact_action_complete")) {
1519
+ return null;
1520
+ }
1521
+ const census = workspaceGapBearingActionableSupply(workspacePlan);
1522
+ if (census.actionableRows <= 0 && !census.frontierHasMoreRows) {
1523
+ return null;
1524
+ }
1525
+ const released = await selectWorkspaceExactTarget(input, workspacePlan, {
1526
+ ...options,
1527
+ waiveCompleteClaims: true,
1528
+ seedExcludedEdges: [...coordinatorExcludedEdges],
1529
+ });
1530
+ // The release may only ADD a dispatch. If it fails to bind an edge, fall
1531
+ // back to this pass's terminal, which already NAMES the refused edges —
1532
+ // 112ak's honesty guarantee must not be traded away for an optimistic
1533
+ // retry that lands on a vaguer blocker.
1534
+ return released.status === "selected" ? released : null;
1535
+ };
1461
1536
  const targetCandidates = actionTargets.filter((candidate) => {
1462
1537
  const key = workspaceExactTargetKey(candidate);
1463
1538
  if (seenTargetKeys.has(key))
@@ -1554,6 +1629,9 @@ async function selectWorkspaceExactTarget(input, workspacePlanOverride, options
1554
1629
  const readyLoadedSelection = readySurplusLoadedSelection(workspacePlan);
1555
1630
  if (readyLoadedSelection)
1556
1631
  return readyLoadedSelection;
1632
+ const releasedEmptyCandidates = await completeClaimReleaseRetry();
1633
+ if (releasedEmptyCandidates)
1634
+ return releasedEmptyCandidates;
1557
1635
  return {
1558
1636
  status: "blocked",
1559
1637
  ...classifyWorkspaceUnavailableTerminal(workspacePlan, (excludedTargets.length > 0 ||
@@ -1732,6 +1810,13 @@ async function selectWorkspaceExactTarget(input, workspacePlanOverride, options
1732
1810
  blocked.blocker === "loaded_awaiting_scheduler") {
1733
1811
  return false;
1734
1812
  }
1813
+ // fix(112as): the release pass must waive here too. post_rebind
1814
+ // re-matches AFTER the exact preflight re-issues the semantic
1815
+ // actionKey, so waiving only at prefilter would leave the edge blocked.
1816
+ if (waiveCompleteClaims &&
1817
+ blocked.blocker === "exact_action_complete") {
1818
+ return false;
1819
+ }
1735
1820
  recordExcludedEdge(exactSelectedTarget, blocked, "post_rebind");
1736
1821
  return true;
1737
1822
  })) {
@@ -1851,6 +1936,9 @@ async function selectWorkspaceExactTarget(input, workspacePlanOverride, options
1851
1936
  const readyLoadedSelection = readySurplusLoadedSelection(workspacePlan);
1852
1937
  if (readyLoadedSelection)
1853
1938
  return readyLoadedSelection;
1939
+ const releasedFilteredCandidates = await completeClaimReleaseRetry();
1940
+ if (releasedFilteredCandidates)
1941
+ return releasedFilteredCandidates;
1854
1942
  return {
1855
1943
  status: "blocked",
1856
1944
  ...classifyWorkspaceUnavailableTerminal(workspacePlan, (workspaceCoverage.remainingReadyOrProjectedGap !== 0
@@ -3018,6 +3106,16 @@ async function resolveRefillSenderSelectors(params) {
3018
3106
  resolvedSelectors,
3019
3107
  };
3020
3108
  }
3109
+ // fix(112ar): exported for a DIRECT pin. Binding this rule through the full
3110
+ // command harness proved impossible without silently voiding the test --
3111
+ // deferWorkspaceExactTarget replaces same-identity entries, and
3112
+ // clearApprovalAttemptsForCampaign removes approve-family keys, so a seeded
3113
+ // defer disappears for reasons that have nothing to do with this fix. A unit
3114
+ // pin binds the writer/cleaner vocabulary contract directly.
3115
+ export const refillSendsDeferInternals = {
3116
+ clearCompleteDefersForCampaign,
3117
+ SUPPLY_INVALIDATED_DEFER_BLOCKERS,
3118
+ };
3021
3119
  export async function executeRefillSendsCommand(input = {}) {
3022
3120
  const normalizedInput = normalizeRefillSendsInput(input);
3023
3121
  const yolo = normalizedInput.yolo === true;
@@ -3871,10 +3969,10 @@ export async function executeRefillSendsCommand(input = {}) {
3871
3969
  WORKSPACE_SUPPLY_ACTION_FAMILIES.has(supplyActionFamily)));
3872
3970
  const coordinatorWorkspaceRunState = prepFamilyLandedOnCampaign
3873
3971
  ? clearApprovalAttemptsForCampaign(supplyLandedOnCampaign
3874
- ? clearCompleteDefersForCampaign(deferredCoordinatorWorkspaceRunState, selectedCoordinatorTarget?.campaignId ?? null)
3972
+ ? clearCompleteDefersForCampaign(deferredCoordinatorWorkspaceRunState, selectedCoordinatorTarget?.campaignId ?? null, selectedCoordinatorTarget?.actionKey ?? null)
3875
3973
  : deferredCoordinatorWorkspaceRunState, selectedCoordinatorTarget?.campaignId ?? null)
3876
3974
  : supplyLandedOnCampaign
3877
- ? clearCompleteDefersForCampaign(deferredCoordinatorWorkspaceRunState, selectedCoordinatorTarget?.campaignId ?? null)
3975
+ ? clearCompleteDefersForCampaign(deferredCoordinatorWorkspaceRunState, selectedCoordinatorTarget?.campaignId ?? null, selectedCoordinatorTarget?.actionKey ?? null)
3878
3976
  : deferredCoordinatorWorkspaceRunState;
3879
3977
  // fix(112aj): continuation-level progress-or-settle. When this dispatch is an
3880
3978
  // active_exact_run resume (continuationHandle set, in_progress), fingerprint
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sellable/mcp",
3
- "version": "0.1.747",
3
+ "version": "0.1.749",
4
4
  "type": "module",
5
5
  "description": "Sellable MCP server for Claude Code, Codex, and Hermes campaign workflows",
6
6
  "main": "dist/index.js",