@sellable/mcp 0.1.727 → 0.1.729

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.
@@ -756,6 +756,25 @@ function withKeywordsHandoffScope(result, scopedInput) {
756
756
  : null;
757
757
  if (!report || !continuation || !template)
758
758
  return result;
759
+ // fix(112ad-b): the resume also needs the exact-target authority the
760
+ // active_exact_run continuation carries (refill-sends.ts :4756-4763): the
761
+ // targetConfig OBJECT (laneScope/revisionInputs/senderScope/targetWindow) plus
762
+ // the runHandle. The base template carries only runId/fence + campaignId/tableId
763
+ // scalars; without the targetConfig object the coordinator re-derives it and its
764
+ // revisions/shape no longer match the fenced authority -> approval_scope_changed
765
+ // with conflict field targetConfig (Clover t2). Prefer the fenced
766
+ // result.targetConfig (the config the fence was opened under — self-consistent
767
+ // with the runId/fence resume, so it cannot introduce a fresh mismatch), falling
768
+ // back to the caller's scopedInput.targetConfig.
769
+ const fencedTargetConfig = result.targetConfig
770
+ ? normalizeRefillTargetConfig(result.targetConfig)
771
+ : (scopedInput.targetConfig ?? null);
772
+ const handleRunId = stringValue(result.runId);
773
+ const handleFence = numberValue(result.fence);
774
+ const fencedRunHandle = recordValue(result.runHandle) ??
775
+ (handleRunId && typeof handleFence === "number"
776
+ ? { runId: handleRunId, fence: handleFence }
777
+ : null);
759
778
  const scopeAdditions = {
760
779
  ...(scopedInput.targetDate ? { targetDate: scopedInput.targetDate } : {}),
761
780
  ...(scopedInput.untilDate ? { untilDate: scopedInput.untilDate } : {}),
@@ -778,6 +797,8 @@ function withKeywordsHandoffScope(result, scopedInput) {
778
797
  ...(scopedInput.workspaceRunState
779
798
  ? { workspaceRunState: scopedInput.workspaceRunState }
780
799
  : {}),
800
+ ...(fencedTargetConfig ? { targetConfig: fencedTargetConfig } : {}),
801
+ ...(fencedRunHandle ? { runHandle: fencedRunHandle } : {}),
781
802
  };
782
803
  return {
783
804
  ...result,
@@ -1292,7 +1313,29 @@ async function selectWorkspaceExactTarget(input, workspacePlanOverride, options
1292
1313
  return (!excludedTargets.some((excluded) => excluded.campaignId === candidate.campaignId &&
1293
1314
  excluded.tableId === candidate.tableId) &&
1294
1315
  !excludedExactTargetKeys.has(key) &&
1295
- !prefilterBlockedTargets.some((blocked) => coordinatorBlockedExactTargetMatches(blocked, candidate)));
1316
+ !prefilterBlockedTargets.some((blocked) => {
1317
+ if (!coordinatorBlockedExactTargetMatches(blocked, candidate)) {
1318
+ return false;
1319
+ }
1320
+ // fix(112ag): a run_scheduler_sweep is the scheduler PLACEMENT action that
1321
+ // RESOLVES a loaded_awaiting_scheduler state — the loaded blocker is set by
1322
+ // the prepare/approve fence that produced the ready rows, not by the sweep.
1323
+ // prefilterBlockedTargets excludes every blocker EXCEPT complete/capped, so
1324
+ // a loaded edge lands here and would drop its own sweep BEFORE the in-loop
1325
+ // "sweeps always bind" bypass can act (Amplify t2: cascade cmrk6nihu loaded
1326
+ // 8x, the dated 2026-07-29 sweep — required because that date is beyond the
1327
+ // 48h ambient window — was prefilter-dropped, 0 sweep dispatches, 37 ready
1328
+ // rows stranded at scheduled 0). Waive ONLY the loaded_awaiting_scheduler
1329
+ // blocker and ONLY for the sweep candidate: every other blocker still
1330
+ // excludes it, prep/approve candidates on a loaded edge are still excluded,
1331
+ // and complete/capped edges (never in prefilterBlockedTargets) still bar
1332
+ // prep re-dispatch via completeDeferredTargets in the loop below.
1333
+ if (blocked.blocker === "loaded_awaiting_scheduler" &&
1334
+ workspaceActionFamily(candidate.actionKey) === "run_scheduler_sweep") {
1335
+ return false;
1336
+ }
1337
+ return true;
1338
+ }));
1296
1339
  });
1297
1340
  if (targetCandidates.length === 0) {
1298
1341
  const pendingWaitAction = workspaceActiveWorkWaitAction(workspaceActions) ??
@@ -1498,7 +1541,20 @@ async function selectWorkspaceExactTarget(input, workspacePlanOverride, options
1498
1541
  // must be enforced again after the exact binding is known.
1499
1542
  actionKey: targetConfig.approvalInputs.expectedActionKey,
1500
1543
  };
1501
- if (blockedExactTargets.some((blocked) => coordinatorBlockedExactTargetMatches(blocked, exactSelectedTarget))) {
1544
+ if (blockedExactTargets.some((blocked) => {
1545
+ if (!coordinatorBlockedExactTargetMatches(blocked, exactSelectedTarget)) {
1546
+ return false;
1547
+ }
1548
+ // fix(112ag): mirror the prefilter waiver after the exact rebind — a
1549
+ // run_scheduler_sweep is the placement action that resolves a
1550
+ // loaded_awaiting_scheduler state, so a loaded blocker on its own edge
1551
+ // must not re-skip it here. Every other blocker still excludes it.
1552
+ if (isSchedulerSweepTarget &&
1553
+ blocked.blocker === "loaded_awaiting_scheduler") {
1554
+ return false;
1555
+ }
1556
+ return true;
1557
+ })) {
1502
1558
  continue;
1503
1559
  }
1504
1560
  const selection = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sellable/mcp",
3
- "version": "0.1.727",
3
+ "version": "0.1.729",
4
4
  "type": "module",
5
5
  "description": "Sellable MCP server for Claude Code, Codex, and Hermes campaign workflows",
6
6
  "main": "dist/index.js",