@sellable/mcp 0.1.553 → 0.1.555

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.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: refill-sends-workflow
3
- description: Internal skill-led refill sends workflow for regular campaigns and evergreen campaigns.
3
+ description: Internal typed workflow contract for regular and evergreen campaign refills.
4
4
  visibility: internal
5
5
  allowed-tools:
6
6
  - mcp__sellable__get_subskill_asset
@@ -49,786 +49,105 @@ allowed-tools:
49
49
 
50
50
  # Refill Sends Workflow
51
51
 
52
- Default mode is read-only research. This workflow decides the next safe refill
53
- step in the parent thread; backend tools remain narrow route, state, source,
54
- prep, readiness, and evergreen primitives.
55
-
56
- ## Entry
57
-
58
- Plain phrases that enter here include "fill", "refill sends", "max out sends",
59
- "load everyone up", and "fill horizon sends".
60
-
61
- Sender-scoped phrases include "refill senders", "fill senders", "max out
62
- senders", and "load everyone up". A sender-scoped request targets senders
63
- enrolled in active campaign-backed sequence campaigns, not one arbitrary active
64
- campaign.
65
-
66
- Workspace contract: scheduled automation and `--yolo` must carry an explicit
67
- request-scoped `workspaceId`. Pass that same `workspaceId` on every refill tool
68
- call in this workflow: `get_refill_target_plan`, `list_senders`,
69
- `get_sender_routing`, `resolve_campaign_fill_route`,
70
- `get_campaign_refill_state`, `get_scheduler_fill_capacity`,
71
- `run_scheduler_sweep`, `refresh_paid_inmail_credits`, source import/readiness
72
- calls, preparation calls, approval calls, and campaign start calls. Missing
73
- `workspaceId` in scheduled or `--yolo` mode is a blocker; return or report
74
- `WORKSPACE_REQUIRED` instead of falling back to shared config state. Manual
75
- interactive workspace switching is diagnostic setup only and is not an
76
- automation control path.
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
- Goal-mode continuation: a skill cannot create or invoke `/goal` by itself. When
93
- this workflow is already running inside an active Codex goal, keep that goal
94
- open until every selected sender lane is horizon-filled by projected coverage
95
- (`sent + scheduled`), Christian explicitly stops/statuses the run, or a concrete
96
- non-scheduler blocker appears. `awaiting_scheduler_after_ready_buffer` is an
97
- in-progress wait state, not a reason to mark the goal complete or blocked.
98
-
99
- Runtime flow asset: after loading this prompt, load
100
- `get_subskill_asset({ subskillName: "refill-sends-workflow", assetPath: "core/flow.v1.json" })`
101
- through MCP, continue chunks until `hasMore:false`, parse the JSON, and verify
102
- `workflow:"refill-sends-workflow"` with a `v1` version before any operational
103
- step. The flow asset is the deterministic gate order: target-plan read, paid
104
- InMail credit freshness gate, action selection, bounded table action, scheduler
105
- wait readback, then completion/blocker. If the asset cannot load or parse, stop
106
- with `blocked:refill_workflow_asset_unavailable`; do not emulate it from local
107
- files or memory.
108
-
109
- 1. Call `get_refill_target_plan` first. This read-only target plan is the
110
- canonical opening receipt: eligible senders, selected sender-local days,
111
- gross target, inferred per-sender send lane/action selections, actual sent
112
- coverage, scheduler-owned scheduled coverage across active enrolled
113
- campaigns, projected coverage (`sent + scheduled`), ready buffer, remaining
114
- projected gap, paid-InMail credit/threshold feasibility, bounded action
115
- candidates, `targetShapeRevision`, and `stateRevision`.
116
- Refill target lanes are connection invites (`send_invite`), standalone paid
117
- InMails (`send_inmail_closed`), or unified Sales Nav cascades represented
118
- publicly as `send_inmail_closed` with
119
- `campaignClassification:"sales_nav_cascade"`. For a Sales Nav cascade, fill
120
- the selected campaign first; its sequence can route prospects to Open InMail,
121
- paid InMail while fresh credits are >= 5, or same-campaign connection
122
- fallback without asking for separate open/paid/connection campaigns. DMs
123
- (`send_dm`) are follow-up actions, not refill horizon capacity. Do not count
124
- their sent, scheduled, or ready cells when deciding whether a sender needs
125
- refill. When `actionTypes` are omitted, trust the target plan's inferred lane;
126
- do not ask the operator which campaign class to fill after the plan has
127
- inferred that from active campaign future scheduled, recent scheduled, and
128
- ready evidence. If a stale planner/tool response selects `send_dm` or
129
- `send_inmail_open`, treat that as unsupported stale refill state and re-plan
130
- with a current planner before any mutation.
131
- Short form: trust the target plan's inferred lane when it is a connection
132
- invite, paid-InMail refill lane, or unified Sales Nav cascade.
133
- Structured planner packet:
134
- - `target.eligibleSenderLedger` is the public sender eligibility ledger.
135
- - `target.senderRefillPlans[]` is the canonical sender-level packet; read and
136
- display it before mutation.
137
- - Each sender packet includes `campaignRanking.options`, `sourcePlan`,
138
- `refillReceipt`, `nextActions`, and `manualAlternates`.
139
- - `refillReceipt` is the public ladder receipt. It carries the selected
140
- campaign/sender/lane summary, skipped rungs, existing-row frontier proof,
141
- and any absolute `wait.deadlineAt`.
142
- - Preserve these coverage labels exactly: `Need to prepare`, `Goal`,
143
- `Already sent`, `Scheduled`, `Ready and waiting to be scheduled`, and
144
- `Still need`.
145
- - `target.globalActionQueue` is the only cross-sender yolo execution queue.
146
- execute exactly one globally ranked primitive from
147
- `target.globalActionQueue[0]`, then rerun `get_refill_target_plan` with
148
- the same `workspaceId` before
149
- choosing another action.
150
- - `nextActions[0]` is the current sender's smallest safe primitive.
151
- - `manualAlternates` are not yolo actions. Threshold lowering and campaign
152
- creation are manual continuations only.
153
- Refill action ladder: approve generated rows only when an explicit bounded
154
- approval gate exists, process all existing same-campaign
155
- unenriched/unprepared rows in bounded batches before any source work, then
156
- copy bounded net-new rows from the selected source (`selectedLeadListId`,
157
- provider, and source fingerprint preserved), then use provider-aligned
158
- source-more. A new source or provider switch changes the reply-rate baseline
159
- and is a manual alternate, not a `--yolo` side effect.
160
- Source/copy/fallback requires receipt-proven exhaustion of earlier rungs:
161
- `existingRowFrontier.hasMoreFrontierRows:false`, zero
162
- `approvalCandidates`, no fresh active prep, no `stuckActiveCells`, and no
163
- non-terminal `approvedNotDispatched` rows. Treat anomalies,
164
- `stuckActiveCells`, and non-terminal `approvedNotDispatched` as
165
- diagnose-and-report gates, not exhaustion. Terminal
166
- `approvedNotDispatched` blockers may be reported, then the ladder can
167
- proceed.
168
- Run-local paid-credit guard: in `--yolo`, the `refill_sends` MCP command
169
- automatically maintains a `refreshedPaidInmailSenderIds` set for the current
170
- command call. If its first target plan has stale/missing paid-InMail credit
171
- facts, it refreshes each selected sender at most once, reruns
172
- `get_refill_target_plan`, and returns the post-refresh `targetPlan` before
173
- choosing the next prep/source-copy/bounded-approval/read-only wait action. If fresh facts are still below
174
- threshold, below-threshold paid-InMail facts fall back to an existing
175
- connection lane, the same Sales Nav cascade campaign's connection branch, or
176
- a manual continuation.
177
- Freshness gate precedes scheduler wait: if any selected
178
- `target.senderRefillPlans[].paidInmail.status` is `missing_credit_facts` or
179
- `stale_credit_facts`, or the target plan contains a
180
- `refresh_paid_inmail_credits` candidate, do not enter
181
- `wait_for_scheduler` even when `remainingReadyOrProjectedGap:0`. Refresh the
182
- exact selected sender credit facts once, rerun `get_refill_target_plan`, and
183
- only then decide whether scheduler wait is the next safe action. If facts
184
- remain missing/stale after the single refresh attempt, stop with a
185
- paid-InMail freshness blocker instead of waiting on scheduler pickup.
186
- The standalone MCP refresh surface is the scoped route
187
- `/api/v3/mcp/senders/:senderId/refresh-inmail-credits` with explicit
188
- `workspaceId`; do not use active-workspace mutation as the automation
189
- control path.
190
- Compact refill lessons: sender-level target plan is final truth; trust
191
- `schedulerGate.sendable` and scheduler gate blockers, not raw
192
- `unipileAccountStatus` labels alone; use compact prep status checks for
193
- long-running jobs; reread target plans after prep or cancel; treat ready rows
194
- as intermediate; avoid huge parallel target-plan reads when output is large.
195
- If a campaign produces prepared/ready rows but sender-level projected
196
- coverage does not move after one bounded settle loop, pivot to compact prep
197
- status or a scheduler-proven lane. Do not keep waiting on campaign-level
198
- ready counts.
199
- For exact-date requests, pass `targetDate` to `get_refill_target_plan`.
200
- When you need raw diagnostic proof, call `get_scheduler_fill_capacity` for
201
- the same exact sender/action/date. That query is read-only and tells the MCP
202
- how many cells the product scheduler will try to place for that sender; it
203
- does not create rows, import, approve, schedule, refresh paid-InMail credits,
204
- or mutate thresholds.
205
- When ready rows exist and the wait is for scheduler pickup, call
206
- `run_scheduler_sweep` with the same explicit `workspaceId` to request the
207
- product scheduler placement pass now and read its receipt. This may place
208
- 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
- Scheduler-run receipt interpretation: `cellsConsidered is
223
- allocation-attempt count`, not total ready supply, while `readyCellsFound`
224
- is ready inventory found before prefilters. Inspect `campaignScopeSummary`
225
- before assuming the selected refill campaign/table was included; if absent,
226
- do not infer that target was ready-but-blocked. Interpret `prefiltered` as
227
- ready cells removed before allocation, `skipped` as considered cells blocked
228
- by scheduler gates, and `deferred` as considered cells waiting on
229
- windows/capacity/cooldown. For ready closed-InMail cells with stale
230
- paid-credit prefilter/defer reasons, refresh paid-InMail credits once through
231
- existing tools, then rerun `run_scheduler_sweep` or read `action:"status"`;
232
- `refresh_paid_inmail_credits_then_rerun` is that path.
233
- `wait_for_capacity_or_window` means report loaded/capped/waiting and do not
234
- source or prep more rows; `no_ready_cells_continue_refill_prep` means return
235
- to the refill/prep ladder. Do not treat `cellsScheduled:0` alone as failure.
236
- If `status:"complete"`, report the target, selected dates, sent count,
237
- scheduled count, projected count, campaign ids, and no-op proof without
238
- asking for approval or mutating.
239
- 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
244
- prep/import/approval. Poll `get_refill_target_plan` every 60-120 seconds, or
245
- on the host's next continuation interval, until projected coverage fills,
246
- a concrete non-scheduler blocker appears, or Christian explicitly asks to
247
- stop or only receive a status report. Treat
248
- `awaiting_scheduler_after_ready_buffer` as an in-progress wait state, not a
249
- close-out condition.
250
- Wait actions are gates, not competing goals. When `wait_for_active_work` or
251
- `wait_for_scheduler` includes receipt `wait.deadlineAt`, honor that absolute
252
- deadline; if it is expired on this call, escalate to diagnostics with the
253
- receipt evidence instead of issuing another blind wait.
254
- If paid InMail credit facts are stale or missing and the first target plan
255
- contains `refresh_paid_inmail_credits`, do not present that as the operator's
256
- next action in `--yolo`. Do not present paid-credit refresh as the next
257
- operator action after `refill_sends` returns `autoPaidInmailRefresh` and the
258
- post-refresh `targetPlan`. Trust `refill_sends.autoPaidInmailRefresh`: it
259
- should show the exact sender ids refreshed once, sender-credit-cache write
260
- receipts, and a returned post-refresh `targetPlan`. Continue from that
261
- post-refresh packet. If paid InMail is below threshold after the fresh credit read, report
262
- the exact campaign/table/column threshold action or same-campaign
263
- connection fallback; `--yolo` does not lower paid-InMail thresholds or create campaigns.
264
- 2. Call `resolve_campaign_fill_route`. Use `intent:"plain"` for generic
265
- fill/load language, `intent:"active"` only when the user explicitly narrowed
266
- to active regular campaigns or when the plain route has stale managed
267
- waterfall evidence, and `intent:"evergreen"` only when the user explicitly
268
- asked for evergreen or horizon work. The resolver must refetch current
269
- dashboard-active campaigns as well as managed waterfall state. If the plain
270
- route returns managed waterfall targets but skipped targets include
271
- archived/completed waterfall slots, or if the returned targets do not cover a
272
- named sender, immediately call `resolve_campaign_fill_route({ intent:"active" })`
273
- and inspect current dashboard-active `ACTIVE` and `PAUSED` campaign-backed
274
- sequence campaigns before declaring a sender blocked.
275
- Short form: stale waterfall bindings do not overrule current dashboard-active campaigns.
276
- 3. Resolve sender context before choosing a target. Call `list_senders`; when a
277
- managed program is involved, also call `get_campaign_waterfall`, and call
278
- `get_sender_routing` when territory rules may constrain sender eligibility.
279
- If the user named senders, map those names to exact sender ids. If the user
280
- did not name senders and the request is sender-scoped:
281
- - in `--yolo`, target all eligible healthy senders enrolled in active
282
- campaign-backed sequence campaigns returned by the route/state evidence;
283
- - outside `--yolo`, ask which eligible enrolled senders to refill before
284
- choosing campaigns or mutating.
285
- If the request is campaign-scoped or ambiguous "fill sends" language, infer
286
- the relevant senders from the most recent scheduler-owned sends in
287
- refill-state readbacks and report that inference.
288
- Short form: `--yolo refill senders` means all eligible enrolled senders; non-yolo asks which enrolled senders.
289
- 4. Read `get_campaign_refill_state` for candidate campaigns from the resolver
290
- result and from the required active-route refetch when managed waterfall
291
- evidence looks stale. For a broad `active_campaigns` route, inspect enough
292
- candidates to identify the campaign or small campaign set that most recently
293
- had scheduler-owned sends for the relevant sender set. Do not stop after the
294
- first resolver target unless it is also the most recent sender-relevant send
295
- lane. A current dashboard-active `PAUSED` campaign-backed sequence campaign is
296
- a start-eligible refill candidate, not an archived blocker; read its refill
297
- state first, then include a bounded `start_campaign` packet only when the
298
- state proves healthy senders, sequence, source/list, ready/preparable rows,
299
- and starting is needed for the product scheduler to schedule/send.
300
- Short form: Do not stop after the first resolver target unless recent-send evidence supports it.
301
- Short form: `PAUSED` dashboard-active campaigns are start-eligible candidates, not skipped archived inventory.
302
- In `--yolo` sender-scoped mode, selecting every active campaign is still a
303
- scope error, but selecting one best refill campaign per eligible sender is
304
- expected. Pick the single highest-ranked recent-send or best-result campaign
305
- for each target sender unless the refill-state evidence proves that a sender
306
- already has enough ready/scheduled rows across enrolled campaigns or that a
307
- different same-sender campaign is needed because the best lane is blocked.
308
- Short form: `--yolo refill senders` selects all eligible enrolled senders, then the best campaign per sender.
309
- 5. Pick exact ids from the selected refill-state response. Do not use campaign
310
- names or table names as target identifiers for tool calls.
311
- 6. Classify the target from refill state:
312
- - regular campaign: campaign-backed workflow table with normal source,
313
- sequence, senders, and send/refill stages.
314
- - evergreen campaign: managed always-on lane with current source evidence.
315
- - `unsupported_campaign_type`: internal direct campaign table; report the
316
- blocker and stop without mutation.
317
-
318
- ## Research Checklist
319
-
320
- Use the refill-state response as the current facts receipt:
321
-
322
- - campaign status/current step, workflow table id, table config type, and public
323
- type, including whether the route target is dashboard-active `PAUSED` and
324
- start-eligible;
325
- - selected source list/provider identity, source id, target prospect gap,
326
- cursor/inventory state, dedupe/DNC/provider exclusions, good-prospect yield,
327
- scan/import caps, and proof;
328
- - sender ids, healthy senders, disconnected senders, and daily capacity;
329
- - target-window saturation ledger per target sender: sender-local send days in
330
- scope, gross target capacity, actual sent coverage, future scheduler-owned
331
- scheduled counts in that window, projected coverage (`sent + scheduled`),
332
- ready-to-schedule buffer, remaining projected gap, paid-InMail
333
- credit/threshold feasibility, `targetShapeRevision`, `stateRevision`, and the
334
- next smallest MCP primitive that can reduce the gap;
335
- - row/stage counts: source available, rows, enriched, passed, generated,
336
- approved, ready to schedule, scheduled;
337
- - active message prep job;
338
- - scheduler-owned scheduled counts by date/action from cells with non-null
339
- `scheduledFor`; treat connection-invite and paid-InMail cells as the refill
340
- lane continuation signal and the last sends/continuation signal, and ignore
341
- DM/open-InMail cells for refill target capacity;
342
- - latest scheduled send date, latest scheduled-cell update when present,
343
- sender overlap with the requested or inferred sender set, and whether future
344
- scheduled sends already exist;
345
- - `freshness.stateHash` and exact campaign/table/workspace ids.
346
-
347
- Empty or unsafe states stop with the blocker: no fillable target, missing or deleted campaign,
348
- missing table, archived/completed campaign, paused campaign without an explicit
349
- selected-start packet, zero sender capacity, zero source candidates, zero viable
350
- rows, no approved/preparable rows, active prep job, awaiting scheduler, or
351
- unsupported direct campaign type.
352
-
353
- ## Regular Campaign Decision
354
-
355
- For regular campaign workspaces, rank regular campaigns from route and
356
- `get_campaign_refill_state` evidence. Choose the best existing refill target.
357
- The default campaign-scoped refill interpretation is "continue the campaign that
358
- was actually sending most recently for the relevant available senders", not
359
- "touch every active campaign". The default sender-scoped refill interpretation is
360
- "fill every eligible target sender from the best enrolled active campaign for
361
- that sender", not "fill only the first/best campaign globally".
362
-
363
- When managed waterfall bindings point at archived/completed campaigns but the
364
- dashboard has current unarchived `ACTIVE` or `PAUSED` campaigns for the same
365
- sender/shared lane, prefer the current dashboard-active campaign for target
366
- discovery. The stale waterfall slot remains diagnostic proof, not a reason to
367
- skip a visible paused shared campaign that can be started through a bounded
368
- packet.
369
-
370
- Default `--yolo` target is the scheduler-forward 48-hour window when the user
371
- asks to fill, refill, load, or max sends without naming a different horizon or
372
- exact `targetDate`.
373
- The planner selects sender-local days whose configured sending windows overlap
374
- that rolling target window; do not treat weekends or other no-send-hour days as
375
- fillable capacity. If the user explicitly names a no-send calendar date, report
376
- that date as unschedulable and continue only for the next valid send day when
377
- the packet says "send days" or the user asked to max/refill senders broadly.
378
-
379
- For campaign-scoped requests, compute the target from scheduler-fillable
380
- capacity in the selected target window/date, not the full daily limit. For
381
- sender-scoped requests, compute that scheduler-fillable gap per target sender
382
- across all active enrolled campaigns for that sender; count ready-to-schedule
383
- cells in any active enrolled campaign toward that sender's fillable gap before
384
- preparing more rows. If ready rows already cover a sender's scheduler-fillable
385
- gap, do not add rows or prep for that sender; report that the sender is loaded,
386
- awaiting scheduler. If the gap is positive, prepare only the gap in the best
387
- same-sender campaign and keep all source-copy/prep caps tied to that target
388
- window/date packet.
389
- Short form: default `--yolo refill senders` target is each eligible sender's
390
- scheduler-forward 48-hour gap.
391
-
392
- Lane selection must choose one refill lane per sender from current
393
- dashboard-active campaign-backed sequence evidence:
394
-
395
- 1. Prefer the sender's most recent future scheduled refill action, then the most
396
- recent recent scheduled refill action, then ready refill rows.
397
- 2. Refill actions are `send_invite` or `send_inmail_closed`; unified Sales Nav
398
- cascades also appear as `send_inmail_closed` with
399
- `campaignClassification:"sales_nav_cascade"`.
400
- 3. If the most recent active campaign evidence is DM, ignore it for refill lane
401
- selection. If open InMail evidence belongs to a unified Sales Nav cascade,
402
- keep the cascade campaign as the selected `send_inmail_closed` target; do not
403
- create side open/paid/connection campaigns.
404
- 4. If no connection/paid-InMail evidence exists, fall back to the selected
405
- active campaign sequence, still choosing only one of `send_invite` or
406
- `send_inmail_closed` for that sender.
407
-
408
- For `--yolo` fill/schedule requests, do not treat "ready" as completion. Build
409
- and maintain a target-window saturation ledger for every selected sender from
410
- `get_refill_target_plan`. A sender is complete only when a final target-plan or
411
- refill-state reread proves projected coverage (`sent + scheduled`) meets or
412
- exceeds the sender's capacity for the selected target window. Put another way:
413
- complete when the same daily-limit/readback model would show no remaining
414
- send-day capacity for that selected lane. Ready-to-schedule rows are only buffer
415
- 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
421
- success and is not a terminal blocker for an active refill goal; it is the
422
- loaded, awaiting scheduler poll state that keeps the thread waiting. It does not
423
- need a prep/import/approval packet.
424
- Short form: ready buffer is not success.
425
- Short form: keep polling the scheduler instead of closing out while ready buffer
426
- covers the gap.
427
- Short form: `--yolo refill senders` completes only on projected target-window
428
- saturation or a concrete blocker.
429
-
430
- Rank candidates in this order:
431
-
432
- 1. **Sender match**: campaigns whose healthy sender ids match the user-named
433
- senders, or the inferred sender set when the user said only "fill sends" or
434
- "load senders". Do not include campaigns merely because they are active when
435
- their sender set is unrelated.
436
- 2. **Recent sends**: campaigns with the newest scheduler-owned scheduled counts
437
- and non-null `scheduledFor` cells for those senders. Future scheduled sends
438
- are stronger continuation evidence than old historical sends; otherwise use
439
- the latest scheduled send date / newest scheduled-cell update from refill
440
- state.
441
- 3. **Continuation capacity**: campaigns with healthy senders, remaining daily
442
- capacity, and a gap between current ready-to-schedule rows and the desired
443
- sender capacity.
444
- 4. **Same-campaign source health**: prefer campaigns whose current source has
445
- enough `sourceAvailable` inventory to prepare the gap. If source inventory
446
- is low or exhausted, choose same-campaign row replenishment before switching
447
- campaigns.
448
- 5. **Campaign scope**: keep the selected set small. For campaign-scoped
449
- requests, normally choose one campaign. For sender-scoped requests, choose at
450
- most one best campaign per target sender unless evidence shows one sender
451
- needs multiple same-sender campaigns because the first is blocked or already
452
- loaded.
453
-
454
- Do not create side campaigns, warm-post-engager side campaigns, on-demand campaigns,
455
- or unrelated campaigns as the default answer to a fill request.
456
-
457
- For each selected campaign, decide the next action by the smallest sufficient
458
- step:
459
-
460
- - **Enrich/prep more rows in the same campaign** when sender health is good,
461
- recent sends point to this campaign, and `sourceAvailable` can cover the
462
- ready-to-schedule gap.
463
- - **Add/import more rows to the same campaign/source path** when the campaign is
464
- the right recent-send lane but source inventory or viable rows cannot cover
465
- the gap.
466
- - **Use a different existing campaign** only when the recent-send/best-result
467
- campaign for that sender is blocked, archived, missing sequence/source/senders,
468
- disconnected, exhausted with no viable same-campaign replenishment path,
469
- already loaded while the sender still has a gap, or the user explicitly asks
470
- to move to another campaign.
471
- - **Ask what to create** only after resolver/state evidence shows there is no
472
- suitable existing campaign for the requested sender set.
473
-
474
- When the best regular campaign is source-exhausted, recommend same-campaign source-ladder replenishment.
475
- Keep `selectedLeadListId` source identity distinct
476
- from the campaign `workflowTableId`.
477
-
478
- Source replenishment choices:
479
-
480
- - existing source list reuse: append/confirm the existing source list when it
481
- has enough eligible rows;
482
- - CSV path: load CSV profiles/domains, then import into the same campaign/source
483
- path;
484
- - Sales Nav path: use Sales Nav lookup/search, then import selected prospects;
485
- - Prospeo path: use account/person search as appropriate, then import selected
486
- prospects;
487
- - Signal Discovery path: search/select posts or engagers, import selected
488
- source prospects into the same campaign/source-list path, then confirm
489
- readiness.
490
-
491
- When reusing an existing source list on an already-large campaign, handle the
492
- campaign-table row cap automatically in `--yolo` mode. If `confirm_lead_list`
493
- fails with `USER_ADDED_ROWS_LIMIT_EXCEEDED`, parse `remainingRows`,
494
- `currentRows`, `requestedRows`, and `maxRows`; do not stop just because the full
495
- source list is too large. Instead, create a bounded same-source split:
496
-
497
- 1. choose a split size no larger than `remainingRows`, the two-day refill row
498
- budget, and the first-pass processing cap unless the packet named a higher
499
- cap;
500
- 2. read compact rows from the current `selectedLeadListId` with
501
- `get_rows_minimal`;
502
- 3. create a temporary bounded LinkedIn profile source list with
503
- `load_csv_linkedin_leads`, preserving useful source columns such as post URL,
504
- post author, engagement type/text, keyword, confidence, and why;
505
- 4. call `confirm_lead_list` with that bounded source-list id, the same campaign
506
- id, and `currentStep:"running"` for ACTIVE campaigns;
507
- 5. verify the campaign table row count and review batch with
508
- `get_campaign_table_schema` before any prep/approval.
509
-
510
- Do not use `add_on_demand_leads` or create an on-demand table as the automatic
511
- regular-campaign fallback. The fallback must stay same-campaign and
512
- source-list-backed.
513
- Short form: row-cap fallback means bounded same-source split, not stop or on-demand.
514
-
515
- ### Running Campaign Signal Discovery Recovery
516
-
517
- For an already-running regular campaign that needs same-campaign Signal
518
- Discovery replenishment, treat the watch/current-step transition as a guarded
519
- repair, not as normal create-campaign navigation.
520
-
521
- Do not call `search_signals` with `currentStep:"signal-discovery"` directly from `currentStep:"running"`. The campaign step guard intentionally rejects that
522
- backwards transition. After exact approval and a fresh refill-state reread, clear `currentStep` only if it still exactly matches `running`:
52
+ This prompt is operator choreography around `core/contract.v2.json` and
53
+ `core/flow.v1.json`. The typed planner and durable run are the executable
54
+ authority. Do not reconstruct allocation, preparation calibration, circuit
55
+ backoff, scheduler selection, or completion mathematics in prose.
56
+
57
+ Default mode is read-only research for both a regular campaign and an evergreen
58
+ campaign. Mutation begins only through the typed approval or bounded yolo gates
59
+ below.
60
+
61
+ Call `get_refill_target_plan` first. Use projected coverage (`sent + scheduled`)
62
+ as the completion measure, and preserve `targetShapeRevision` across every
63
+ approved action. The workflow does not lower paid-InMail thresholds. Any
64
+ threshold change remains a separate operator gate.
65
+
66
+ ## Read-only routing compatibility
67
+
68
+ Preserve the established discovery order without reimplementing its decisions:
69
+
70
+ 1. Call `resolve_campaign_fill_route`; stop on `unsupported_campaign_type`.
71
+ 2. Call `get_campaign_refill_state` and bind `freshness.stateHash`. After any
72
+ primitive, reread `get_campaign_refill_state` before deciding again.
73
+ 3. Treat `fill_campaign_horizon` as a legacy evergreen-only lower-level primitive.
74
+ Reach it only through the durable contract when the current source is exhausted,
75
+ and preserve all scan/import caps.
76
+
77
+ ## Contract load
78
+
79
+ Load both assets completely to `hasMore:false`. Require
80
+ `workflow:"refill-sends-workflow"`, a supported v1 flow, contract major 2, and
81
+ matching `contractVersion`, `cacheVersion`, `contractHash`, semantic ID sets,
82
+ and backend projection hash. Any mismatch is a terminal pre-execution blocker.
83
+
84
+ The public command is `refill_sends`. `refill_sends_v2` remains a
85
+ server-internal implementation detail and is never advertised or invoked by a
86
+ customer prompt.
87
+
88
+ ## Durable choreography
89
+
90
+ 1. Resolve and echo the explicit workspace and sender-local date scope.
91
+ 2. Read the canonical target packet. Render its normal bounded approval packet
92
+ even when yolo auto-accepts it.
93
+ 3. Preserve immutable workspace, selectors, date, timezone, contract/cache,
94
+ expected-target hash, placement cap, approval fingerprint, and installed
95
+ identities. Display labels never define scope.
96
+ 4. Execute exactly one current packet action through the public durable entry.
97
+ The run records planned -> did -> outcome, reconciles uncertain outcomes,
98
+ rereads authoritative target truth, and replans before another primitive.
99
+ 5. Treat expected scheduler targets as diagnostic receipts only. Placement
100
+ remains workspace-wide and every expected target must be `included` or
101
+ `omitted` with a typed reason.
102
+ 6. Stop exact preparation only after a fresh canonical deficit read proves the
103
+ target satisfied. Repeated zero-yield work follows the contract's closed,
104
+ open, and single-fenced half-open circuit receipts.
105
+
106
+ Use the packet's campaign and sender names first. Preserve the six coverage
107
+ labels: `Need to prepare`, `Goal`, `Already sent`, `Scheduled`,
108
+ `Ready and waiting to be scheduled`, and `Still need`.
109
+
110
+ ## Approval and safety
111
+
112
+ Interactive mode posts the complete packet in normal chat, then asks one compact
113
+ host-native question with exactly `Accept` and `Decline`. Codex uses
114
+ `request_user_input`; Claude Code uses `AskUserQuestion`. Decline means no
115
+ mutation. A plain chat yes is not approval. Yolo is explicit bounded
116
+ auto-accept of the rendered packet only.
117
+
118
+ Preserve workspace access, approval, source-family, threshold, scheduler,
119
+ campaign-lifecycle, send-time, and no-direct-send gates. Never direct-send,
120
+ raw-write `scheduledFor`/`scheduledAt`, create/archive/delete campaigns, lower
121
+ paid InMail thresholds, mutate sender configuration, or broaden source family.
122
+ Only a packet-named paused campaign start or scheduler sweep may use the
123
+ existing product-gated path. A scheduler sweep is customer-visible and may
124
+ place unrelated eligible workspace cells within the approved global cap.
125
+
126
+ Proof is Sellable MCP evidence only: target plan, refill state, scheduler
127
+ capacity, complete target receipts, sender-dimensional changed counts, and
128
+ durable run events. Never use cell IDs, Prisma, SQL, direct database access, or
129
+ production scripts as completion proof.
130
+
131
+ ## Terminal report
132
+
133
+ Render `projected_full` only from canonical projected coverage. Otherwise name
134
+ the target-specific `concrete_blocker`, `deadline_reached`, `iteration_limit`,
135
+ or `operator_stopped` receipt. `ready_buffer_exists_is_not_complete`; ready rows
136
+ and `awaiting_scheduler_after_ready_buffer` are progress, not terminal success.
137
+
138
+ <!-- REFILL_CONTRACT_GENERATED:START -->
139
+ ## Generated refill contract metadata
140
+
141
+ contractVersion: 2.0.0
142
+ cacheVersion: refill-contract-v1
143
+ contractHash: e54ba0f80bc534fd70fd8c10c1caab109fe9a91c205cfc423f5f6735cd53fdc1
523
144
 
524
145
  ```text
525
- update_campaign({ campaignId, currentStep:null, clearCurrentStepIfMatches:"running" })
146
+ scope: workspace_id, target_date, sender_selectors, campaign_selectors, approval_mode, contract_identity, installed_identity
147
+ gates: approval_packet, one_primitive, fresh_reread, normalized_accounting, prep_circuit
148
+ release identities (independent of semantic hash): mcpPackageVersion, installPackageVersion, codexPluginVersion
149
+ forbidden: direct_send, raw_scheduler_write, campaign_create, campaign_archive_delete, threshold_lowering, unselected_source_mutation, unapproved_campaign_start, sender_config_write
150
+ terminal: 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
151
+ ready_buffer_exists_is_not_complete
526
152
  ```
527
-
528
- Then register provider preflight and run a campaign-scoped `search_signals` so
529
- post rows exist in the campaign's Signal Discovery state:
530
-
531
- ```text
532
- get_provider_prompt({ provider:"signal-discovery", campaignOfferId, confirmed:true })
533
- search_signals({ campaignOfferId, currentStep:"signal-discovery", confirmed:true, ... })
534
- ```
535
-
536
- Use `select_promising_posts` before importing. For a fresh source refill, prefer
537
- `selectionMode:"replace"` and `scrapePlanMode:"all-selected"`, then call
538
- `import_leads` without `targetEngagerCount` or `maxPostsToScrape` so the scrape
539
- uses the selected posts' max available engagers within backend provider caps.
540
- Do not invent, lower, or pass a people-to-check target for refill imports unless
541
- Christian explicitly supplied that target or post cap in the current request or
542
- approval packet. If Christian did supply an explicit `targetEngagerCount` or
543
- `maxPostsToScrape`, use `scrapePlanMode:"capacity-target"` and respect the
544
- under-capacity refusal: ask for approval to expand the selected post set or
545
- switch source instead of scraping a target-mismatched set.
546
-
547
- If `import_leads` returns `reusedExistingSourceList` but the user explicitly
548
- approved a different selected-post scrape, retry `import_leads` with the existing `sourceLeadListId` from that response or from refill state. For Signal
549
- Discovery this bypasses the stale reuse guard and materializes the newly
550
- selected campaign-scoped posts into a fresh source list.
551
-
552
- After `wait_for_lead_list_ready`, call `confirm_lead_list` with the new
553
- source-list id and same campaign id. Pass `currentStep:"running"` to `confirm_lead_list` for an ACTIVE already-running campaign so the watched state
554
- returns to Running after same-campaign source rows are copied. Do not call
555
- `update_campaign` to fake this after the copy; `confirm_lead_list` owns the
556
- post-copy state transition.
557
-
558
- Before any source mutation, show exact approval evidence: workspace id,
559
- campaign name, campaign id, workflow table id, source/provider id, source-list
560
- id when known, import caps, target dates/caps, dedupe/DNC/provider exclusion expectations, and expected row side effects. Present the campaign name and plain-English reason first; include ids only as proof and execution targets.
561
- Then reread `get_campaign_refill_state`; if `freshness.stateHash` or exact ids
562
- changed, stop and ask for a fresh approval.
563
-
564
- After source import, call `wait_for_lead_list_ready` and `confirm_lead_list`
565
- with the source-list id and campaign id. Imports append to the existing
566
- campaign/source path; they must not reset campaign state, sequence, sender
567
- assignment, current step, or watch state. If provider auth, rate limit, timeout,
568
- partial import, duplicate-only import, DNC-only result, CSV parse failure,
569
- readiness timeout, or `confirm_lead_list` failure occurs, stop before prep and
570
- report the blocker/retry path.
571
-
572
- ## Prep, Approval, And Scheduler Proof
573
-
574
- Existing rows normally move through enrichment/prep/approval using
575
- `start_campaign_message_preparation` and
576
- `get_campaign_message_preparation_status`. Standalone Generate Message is not the normal refill action;
577
- it is only for a manual/user-authored message path
578
- that requires it.
579
-
580
- Approval mode:
581
-
582
- - default is `approvalMode:"mark_ready"`, not approve;
583
- - use `approvalMode:"approve"` only when the user explicitly asks to approve
584
- messages or schedule sends and has approved the exact bounded cohort;
585
- - `start_campaign` is allowed only as a bounded start/resume step for a
586
- selected `PAUSED`, dashboard-active, campaign-backed sequence refill target;
587
- - never launch/start unrelated, archived, completed, draft, direct, or
588
- non-selected campaigns from refill.
589
-
590
- Paused campaign start discipline:
591
-
592
- - `PAUSED`, dashboard-active campaign-backed sequence campaigns are existing
593
- refill targets, not archived inventory.
594
- - If the route or active-campaign refetch marks a target as start-eligible, read
595
- `get_campaign_refill_state` for that campaign/table before deciding whether to
596
- start, prep, or skip it.
597
- - If the selected refill target is `PAUSED` and has healthy senders, sequence,
598
- source/list, and ready/preparable rows or a bounded source/prep packet, the
599
- final packet may include `start_campaign` when starting is needed for the
600
- scheduler to schedule/send approved eligible rows.
601
- - In non-yolo mode, the `Accept` choice must say that starting the paused
602
- campaign can let the product scheduler schedule/send approved eligible
603
- sequence actions.
604
- - In `--yolo`, `start_campaign` is auto-accepted only for the exact selected
605
- paused campaign ids, sender scope, caps, approval mode, and start side effect
606
- named in the packet after the final reread.
607
- - Do not start if the campaign is archived, completed, draft, direct, lacks a
608
- sequence/senders/source, has no viable row path, or state drifts.
609
-
610
- Before prep or approval mutation, reread `get_campaign_refill_state` and compare
611
- `freshness.stateHash`, campaign id, table id, workspace id, source id, and caps.
612
- If they changed, stop. A second concurrent refill run must see the first run's
613
- import/prep state on reread and avoid duplicate work.
614
-
615
- After the final reread and before the first mutating refill primitive, render
616
- one final approval packet in normal chat, in campaign-name-first language, so
617
- Codex/Claude can display the packet as Markdown. Then ask a host-native
618
- structured question with exactly two choices: `Accept` and `Decline`. The
619
- question is the execution boundary, but the full packet belongs in chat, not in
620
- the structured question body.
621
- Short form: exactly two choices: `Accept` and `Decline`.
622
-
623
- - In Codex interactive sessions, use `request_user_input`.
624
- - In Claude Code interactive sessions, use `AskUserQuestion`.
625
- - The normal chat message immediately before the structured question must
626
- include this exact operator output packet shape:
627
- - workspace name/id and mode (`--yolo` or approval-required);
628
- - sender scope, including selected sender names and skipped sender names with
629
- health/enrollment reasons;
630
- - a campaign-by-campaign plan table with campaign name, sender names, action,
631
- target count/cap, source/list, and blocker/skip reason;
632
- - exact workspace id, campaign id, workflow table id, source/action ids when
633
- relevant, freshness/state hash, caps/dates, approval mode, and the next
634
- MCP primitive to call;
635
- - expected side effects, including any exact-sender
636
- `refresh_paid_inmail_credits` credit-cache writes, forbidden actions, and the
637
- stop/rollback condition.
638
- - The structured question body must be compact and refer back to the posted
639
- chat packet. Do not duplicate the campaign table or full operator packet
640
- inside `request_user_input` / `AskUserQuestion`; refer back to the posted
641
- packet instead of duplicating it.
642
- - The `Accept` choice description must name that it accepts only the posted
643
- packet, with its exact workspace, campaign/table/source/action ids,
644
- caps/dates, approval mode, side effects, and stop condition.
645
- - The `Decline` choice must stop with no mutation.
646
- - Do not proceed from a plain chat "ok", "yes", "go", or "do it" when the
647
- structured question tool is available. If the structured question tool is not
648
- available in an interactive session, stop and tell the user the quick question
649
- panel is required for refill approvals. In non-interactive exec/automation,
650
- print the approval packet and stop before mutation.
651
-
652
- `--yolo` mode is explicit auto-accept. If Christian includes `--yolo` in the
653
- same refill request, do not ask the `Accept` / `Decline` question. Instead:
654
-
655
- 1. render the same final approval packet;
656
- 2. reread `get_campaign_refill_state` and, when the packet includes paid-InMail
657
- credit refreshes, verify the current `get_refill_target_plan` action
658
- candidates still name the same sender ids, campaign ids, table ids, and
659
- column ids;
660
- 3. verify the route, workspace id, campaign id, table id, source/action ids,
661
- caps/dates, approval mode, blockers, and side-effect class still match the
662
- packet;
663
- 4. execute only the exact packet;
664
- 5. after each terminal credit-refresh/apply/prep/source-copy/bounded-approval/read-only wait result, rerun
665
- `get_refill_target_plan`, reread state, settle processing when needed,
666
- recompute the target-window saturation ledger, and continue with the next smallest
667
- safe action inside the same bounded packet until every selected sender is
668
- saturated by projected coverage or blocked by non-scheduler evidence. Do not
669
- stop at "loaded" or "awaiting scheduler"; when no in-packet MCP mutation
670
- remains and ready rows cover the gap, keep the run open in read-only
671
- scheduler polling until the sender is projected-full or Christian stops it.
672
-
673
- In `--yolo`, do not stop after the first selected campaign if the request was
674
- sender-scoped and more selected senders or same-packet start-eligible campaigns
675
- remain. If the first candidate is duplicate-only, already loaded, awaiting
676
- scheduler, source-exhausted, or otherwise blocked, continue to the next
677
- same-sender candidate that was already in the rendered packet and still matches
678
- the fresh route/refill-state evidence. If no in-packet safe action remains, stop
679
- before mutation and return continuation options instead of guessing.
680
-
681
- Continuation options must be campaign-name-first and concrete. For each blocked
682
- sender/campaign, list the next viable options with exact ids and the approval
683
- boundary, for example: start an already selected start-eligible paused campaign,
684
- repair stale waterfall bindings, replenish the current source, expand Signal
685
- Discovery post selection, use the next same-sender campaign, or run evergreen
686
- setup/repair. Mark which options are covered by the current `--yolo` packet and
687
- which require a new approval packet.
688
- Short form: in `--yolo`, go as far as the packet safely allows, then give exact continuation options.
689
-
690
- `--yolo` authorizes `start_campaign` only for selected `PAUSED` refill targets
691
- named in the exact packet. It never authorizes starting unrelated, archived,
692
- completed, draft, or direct campaigns, separate launch/send actions,
693
- archive/delete cleanup, raw scheduler writes, sender reassignment, paid-InMail
694
- credit refreshes for senders not named in the packet, extra senders beyond the
695
- eligible sender set, or higher caps than the packet named. In
696
- sender-scoped `--yolo`, a bounded packet containing all eligible enrolled
697
- senders and at most one best campaign per sender is covered; arbitrary expanded
698
- campaign sets are not. If any state or scope drifts, stop and re-plan instead of
699
- auto-accepting the changed action.
700
- Short form: all eligible enrolled senders are covered by sender-scoped `--yolo`; arbitrary expanded campaign sets are not.
701
- Short form: direct scheduler writes are not covered by `--yolo`.
702
- Short form: stop and re-plan instead of auto-accepting the changed action.
703
-
704
- Before choosing a refill prep primitive, inspect the table frontier from
705
- `get_campaign_refill_state.preparationFrontier`. If
706
- `hasLaterPreparedIsland:true` or `earliestUnpreparedRow` exists before later
707
- successful enrichment, treat that as a top-down gap: use
708
- `select_campaign_cells`/`queue_campaign_cells` with
709
- `rowSelector:{ type:"needsEnrichment" }` and `columnRole:"enrich"` in bounded
710
- row-position order, or use `start_campaign_message_preparation` with the
711
- adaptive defaults for the full enrich -> rubric -> Generate Message loop. Do not
712
- use the UI Jump anchor as the automation cursor; Jump is a navigation affordance
713
- and can be fooled by a later enriched island.
714
-
715
- After same-campaign source copy, inspect the actual campaign-table position of
716
- the copied rows before starting prep. Newly copied rows often land after the
717
- first 100 table rows. Use `get_campaign_table_schema` to read the `reviewBatch`
718
- and `select_campaign_cells` diagnostics against
719
- `rowSelector:{ type:"reviewBatch" }` only to understand the copied row set. Do
720
- not operate on `reviewBatch` before earlier `needsEnrichment` rows unless the
721
- approved packet explicitly says to prioritize the just-copied bounded split and
722
- the earlier rows are exhausted, dependency-blocked, or intentionally excluded.
723
-
724
- For bounded split refills, prefer top-down `needsEnrichment` or adaptive
725
- `start_campaign_message_preparation` first. If the bounded packet explicitly
726
- uses `approvalMode:"approve"` because the user asked to fill/schedule sends or
727
- provided `--yolo` for a two-day send fill, inspect approval candidates with
728
- `rowSelector:{ type:"needsApproval" }` after current generated messages exist,
729
- then approve only the bounded cohort covered by the packet. Do not broad approve
730
- existing table rows.
731
-
732
- If enrich cells are pending or Generate Message cells are dependency-blocked,
733
- omit `maxRowsToCheck` so the adaptive prep job can cover the bounded table scan,
734
- or set a bounded cap high enough to include the necessary row-position frontier
735
- when row count evidence requires it. Do not run a fixed `maxRowsToCheck:100`
736
- prep pass after appending rows to a larger existing campaign table; it can spend
737
- the whole budget on older rows and miss the refill batch.
738
-
739
- Bound `targetPreparedMessages` to the actual ready-to-schedule gap for the
740
- selected campaign and sender set. In sender-scoped mode, compute and report the
741
- gap per sender. If ready/scheduled rows across active enrolled campaigns already
742
- cover a sender's gap, do not start prep for that sender; report that the sender
743
- is already loaded and awaiting the scheduler. If source inventory is available
744
- and the gap is small, prepare only the sender gap instead of filling every active
745
- campaign.
746
- Short form: prepare only the per-sender gap instead of filling every active campaign.
747
-
748
- Scheduled success requires a post-action reread proving scheduler-owned cells
749
- with non-null `scheduledFor`. Prepared, approved, and ready-to-schedule rows are
750
- intermediate states; report them as awaiting scheduler unless scheduled cells
751
- are present.
752
-
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
- preparedMessages can remain 0 while scheduler-ready state changes downstream.
762
- After a prep job reaches a terminal state, run `wait_for_campaign_processing`
763
- when generated/pass counts are still settling, then poll `get_campaign_refill_state` until `readyToSchedule` drops, scheduled counts increase, or the state clearly
764
- remains awaiting scheduler. Do not force scheduler fields directly.
765
-
766
- For requested fill/refill completion, continue the saturation loop after each
767
- poll: recompute projected target-window coverage by sender and date, subtract it
768
- from the requested target capacity, and decide whether another safe prep/import/
769
- approval pass is required. If projected coverage is still short and ready buffer
770
- is also short, run the next bounded MCP primitive that can create more eligible
771
- rows: `fill_campaign_horizon` for the selected evergreen target, or
772
- `start_campaign_message_preparation`, source import/replenishment, and bounded
773
- approval for the selected regular target. If projected coverage is short but
774
- ready buffer covers the gap, keep polling the scheduler until it fills, a
775
- concrete non-scheduler blocker appears, or Christian explicitly stops/statuses
776
- the run. Never mark the refill complete or blocked while a daily limit/readback
777
- equivalent would still show the selected send day below capacity and the only
778
- remaining state is scheduler pickup.
779
-
780
- ## Evergreen Campaign Discipline
781
-
782
- `fill_campaign_horizon` is a legacy evergreen-only lower-level primitive. Call it
783
- only after `resolve_campaign_fill_route` and `get_campaign_refill_state` prove an
784
- evergreen campaign target.
785
-
786
- For evergreen campaigns, do not advance down the source ladder while the current source can produce enough good prospects.
787
- The current source is exhausted, or
788
- unable to produce enough good prospects, only when evidence includes source id,
789
- target prospect gap, cursor/inventory state, dedupe/DNC/provider exclusions,
790
- good-prospect yield, and scan/import caps. If that proof is missing, continue
791
- the current source or ask for more research instead of walking the ladder.
792
-
793
- ## Hard Safety Rules
794
-
795
- - Never call launch/start tools except `start_campaign` for an exact selected
796
- `PAUSED`, dashboard-active, campaign-backed sequence refill target in the
797
- rendered packet.
798
- - Never raw-write `scheduledFor`, `scheduledAt`, scheduled status, or sender
799
- assignment fields.
800
- - Never expose internal direct campaign types as an operator refill path.
801
- - Never claim scheduled success without rereading scheduler-owned cells with
802
- non-null `scheduledFor`.
803
- - Never call `refresh_paid_inmail_credits` except for exact sender ids named in
804
- the rendered refill packet; after refresh, rerun `get_refill_target_plan` and
805
- stop if the fresh status is still missing, stale, below threshold, or drifts to
806
- a different campaign/table/column.
807
- - No mutation in production unless Christian explicitly approves exact
808
- workspace, campaign/table ids, source/action ids, caps/dates, approval mode,
809
- expected side effects, and rollback/stop condition.
810
- - In interactive Codex or Claude Code, that explicit approval must be collected
811
- through the host-native `Accept` / `Decline` question gate.
812
- - `--yolo` in the current refill request is explicit auto-accept for the
813
- rendered bounded refill packet only; it does not loosen the unrelated-campaign
814
- start/send, scheduler-write, archive/delete, or drift rules above.
815
-
816
- ## Report
817
-
818
- Report in campaign-name-first language:
819
-
820
- - selected campaign name(s), target type, and sender names;
821
- - why they were selected, including last scheduled send date/future scheduled
822
- send evidence and sender overlap;
823
- - whether the smallest next step is enrich/prep more in that campaign, add rows
824
- to that campaign/source, use a different existing campaign, or ask what to
825
- create;
826
- - source state, blockers, exact next primitive, approval required, and the
827
- freshness hash used.
828
- - for `--yolo`, how far the run continued automatically, which selected senders
829
- are loaded/scheduled/awaiting scheduler, and the exact continuation options for
830
- any sender/campaign that remains blocked.
831
-
832
- Keep ids visible but secondary: show them under "Exact target" or "Proof", not
833
- as the main decision text. Say explicitly whether a selected paused campaign was
834
- started; otherwise say nothing was started and nothing was sent.
153
+ <!-- REFILL_CONTRACT_GENERATED:END -->