@sellable/mcp 0.1.553 → 0.1.554

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.
@@ -10,7 +10,6 @@ const SAFE_PACKET_ACTION_TYPES = new Set([
10
10
  "approve_messages",
11
11
  "start_paused_campaign",
12
12
  "rerun_errored_cells",
13
- "run_scheduler_sweep",
14
13
  "wait_for_scheduler",
15
14
  "wait_for_active_work",
16
15
  "wait_for_source_import",
@@ -74,21 +73,6 @@ const PREP_FAILURE_RECOMMENDED_ACTIONS = new Set([
74
73
  "approve_or_repair_approval_cells",
75
74
  "inspect_rows",
76
75
  ]);
77
- const SCHEDULER_SWEEP_ALLOWED_SIDE_EFFECTS = [
78
- "schedule any eligible workspace cells on the approved date within scheduler gates",
79
- ];
80
- const SCHEDULER_SWEEP_FORBIDDEN_SIDE_EFFECTS = [
81
- "send directly",
82
- "write scheduler fields directly",
83
- "change campaign state",
84
- "change sender limits",
85
- "change source selection",
86
- ];
87
- const SCHEDULER_SWEEP_RECEIPT_GROUPS = [
88
- "campaignId",
89
- "tableId",
90
- "actionType",
91
- ];
92
76
  async function postRefillTargetPlan(body, workspaceId) {
93
77
  const api = getApi();
94
78
  const requestOptions = workspaceRequestOptions(workspaceId);
@@ -531,7 +515,6 @@ function sanitizeStructuredAction(action, selectedBySender, mode, rank) {
531
515
  : null,
532
516
  stopCondition: stringValue(action.stopCondition) ?? "",
533
517
  yoloEligible,
534
- actionKey: stringValue(action.actionKey),
535
518
  capSaturated: booleanValue(action.capSaturated) === true ? true : undefined,
536
519
  prepFailureDiagnosis: sanitizePrepFailureDiagnosis(action.prepFailureDiagnosis),
537
520
  };
@@ -831,154 +814,6 @@ function buildSanitizedGlobalActionQueue(senderRefillPlans) {
831
814
  rank: index + 1,
832
815
  }));
833
816
  }
834
- function sortedUniqueStrings(value) {
835
- return [...new Set(stringArray(value))].sort();
836
- }
837
- function sameStrings(left, right) {
838
- return (left.length === right.length &&
839
- left.every((value, index) => value === right[index]));
840
- }
841
- function sanitizeSchedulerSweepSourceScopes(value) {
842
- if (!Array.isArray(value))
843
- return [];
844
- const scopes = value.flatMap((entry) => {
845
- if (!isRecord(entry))
846
- return [];
847
- const campaignId = stringValue(entry.campaignId)?.trim();
848
- const tableId = stringValue(entry.tableId)?.trim();
849
- const sourceLeadListId = stringValue(entry.sourceLeadListId)?.trim();
850
- const leadSourceProvider = stringValue(entry.leadSourceProvider)?.trim();
851
- if (!campaignId ||
852
- !tableId ||
853
- !sourceLeadListId ||
854
- !leadSourceProvider) {
855
- return [];
856
- }
857
- return [
858
- { campaignId, tableId, sourceLeadListId, leadSourceProvider },
859
- ];
860
- });
861
- const unique = new Map(scopes.map((scope) => [
862
- [
863
- scope.campaignId,
864
- scope.tableId,
865
- scope.sourceLeadListId,
866
- scope.leadSourceProvider,
867
- ].join(":"),
868
- scope,
869
- ]));
870
- return [...unique.values()].sort((a, b) => {
871
- if (a.campaignId !== b.campaignId) {
872
- return a.campaignId.localeCompare(b.campaignId);
873
- }
874
- return a.tableId.localeCompare(b.tableId);
875
- });
876
- }
877
- function sanitizeTargetSchedulerSweep(params) {
878
- if (!Array.isArray(params.value) ||
879
- !params.expectedWorkspaceId ||
880
- !params.expectedTargetDate ||
881
- !/^\d{4}-\d{2}-\d{2}$/.test(params.expectedTargetDate) ||
882
- !params.expectedTargetShapeRevision ||
883
- !params.expectedStateRevision ||
884
- params.remainingProjectedGap <= 0 ||
885
- params.remainingReadyOrProjectedGap !== 0) {
886
- return null;
887
- }
888
- const expectedSenderIds = [...params.selectedBySender.keys()].sort();
889
- const expectedActionTypes = [
890
- ...new Set(params.selectedBySender.values()),
891
- ].sort();
892
- if (expectedSenderIds.length === 0 || expectedActionTypes.length === 0) {
893
- return null;
894
- }
895
- for (const rawAction of params.value) {
896
- if (!isRecord(rawAction) || rawAction.type !== "run_scheduler_sweep") {
897
- continue;
898
- }
899
- const input = isRecord(rawAction.toolInput) ? rawAction.toolInput : {};
900
- const actionKey = stringValue(rawAction.actionKey)?.trim();
901
- const requestKey = stringValue(input.requestKey)?.trim();
902
- const senderIds = sortedUniqueStrings(input.senderIds);
903
- const actionTypes = sortedUniqueStrings(input.actionTypes).filter((actionType) => allowedActionType(actionType) === actionType);
904
- const campaignIds = sortedUniqueStrings(input.campaignIds);
905
- const tableIds = sortedUniqueStrings(input.tableIds);
906
- const sourceScopes = sanitizeSchedulerSweepSourceScopes(input.sourceScopes);
907
- const receiptRequirements = isRecord(rawAction.receiptRequirements)
908
- ? rawAction.receiptRequirements
909
- : {};
910
- const groupBy = stringArray(receiptRequirements.groupBy);
911
- const allowedSideEffects = stringArray(rawAction.allowedSideEffects);
912
- const forbiddenSideEffects = stringArray(rawAction.forbiddenSideEffects);
913
- const rawActionType = allowedActionType(rawAction.actionType);
914
- if (input.action !== "run" ||
915
- input.workspaceId !== params.expectedWorkspaceId ||
916
- input.targetDate !== params.expectedTargetDate ||
917
- input.targetDateKey !== params.expectedTargetDate ||
918
- input.targetShapeRevision !== params.expectedTargetShapeRevision ||
919
- input.stateRevision !== params.expectedStateRevision ||
920
- !actionKey ||
921
- requestKey !== actionKey ||
922
- !sameStrings(senderIds, expectedSenderIds) ||
923
- !sameStrings(actionTypes, expectedActionTypes) ||
924
- (expectedActionTypes.length === 1 &&
925
- rawActionType !== expectedActionTypes[0]) ||
926
- campaignIds.length === 0 ||
927
- tableIds.length === 0 ||
928
- sourceScopes.length === 0 ||
929
- sourceScopes.some((scope) => !campaignIds.includes(scope.campaignId) ||
930
- !tableIds.includes(scope.tableId)) ||
931
- rawAction.toolName !== "run_scheduler_sweep" ||
932
- rawAction.sideEffectClass !== "scheduler_placement" ||
933
- rawAction.workspaceWide !== true ||
934
- rawAction.yoloEligible !== true ||
935
- receiptRequirements.nonTruncated !== true ||
936
- !sameStrings(groupBy, SCHEDULER_SWEEP_RECEIPT_GROUPS) ||
937
- !sameStrings(allowedSideEffects, SCHEDULER_SWEEP_ALLOWED_SIDE_EFFECTS) ||
938
- !sameStrings(forbiddenSideEffects, SCHEDULER_SWEEP_FORBIDDEN_SIDE_EFFECTS)) {
939
- continue;
940
- }
941
- return {
942
- rank: 1,
943
- type: "run_scheduler_sweep",
944
- actionType: rawActionType,
945
- toolName: "run_scheduler_sweep",
946
- sideEffectClass: "scheduler_placement",
947
- ids: {},
948
- toolInput: {
949
- action: "run",
950
- workspaceId: params.expectedWorkspaceId,
951
- targetDate: params.expectedTargetDate,
952
- targetDateKey: params.expectedTargetDate,
953
- senderIds,
954
- actionTypes,
955
- campaignIds,
956
- tableIds,
957
- sourceScopes,
958
- targetShapeRevision: params.expectedTargetShapeRevision,
959
- stateRevision: params.expectedStateRevision,
960
- requestKey,
961
- },
962
- inputSummary: stringValue(rawAction.inputSummary) ?? "",
963
- reason: stringValue(rawAction.reason) ?? "",
964
- prerequisites: stringArray(rawAction.prerequisites),
965
- rereadAfter: rawAction.rereadAfter === "get_refill_target_plan"
966
- ? "get_refill_target_plan"
967
- : null,
968
- stopCondition: stringValue(rawAction.stopCondition) ?? "",
969
- yoloEligible: true,
970
- workspaceWide: true,
971
- allowedSideEffects: [...SCHEDULER_SWEEP_ALLOWED_SIDE_EFFECTS],
972
- forbiddenSideEffects: [...SCHEDULER_SWEEP_FORBIDDEN_SIDE_EFFECTS],
973
- receiptRequirements: {
974
- nonTruncated: true,
975
- groupBy: [...SCHEDULER_SWEEP_RECEIPT_GROUPS],
976
- },
977
- actionKey,
978
- };
979
- }
980
- return null;
981
- }
982
817
  function paidRefreshNeededSenderIds(senderRefillPlans) {
983
818
  const senderIds = new Set();
984
819
  for (const plan of senderRefillPlans) {
@@ -1124,8 +959,8 @@ function sanitizeRefillTargetPlanResult(result) {
1124
959
  const grossTarget = senderPlans.reduce((sum, plan) => sum + numberValue(plan.grossTarget), 0);
1125
960
  const requestedTarget = senderPlans.reduce((sum, plan) => sum + numberValue(plan.requestedTarget), 0);
1126
961
  const effectiveTarget = senderPlans.reduce((sum, plan) => {
1127
- const target = typeof plan.effectiveTarget === "number"
1128
- ? plan.effectiveTarget
962
+ const target = typeof plan.schedulerCapacityTarget === "number"
963
+ ? plan.schedulerCapacityTarget
1129
964
  : numberValue(plan.grossTarget);
1130
965
  return sum + target;
1131
966
  }, 0);
@@ -1140,20 +975,7 @@ function sanitizeRefillTargetPlanResult(result) {
1140
975
  const senderRefillPlans = sanitizeStructuredSenderPlans(target.senderRefillPlans, selectedBySender);
1141
976
  const paidRefreshNeededSenderIdSet = paidRefreshNeededSenderIds(senderRefillPlans);
1142
977
  const blockers = sanitizeBlockers(result.blockers, selectedKeys, paidRefreshNeededSenderIdSet);
1143
- const request = isRecord(result.request) ? result.request : {};
1144
- const schedulerSweepAction = sanitizeTargetSchedulerSweep({
1145
- value: target.globalActionQueue,
1146
- selectedBySender,
1147
- expectedWorkspaceId: stringValue(target.workspaceId),
1148
- expectedTargetDate: stringValue(request.targetDate),
1149
- expectedTargetShapeRevision: stringValue(result.targetShapeRevision),
1150
- expectedStateRevision: stringValue(result.stateRevision),
1151
- remainingProjectedGap,
1152
- remainingReadyOrProjectedGap,
1153
- });
1154
- const globalActionQueue = schedulerSweepAction
1155
- ? [schedulerSweepAction]
1156
- : buildSanitizedGlobalActionQueue(senderRefillPlans);
978
+ const globalActionQueue = buildSanitizedGlobalActionQueue(senderRefillPlans);
1157
979
  const hasTerminalNoActionBlocker = globalActionQueue.length === 0 &&
1158
980
  blockers.some((blocker) => TERMINAL_NO_ACTION_BLOCKER_CODES.has(String(blocker.code)));
1159
981
  const status = remainingProjectedGap === 0
@@ -7546,14 +7546,6 @@ export declare const allTools: ({
7546
7546
  type: string;
7547
7547
  description: string;
7548
7548
  };
7549
- requestKey: {
7550
- type: string;
7551
- description: string;
7552
- };
7553
- targetShapeRevision: {
7554
- type: string;
7555
- description: string;
7556
- };
7557
7549
  };
7558
7550
  required: string[];
7559
7551
  additionalProperties: boolean;
@@ -10,7 +10,7 @@ async function postSchedulerFillCapacity(body, workspaceId) {
10
10
  export const schedulerFillCapacityToolDefinitions = [
11
11
  {
12
12
  name: "get_scheduler_fill_capacity",
13
- description: "read-only scheduler capacity query for refill-sends before any refill mutation. It asks the product scheduler model how many additional cells the scheduler will try to place for exact sender/action requests, using the default scheduler-forward horizon or one exact targetDate. It returns scheduler-fillable slots, occupied scheduled/processing slots, rolling-weekly candidate timing that shows when capacity frees later in the send window, sender sendability gates, cooldowns, Sales Navigator status for paid InMail, cached paid-InMail credit feasibility, threshold source, blockers, warnings, and explicit sideEffects false. This tool does not create rows, import leads, prepare messages, approve messages, does not schedule sends, does not refresh paid InMail credits, mutate thresholds, start campaigns, launch, or send. Use exact senderId values only; never pass sender names.",
13
+ description: "read-only scheduler capacity query for refill-sends before any refill mutation. It asks the product scheduler model how many additional cells the scheduler will try to place for exact sender/action requests, using the default scheduler-forward horizon or one exact targetDate. It returns scheduler-fillable slots, occupied scheduled/processing slots, sender sendability gates, cooldowns, Sales Navigator status for paid InMail, cached paid-InMail credit feasibility, threshold source, blockers, warnings, and explicit sideEffects false. This tool does not create rows, import leads, prepare messages, approve messages, does not schedule sends, does not refresh paid InMail credits, mutate thresholds, start campaigns, launch, or send. Use exact senderId values only; never pass sender names.",
14
14
  inputSchema: {
15
15
  type: "object",
16
16
  properties: {
@@ -3,8 +3,6 @@ type RunSchedulerSweepInput = {
3
3
  workspaceId: string;
4
4
  action?: SchedulerRunAction;
5
5
  targetDate?: string;
6
- requestKey?: string;
7
- targetShapeRevision?: string;
8
6
  };
9
7
  export declare const schedulerRunToolDefinitions: {
10
8
  name: string;
@@ -25,14 +23,6 @@ export declare const schedulerRunToolDefinitions: {
25
23
  type: string;
26
24
  description: string;
27
25
  };
28
- requestKey: {
29
- type: string;
30
- description: string;
31
- };
32
- targetShapeRevision: {
33
- type: string;
34
- description: string;
35
- };
36
26
  };
37
27
  required: string[];
38
28
  additionalProperties: boolean;
@@ -21,14 +21,6 @@ function normalizeTargetDate(value) {
21
21
  }
22
22
  return targetDate;
23
23
  }
24
- function normalizeOptionalScopeValue(value, field) {
25
- if (value === undefined || value === null)
26
- return null;
27
- if (typeof value !== "string" || !value.trim()) {
28
- throw new Error(`${field} must be a non-empty string when provided.`);
29
- }
30
- return value.trim();
31
- }
32
24
  export const schedulerRunToolDefinitions = [
33
25
  {
34
26
  name: "run_scheduler_sweep",
@@ -49,14 +41,6 @@ export const schedulerRunToolDefinitions = [
49
41
  type: "string",
50
42
  description: "Optional one exact sender-local date (YYYY-MM-DD) to scope scheduler placement/status. The run remains workspace-wide inside that date.",
51
43
  },
52
- requestKey: {
53
- type: "string",
54
- description: "Optional deterministic planner action key used to attach to or replay the same exact scheduler attempt.",
55
- },
56
- targetShapeRevision: {
57
- type: "string",
58
- description: "Optional stable approved refill target-shape revision associated with requestKey.",
59
- },
60
44
  },
61
45
  required: ["workspaceId"],
62
46
  additionalProperties: false,
@@ -70,8 +54,6 @@ export async function runSchedulerSweep(input) {
70
54
  }
71
55
  const action = input.action ?? "run";
72
56
  const targetDate = normalizeTargetDate(input.targetDate);
73
- const requestKey = normalizeOptionalScopeValue(input.requestKey, "requestKey");
74
- const targetShapeRevision = normalizeOptionalScopeValue(input.targetShapeRevision, "targetShapeRevision");
75
57
  if (action !== "run" && action !== "status") {
76
58
  throw new Error('action must be "run" or "status" for run_scheduler_sweep.');
77
59
  }
@@ -79,7 +61,5 @@ export async function runSchedulerSweep(input) {
79
61
  workspaceId,
80
62
  action,
81
63
  ...(targetDate ? { targetDate } : {}),
82
- ...(requestKey ? { requestKey } : {}),
83
- ...(targetShapeRevision ? { targetShapeRevision } : {}),
84
64
  }, workspaceId);
85
65
  }
@@ -142,15 +142,17 @@ export declare function listWorkspaces(): Promise<{
142
142
  workspaces: WorkspaceSummary[];
143
143
  workspaceLock: {
144
144
  enabled: boolean;
145
- workspaceId?: undefined;
146
- hiddenWorkspaceCount?: undefined;
145
+ workspaceId: string;
146
+ hiddenWorkspaceCount: number;
147
+ siblingInventoryFetched: boolean;
147
148
  };
148
149
  } | {
149
150
  workspaces: WorkspaceSummary[];
150
151
  workspaceLock: {
151
152
  enabled: boolean;
152
- workspaceId: string;
153
- hiddenWorkspaceCount: number;
153
+ workspaceId?: undefined;
154
+ hiddenWorkspaceCount?: undefined;
155
+ siblingInventoryFetched?: undefined;
154
156
  };
155
157
  }>;
156
158
  export declare function getActiveWorkspace(): {
@@ -80,19 +80,21 @@ export const workspaceToolDefinitions = [
80
80
  ];
81
81
  export async function listWorkspaces() {
82
82
  const api = getApi();
83
- const { workspaces } = await api.get("/api/v3/workspaces");
84
83
  const lockedWorkspaceId = getLockedWorkspaceId();
85
- if (!lockedWorkspaceId) {
86
- return { workspaces, workspaceLock: { enabled: false } };
84
+ if (lockedWorkspaceId) {
85
+ const { workspace } = await api.get(`/api/v3/workspaces/${encodeURIComponent(lockedWorkspaceId)}`);
86
+ return {
87
+ workspaces: [workspace],
88
+ workspaceLock: {
89
+ enabled: true,
90
+ workspaceId: lockedWorkspaceId,
91
+ hiddenWorkspaceCount: 0,
92
+ siblingInventoryFetched: false,
93
+ },
94
+ };
87
95
  }
88
- return {
89
- workspaces: workspaces.filter((ws) => ws.id === lockedWorkspaceId),
90
- workspaceLock: {
91
- enabled: true,
92
- workspaceId: lockedWorkspaceId,
93
- hiddenWorkspaceCount: workspaces.filter((ws) => ws.id !== lockedWorkspaceId).length,
94
- },
95
- };
96
+ const { workspaces } = await api.get("/api/v3/workspaces");
97
+ return { workspaces, workspaceLock: { enabled: false } };
96
98
  }
97
99
  export function getActiveWorkspace() {
98
100
  const config = getConfig();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sellable/mcp",
3
- "version": "0.1.553",
3
+ "version": "0.1.554",
4
4
  "type": "module",
5
5
  "description": "Sellable MCP server for Claude Code, Codex, and Hermes campaign workflows",
6
6
  "main": "dist/index.js",
@@ -83,8 +83,6 @@ Accepted invocation flags in the same user request:
83
83
  - `senderIds: <id>, <id>` or `senderNames: <name>, <name>`: explicit selector
84
84
  alternatives when the host preserves natural-language arguments better than
85
85
  shell-style flags.
86
- - `actionTypes: send_invite, send_inmail_closed`: optional lane selector. Omit
87
- `actionTypes` to preserve the target planner's lane inference.
88
86
  - `untilDate: YYYY-MM-DD`: explicit date selector alternative when the host
89
87
  preserves natural-language arguments better than shell-style flags.
90
88
  - `targetDate: YYYY-MM-DD`: exact-date selector alternative when the host
@@ -93,7 +91,7 @@ Accepted invocation flags in the same user request:
93
91
  When the host can call typed MCP tools, start with:
94
92
 
95
93
  ```text
96
- refill_sends({ yolo?: boolean, executionMode?: "manual" | "scheduled" | "yolo", requireWorkspace?: boolean, workspaceId?: string, senders?: string[], senderIds?: string[], senderNames?: string[], actionTypes?: ("send_invite" | "send_inmail_closed")[], horizonSendDays?: number, untilDate?: "YYYY-MM-DD", targetDate?: "YYYY-MM-DD" })
94
+ refill_sends({ yolo?: boolean, executionMode?: "manual" | "scheduled" | "yolo", requireWorkspace?: boolean, workspaceId?: string, senders?: string[], senderIds?: string[], senderNames?: string[], horizonSendDays?: number, untilDate?: "YYYY-MM-DD", targetDate?: "YYYY-MM-DD" })
97
95
  ```
98
96
 
99
97
  That command helper normalizes arguments and returns the execution contract. In
@@ -101,22 +99,14 @@ non-yolo mode it does not mutate. In `--yolo`, it may execute exactly one safe
101
99
  bounded primitive from the fresh `target.globalActionQueue[0]`, then reread and
102
100
  return the new target plan; currently safe primitives are paid-credit refresh,
103
101
  existing-row message preparation, generated-message approval, receipt-proven
104
- same-source row copy, a request-scoped exact-date product scheduler sweep, and
105
- read-only wait rereads. Same-source copy/source
102
+ same-source row copy, and read-only wait rereads. Same-source copy/source
106
103
  fallback is safe only after receipt-proven exhaustion:
107
104
  `hasMoreFrontierRows:false`, zero `approvalCandidates`, no `stuckActiveCells`,
108
- and no non-terminal `approvedNotDispatched` work. It does not run unbounded
109
- approval, lower paid-InMail thresholds, switch source families, create
110
- campaigns, launch, or send directly; it never raw-writes scheduler fields.
111
- Continue with the workflow below for route selection, state rereads, approval
112
- gating, source import, preparation, and bounded approval.
113
-
114
- The approval scope is the exact `workspaceId`, `targetDate`, sender ids, action
115
- types, campaign/table/source ids, `targetShapeRevision`, and `actionKey` in the
116
- rendered packet. `stateRevision` and sent/scheduled/ready counts are mutable
117
- progress, not approval-scope drift. Execute only
118
- `target.globalActionQueue[0]`, then perform a full authoritative reread before
119
- deciding any next action.
105
+ and no non-terminal `approvedNotDispatched` work. It does not run unbounded approval, lower
106
+ paid-InMail thresholds, switch source families, create campaigns, launch, send,
107
+ or write scheduler rows. Continue with the workflow below for route selection,
108
+ state rereads, approval gating, source import, preparation, and bounded
109
+ approval.
120
110
 
121
111
  ## Workspace Contract
122
112
 
@@ -286,27 +276,10 @@ need raw proof, call the read-only `get_scheduler_fill_capacity` query for the
286
276
  same sender/action/date; it tells the MCP how many cells the product scheduler
287
277
  will try to place and does not import, approve, schedule, refresh credits, or
288
278
  mutate.
289
- Treat `rollingWeeklyInvite.capacityFreedDuringWindow:true` as proof that
290
- rolling-weekly capacity frees later in the send window and remains schedulable;
291
- use its timing fields instead of treating the window-start gate as a permanent
292
- full-day blocker.
293
279
  When the refill loop has ready rows and needs scheduler pickup now, use
294
280
  `run_scheduler_sweep` with the same explicit `workspaceId`; it can place cells
295
281
  within existing scheduler gates and returns the receipt, but it never sends or
296
282
  bypasses limits.
297
- A scheduler sweep is a visible workspace-wide scheduling side effect. The
298
- request packet limits the expected target changes to its exact date, senders,
299
- action types, campaigns, tables, and stable sources, but the product scheduler
300
- may also place unrelated eligible workspace work; disclose that possibility in
301
- the approval packet and receipt. For an exact-date sweep action, execute it
302
- once, then reread the full target plan before taking or presenting another
303
- action.
304
- The exact-date `run_scheduler_sweep` may schedule eligible workspace cells
305
- through existing product gates; it never sends directly or raw-writes scheduler
306
- fields. Only non-exact or no-sweep scheduler waits are read-only.
307
- On resume, reconcile the current target plan and matching sweep status/receipt
308
- before retrying. A matching same-key terminal receipt replays; an
309
- `uncertain_outcome` stops for reconciliation and must not schedule again.
310
283
  Scheduler-run receipt interpretation: `cellsConsidered is allocation-attempt
311
284
  count`, not total ready supply, while `readyCellsFound` is ready inventory found
312
285
  before prefilters. Inspect `campaignScopeSummary` before assuming the selected
@@ -419,14 +392,6 @@ scheduler wait loop. Do not finish the refill goal, mark it complete, or mark it
419
392
  blocked only because it is still `awaiting_scheduler_after_ready_buffer`; keep
420
393
  waiting unless Christian stops the run or the host cannot continue.
421
394
 
422
- Future scheduled coverage and already sent actions are distinct; only
423
- scheduler-owned future scheduled actions count as scheduled coverage. For
424
- multiple target dates, finish D1 execution and the full D1 reread before
425
- planning D2. Completion proof is product-native Sellable MCP evidence only:
426
- target plan, campaign refill state, scheduler capacity, sweep/status, and
427
- bounded receipts. Never use individual cell ids, Prisma, SQL, direct database
428
- access, or production-environment scripts as completion proof.
429
-
430
395
  In `--yolo`, the default fill target is the scheduler-forward 48-hour window
431
396
  unless `--target-date`/`targetDate`, `--until`/`untilDate`, or an explicit
432
397
  compatibility `horizonSendDays` is provided. If a target date is provided,
@@ -75,20 +75,6 @@ calls, preparation calls, approval calls, and campaign start calls. Missing
75
75
  interactive workspace switching is diagnostic setup only and is not an
76
76
  automation control path.
77
77
 
78
- Typed command scope:
79
-
80
- ```text
81
- refill_sends({ yolo?: boolean, executionMode?: "manual" | "scheduled" | "yolo", requireWorkspace?: boolean, workspaceId?: string, senders?: string[], senderIds?: string[], senderNames?: string[], actionTypes?: ("send_invite" | "send_inmail_closed")[], horizonSendDays?: number, untilDate?: "YYYY-MM-DD", targetDate?: "YYYY-MM-DD" })
82
- ```
83
-
84
- Omit `actionTypes` to preserve the target planner's lane inference. The
85
- approval scope is the exact `workspaceId`, `targetDate`, sender ids, action
86
- types, campaign/table/source ids, `targetShapeRevision`, and `actionKey` in the
87
- rendered packet. `stateRevision` and sent/scheduled/ready counts are mutable
88
- progress, not approval-scope drift. Execute only
89
- `target.globalActionQueue[0]`, then perform a full authoritative reread before
90
- deciding any next action.
91
-
92
78
  Goal-mode continuation: a skill cannot create or invoke `/goal` by itself. When
93
79
  this workflow is already running inside an active Codex goal, keep that goal
94
80
  open until every selected sender lane is horizon-filled by projected coverage
@@ -206,19 +192,6 @@ files or memory.
206
192
  `run_scheduler_sweep` with the same explicit `workspaceId` to request the
207
193
  product scheduler placement pass now and read its receipt. This may place
208
194
  cells within existing gates, never sends messages, and never bypasses limits.
209
- A scheduler sweep is a visible workspace-wide scheduling side effect. The
210
- request packet limits expected target changes to the exact date, senders,
211
- action types, campaigns, tables, and stable sources, but unrelated eligible
212
- workspace work may also be scheduled by the product scheduler and must be
213
- disclosed. For an exact-date sweep action, execute it once and perform the
214
- full target-plan reread before taking or presenting another action.
215
- The exact-date `run_scheduler_sweep` may schedule eligible workspace cells
216
- through existing product gates; it never sends directly or raw-writes
217
- scheduler fields. Only non-exact or no-sweep scheduler waits are read-only.
218
- On resume, reconcile the current target plan and matching sweep
219
- status/receipt before retrying. A matching same-key terminal receipt
220
- replays; an `uncertain_outcome` stops for reconciliation and must not
221
- schedule again.
222
195
  Scheduler-run receipt interpretation: `cellsConsidered is
223
196
  allocation-attempt count`, not total ready supply, while `readyCellsFound`
224
197
  is ready inventory found before prefilters. Inspect `campaignScopeSummary`
@@ -237,10 +210,8 @@ files or memory.
237
210
  scheduled count, projected count, campaign ids, and no-op proof without
238
211
  asking for approval or mutating.
239
212
  If `remainingReadyOrProjectedGap:0` but `remainingProjectedGap>0`, and paid
240
- InMail credit freshness is clean for every selected paid-InMail lane,
241
- execute an exact-date `run_scheduler_sweep` action once when it is
242
- `target.globalActionQueue[0]`, then fully reread. Otherwise, run only a
243
- persistent read-only scheduler wait/reread loop; do not ask for
213
+ InMail credit freshness is clean for every selected paid-InMail lane, run
214
+ only a persistent read-only scheduler wait/reread loop; do not ask for
244
215
  prep/import/approval. Poll `get_refill_target_plan` every 60-120 seconds, or
245
216
  on the host's next continuation interval, until projected coverage fills,
246
217
  a concrete non-scheduler blocker appears, or Christian explicitly asks to
@@ -413,11 +384,10 @@ exceeds the sender's capacity for the selected target window. Put another way:
413
384
  complete when the same daily-limit/readback model would show no remaining
414
385
  send-day capacity for that selected lane. Ready-to-schedule rows are only buffer
415
386
  for the product scheduler. If ready plus projected coverage covers the target
416
- window but scheduled cells do not yet, execute the exact-date sweep when the
417
- planner emits it; otherwise run a persistent read-only scheduler wait loop:
418
- wait, reread, recompute the ledger, and continue until projected coverage is
419
- proved, a concrete non-scheduler blocker appears, or Christian explicitly stops
420
- or asks for status only. `awaiting_scheduler_after_ready_buffer` is not
387
+ window but scheduled cells do not yet, run a persistent read-only scheduler wait
388
+ loop: wait, reread, recompute the ledger, and continue until projected coverage
389
+ is proved, a concrete non-scheduler blocker appears, or Christian explicitly
390
+ stops or asks for status only. `awaiting_scheduler_after_ready_buffer` is not
421
391
  success and is not a terminal blocker for an active refill goal; it is the
422
392
  loaded, awaiting scheduler poll state that keeps the thread waiting. It does not
423
393
  need a prep/import/approval packet.
@@ -750,14 +720,6 @@ with non-null `scheduledFor`. Prepared, approved, and ready-to-schedule rows are
750
720
  intermediate states; report them as awaiting scheduler unless scheduled cells
751
721
  are present.
752
722
 
753
- Future scheduled coverage and already sent actions are distinct; only
754
- scheduler-owned future scheduled actions count as scheduled coverage. For
755
- multiple target dates, finish D1 execution and the full D1 reread before
756
- planning D2. Completion proof is product-native Sellable MCP evidence only:
757
- target plan, campaign refill state, scheduler capacity, sweep/status, and
758
- bounded receipts. Never use individual cell ids, Prisma, SQL, direct database
759
- access, or production-environment scripts as completion proof.
760
-
761
723
  preparedMessages can remain 0 while scheduler-ready state changes downstream.
762
724
  After a prep job reaches a terminal state, run `wait_for_campaign_processing`
763
725
  when generated/pass counts are still settling, then poll `get_campaign_refill_state` until `readyToSchedule` drops, scheduled counts increase, or the state clearly