@sellable/mcp 0.1.557 → 0.1.558

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.
Files changed (63) hide show
  1. package/README.md +2 -13
  2. package/agents/registry.json +2 -2
  3. package/dist/api.js +6 -3
  4. package/dist/auth.d.ts +6 -0
  5. package/dist/auth.js +44 -2
  6. package/dist/refill-contract.d.ts +157 -0
  7. package/dist/refill-contract.js +487 -0
  8. package/dist/refill-run-client.d.ts +10 -0
  9. package/dist/refill-run-client.js +22 -0
  10. package/dist/refill-run-loop.d.ts +14 -2
  11. package/dist/refill-run-loop.js +160 -15
  12. package/dist/server.js +0 -23
  13. package/dist/tools/auth.d.ts +5 -0
  14. package/dist/tools/auth.js +49 -12
  15. package/dist/tools/campaign-message-preparation.d.ts +62 -0
  16. package/dist/tools/campaign-message-preparation.js +41 -0
  17. package/dist/tools/campaigns.js +2 -2
  18. package/dist/tools/csv-dnc.js +2 -2
  19. package/dist/tools/evergreen-refill-plan.d.ts +3 -0
  20. package/dist/tools/evergreen-refill-plan.js +29 -7
  21. package/dist/tools/leads.d.ts +32 -317
  22. package/dist/tools/leads.js +10 -171
  23. package/dist/tools/model-quality.js +6 -4
  24. package/dist/tools/prompts.d.ts +3 -3
  25. package/dist/tools/prompts.js +15 -7
  26. package/dist/tools/provider-preflight.d.ts +2 -65
  27. package/dist/tools/provider-preflight.js +10 -97
  28. package/dist/tools/readiness.d.ts +5 -89
  29. package/dist/tools/readiness.js +0 -66
  30. package/dist/tools/refill-executors.d.ts +38 -0
  31. package/dist/tools/refill-executors.js +222 -3
  32. package/dist/tools/refill-sends-v2.d.ts +118 -1
  33. package/dist/tools/refill-sends-v2.js +312 -3
  34. package/dist/tools/refill-sends.d.ts +678 -32
  35. package/dist/tools/refill-sends.js +274 -13
  36. package/dist/tools/refill-target-plan.js +486 -14
  37. package/dist/tools/registry.d.ts +115 -330
  38. package/dist/tools/registry.js +1 -7
  39. package/dist/tools/scheduler-fill-capacity.js +1 -1
  40. package/dist/tools/scheduler-run.d.ts +71 -0
  41. package/dist/tools/scheduler-run.js +203 -1
  42. package/dist/tools/setup-evergreen-campaigns.js +1 -1
  43. package/dist/tools/workspace-context.d.ts +1 -1
  44. package/dist/tools/workspace-context.js +8 -3
  45. package/dist/tools/workspace-export.js +2 -2
  46. package/dist/tools/workspaces.d.ts +48 -2
  47. package/dist/tools/workspaces.js +48 -5
  48. package/package.json +1 -1
  49. package/skills/create-campaign/SKILL.md +3 -3
  50. package/skills/create-campaign-v2/SKILL.md +1 -1
  51. package/skills/create-evergreen-campaigns/SKILL.md +16 -16
  52. package/skills/find-leads/SKILL.md +630 -48
  53. package/skills/refill-sends/SKILL.md +91 -353
  54. package/skills/refill-sends-v2/SKILL.md +6 -6
  55. package/skills/refill-sends-v2-workflow/SKILL.md +5 -5
  56. package/skills/refill-sends-v2-workflow/core/flow.v1.json +8 -8
  57. package/skills/refill-sends-workflow/SKILL.md +100 -743
  58. package/skills/refill-sends-workflow/core/contract.v2.json +543 -0
  59. package/skills/refill-sends-workflow/core/flow.v1.json +185 -1
  60. package/dist/tools/find-leads-runs.d.ts +0 -151
  61. package/dist/tools/find-leads-runs.js +0 -98
  62. package/skills/find-leads-v2/SKILL.md +0 -70
  63. package/skills/find-leads-v2/core/flow.v1.json +0 -31
package/README.md CHANGED
@@ -16,9 +16,8 @@ Each message gets 5+ minutes of Claude attention with deep research - no other t
16
16
 
17
17
  ### Prompt Source Of Truth
18
18
 
19
- There are nine public Sellable entrypoints shared across hosts:
19
+ There are eight public Sellable entrypoints shared across hosts:
20
20
 
21
- - `sellable:find-leads`
22
21
  - `sellable:create-campaign`
23
22
  - `sellable:create-ab-test`
24
23
  - `sellable:create-evergreen-campaigns`
@@ -34,11 +33,6 @@ the approval-gated workflow from:
34
33
 
35
34
  - `mcp/sellable/skills/create-campaign-v2/SKILL.md`
36
35
 
37
- The find-leads public wrapper builds a live exportable source list without a
38
- campaign and loads its durable approval-gated workflow from:
39
-
40
- - `mcp/sellable/skills/find-leads-v2/SKILL.md`
41
-
42
36
  The create-ab-test public wrapper prepares clean A/B split lead lists and
43
37
  review-copy campaigns from:
44
38
 
@@ -211,7 +205,7 @@ thread and select `Sellable Create Campaign`, `Sellable Create A/B Test`,
211
205
  `Sellable Create Evergreen Campaigns`, `Sellable Foundation`,
212
206
  `Sellable Content`, `Sellable Create Post`, `Sellable Refresh Sender Engagement`,
213
207
  or `Sellable Refill Sends`; or invoke
214
- `$sellable:find-leads`, `$sellable:create-campaign`, `$sellable:create-ab-test`,
208
+ `$sellable:create-campaign`, `$sellable:create-ab-test`,
215
209
  `$sellable:create-evergreen-campaigns`, `$sellable:foundation`,
216
210
  `$sellable:content`, `$sellable:create-post`,
217
211
  `$sellable:refresh-sender-engagement`, or `$sellable:refill-sends`. If the app still says
@@ -226,7 +220,6 @@ the Sellable MCP tools for Codex Desktop.
226
220
  Use these names consistently:
227
221
 
228
222
  - Claude Code command: `/sellable:create-campaign`
229
- - Claude Code command: `/sellable:find-leads`
230
223
  - Claude Code command: `/sellable:create-ab-test`
231
224
  - Claude Code command: `/sellable:create-evergreen-campaigns`
232
225
  - Claude Code command: `/sellable:foundation`
@@ -235,7 +228,6 @@ Use these names consistently:
235
228
  - Claude Code command: `/sellable:refresh-sender-engagement`
236
229
  - Claude Code command: `/sellable:refill-sends`
237
230
  - Codex command: `$sellable:create-campaign`
238
- - Codex command: `$sellable:find-leads`
239
231
  - Codex command: `$sellable:create-ab-test`
240
232
  - Codex command: `$sellable:create-evergreen-campaigns`
241
233
  - Codex command: `$sellable:foundation`
@@ -245,7 +237,6 @@ Use these names consistently:
245
237
  - Codex command: `$sellable:refill-sends`
246
238
  - Codex Desktop plugin: `sellable@sellable`
247
239
  - Codex visible skill: `Sellable Create Campaign`
248
- - Codex visible skill: `Sellable Find Leads`
249
240
  - Codex visible skill: `Sellable Create A/B Test`
250
241
  - Codex visible skill: `Sellable Create Evergreen Campaigns`
251
242
  - Codex visible skill: `Sellable Foundation`
@@ -254,7 +245,6 @@ Use these names consistently:
254
245
  - Codex visible skill: `Sellable Refresh Sender Engagement`
255
246
  - Codex visible skill: `Sellable Refill Sends`
256
247
  - Codex skill frontmatter name: `create-campaign`
257
- - Codex skill frontmatter name: `find-leads`
258
248
  - Codex skill frontmatter name: `create-ab-test`
259
249
  - Codex skill frontmatter name: `create-evergreen-campaigns`
260
250
  - Codex skill frontmatter name: `foundation`
@@ -264,7 +254,6 @@ Use these names consistently:
264
254
  - Codex skill frontmatter name: `refill-sends`
265
255
  - MCP server name: `sellable`
266
256
  - Internal workflow prompt: `create-campaign-v2`
267
- - Internal workflow prompt: `find-leads-v2`
268
257
  - Internal workflow prompt: `refill-sends-workflow`
269
258
  - Internal/backward-compatible memory prompt: `interview`
270
259
 
@@ -26,8 +26,8 @@
26
26
  "ownership": "message strategy, proof inventory, token rules, skeptical-prospect review, and selected winner only",
27
27
  "codex": {
28
28
  "description": "Message Drafting worker for campaign-backed template proposals after confirm_lead_list imports a non-empty bounded review batch.",
29
- "model": "gpt-5.5",
30
- "modelReasoningEffort": "xhigh",
29
+ "model": "gpt-5.6-sol",
30
+ "modelReasoningEffort": "high",
31
31
  "sandboxMode": "read-only",
32
32
  "nicknameCandidates": [
33
33
  "Message Drafting",
package/dist/api.js CHANGED
@@ -3,7 +3,7 @@ import { mkdir, rename, rm, stat } from "node:fs/promises";
3
3
  import path from "node:path";
4
4
  import { Readable } from "node:stream";
5
5
  import { pipeline } from "node:stream/promises";
6
- import { getConfig, getConfigPath } from "./auth.js";
6
+ import { getConfig, getConfigPath, getEffectiveConfiguredWorkspaceId, resolveWorkspaceIdForRequest, } from "./auth.js";
7
7
  export class SellableApiError extends Error {
8
8
  status;
9
9
  body;
@@ -42,9 +42,12 @@ export class SellableApi {
42
42
  // Re-read config on every request so workspace switches take effect immediately
43
43
  const config = getConfig();
44
44
  const url = `${config.apiUrl}${path}`;
45
- const workspaceId = options && Object.prototype.hasOwnProperty.call(options, "workspaceId")
45
+ const requestedWorkspaceId = options && Object.prototype.hasOwnProperty.call(options, "workspaceId")
46
46
  ? options.workspaceId
47
- : config.activeWorkspaceId || config.workspaceId || null;
47
+ : getEffectiveConfiguredWorkspaceId(config);
48
+ const workspaceId = options && Object.prototype.hasOwnProperty.call(options, "workspaceId")
49
+ ? resolveWorkspaceIdForRequest(requestedWorkspaceId, `${method} ${path}`)
50
+ : requestedWorkspaceId;
48
51
  const response = await fetch(url, {
49
52
  method,
50
53
  headers: {
package/dist/auth.d.ts CHANGED
@@ -40,6 +40,12 @@ export type SkillState = {
40
40
  export declare function setConfigFile(fileName: string): void;
41
41
  export declare function getResolvedConfigsDir(): string | null;
42
42
  export declare function getConfigPath(): string;
43
+ export declare function getLockedWorkspaceId(): string | null;
44
+ export declare function isWorkspaceLockRequired(): boolean;
45
+ export declare function workspaceLockRequiredMessage(action?: string): string;
46
+ export declare function assertWorkspaceLockSatisfied(action?: string): void;
47
+ export declare function getEffectiveConfiguredWorkspaceId(config: Pick<SellableConfig, "activeWorkspaceId" | "workspaceId">): string | null;
48
+ export declare function resolveWorkspaceIdForRequest(requestedWorkspaceId: string | null | undefined, action?: string): string | null;
43
49
  export declare function getConfig(): SellableConfig;
44
50
  export declare function updateActiveWorkspace(params: {
45
51
  workspaceId: string;
package/dist/auth.js CHANGED
@@ -2,6 +2,8 @@ import * as fs from "fs";
2
2
  import * as os from "os";
3
3
  import * as path from "path";
4
4
  const DEFAULT_API_URL = "https://app.sellable.dev";
5
+ const WORKSPACE_LOCK_ENV = "SELLABLE_LOCK_WORKSPACE_ID";
6
+ const REQUIRE_WORKSPACE_LOCK_ENV = "SELLABLE_REQUIRE_WORKSPACE_LOCK";
5
7
  // No caching — re-read config on every call so token/workspace changes
6
8
  // made by the LLM (editing sellable.json) take effect immediately
7
9
  // without requiring an MCP server restart.
@@ -85,6 +87,44 @@ function normalizeConfig(raw) {
85
87
  apiUrl: raw.apiUrl || DEFAULT_API_URL,
86
88
  };
87
89
  }
90
+ export function getLockedWorkspaceId() {
91
+ const value = process.env[WORKSPACE_LOCK_ENV]?.trim();
92
+ return value || null;
93
+ }
94
+ export function isWorkspaceLockRequired() {
95
+ const value = process.env[REQUIRE_WORKSPACE_LOCK_ENV]?.trim().toLowerCase();
96
+ return value === "1" || value === "true" || value === "yes";
97
+ }
98
+ export function workspaceLockRequiredMessage(action = "Sellable request") {
99
+ return (`Workspace lock required: ${action} cannot run because ` +
100
+ `${REQUIRE_WORKSPACE_LOCK_ENV}=1 but ${WORKSPACE_LOCK_ENV} is missing. ` +
101
+ "Ask the sellable-admin profile to provision this customer profile with an approved customer workspace.");
102
+ }
103
+ export function assertWorkspaceLockSatisfied(action = "Sellable request") {
104
+ if (isWorkspaceLockRequired() && !getLockedWorkspaceId()) {
105
+ throw new Error(workspaceLockRequiredMessage(action));
106
+ }
107
+ }
108
+ function normalizeWorkspaceId(value) {
109
+ return typeof value === "string" && value.trim() ? value.trim() : null;
110
+ }
111
+ export function getEffectiveConfiguredWorkspaceId(config) {
112
+ assertWorkspaceLockSatisfied("workspace resolution");
113
+ return (getLockedWorkspaceId() ||
114
+ normalizeWorkspaceId(config.activeWorkspaceId) ||
115
+ normalizeWorkspaceId(config.workspaceId));
116
+ }
117
+ export function resolveWorkspaceIdForRequest(requestedWorkspaceId, action = "Sellable request") {
118
+ assertWorkspaceLockSatisfied(action);
119
+ const lockedWorkspaceId = getLockedWorkspaceId();
120
+ const requested = normalizeWorkspaceId(requestedWorkspaceId);
121
+ if (!lockedWorkspaceId)
122
+ return requested;
123
+ if (requested && requested !== lockedWorkspaceId) {
124
+ throw new Error(`Workspace lock violation: ${action} requested workspace ${requested}, but this profile is locked to ${lockedWorkspaceId}.`);
125
+ }
126
+ return lockedWorkspaceId;
127
+ }
88
128
  export function getConfig() {
89
129
  // Config cache removed 2026-05-04: we always re-read from disk so
90
130
  // workspace switches (set_active_workspace) take effect immediately
@@ -139,6 +179,7 @@ export function getConfig() {
139
179
  }
140
180
  }
141
181
  export function updateActiveWorkspace(params) {
182
+ resolveWorkspaceIdForRequest(params.workspaceId, "set_active_workspace");
142
183
  const configPath = getConfigPath();
143
184
  const configDir = path.dirname(configPath);
144
185
  if (!fs.existsSync(configDir)) {
@@ -226,6 +267,7 @@ function writeRawConfigFile(configPath, raw) {
226
267
  * new config without an MCP server restart.
227
268
  */
228
269
  export function writeNewConfig(opts) {
270
+ resolveWorkspaceIdForRequest(opts.activeWorkspaceId, "write Sellable auth config");
229
271
  const configPath = getConfigWritePath();
230
272
  let raw = {};
231
273
  if (fs.existsSync(configPath)) {
@@ -283,7 +325,7 @@ function getActiveEnvConfigRef(raw) {
283
325
  }
284
326
  export function getEngageState() {
285
327
  const config = getConfig();
286
- const workspaceId = config.activeWorkspaceId || config.workspaceId || null;
328
+ const workspaceId = getEffectiveConfiguredWorkspaceId(config);
287
329
  if (!workspaceId) {
288
330
  return { activeWorkspaceId: null, state: null };
289
331
  }
@@ -294,7 +336,7 @@ export function updateEngageState(patch) {
294
336
  const { configPath, raw } = readRawConfigFile();
295
337
  const { envConfig, set } = getActiveEnvConfigRef(raw);
296
338
  const normalized = normalizeConfig(envConfig);
297
- const workspaceId = normalized.activeWorkspaceId || normalized.workspaceId || null;
339
+ const workspaceId = getEffectiveConfiguredWorkspaceId(normalized);
298
340
  if (!workspaceId) {
299
341
  throw new Error("No active workspace selected. Run list_workspaces then set_active_workspace.");
300
342
  }
@@ -0,0 +1,157 @@
1
+ export declare const REFILL_CONTRACT_VERSION: "2.0.0";
2
+ export declare const REFILL_CONTRACT_CACHE_VERSION: "refill-contract-v1";
3
+ export declare const REFILL_CONTRACT_SUPPORTED_MAJOR: 2;
4
+ export declare const REFILL_CONTRACT_ERROR_CODES: readonly ["refill_contract_not_implemented", "unsupported_refill_contract_major", "refill_contract_hash_mismatch", "refill_contract_semantic_mismatch"];
5
+ export type RefillContractErrorCode = (typeof REFILL_CONTRACT_ERROR_CODES)[number];
6
+ export declare class RefillContractError extends Error {
7
+ readonly code: RefillContractErrorCode;
8
+ constructor(code: RefillContractErrorCode, message: string);
9
+ }
10
+ export declare const REFILL_SCOPE_IDS: readonly ["workspace_id", "target_date", "sender_selectors", "campaign_selectors", "approval_mode", "contract_identity", "installed_identity"];
11
+ export declare const REFILL_GATE_IDS: readonly ["workspace_access", "approval_packet", "source_family", "threshold", "scheduler", "campaign_lifecycle", "send_time", "no_direct_send", "one_primitive", "fresh_reread", "normalized_accounting", "prep_circuit", "terminal_truth"];
12
+ export declare const REFILL_STATE_IDS: readonly ["planning", "awaiting_approval", "executing", "settling", "replanning", "terminal"];
13
+ export declare const REFILL_ACTION_IDS: readonly ["prepare_messages", "approve_messages", "rerun_errored_cells", "start_paused_campaign", "run_scheduler_sweep", "scheduler_first_settle", "wait_for_scheduler", "wait_for_active_work", "wait_for_source_import", "copy_selected_source_rows", "continue_signal_discovery_source", "continue_sales_nav_source", "continue_prospeo_source", "manual_source_replenishment", "refresh_paid_inmail_credits", "lower_paid_inmail_threshold", "switch_to_connection_lane", "create_connection_campaign", "next_campaign", "done"];
14
+ export declare const REFILL_RECEIPT_IDS: readonly ["target_plan_receipt", "preparation_receipt", "scheduler_receipt", "run_receipt"];
15
+ export declare const REFILL_SIDE_EFFECT_CLASS_IDS: readonly ["read_only", "message_preparation", "message_approval", "source_replenishment", "credit_refresh", "campaign_start", "scheduler_placement"];
16
+ export declare const REFILL_FORBIDDEN_ACTION_IDS: readonly ["direct_send", "raw_scheduler_write", "campaign_create", "campaign_archive_delete", "threshold_lowering", "unselected_source_mutation", "unapproved_campaign_start", "sender_config_write"];
17
+ export declare const REFILL_TERMINAL_REASON_IDS: readonly ["projected_full", "concrete_blocker", "deadline_reached", "iteration_limit", "operator_stopped", "capped_by_scheduler", "loaded_awaiting_scheduler", "lanes_exhausted", "not_an_evergreen_workspace", "no_refillable_campaigns"];
18
+ export type RefillScopeId = (typeof REFILL_SCOPE_IDS)[number];
19
+ export type RefillGateId = (typeof REFILL_GATE_IDS)[number];
20
+ export type RefillStateId = (typeof REFILL_STATE_IDS)[number];
21
+ export type RefillActionId = (typeof REFILL_ACTION_IDS)[number];
22
+ export type RefillReceiptId = (typeof REFILL_RECEIPT_IDS)[number];
23
+ export type RefillSideEffectClassId = (typeof REFILL_SIDE_EFFECT_CLASS_IDS)[number];
24
+ export type RefillForbiddenActionId = (typeof REFILL_FORBIDDEN_ACTION_IDS)[number];
25
+ export type RefillTerminalReasonId = (typeof REFILL_TERMINAL_REASON_IDS)[number];
26
+ export type RefillAction = {
27
+ [Kind in RefillActionId]: {
28
+ kind: Kind;
29
+ actionKey: string;
30
+ sideEffectClass: RefillSideEffectClassId;
31
+ };
32
+ }[RefillActionId];
33
+ export type RefillReceipt = {
34
+ [Kind in RefillReceiptId]: {
35
+ kind: Kind;
36
+ actionKey: string;
37
+ recordedAt: string;
38
+ };
39
+ }[RefillReceiptId];
40
+ export type RefillTerminal = {
41
+ [Reason in RefillTerminalReasonId]: {
42
+ kind: "terminal";
43
+ reason: Reason;
44
+ evidence: Record<string, unknown>;
45
+ };
46
+ }[RefillTerminalReasonId];
47
+ export declare function canonicalizeRefillContract(value: unknown): string;
48
+ export declare function computeRefillContractHash(value: unknown): string;
49
+ export declare const REFILL_CONTRACT_HASH: string;
50
+ export declare const refillContract: {
51
+ readonly contractHash: string;
52
+ readonly contractVersion: "2.0.0";
53
+ readonly cacheVersion: "refill-contract-v1";
54
+ readonly supportedMajor: 2;
55
+ readonly semantics: {
56
+ readonly scope: {
57
+ id: "workspace_id" | "target_date" | "sender_selectors" | "campaign_selectors" | "approval_mode" | "contract_identity" | "installed_identity";
58
+ }[];
59
+ readonly gates: {
60
+ id: "workspace_access" | "approval_packet" | "source_family" | "threshold" | "scheduler" | "campaign_lifecycle" | "send_time" | "no_direct_send" | "one_primitive" | "fresh_reread" | "normalized_accounting" | "prep_circuit" | "terminal_truth";
61
+ }[];
62
+ readonly states: {
63
+ id: "planning" | "awaiting_approval" | "executing" | "settling" | "replanning" | "terminal";
64
+ }[];
65
+ readonly actions: {
66
+ id: "prepare_messages" | "approve_messages" | "rerun_errored_cells" | "start_paused_campaign" | "run_scheduler_sweep" | "scheduler_first_settle" | "wait_for_scheduler" | "wait_for_active_work" | "wait_for_source_import" | "copy_selected_source_rows" | "continue_signal_discovery_source" | "continue_sales_nav_source" | "continue_prospeo_source" | "manual_source_replenishment" | "refresh_paid_inmail_credits" | "lower_paid_inmail_threshold" | "switch_to_connection_lane" | "create_connection_campaign" | "next_campaign" | "done";
67
+ sideEffectClass: "read_only" | "message_preparation" | "message_approval" | "source_replenishment" | "credit_refresh" | "campaign_start" | "scheduler_placement";
68
+ }[];
69
+ readonly receipts: readonly [{
70
+ readonly id: "target_plan_receipt";
71
+ readonly requiredFields: readonly ["refillLaneKey", "branchMetrics", "ledger", "targetDate", "actionKey", "targetShapeRevision", "stateRevision"];
72
+ }, {
73
+ readonly id: "preparation_receipt";
74
+ readonly requiredFields: readonly ["dependency", "circuit", "batchCalibration", "cooperativeStop"];
75
+ }, {
76
+ readonly id: "scheduler_receipt";
77
+ readonly requiredFields: readonly ["receiptVersion", "diagnosticsVersion", "status", "trigger", "workspaceId", "runId", "leaseFence", "expectedTargetsHash", "maxPlacements", "readyCellsFound", "cellsConsidered", "cellsScheduled", "cellsSkipped", "cellsDeferred", "campaignScopeSummary", "expectedTargetSummary", "changedCounts", "summary", "nextAction", "errorCount", "error"];
78
+ }, {
79
+ readonly id: "run_receipt";
80
+ readonly requiredFields: readonly ["runId", "fence", "gate", "gateSeq", "events", "doneReason"];
81
+ }];
82
+ readonly sideEffectClasses: {
83
+ id: "read_only" | "message_preparation" | "message_approval" | "source_replenishment" | "credit_refresh" | "campaign_start" | "scheduler_placement";
84
+ }[];
85
+ readonly forbiddenActions: {
86
+ id: "direct_send" | "raw_scheduler_write" | "campaign_create" | "campaign_archive_delete" | "threshold_lowering" | "unselected_source_mutation" | "unapproved_campaign_start" | "sender_config_write";
87
+ }[];
88
+ readonly terminalReasons: {
89
+ id: "projected_full" | "concrete_blocker" | "deadline_reached" | "iteration_limit" | "operator_stopped" | "capped_by_scheduler" | "loaded_awaiting_scheduler" | "lanes_exhausted" | "not_an_evergreen_workspace" | "no_refillable_campaigns";
90
+ terminalKind: string;
91
+ }[];
92
+ readonly transitions: readonly [{
93
+ readonly from: "planning";
94
+ readonly to: "awaiting_approval";
95
+ }, {
96
+ readonly from: "awaiting_approval";
97
+ readonly to: "executing";
98
+ }, {
99
+ readonly from: "executing";
100
+ readonly to: "settling";
101
+ }, {
102
+ readonly from: "settling";
103
+ readonly to: "replanning";
104
+ }, {
105
+ readonly from: "replanning";
106
+ readonly to: "executing";
107
+ }, {
108
+ readonly from: "replanning";
109
+ readonly to: "terminal";
110
+ }];
111
+ };
112
+ readonly backendBindings: {
113
+ readonly planner: {
114
+ readonly actions: ("prepare_messages" | "approve_messages" | "rerun_errored_cells" | "start_paused_campaign" | "run_scheduler_sweep" | "scheduler_first_settle" | "wait_for_scheduler" | "wait_for_active_work" | "wait_for_source_import" | "copy_selected_source_rows" | "continue_signal_discovery_source" | "continue_sales_nav_source" | "continue_prospeo_source" | "manual_source_replenishment" | "refresh_paid_inmail_credits" | "lower_paid_inmail_threshold" | "switch_to_connection_lane" | "create_connection_campaign" | "next_campaign" | "done")[];
115
+ readonly receiptFields: readonly ["refillLaneKey", "branchMetrics", "ledger", "targetDate", "actionKey", "targetShapeRevision", "stateRevision"];
116
+ };
117
+ readonly preparation: {
118
+ readonly dependencyClasses: readonly ["active", "transient", "permanent", "changed", "exhausted"];
119
+ readonly dependencyReasons: readonly ["active_cells", "dependency_timeout", "rate_limited", "provider_unavailable", "authentication_failed", "validation_failed", "schema_invalid", "config_epoch_changed", "source_epoch_changed", "frontier_exhausted", "unknown_dependency"];
120
+ readonly circuitStates: readonly ["closed", "open", "half_open", "reset"];
121
+ readonly cooperativeStopReasons: readonly ["target_satisfied_during_prep"];
122
+ readonly receiptFields: readonly ["dependency", "circuit", "batchCalibration", "cooperativeStop"];
123
+ };
124
+ readonly scheduler: {
125
+ readonly targetOutcomes: readonly ["included", "omitted"];
126
+ readonly omissionReasons: readonly ["no_ready_cells", "not_scheduler_eligible", "sender_mismatch", "capacity_prefiltered", "outside_target_date", "receipt_error"];
127
+ readonly runStatuses: readonly ["ran", "window_closed_noop", "failed"];
128
+ readonly nextActions: readonly ["refresh_paid_inmail_credits_then_rerun", "wait_for_capacity_or_window", "inspect_sender_mismatch", "no_ready_cells_continue_refill_prep", "scheduled_cells", "investigate_deferred_reasons", "investigate_scheduler_failure"];
129
+ readonly receiptFields: readonly ["receiptVersion", "diagnosticsVersion", "status", "trigger", "workspaceId", "runId", "leaseFence", "expectedTargetsHash", "maxPlacements", "readyCellsFound", "cellsConsidered", "cellsScheduled", "cellsSkipped", "cellsDeferred", "campaignScopeSummary", "expectedTargetSummary", "changedCounts", "summary", "nextAction", "errorCount", "error"];
130
+ };
131
+ readonly run: {
132
+ readonly gates: readonly ["g0_bootstrap", "g1_plan", "g2_execute", "g3_verify", "g4_terminal"];
133
+ readonly states: readonly ["planning", "awaiting_approval", "executing", "settling", "replanning", "terminal"];
134
+ readonly resultKinds: readonly ["started", "awaiting_approval", "active_run_in_progress", "resumed", "lease_lost", "scope_drift", "approval_expired", "approval_fingerprint_mismatch"];
135
+ readonly terminalReasons: readonly ["complete", "capped_by_scheduler", "loaded_awaiting_scheduler", "lanes_exhausted", "blocked", "not_an_evergreen_workspace", "no_refillable_campaigns"];
136
+ readonly refusals: readonly ["scope_drift", "approval_expired", "approval_fingerprint_mismatch", "legacy_read_only", "expected_target_overflow", "scheduler_receipt_incomplete"];
137
+ readonly scopeFields: readonly ["workspaceId", "intent", "senderIds", "campaignIds", "tableIds", "actionIds", "approvalMode", "dateSelector", "senderTimezones", "expectedTargetsHash", "maxPlacements", "contract", "installed"];
138
+ readonly approvalFields: readonly ["scopeHash", "targetShapeRevision", "actionFingerprint", "expectedTargetsHash", "sideEffectEnvelope", "maxPlacements", "approvalExpiresAt", "approvalFingerprint"];
139
+ };
140
+ };
141
+ };
142
+ export type RefillContract = typeof refillContract;
143
+ export declare function assertSupportedRefillContractMajor(version: string): void;
144
+ export declare function validateRefillContractAsset(value: unknown): RefillContract;
145
+ export declare function refillContractSemanticProjection(): {
146
+ contractVersion: "2.0.0";
147
+ cacheVersion: "refill-contract-v1";
148
+ contractHash: string;
149
+ semanticIds: {
150
+ [k: string]: string[];
151
+ };
152
+ };
153
+ export declare function validateRefillFlowProjection(value: unknown): void;
154
+ export declare function renderRefillBootstrapGuidance(): string;
155
+ export declare function renderRefillSafetyGuidance(): string;
156
+ export declare function renderRefillTerminalGuidance(): string;
157
+ export declare function assertNeverRefillVariant(value: never): never;