@sellable/mcp 0.1.556 → 0.1.557

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