@sellable/install 0.1.758 → 0.1.760-wip.refill-autonomy.20260920190349
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.
- package/lib/sellable-agent/default-profile-bundles/shared/manifest.fragment.json +1 -1
- package/lib/sellable-agent/default-profile-bundles/shared/skills/sellable/sellable-refill-sends/SKILL.md +17 -2
- package/lib/sellable-agent/fly-admin-image/Dockerfile +1 -1
- package/lib/sellable-agent/fly-customer-image/Dockerfile +1 -1
- package/lib/sellable-agent/public-skills.json +1 -1
- package/package.json +1 -1
- package/skill-templates/refill-sends.md +17 -2
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"ownership": "system_managed",
|
|
22
22
|
"path": "skills/sellable/sellable-refill-sends/SKILL.md",
|
|
23
23
|
"mode": "0444",
|
|
24
|
-
"content": "---\nname: sellable-refill-sends\ndescription: Refill projected sends across a workspace or selected senders through the canonical fenced coordinator.\nvisibility: public\nallowed-tools:\n - mcp_sellable_refill_sends\n - mcp_sellable_get_auth_status\n - mcp_sellable_start_cli_login\n - mcp_sellable_wait_for_cli_login\n - mcp_sellable_get_active_workspace\n - mcp_sellable_list_workspaces\n - mcp_sellable_set_active_workspace\n - mcp_sellable_get_subskill_prompt\n - mcp_sellable_get_subskill_asset\n - mcp_sellable_search_subskill_prompts\n - mcp_sellable_get_scheduler_fill_capacity\n - mcp_sellable_run_scheduler_sweep\n - mcp_sellable_refresh_paid_inmail_credits\n - mcp_sellable_list_senders\n - mcp_sellable_get_sender_routing\n - mcp_sellable_get_campaign_waterfall\n - mcp_sellable_resolve_campaign_fill_route\n - mcp_sellable_get_campaign_refill_state\n - mcp_sellable_get_refill_target_plan\n - mcp_sellable_fill_campaign_horizon\n - mcp_sellable_get_campaign\n - mcp_sellable_get_campaign_context\n - mcp_sellable_update_campaign\n - mcp_sellable_get_provider_prompt\n - mcp_sellable_get_campaign_message_preparation_status\n - mcp_sellable_start_campaign_message_preparation\n - mcp_sellable_cancel_campaign_message_preparation\n - mcp_sellable_import_leads\n - mcp_sellable_wait_for_lead_list_ready\n - mcp_sellable_confirm_lead_list\n - mcp_sellable_search_signals\n - mcp_sellable_select_promising_posts\n - mcp_sellable_fetch_post_engagers\n - mcp_sellable_search_sales_nav\n - mcp_sellable_lookup_sales_nav_filter\n - mcp_sellable_search_prospeo\n - mcp_sellable_search_prospeo_companies\n - mcp_sellable_confirm_prospeo_company_accounts\n - mcp_sellable_load_csv_linkedin_leads\n - mcp_sellable_load_csv_domains\n - mcp_sellable_list_dnc_entries\n - mcp_sellable_load_csv_dnc_entries\n - mcp_sellable_get_rows\n - mcp_sellable_get_rows_minimal\n - mcp_sellable_get_table_rows\n - mcp_sellable_get_campaign_table_schema\n - mcp_sellable_select_campaign_cells\n - mcp_sellable_queue_campaign_cells\n - mcp_sellable_wait_for_campaign_processing\n - mcp_sellable_get_sender\n---\n\n# Refill Sends\n\n## Installed Host Contract\n\nThis installed skill is running in Hermes Agent. When the shared workflow body\nor fallback text mentions Claude Code, Codex, or Hermes for internal parity,\nchoose the Hermes instruction for customer-facing language and host functions.\n\n- Customer-facing command: `/sellable-refill-sends`\n- MCP tool naming: Hermes exposes Sellable tools as `mcp_sellable_<tool>`;\n when shared instructions show `mcp_sellable_<tool>`, call the matching\n `mcp_sellable_<tool>` tool instead.\n- Structured questions: ask plainly in chat unless a Hermes-native approval or\n question tool is visible in the current session.\n- Bootstrap host label: `host: \"Hermes\"`\n- Install/reload blocker label: Hermes install/reload problem\n- Reload instruction: restart Hermes, or run `/reload-mcp` in the active\n Hermes session after install\n\nDo not tell Hermes users to run Codex or Claude command forms, use Codex/Claude structured-question APIs, or restart Codex Desktop or Claude Code. Do not describe this run as Claude Code or Codex.\n\nUse this skill for “fill”, “refill sends”, “max out sends”, “load everyone up”,\nor “fill horizon sends”. Exactly one coordinator owns execution: `refill_v3_advance`\non the V3 route, `refill_sends` on the V1 route. The host resolves the request,\ninvokes that coordinator, and follows its exact continuation; it never\nreconstructs the refill ladder from low-level tools.\n\nHost commands:\n\n- Claude Code: `/sellable-refill-sends`\n- Codex: `/sellable-refill-sends`\n\n## Scheduled customer-program entry\n\nA scheduled invocation is one downstream action of the existing customer\nprogram. It does not create a second refill loop or choose a new campaign. The\nprogram wrapper supplies one already-claimed home workspace plus its exact\ncampaign/sender cohort and one to three sender-local dates. Use that exact scope,\npass `yolo:true` to the same canonical Refill V3 advance/continue flow below,\nand retain the server-issued run continuity until the run settles. Never switch\nan Admin runtime to another workspace, widen the cohort, add dates, or create a\nchild schedule.\n\nReuse a persisted refill enrollment and its approved campaign, exclusion,\nsource, message, and sender rules. A human pause, a missing enrollment, a\nnever-launched campaign, legacy PAUSED state with no provenance, or generation\ndrift is a hold. Return the one exact decision or action the customer must take;\ndo not restart the campaign, invent permission, or ask for the same permission\nevery morning. An explicit authenticated Start/resume remains human-owned.\n\nScheduled results use five product meanings:\n\n- `settled`: independent readback proves the exact scheduled additions.\n- `partial`: some additions are proven and the remaining exact gaps/blockers are\n named.\n- `pending`: the same run or scheduler receipt is still active; retain and poll\n that identity.\n- `blocked`: no allowed next mutation exists; name the precise human or provider\n action and safe retry condition.\n- `quiet`: coverage was already healthy or routine maintenance settled with no\n customer action. Make the result available to the daily review; do not post a\n second routine message.\n\nInteractive `refill-sends --yolo` always receives its actual result immediately.\nState connection invitations and paid InMail separately: invitation capacity is\nnot paid InMail credit, and paid InMail coverage is never proof of invitation\ncoverage. “Added” means scheduler-owned rows with a non-null scheduled time; it\nnever means LinkedIn delivered them.\n\n## Route selection — do this FIRST\n\nDecide the route before parsing scope, before loading any flow asset, and before\nany tool call other than auth/workspace resolution. The predicate is\nMECHANICAL and observable in the connected Sellable MCP tool list:\n\n> **Is `refill_v3_advance` one of the tools this server exposes?**\n\n- **Yes → take the Refill V3 route.** This is the default for every workspace on\n a server that exposes the tool. Go to [Refill V3](#refill-v3) and follow it;\n the V1 ladder in the rest of this document does not apply.\n- **No → take the V1 route.** The installed server predates Refill V3, so\n `refill_sends` is the only coordinator available. Follow this document from\n [Entry and exact scope](#entry-and-exact-scope) onward.\n\nNever infer the route from a workspace flag, a campaign field, a tool result, or\nthe operator's wording: no such cutover signal exists, and guessing at one is\nwhat makes an ordinary refill request silently take the wrong route. Report the\nselected route explicitly before the first coordinator call.\n\n## Entry and exact scope\n\nEverything from here down to [Refill V3](#refill-v3) is the **V1 route**. Skip it\nentirely when route selection chose V3. On this route `refill_sends` is the only\nexecution owner and the host follows its exact continuation; it never\nreconstructs the refill ladder from low-level tools.\n\nAccepted request fields are `--yolo`, `workspaceId`, `--sender`/`senderIds`/\n`senderNames`, `actionTypes`, `--until`/`untilDate`, `--target-date`/\n`targetDate`, and compatibility `horizonSendDays`. Omitted dates mean the\nscheduler-forward 48-hour window. `untilDate` is sender-local and inclusive;\n`targetDate` is one sender-local scheduler-fillable date. Skip no-send days and\nnever extend beyond the requested date. Finish the full D1 reread before D2.\nOrdinary refill defaults to `yolo:true`; only an explicit `yolo:false` or a\nclear request for review-first/manual execution opts out.\n\n```text\nrefill_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\", runHandle?: RefillRunHandleV1, targetConfig?: RefillTargetConfigV1, reportingContext?: RefillReportingContextV2, messageTemplateRevision?: MessageTemplateRevisionV1 })\n```\n\n```mermaid\nflowchart TD\n A[\"Parse the operator request\"] --> AUTH{\"Sellable auth valid?\"}\n AUTH -- No --> LOGIN[\"Run the returned login flow and wait\"]\n LOGIN --> AUTH\n AUTH -- Yes --> WS[\"Resolve exact workspace by ID, exact name, or install mapping\"]\n WS --> WSG{\"One accessible workspace match?\"}\n WSG -- No --> WB[\"Output: blocked_retryable / WORKSPACE_REQUIRED or workspace_ambiguous\"]\n WSG -- Yes --> SENDERS[\"Resolve each sender inside that workspace by ID, exact name, or unambiguous prefix\"]\n SENDERS --> SG{\"Every selector resolves exactly?\"}\n SG -- No --> SB[\"Output: blocked_retryable / sender_selector_unresolved with candidates\"]\n SG -- Yes --> DATE[\"Normalize 48h, exact targetDate, or inclusive untilDate in sender-local time\"]\n DATE --> ROUTE{\"Does this server expose refill_v3_advance?\"}\n ROUTE -- Yes --> V3[\"Refill V3 route: load core/flow.v3.json and call refill_v3_advance\"]\n ROUTE -- No --> D1[\"D1: call get_refill_target_plan read-only with exact scope\"]\n D1 --> RENDER[\"Render sender/campaign waterfall, coverage ledger, first action, side effects, forbidden actions, and stop condition\"]\n RENDER --> D2[\"D2: call refill_sends with workspaceCoordinator true plus displayed targetShapeRevision and actionKey\"]\n```\n\nScheduled and `--yolo` execution require an explicit `workspaceId` on every\ncall. Never change the shared active workspace to control an automation, never\nfall back to its full fleet, and never mutate the workspace that merely happens\nto be active. If the native tool is unavailable, use only the host’s exact\nconfigured Sellable MCP transport; otherwise stop with `sellable_mcp_unavailable`\ninstead of manually reproducing the workflow.\n\nBefore product work, load the closed workflow asset completely and verify it:\n\n```text\nget_subskill_prompt({ subskillName: \"refill-sends-workflow\" })\nget_subskill_asset({ subskillName: \"refill-sends-workflow\", assetPath: \"core/flow.v1.json\" })\n```\n\nContinue chunks until `hasMore:false`; require `workflow:\"refill-sends-workflow\"`\nand a COMPATIBLE version: same major (`v1`) and minor at or above the minimum\n`v1.9` — so `v1.9`, `v1.10` pass while `v1.8` and `v2.x` do not. Report the\nverified version before D1. A missing, unparseable, wrong-major, or\nbelow-minimum version is `workflow_version_mismatch`: stop before\n`get_refill_target_plan` or mutation. Do NOT require exact string equality: the\nflow asset ships in the npm package while this skill is installed separately,\nso an exact pin makes every additive contract change a breaking one.\nRoute intent is immutable: ordinary refill uses `intent:\"auto\"` from first plan\nthrough terminal; explicit `yolo:false` uses the review-first path.\n\n## Mandatory visible plan before execution\n\nEvery refill in every mode begins with D1, a read-only\n`get_refill_target_plan` with the exact workspace, sender/action selectors, and\ndate envelope. For default yolo execution, the first D1 call must explicitly pass\n`approvalMode:\"approve\"`; never rely on the planner's `mark_ready` default and\nthen discover the scope mismatch at D2. Invoke D1 exactly once, retain and parse\nthat response in the same host composition, and never call D1 again only to\nformat or render it. Render its plan in normal chat before any mutation. At minimum,\nshow one row per selected sender/campaign lane with sender, campaign, lane/source\nfamily, planned first action, target/cap, sent, scheduled, ready, still needing\npreparation, fallback order, and blocker/skip reason. Then show the bounded side\neffects, forbidden actions, stop condition, `targetShapeRevision`, and first\n`globalActionQueue[0].actionKey`.\n\nIf a stale or missing paid-credit fact prevents a certified fillable cap, show\n`pending credit refresh`, never bare `unknown`. The target remains visible and\nyolo executes the displayed refresh action before replanning the numeric cap.\n\nAfter rendering D1, explicit `yolo:false` asks Accept or Decline and invokes\nonly the returned `planned_manual_run` after Accept. Default `yolo:true` does\nnot ask: call\n`refill_sends` D2 with `workspaceCoordinator:true`, the identical scope, and\nboth `expectedTargetShapeRevision` and `expectedActionKey` copied from the\ndisplayed packet. The server may itself return `status:\"plan_ready\"`; render\nthat returned plan before invoking `planned_manual_run` or\n`planned_workspace_run`. Thus the modes share the exact same visible plan and\nrevision fence. The only difference is that non-yolo pauses for decisions while\n`--yolo` auto-accepts the displayed packet and autonomously traverses every\nplanner-ranked existing campaign, lane, source, safe rubric trial, and scheduler\nhandoff until terminal. If either pin drifts, render the fresh read-only\nreplacement packet; do not mutate from the stale plan. No credit refresh, fence,\nor product mutation may exist before this render.\n\n## Coordinator lifecycle\n\n```mermaid\nflowchart TD\n A[\"Fresh read-only workspace refill plan rendered to the user\"] --> FULL{\"Projected coverage sent + scheduled is full?\"}\n FULL -- Yes --> COMPLETE[\"Terminal: complete\"]\n FULL -- No --> ACTIVE{\"Active exact fenced run exists?\"}\n ACTIVE -- Yes --> RESUME[\"Resume only issued runId, fence, targetConfig, reportingContext\"]\n ACTIVE -- No --> PICK[\"Select globalActionQueue 0\"]\n PICK --> PREFLIGHT[\"Exact campaign, table, sender, action, lane preflight\"]\n PREFLIGHT --> ACT[\"Execute one bounded planner action\"]\n RESUME --> ACT\n ACT --> OUTCOME{\"Canonical outcome?\"}\n OUTCOME -- \"Committed or canonical no-op\" --> A\n OUTCOME -- \"Still running\" --> WAIT[\"Bounded read-only wait or receipt reconciliation\"]\n WAIT --> A\n OUTCOME -- \"Source exhausted\" --> NEXT{\"Another planner-ranked existing target?\"}\n NEXT -- Yes --> HANDOFF[\"Terminalize exact fence as next_exact_target\"]\n HANDOFF --> A\n NEXT -- No --> NC[\"Terminal: new_campaign_required; ask whether to create it\"]\n OUTCOME -- \"Provider unavailable after one retry\" --> RETRY[\"Terminal: blocked_retryable; universeExhausted false\"]\n OUTCOME -- \"Scope, config, readiness, or receipt drift\" --> BLOCK[\"Terminal: blocked_retryable with exact blocker\"]\n OUTCOME -- \"Planner marker done\" --> DONE[\"Terminalize marker; never dispatch it\"]\n```\n\nIf `status:\"plan_ready\"`, render its full plan packet first. Non-yolo asks for\nAccept or Decline before `planned_manual_run`; `--yolo` invokes\n`planned_workspace_run` automatically. If `status:\"in_progress\"`, invoke only the returned\n`continuation.arguments`. `targetConfig` and `runHandle` are separate and remain\nunchanged except for a server-issued takeover fence. `active_exact_run` resumes\nthat fence; `next_exact_target` carries no stale run fence. Never open a second\nor overlapping run, ask the user to type “continue”, redispatch a control marker, or\nturn `done`, `next_campaign`, or a continuation object into a product action.\n\n## Per-sender campaign and lane waterfall\n\nUse managed evergreen order when healthy. Otherwise build the same waterfall\non the fly from existing eligible campaigns the sender is already attached to.\nThis makes regular and evergreen campaigns differ only in where ordering comes\nfrom, not in how refill proceeds.\n\n```mermaid\nflowchart TD\n A[\"All existing campaign-backed sequences attached to one sender\"] --> FILTER[\"Exclude wrong workspace/sender, archived, completed, direct, disconnected, or sequence-invalid targets\"]\n FILTER --> STALE{\"Managed waterfall complete and live?\"}\n STALE -- Yes --> MANAGED[\"Use configured priority order\"]\n STALE -- No --> DERIVE[\"Derive deterministic order from dashboard-active campaigns\"]\n DERIVE --> P1[\"Prefer canonical source/lane priority\"]\n P1 --> P2[\"Then future scheduled and ready inventory\"]\n P2 --> P3[\"Then recent successful sends and source health\"]\n P3 --> P4[\"Then active before exact start-eligible paused, recency, stable ID\"]\n MANAGED --> PIN[\"Pin exact per-sender and per-action lane chain for this run\"]\n P4 --> PIN\n PIN --> LANE[\"Select highest-priority non-exhausted lane\"]\n LANE --> REFILL[\"Run row lifecycle\"]\n REFILL --> EX{\"Lane structurally exhausted?\"}\n EX -- No --> REFILL\n EX -- Yes --> MORE{\"Another pinned existing lane or source family?\"}\n MORE -- Yes --> LANE\n MORE -- No --> END[\"Output: lanes_exhausted, then new_campaign_required if coverage still short\"]\n```\n\nCampaign enrollment/removal, missing pinned targets, or loss of eligibility is\ntyped scope drift; a fresh planner may rederive, but the host cannot silently\nsubstitute a target. A current dashboard-active `PAUSED` campaign is eligible\nonly when the planner names that exact campaign as start-eligible. Starting it\nmay let the product scheduler schedule/send approved sequence actions and must\nbe reported. DMs are follow-ups, not refill horizon targets. Mixed sequences\nkeep distinct exact target paths; do not choose campaign-union behavior.\n\n## Connection and InMail capacity overlay\n\n```mermaid\nflowchart TD\n S[\"Sender capacity and exact selected days\"] --> C{\"Connection slots available now or later in rolling week?\"}\n S --> F{\"Paid-InMail credit facts fresh?\"}\n F -- No --> RF[\"Refresh exact selected sender once per run, then replan\"]\n RF --> P{\"Credits meet existing threshold, normally 5?\"}\n F -- Yes --> P\n C -- Yes --> INV[\"Enable existing invite lanes\"]\n C -- No --> INVCAP[\"Cap invite lane with timing evidence\"]\n P -- Yes --> MAIL[\"Enable existing paid-InMail or cascade lane\"]\n P -- No --> MAILCAP[\"Skip paid lane; never lower threshold\"]\n INV --> UNION[\"Rank enabled existing lanes per sender\"]\n MAIL --> UNION\n INVCAP --> ALT{\"Paid lane enabled?\"}\n MAILCAP --> ALT2{\"Invite or same-campaign connection fallback enabled?\"}\n ALT -- Yes --> UNION\n ALT -- No --> CAP[\"Output: blocked_retryable / capacity or window\"]\n ALT2 -- Yes --> UNION\n ALT2 -- No --> CAP\n UNION --> POOL[\"Pool shared-campaign prepared inventory; never double-enrich\"]\n```\n\n`rollingWeeklyInvite.capacityFreedDuringWindow:true` means later capacity is\nschedulable; use its timing fields rather than treating the opening gate as a\nfull-day blocker. Credit freshness precedes scheduler wait. Fresh facts below\nthreshold authorize only an already-eligible existing connection fallback or\nanother existing campaign—not a threshold change or new campaign.\n\n## Row lifecycle\n\nFor every selected lane, use the smallest action that can reduce its gap.\n\n```mermaid\nflowchart TD\n A[\"Lane still has projected gap\"] --> ACTIVE{\"Active import, preparation, or stuck work?\"}\n ACTIVE -- \"Healthy active\" --> WAIT[\"Bounded read-only wait; honor wait.deadlineAt\"]\n WAIT --> A\n ACTIVE -- \"Stuck or anomalous\" --> REPAIR[\"Run only planner-bounded repairable cells or return blocker\"]\n REPAIR --> A\n ACTIVE -- No --> APPROVE{\"Generated rows can be approved?\"}\n APPROVE -- Yes --> AP[\"Approve exact bounded cohort with readiness authority\"]\n AP --> REPLAN[\"Record receipt and full authoritative replan\"]\n APPROVE -- No --> ENRICH{\"Existing rows can be enriched or prepared?\"}\n ENRICH -- Yes --> PREP[\"Enrich, generate, or rerun exact bounded cohort\"]\n PREP --> REPLAN\n ENRICH -- No --> SOURCE{\"Selected source can add qualified rows?\"}\n SOURCE -- Yes --> ADD[\"Copy/import bounded rows from exact selected source\"]\n ADD --> REPLAN\n SOURCE -- No --> EXPAND[\"Run source-family acquisition flow\"]\n EXPAND --> REPLAN\n REPLAN --> A\n```\n\nStructural exhaustion requires receipt-proven\n`hasMoreFrontierRows:false`, zero `approvalCandidates`, no fresh active prep,\nno `stuckActiveCells`, and no non-terminal `approvedNotDispatched` work. A dry\npreparation receipt is run-scoped and prevents the identical no-op from\nrepeating. `USER_ADDED_ROWS_LIMIT_EXCEEDED` may use a bounded same-source split\nthrough `load_csv_linkedin_leads` into the exact review batch; a true campaign\ntable hard cap returns a capacity blocker and never deletes rows.\n\n## Sender Post Engagers acquisition\n\n```mermaid\nflowchart TD\n A[\"Sender Post Engagers lane needs rows\"] --> UNUSED{\"Unused selected post/engager rows exist?\"}\n UNUSED -- Yes --> USE[\"Import/copy bounded unused rows\"]\n UNUSED -- No --> REFRESH[\"Refresh this sender's latest recent authored posts\"]\n REFRESH --> SELECT[\"Select new unprocessed relevant high-engagement posts\"]\n SELECT --> FETCH[\"Fetch/import their engagers and dedupe\"]\n FETCH --> YIELD{\"Usable qualified yield?\"}\n YIELD -- Yes --> USE\n YIELD -- No --> EX[\"Exhaust only this Post Engagers lane\"]\n EX --> NEXT[\"Advance to Shared Signal Discovery or next pinned existing lane\"]\n```\n\nThe campaign must be sender-owned: exactly that sender, authored posts only.\nNever invent keywords, search third-party posts, or run general Signal Discovery\nagainst the Post Engagers campaign.\n\n## Shared Signal Discovery acquisition\n\n```mermaid\nflowchart TD\n A[\"Shared Signal lane needs rows\"] --> UNUSED{\"Unused selected rows or unprocessed posts exist?\"}\n UNUSED -- Yes --> USE[\"Import/copy bounded rows\"]\n UNUSED -- No --> STALE[\"Re-search stale existing topics for newly published posts\"]\n STALE --> SY{\"Projected qualified yield meets min remaining gap or 100?\"}\n SY -- Yes --> USE\n SY -- No --> DERIVE[\"Derive up to five concise positive-ICP topics from approved campaign intent\"]\n DERIVE --> DY{\"Projected qualified yield meets floor?\"}\n DY -- Yes --> USE\n DY -- No --> AGENT[\"Request 3-5 new agent-supplied topics through the same fenced continuation\"]\n AGENT --> SEARCH[\"Search once, excluding searchedKeywords, then project actual returned candidates\"]\n SEARCH --> PROVIDER{\"All LinkedIn providers failed?\"}\n PROVIDER -- Yes --> RETRY[\"Retry the same bounded search once\"]\n RETRY --> RECOVER{\"Provider recovered?\"}\n RECOVER -- No --> BLOCK[\"Output: blocked_retryable / provider_unavailable; universeExhausted false\"]\n RECOVER -- Yes --> AY{\"Actual qualified yield meets floor?\"}\n PROVIDER -- No --> AY\n AY -- Yes --> USE\n AY -- No --> EX[\"Receipt-proven signal_yield_below_floor\"]\n EX --> NEXT[\"Advance to next pinned existing lane\"]\n```\n\nProvider outage never consumes a keyword tier or proves exhaustion. Temporary\nderived search state is run-scoped; later runs may rediscover new posts. Agent\nkeywords are supplied only through the exact run continuation, never by user\nsteering or a second run.\n\n## Sales Nav and Prospeo acquisition\n\n```mermaid\nflowchart TD\n A[\"Cold-provider lane needs rows\"] --> UNUSED{\"Unused exact-source rows exist?\"}\n UNUSED -- Yes --> USE[\"Import/copy bounded rows\"]\n UNUSED -- No --> DEEP[\"Continue latest/unfetched pages of exact saved Sales Nav or Prospeo search\"]\n DEEP --> DY{\"Qualified yield?\"}\n DY -- Yes --> USE\n DY -- No --> OPTIONAL{\"Known activity/recency filter exists?\"}\n OPTIONAL -- No --> NEXT[\"Advance to next pinned existing lane\"]\n OPTIONAL -- Yes --> CLONE[\"Clone exact approved search; remove one optional activity/recency filter\"]\n CLONE --> PROOF{\"Original unchanged and every hard-fit filter fingerprint preserved?\"}\n PROOF -- No --> BLOCK[\"Output: blocked_retryable / provider_search_drift\"]\n PROOF -- Yes --> TRIAL[\"Import bounded trial candidates into existing gated source\"]\n TRIAL --> GATE[\"Run current ICP, exclusion, DNC, persona, geography, and company-fit gates\"]\n GATE --> GY{\"Qualified yield?\"}\n GY -- Yes --> USE\n GY -- No --> QUARANTINE[\"Rejects remain unsendable; advance lane\"]\n QUARANTINE --> NEXT\n```\n\nThe original saved search is immutable. An automatic trial may remove only a\nknown activity/recency signal; role, seniority, geography, industry, company\nsize, domain, include/exclude, DNC, and every other hard-fit constraint remain\nbyte-for-byte. Imported candidates are not approvals: current campaign gates\nquarantine bad fits. If rubric rejects dominate — including a receipt-proven\n`low_yield` cohort below the 10% planning floor, not only zero-prepared — enter\nthe bounded sample-quality trial below before another source add. Do not repeat\na spent trial or switch outside planner order.\n\n## Provider prompt before any new provider search\n\nDraining an already-imported source list needs no provider context. But before\nany action that runs a NEW provider search — a `broaden_signal_search` round\n(especially when supplying `agentKeywords`), a Sales Nav or Prospeo cloned-\nsearch broadening, or any source add that dispatches a fresh search — load the\nmatching specialized prompt first with\n`get_provider_prompt({ provider, campaignOfferId })` and apply its discipline:\nsample-first fit checks against the headline ICP criteria, the 10% planning\nfloor, sample math (target ÷ observed pass rate) for sizing, and the keyword-\nquality guidance for Signal Discovery. Inventing broaden keywords or sizing a\nscrape without the provider prompt in context repeats the blind-import failure\nthe sampling discipline exists to prevent. The search tools also enforce this\npreflight server-side; loading it late wastes a fenced round on a typed refusal.\n\n## Rubric sample-quality trial\n\nRubric rejection may mean the source is poor or that one or several required\nchecks are unnecessarily narrow. Decide from an exact sample, not pass-rate alone.\n\n```mermaid\nflowchart TD\n A[\"Rows fail ICP/rubric gate\"] --> STALE{\"Score stale, errored, or computed under mismatched authority?\"}\n STALE -- Yes --> RESCORE[\"Rerun exact bounded cohort under unchanged current rubric\"]\n RESCORE --> RESULT{\"Now qualified?\"}\n RESULT -- Yes --> CONTINUE[\"Continue row lifecycle\"]\n RESULT -- No --> SAMPLE\n STALE -- No --> SAMPLE[\"Take exact representative rejected sample from prep receipt\"]\n SAMPLE --> SNAP[\"Snapshot complete rubric and prior digest\"]\n SNAP --> PROPOSE[\"Propose smallest 1-3 required-to-advisory bundle that creates useful new passes\"]\n PROPOSE --> HARD{\"Touches employment, DNC/opt-out, legal/compliance, or explicit exclusion?\"}\n HARD -- Yes --> REJECT[\"Reject proposal; preserve complete prior rubric\"]\n HARD -- No --> SIM[\"Simulate bundle from recorded per-prospect evaluations; no mutation\"]\n SIM --> DELTA{\"Any newly passing prospects?\"}\n DELTA -- No --> REJECT\n DELTA -- Yes --> QUALITY[\"Review only newly passing profiles in campaign and customer context\"]\n QUALITY --> REPLY{\"If these prospects replied, would the customer be comfortable and consider the replies relevant?\"}\n REPLY -- No --> REJECT\n REPLY -- Yes --> DRIFT{\"Live rubric digest still equals prior digest?\"}\n DRIFT -- No --> BLOCK[\"Output: blocked_retryable / rubric config drift\"]\n DRIFT -- Yes --> APPLY[\"Guarded apply entire required-to-advisory bundle\"]\n APPLY --> EXACT[\"Force exact bounded ICP rescore for accepted sample\"]\n EXACT --> VERIFY{\"Dispatch and accepted quality receipt valid?\"}\n VERIFY -- Yes --> KEEP[\"Keep bundle; receipt before/after digests, changed checks, sample counts, and verdict\"]\n VERIFY -- No --> ROLLBACK[\"Restore complete prior snapshot and receipt rollback\"]\n REJECT --> BETTER[\"Keep rows unsendable; continue better supply or next existing lane\"]\n ROLLBACK --> BETTER\n```\n\n`--yolo` may change more than one required rubric at a time only through this\nsingle bounded reversible bundle. The change demotes selected required checks to\nadvisory scoring; it does not erase their evidence. The acceptance test is the\nnewly passing delta: if any reviewed prospect would make the customer unhappy,\nsurprised, or consider the reply irrelevant, keep the complete prior rubric and\ncontinue the source waterfall. Never expose raw prospect profiles in the public\nreceipt.\n\n## Scheduler and uncertain-receipt recovery\n\n```mermaid\nflowchart TD\n A[\"Ready buffer covers remaining projected gap\"] --> CREDIT{\"Every selected paid lane has fresh credit facts?\"}\n CREDIT -- No --> RF[\"Refresh each exact selected sender once, then full replan\"]\n RF --> A\n CREDIT -- Yes --> DATE{\"Exact targetDate?\"}\n DATE -- Yes --> SWEEP[\"Dispatch one request-scoped product scheduler sweep\"]\n DATE -- No --> WAIT[\"Enter coordinator-owned bounded scheduler wait\"]\n SWEEP --> RECEIPT{\"Receipt state?\"}\n RECEIPT -- Terminal --> READ[\"Canonical target-plan and request/effect readback\"]\n RECEIPT -- Active --> POLL[\"Return in_progress and poll only the same request key\"]\n RECEIPT -- uncertain_outcome --> RECON[\"Reconcile same request key read-only; never redispatch\"]\n POLL --> RECEIPT\n RECON --> TERM[\"Terminal: blocked_retryable with request identity intact\"]\n WAIT --> READ\n READ --> FULL{\"Projected coverage full?\"}\n FULL -- Yes --> COMPLETE[\"Terminal: complete\"]\n FULL -- No --> READY{\"Ready buffer still covers gap?\"}\n READY -- Yes --> OTHER{\"Any other workspace target still needs preparation or an executable gate?\"}\n OTHER -- Yes --> PREP[\"Continue next planner-ranked exact target\"]\n OTHER -- No --> BLOCK[\"Terminal: receipt-backed blocked_retryable scheduler gap\"]\n READY -- No --> PREP[\"Return to row lifecycle\"]\n```\n\nA scheduler sweep is a visible workspace-wide scheduling side effect: existing\nproduct gates may schedule unrelated eligible cells in that workspace/date.\nIt never sends directly or raw-writes scheduler fields. `cellsConsidered is\nallocation-attempt count`; `readyCellsFound` is prefilter inventory. Inspect\n`campaignScopeSummary`, `prefiltered`, `skipped`, and `deferred`. For ready\nclosed-InMail cells with stale paid-credit evidence, use\n`refresh_paid_inmail_credits_then_rerun`. `wait_for_capacity_or_window` means do\nnot source or prep more rows; `no_ready_cells_continue_refill_prep` returns to\nthe row lifecycle. `cellsScheduled:0` alone is not failure. Once a sweep is\ndispatched, a host wait budget yields an `in_progress` continuation carrying\nthe same run identity. Keep polling that request key until its official\nterminal receipt, then reread the full target plan. Never convert an active\nsweep into `loaded_awaiting_scheduler`.\n\n## Explicit message-template revision\n\nOrdinary refill never changes copy. Only a literal user-approved revision\nenvelope may enter this side path.\n\n```mermaid\nflowchart TD\n A[\"Literal messageTemplateRevision with approved markdown, digests, 1-500 row IDs, request/effect IDs\"] --> DIGEST{\"Current prior authority digest present?\"}\n DIGEST -- No --> FENCE[\"Acquire exact run and read reportingContext source templateAuthorityDigest\"]\n FENCE --> DG{\"Digest returned?\"}\n DG -- No --> BLOCK[\"Terminal: blocked_retryable / template_authority_missing\"]\n DG -- Yes --> REVISE[\"Apply revision to exact cohort\"]\n DIGEST -- Yes --> REVISE\n REVISE --> AUDIT[\"select_campaign_cells in batches <=20 with includeGeneratedMessageReview:true\"]\n AUDIT --> MATCH{\"Every authoritativeGeneratedMessageReview complete, exact text/digest, matchesCurrentTemplateAuthority true?\"}\n MATCH -- No --> FAIL[\"Stop before approval: regenerated_copy_integrity_failed\"]\n MATCH -- Yes --> APPROVE[\"Approve only exact rowIds using compiled readiness authority\"]\n APPROVE --> RECEIPT{\"Bounded preparation receipt includes laneScope?\"}\n RECEIPT -- No --> FAIL\n RECEIPT -- Yes --> PLAN[\"Return to canonical refill plan\"]\n```\n\nFormula Message/Subject columns, previews, exports, and counts are not copy\nauthority. `forceRerun:true` never implies a revision or approval.\n\n## Manual approval and `--yolo`\n\n```mermaid\nflowchart TD\n A[\"Render fresh bounded packet in normal chat as Markdown\"] --> MODE{\"--yolo present?\"}\n MODE -- Yes --> AUTO[\"Auto-accept all planner-ranked transitions among existing campaigns, lanes, sources, and safe refill primitives\"]\n MODE -- No --> ASK[\"Open host-native structured question with exactly Accept and Decline\"]\n ASK --> DECISION{\"Operator choice?\"}\n DECISION -- Accept --> RUN[\"Execute only rendered envelope\"]\n DECISION -- Decline --> STOP[\"Stop with no mutation\"]\n AUTO --> RUN\n```\n\nUse `plain chat` in Codex and `plain chat` in Claude Code. The\nfull packet belongs in the normal chat message immediately before the question:\nworkspace, sender scope, campaign-by-campaign plan table, action, target/cap,\nsource, blocker/skip reason, exact IDs, expected side effects, forbidden actions,\nand stop condition. The question body must be compact and refer back to the\nposted packet instead of duplicating it. `--yolo` may switch among every fresh\nplanner-ranked existing campaign/lane/source family and start the exact selected\n`PAUSED` campaign. It does not create campaigns, direct-send, archive/delete,\nchange sender limits or paid-InMail thresholds, reassign senders, or invent\nsource selection outside the planner.\n\n## Typed outputs\n\n```mermaid\nflowchart TD\n A[\"Fresh canonical state\"] --> C{\"Terminal classification\"}\n C -- \"sent + scheduled meets target\" --> COMPLETE[\"complete: report saturation ledger\"]\n C -- \"all remaining exact targets scheduler-owned and workspace ready-or-projected gap is zero\" --> LOADED[\"loaded_awaiting_scheduler: report expected pickup and stop\"]\n C -- \"recoverable external, capacity, active-work, or receipt condition\" --> BLOCKED[\"blocked_retryable: exact blocker, receipt, and safe retry condition\"]\n C -- \"current lane spent but another existing target remains\" --> EX[\"lanes_exhausted internally; continue next_exact_target\"]\n C -- \"every existing campaign/lane/source spent or infeasible\" --> NEW[\"new_campaign_required: propose missing shape and ask whether to create it\"]\n C -- \"scope/config/readiness changed\" --> DRIFT[\"blocked_retryable: typed drift; never guess\"]\n```\n\nOne scheduler-loaded exact lane is not a workspace terminal: skip it and\ncontinue other planner-ranked lanes. Workspace `loaded_awaiting_scheduler` is\nadmissible only when no refill-owned scheduler request is active. After refill\ndispatches a sweep, keep the same fence alive until the official terminal\nreceipt; then return `complete` from the post-receipt readback or a concrete\nreceipt-backed retryable scheduler blocker if coverage remains short. The sole\nrefill-ladder expansion\nthat asks the user in `--yolo` is `new_campaign_required`; refill itself never\ncreates that campaign. `new_campaign_required` is also the truthful terminal\nwhen receipts prove every existing lane is spent but the planner has no\nautomatic cold rung to propose (Signal Discovery workspaces): report the\nremaining gap and ask the user; a future handler may automate the creation. A\n`actionable_supply_not_queued` terminal means actionable row frontiers\n(approval/generate/enrich/rubric or unprocessed frontier rows) still exist but\nno executable exact edge surfaced: retry once with a fresh command, and if it\nrepeats report it as a planner-exposure defect instead of treating the\nworkspace as exhausted. That census counts CONVERTIBLE rows only, de-duplicated\nper campaign/table lane — a frontier whose own preparation receipt carries a\nnon-retryable `icp_or_rubric_rejection` diagnosis is proven unable to convert,\nso it never inflates the census. When such receipts are all that remain, the\nterminal is `source_supply_exhausted_at_rubric`: a truthful source exhaustion,\nnot a defect and not retryable. Report the per-lane evidence from the note and\ntell the user that widening the rubric or adding fresh source rows is the only\nremaining fill path. Whenever a terminal reports a non-empty census, it also\nnames every exact edge the run refused (`Exact edges this run refused: ...`) —\nsurface those named blockers rather than describing the workspace as having no\navailable work.\n\n## Non-negotiable authority and proof\n\n- Before preparation, approval, or exact-date scheduling, require a validated\n compiled campaign and positive exact target readiness identity from the\n backend compiler: `profileSchemaVersion`, `compilerVersion`,\n `campaignDigest`, `actionColumnId`, action, `pathDigest`,\n `dependsOnColumnIds`, `runCondition`, the selected target's `capabilities`,\n `requestId`, `effectId`, and `dateGuards`. Never infer no-message behavior\n from a missing Generate Message column. Prepare rows according to the\n persisted sequence; bounded enrichment and LLM prerequisite calls are\n allowed only when authorized by the exact readiness packet and receipted.\n- Refuse approval outside the bounded authorized cohort. The exact selected\n target path controls message, subject, comment, reaction, and row approval.\n For exact dates, require the date strictly after sender-local today and inside\n the fill horizon. Prepared, approved, and ready rows remain intermediate\n evidence; completion requires request/effect-attributed scheduler-owned\n scheduled readback.\n- Execute one bounded primitive, then perform a full authoritative reread.\n Never call a LinkedIn outreach/provider-send surface from refill. No direct\n sends, raw scheduler writes, broad approval, threshold/limit changes,\n sender reassignment, destructive cleanup, or new campaign creation.\n- Maintain the target-window saturation ledger per sender: selected days,\n gross capacity, actual sent, future scheduler-owned scheduled with non-null\n `scheduledFor`, projected coverage (`sent + scheduled`), ready buffer,\n remaining gap, paid-InMail feasibility, `targetShapeRevision`, and\n `stateRevision`. Future scheduled coverage and already sent actions are\n distinct.\n- Carry canonical `refill_reporting.v2` unchanged through progress,\n continuation, replay, and terminal output. Completion proof is Sellable MCP\n evidence only: target plan, campaign refill state, scheduler capacity,\n sweep/status, and bounded receipts. Never use individual cell ids, Prisma,\n SQL, direct database access, or production-environment scripts as completion\n proof. Redact raw copy and prospect fields.\n\n## Refill V3\n\nThis is the DEFAULT route whenever `refill_v3_advance` is exposed (see\n[Route selection](#route-selection--do-this-first)). `refill_v3_advance` is then\nthe only execution owner and `refill-sends-workflow` plus its `core/flow.v3.json`\nasset is the contract to load — load the prompt and that asset, verify the `v3`\ncompatible range, and report the version before the first call. Start from the\nbase request `{workspaceId, scope}`, add `yolo:true` by default, and call it\nagain after each `advanced` or\nsettled `campaign_attention_required` result. A `run_step_pending` result means\nthe server is still completing the already-consumed step: wait its\n`retryAfterMs`, then call advance with the same public inputs. The MCP retains\nthe identical token internally; never copy a token, route to AI, or execute an\nauthority for this transport-reconciliation wait. `refill_v3_continue` itself\nsettles the exact packet action before it returns. Bounded enrichment and an\nalready-active preparation job use the shared Create Campaign waiter and\ndurable preparation owner; directly queued row repair uses the campaign waiter.\nSynchronous source, configuration, rubric, and exhaustion authorities already\nreturn after their own exact reread, so they return `settlement.ready:true` from\nthat bounded authority receipt and never wait on unrelated campaign-wide\nprocessing cells.\n\nWhen an explicit `yolo:false` request names a campaign, resolve that visible name with one\nauthorized bounded `get_campaigns` call carrying an explicit `limit`. Require\nexactly one case-insensitive exact match; if none or more than one match, stop\nwithout preview or mutation. Retain only the returned stable campaign ID. Call\n`refill_v3_world_state({workspaceId, scope, campaignId})`, render that exact\ncampaign's two-lane readiness and its explicit zero product side effects, then\nstop at the product-native question with exactly Accept and Decline. Do not call\n`refill_v3_advance` before Accept. Accept calls\n`refill_v3_advance({workspaceId, scope, campaignId})`; Decline stops. Carry the\nsame campaignId through every advance, continue, replay, partial-wait, and\npost-wait repeat. Display-name changes never alter this retained identity, and\nno sibling campaign may replace it.\nCall the next advance only when `settlement.ready` is true. When it is false,\ncall `wait_for_campaign_processing` with `settlement.resumeInput` **unchanged**;\nthat carries the exact `preparationJobId`, `requirePreparationTerminal:true`,\nand `requireIdle:true`. Repeat the returned `resumeInput` until ready; never\nfall back to a stats-only campaign wait for this settlement. An\n`awaiting_external_change` result with\n`deferral.code:\"campaign_work_in_flight\"` and a campaign id is a bounded\nread-only continuation, not permission to walk the next campaign: call\n`wait_for_campaign_processing({ workspaceId, campaignId, requireIdle:true })`,\nthen call `refill_v3_advance` again with the identical scope and yolo grant.\nThis reuses Create Campaign's campaign-table waiter and guarantees the same\ncampaign is freshly replanned after its cohort settles. If the bounded wait\nreturns a partial timeout, surface that checkpoint and make the fresh advance;\nif it reports the same live campaign, repeat the bounded wait. Stop on every\nother `awaiting_external_change`, `complete`, or `blocked` result. For each of\nthose terminal results, report **every** entry in `terminalEvidence.rows`, one\nper scoped sender/date/lane—not only the headline deferral or blocker. Include\n`targetSlots`, `takenSlots`, `remainingTargetGap`, `fillableSlotsNow`,\n`blockedGap`, `terminalClassification`, `reasonCodes`, `approvedDelta`, and\n`scheduledDelta`. When `reasonCodes` contains\n`paid_inmail_credit_refresh_failed`, also report `paidCreditRefreshAttempt`\nexactly: `attemptedAt`, `outcome`, `errorClass`, `errorDetail`, and `durationMs`.\nA cumulative observation, vague \"credit refresh\" label, or one surfaced blocker\nis never a row-complete terminal summary.\n\n`terminalEvidence.rows` covers exactly two Refill V3 lanes:\n`connection_invite` and closed/paid InMail. It does **not** report Open InMail.\nCampaign `supply.readyToSchedule` is a broad first-touch table count and can\ninclude Open InMail rows that the normal scheduler can place independently.\nNever present that broad count as connection or paid inventory, never infer\nOpen InMail is empty or unscheduled from a Refill V3 row, and never explain the\ndifference as sender affinity unless exact lane evidence proves it. If asked\nwhether Open InMail is maxed, say the two-lane refill receipt cannot answer that\nquestion and obtain an action-type-specific scheduled readback before answering.\n\nLead every row-complete terminal summary by stating that all scoped\nsender/date/lane rows were explored. Never say the workspace \"stopped on\" one\nsender or headline blocker: that blocker classifies one row after independent\nsibling work was explored; it is not the traversal stop.\n\nResolve the workspace BEFORE the first call, exactly as the V1 route already\nrequires. `workspaceId` must be an exact id on every automation call: when the\noperator names a workspace, call `list_workspaces` first and match that name to\nits id. Prefer one case-insensitive exact name match; if none exists, accept one\ncase-insensitive prefix match (so `Damiano` resolves `Damiano R`). Use the\nconfigured or active workspace only when the operator named none. If zero or\nmultiple prefix matches remain, stop and say so — do not fall back to the\nconfigured workspace — and never change the shared active workspace to steer\nan automation.\n\nThe command-shaped form is unambiguous: in `refill sends <name> [flags]`,\n`<name>` is the workspace override, never a sender name. A sender restriction\nmust be explicit through `--sender`/`senderIds`/`senderNames` or prose that says\n“sender.” Therefore call `list_workspaces` and resolve `<name>` first. Do not\nlist configured-workspace senders before that workspace match; doing so is both\nscope drift and avoidable latency.\n\nMap the rest of the request onto those keys and nothing else: the sender/date\nenvelope becomes `scope`. `sender_local_horizon` (1-3 days) is ONLY for\nrequests with no date control at all (\"refill sends X\"); the moment the\noperator names any date — `--target-date`, `--until-date`, or dated prose —\nthe scope is `exact_sender_dates`, on the FIRST call and every later call of\nthe run. There is no mode: WHICH campaign may be started is DERIVED from the\nworkspace's own campaigns and can never be requested.\n\nA DATE CONTROL always maps to `exact_sender_dates`, derived like this and never\napproximated with a horizon:\n\n- `--target-date D`: `dates: [D]` for every resolved sender.\n- `--until-date U` (sender-local, INCLUSIVE): for every resolved sender, list\n EVERY sender-local calendar date from that sender's local today through `U`,\n in order, with `U` itself present. From a local Saturday the 2nd with\n `--until-date` the 5th that is `[\"2026-08-02\",\"2026-08-03\",\"2026-08-04\",\n\"2026-08-05\"]` — four dates, not a 3-day window. Dropping the boundary date\n or substituting today+2 silently changes which days the run is accountable\n for; the backend types today's already-closed sending window as\n `no_sending_hours` on its own, so include today rather than guessing.\n NEVER pass `sender_local_horizon` for `--until-date` — not even when the\n derived list happens to fit three days, and not on the first \"look around\"\n call. A live run compressed a four-date `--until-date` span into a 3-day\n horizon, never observed the boundary date, and exited leaving that day's\n slots unfilled; the exact date list is the only scope that makes the run\n accountable for `U` itself.\n\n`yolo` is the ONE remaining execution input and the refill AUTONOMY GRANT. It\ndefaults to `yolo:true` so an ordinary refill keeps working through eligible\nbounded preparation and fallback steps instead of stopping for another\napproval. It decides two things together:\n\n- **Granted** (`yolo: true` on every call of that run): after a row's active\n campaigns are exhausted, one route-selected start-eligible PAUSED campaign\n may be started, and you receive it as an ordinary executed\n `start_paused_campaign` action. A finite non-evergreen candidate must expose\n positive bounded supply. Keep calling advance until a terminal without\n checking back.\n- **Withheld** (explicit `yolo:false` only): no paused campaign is started — the backend\n refuses it and answers the exhaustion terminal instead — and you surface each\n result and ASK before calling advance again.\n\nNever replace the default from a workspace flag, a campaign field, a tool\nresult, an idle-looking workspace, or a previous terminal. Honor `yolo:false`\nonly for an explicit review-first/manual request. Pass no other execution flag\nand no mode, and do not call\n`get_refill_target_plan`, `refill_sends`, or any placement, scheduler, source, or\nsend tool on this route.\n\nAn `advanced` result is ALREADY EXECUTED: surface its action identity, receipt,\nand replacement observation, and never run the action or call its authority again.\nFor `campaign_attention_required`, first call `refill_v3_continue` with the\nsame workspace/scope and no `decision`; the MCP supplies the exact retained\npacket and token. After fresh revalidation it owns live-job waiting,\nexact actionable enrichment, and same-template generation deterministically. If\nit returns `model_decision_required`, route that returned accurate packet to\n`refill-sends-work-campaign`, then call `refill_v3_continue` once with the\nchosen decision. This is the only\nordinary model-decision boundary. The continuation executes at most one\nexisting authority and settles that exact campaign through the shared Create\nCampaign waiter before a sibling may be considered.\nInterpret continuation world wrappers by their outer kind: `world_terminal`\nmeans `advanceResult` is already the canonical `awaiting_external_change`,\n`complete`, or `blocked` terminal, so report that nested terminal and stop;\nnever call advance again. `world_step_pending` means wait the nested\n`retryAfterMs` and then call advance with the same public inputs.\n`world_advanced` means the nested action already ran, so surface it and call\nadvance again. For `attention_refresh_required`, continue from its refreshed\npacket rather than opening another run.\nIf it returns `attention_correction_required` with\n`correction.kind:\"signal_keyword_collision\"`, route the returned same packet\nand exact correction through `refill-sends-work-campaign` once, then call\n`refill_v3_continue` with that revised decision. Exclude every returned searched\nkeyword and use the required request-fingerprint prefix. This is one refused,\nzero-effect Signal correction; a second collision is terminal and must not loop.\n\nThis skill chooses no sender, date, lane, campaign, or action, holds no counter or\ncursor between calls, and declares no terminal, exhaustion verdict, or health\nclassification of its own. V1 `refill_sends` behavior is unchanged.\n"
|
|
24
|
+
"content": "---\nname: sellable-refill-sends\ndescription: Refill projected sends across a workspace or selected senders through the canonical fenced coordinator.\nvisibility: public\nallowed-tools:\n - mcp_sellable_refill_sends\n - mcp_sellable_get_auth_status\n - mcp_sellable_start_cli_login\n - mcp_sellable_wait_for_cli_login\n - mcp_sellable_get_active_workspace\n - mcp_sellable_list_workspaces\n - mcp_sellable_set_active_workspace\n - mcp_sellable_get_subskill_prompt\n - mcp_sellable_get_subskill_asset\n - mcp_sellable_search_subskill_prompts\n - mcp_sellable_get_scheduler_fill_capacity\n - mcp_sellable_run_scheduler_sweep\n - mcp_sellable_refresh_paid_inmail_credits\n - mcp_sellable_list_senders\n - mcp_sellable_get_sender_routing\n - mcp_sellable_get_campaign_waterfall\n - mcp_sellable_resolve_campaign_fill_route\n - mcp_sellable_get_campaign_refill_state\n - mcp_sellable_get_refill_target_plan\n - mcp_sellable_fill_campaign_horizon\n - mcp_sellable_get_campaign\n - mcp_sellable_get_campaign_context\n - mcp_sellable_update_campaign\n - mcp_sellable_get_provider_prompt\n - mcp_sellable_get_campaign_message_preparation_status\n - mcp_sellable_start_campaign_message_preparation\n - mcp_sellable_cancel_campaign_message_preparation\n - mcp_sellable_import_leads\n - mcp_sellable_wait_for_lead_list_ready\n - mcp_sellable_confirm_lead_list\n - mcp_sellable_search_signals\n - mcp_sellable_select_promising_posts\n - mcp_sellable_fetch_post_engagers\n - mcp_sellable_search_sales_nav\n - mcp_sellable_lookup_sales_nav_filter\n - mcp_sellable_search_prospeo\n - mcp_sellable_search_prospeo_companies\n - mcp_sellable_confirm_prospeo_company_accounts\n - mcp_sellable_load_csv_linkedin_leads\n - mcp_sellable_load_csv_domains\n - mcp_sellable_list_dnc_entries\n - mcp_sellable_load_csv_dnc_entries\n - mcp_sellable_get_rows\n - mcp_sellable_get_rows_minimal\n - mcp_sellable_get_table_rows\n - mcp_sellable_get_campaign_table_schema\n - mcp_sellable_select_campaign_cells\n - mcp_sellable_queue_campaign_cells\n - mcp_sellable_wait_for_campaign_processing\n - mcp_sellable_get_sender\n---\n\n# Refill Sends\n\n## Installed Host Contract\n\nThis installed skill is running in Hermes Agent. When the shared workflow body\nor fallback text mentions Claude Code, Codex, or Hermes for internal parity,\nchoose the Hermes instruction for customer-facing language and host functions.\n\n- Customer-facing command: `/sellable-refill-sends`\n- MCP tool naming: Hermes exposes Sellable tools as `mcp_sellable_<tool>`;\n when shared instructions show `mcp_sellable_<tool>`, call the matching\n `mcp_sellable_<tool>` tool instead.\n- Structured questions: ask plainly in chat unless a Hermes-native approval or\n question tool is visible in the current session.\n- Bootstrap host label: `host: \"Hermes\"`\n- Install/reload blocker label: Hermes install/reload problem\n- Reload instruction: restart Hermes, or run `/reload-mcp` in the active\n Hermes session after install\n\nDo not tell Hermes users to run Codex or Claude command forms, use Codex/Claude structured-question APIs, or restart Codex Desktop or Claude Code. Do not describe this run as Claude Code or Codex.\n\nUse this skill for “fill”, “refill sends”, “max out sends”, “load everyone up”,\nor “fill horizon sends”. Exactly one coordinator owns execution: `refill_v3_advance`\non the V3 route, `refill_sends` on the V1 route. The host resolves the request,\ninvokes that coordinator, and follows its exact continuation; it never\nreconstructs the refill ladder from low-level tools.\n\nHost commands:\n\n- Claude Code: `/sellable-refill-sends`\n- Codex: `/sellable-refill-sends`\n\n## Scheduled customer-program entry\n\nA scheduled invocation is one downstream action of the existing customer\nprogram. It does not create a second refill loop or choose a new campaign. The\nprogram wrapper supplies one already-claimed home workspace plus its exact\ncampaign/sender cohort and one to three sender-local dates. Use that exact scope,\npass `yolo:true` to the same canonical Refill V3 advance/continue flow below,\nand retain the server-issued run continuity until the run settles. Never switch\nan Admin runtime to another workspace, widen the cohort, add dates, or create a\nchild schedule.\n\nReuse a persisted refill enrollment and its approved campaign, exclusion,\nsource, message, and sender rules. A human pause, a missing enrollment, a\nnever-launched campaign, legacy PAUSED state with no provenance, or generation\ndrift is a hold. Return the one exact decision or action the customer must take;\ndo not restart the campaign, invent permission, or ask for the same permission\nevery morning. An explicit authenticated Start/resume remains human-owned.\n\nScheduled results use five product meanings:\n\n- `settled`: independent readback proves the exact scheduled additions.\n- `partial`: some additions are proven and the remaining exact gaps/blockers are\n named.\n- `pending`: the same run or scheduler receipt is still active; retain and poll\n that identity.\n- `blocked`: no allowed next mutation exists; name the precise human or provider\n action and safe retry condition.\n- `quiet`: coverage was already healthy or routine maintenance settled with no\n customer action. Make the result available to the daily review; do not post a\n second routine message.\n\nInteractive `refill-sends --yolo` always receives its actual result immediately.\nState connection invitations and paid InMail separately: invitation capacity is\nnot paid InMail credit, and paid InMail coverage is never proof of invitation\ncoverage. “Added” means scheduler-owned rows with a non-null scheduled time; it\nnever means LinkedIn delivered them.\n\n## Route selection — do this FIRST\n\nDecide the route before parsing scope, before loading any flow asset, and before\nany tool call other than auth/workspace resolution. The predicate is\nMECHANICAL and observable in the connected Sellable MCP tool list:\n\n> **Is `refill_v3_advance` one of the tools this server exposes?**\n\n- **Yes → take the Refill V3 route.** This is the default for every workspace on\n a server that exposes the tool. Go to [Refill V3](#refill-v3) and follow it;\n the V1 ladder in the rest of this document does not apply.\n- **No → take the V1 route.** The installed server predates Refill V3, so\n `refill_sends` is the only coordinator available. Follow this document from\n [Entry and exact scope](#entry-and-exact-scope) onward.\n\nNever infer the route from a workspace flag, a campaign field, a tool result, or\nthe operator's wording: no such cutover signal exists, and guessing at one is\nwhat makes an ordinary refill request silently take the wrong route. Report the\nselected route explicitly before the first coordinator call.\n\n## Entry and exact scope\n\nEverything from here down to [Refill V3](#refill-v3) is the **V1 route**. Skip it\nentirely when route selection chose V3. On this route `refill_sends` is the only\nexecution owner and the host follows its exact continuation; it never\nreconstructs the refill ladder from low-level tools.\n\nAccepted request fields are `--yolo`, `workspaceId`, `--sender`/`senderIds`/\n`senderNames`, `actionTypes`, `--until`/`untilDate`, `--target-date`/\n`targetDate`, and compatibility `horizonSendDays`. Omitted dates mean the\nscheduler-forward 48-hour window. `untilDate` is sender-local and inclusive;\n`targetDate` is one sender-local scheduler-fillable date. Skip no-send days and\nnever extend beyond the requested date. Finish the full D1 reread before D2.\nOrdinary refill defaults to `yolo:true`; only an explicit `yolo:false` or a\nclear request for review-first/manual execution opts out.\n\n```text\nrefill_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\", runHandle?: RefillRunHandleV1, targetConfig?: RefillTargetConfigV1, reportingContext?: RefillReportingContextV2, messageTemplateRevision?: MessageTemplateRevisionV1 })\n```\n\n```mermaid\nflowchart TD\n A[\"Parse the operator request\"] --> AUTH{\"Sellable auth valid?\"}\n AUTH -- No --> LOGIN[\"Run the returned login flow and wait\"]\n LOGIN --> AUTH\n AUTH -- Yes --> WS[\"Resolve exact workspace by ID, exact name, or install mapping\"]\n WS --> WSG{\"One accessible workspace match?\"}\n WSG -- No --> WB[\"Output: blocked_retryable / WORKSPACE_REQUIRED or workspace_ambiguous\"]\n WSG -- Yes --> SENDERS[\"Resolve each sender inside that workspace by ID, exact name, or unambiguous prefix\"]\n SENDERS --> SG{\"Every selector resolves exactly?\"}\n SG -- No --> SB[\"Output: blocked_retryable / sender_selector_unresolved with candidates\"]\n SG -- Yes --> DATE[\"Normalize 48h, exact targetDate, or inclusive untilDate in sender-local time\"]\n DATE --> ROUTE{\"Does this server expose refill_v3_advance?\"}\n ROUTE -- Yes --> V3[\"Refill V3 route: load core/flow.v3.json and call refill_v3_advance\"]\n ROUTE -- No --> D1[\"D1: call get_refill_target_plan read-only with exact scope\"]\n D1 --> RENDER[\"Render sender/campaign waterfall, coverage ledger, first action, side effects, forbidden actions, and stop condition\"]\n RENDER --> D2[\"D2: call refill_sends with workspaceCoordinator true plus displayed targetShapeRevision and actionKey\"]\n```\n\nScheduled and `--yolo` execution require an explicit `workspaceId` on every\ncall. Never change the shared active workspace to control an automation, never\nfall back to its full fleet, and never mutate the workspace that merely happens\nto be active. If the native tool is unavailable, use only the host’s exact\nconfigured Sellable MCP transport; otherwise stop with `sellable_mcp_unavailable`\ninstead of manually reproducing the workflow.\n\nBefore product work, load the closed workflow asset completely and verify it:\n\n```text\nget_subskill_prompt({ subskillName: \"refill-sends-workflow\" })\nget_subskill_asset({ subskillName: \"refill-sends-workflow\", assetPath: \"core/flow.v1.json\" })\n```\n\nContinue chunks until `hasMore:false`; require `workflow:\"refill-sends-workflow\"`\nand a COMPATIBLE version: same major (`v1`) and minor at or above the minimum\n`v1.9` — so `v1.9`, `v1.10` pass while `v1.8` and `v2.x` do not. Report the\nverified version before D1. A missing, unparseable, wrong-major, or\nbelow-minimum version is `workflow_version_mismatch`: stop before\n`get_refill_target_plan` or mutation. Do NOT require exact string equality: the\nflow asset ships in the npm package while this skill is installed separately,\nso an exact pin makes every additive contract change a breaking one.\nRoute intent is immutable: ordinary refill uses `intent:\"auto\"` from first plan\nthrough terminal; explicit `yolo:false` uses the review-first path.\n\n## Mandatory visible plan before execution\n\nEvery refill in every mode begins with D1, a read-only\n`get_refill_target_plan` with the exact workspace, sender/action selectors, and\ndate envelope. For default yolo execution, the first D1 call must explicitly pass\n`approvalMode:\"approve\"`; never rely on the planner's `mark_ready` default and\nthen discover the scope mismatch at D2. Invoke D1 exactly once, retain and parse\nthat response in the same host composition, and never call D1 again only to\nformat or render it. Render its plan in normal chat before any mutation. At minimum,\nshow one row per selected sender/campaign lane with sender, campaign, lane/source\nfamily, planned first action, target/cap, sent, scheduled, ready, still needing\npreparation, fallback order, and blocker/skip reason. Then show the bounded side\neffects, forbidden actions, stop condition, `targetShapeRevision`, and first\n`globalActionQueue[0].actionKey`.\n\nIf a stale or missing paid-credit fact prevents a certified fillable cap, show\n`pending credit refresh`, never bare `unknown`. The target remains visible and\nyolo executes the displayed refresh action before replanning the numeric cap.\n\nAfter rendering D1, explicit `yolo:false` asks Accept or Decline and invokes\nonly the returned `planned_manual_run` after Accept. Default `yolo:true` does\nnot ask: call\n`refill_sends` D2 with `workspaceCoordinator:true`, the identical scope, and\nboth `expectedTargetShapeRevision` and `expectedActionKey` copied from the\ndisplayed packet. The server may itself return `status:\"plan_ready\"`; render\nthat returned plan before invoking `planned_manual_run` or\n`planned_workspace_run`. Thus the modes share the exact same visible plan and\nrevision fence. The only difference is that non-yolo pauses for decisions while\n`--yolo` auto-accepts the displayed packet and autonomously traverses every\nplanner-ranked existing campaign, lane, source, safe rubric trial, and scheduler\nhandoff until terminal. If either pin drifts, render the fresh read-only\nreplacement packet; do not mutate from the stale plan. No credit refresh, fence,\nor product mutation may exist before this render.\n\n## Coordinator lifecycle\n\n```mermaid\nflowchart TD\n A[\"Fresh read-only workspace refill plan rendered to the user\"] --> FULL{\"Projected coverage sent + scheduled is full?\"}\n FULL -- Yes --> COMPLETE[\"Terminal: complete\"]\n FULL -- No --> ACTIVE{\"Active exact fenced run exists?\"}\n ACTIVE -- Yes --> RESUME[\"Resume only issued runId, fence, targetConfig, reportingContext\"]\n ACTIVE -- No --> PICK[\"Select globalActionQueue 0\"]\n PICK --> PREFLIGHT[\"Exact campaign, table, sender, action, lane preflight\"]\n PREFLIGHT --> ACT[\"Execute one bounded planner action\"]\n RESUME --> ACT\n ACT --> OUTCOME{\"Canonical outcome?\"}\n OUTCOME -- \"Committed or canonical no-op\" --> A\n OUTCOME -- \"Still running\" --> WAIT[\"Bounded read-only wait or receipt reconciliation\"]\n WAIT --> A\n OUTCOME -- \"Source exhausted\" --> NEXT{\"Another planner-ranked existing target?\"}\n NEXT -- Yes --> HANDOFF[\"Terminalize exact fence as next_exact_target\"]\n HANDOFF --> A\n NEXT -- No --> NC[\"Terminal: new_campaign_required; ask whether to create it\"]\n OUTCOME -- \"Provider unavailable after one retry\" --> RETRY[\"Terminal: blocked_retryable; universeExhausted false\"]\n OUTCOME -- \"Scope, config, readiness, or receipt drift\" --> BLOCK[\"Terminal: blocked_retryable with exact blocker\"]\n OUTCOME -- \"Planner marker done\" --> DONE[\"Terminalize marker; never dispatch it\"]\n```\n\nIf `status:\"plan_ready\"`, render its full plan packet first. Non-yolo asks for\nAccept or Decline before `planned_manual_run`; `--yolo` invokes\n`planned_workspace_run` automatically. If `status:\"in_progress\"`, invoke only the returned\n`continuation.arguments`. `targetConfig` and `runHandle` are separate and remain\nunchanged except for a server-issued takeover fence. `active_exact_run` resumes\nthat fence; `next_exact_target` carries no stale run fence. Never open a second\nor overlapping run, ask the user to type “continue”, redispatch a control marker, or\nturn `done`, `next_campaign`, or a continuation object into a product action.\n\n## Per-sender campaign and lane waterfall\n\nUse managed evergreen order when healthy. Otherwise build the same waterfall\non the fly from existing eligible campaigns the sender is already attached to.\nThis makes regular and evergreen campaigns differ only in where ordering comes\nfrom, not in how refill proceeds.\n\n```mermaid\nflowchart TD\n A[\"All existing campaign-backed sequences attached to one sender\"] --> FILTER[\"Exclude wrong workspace/sender, archived, completed, direct, disconnected, or sequence-invalid targets\"]\n FILTER --> STALE{\"Managed waterfall complete and live?\"}\n STALE -- Yes --> MANAGED[\"Use configured priority order\"]\n STALE -- No --> DERIVE[\"Derive deterministic order from dashboard-active campaigns\"]\n DERIVE --> P1[\"Prefer canonical source/lane priority\"]\n P1 --> P2[\"Then future scheduled and ready inventory\"]\n P2 --> P3[\"Then recent successful sends and source health\"]\n P3 --> P4[\"Then active before exact start-eligible paused, recency, stable ID\"]\n MANAGED --> PIN[\"Pin exact per-sender and per-action lane chain for this run\"]\n P4 --> PIN\n PIN --> LANE[\"Select highest-priority non-exhausted lane\"]\n LANE --> REFILL[\"Run row lifecycle\"]\n REFILL --> EX{\"Lane structurally exhausted?\"}\n EX -- No --> REFILL\n EX -- Yes --> MORE{\"Another pinned existing lane or source family?\"}\n MORE -- Yes --> LANE\n MORE -- No --> END[\"Output: lanes_exhausted, then new_campaign_required if coverage still short\"]\n```\n\nCampaign enrollment/removal, missing pinned targets, or loss of eligibility is\ntyped scope drift; a fresh planner may rederive, but the host cannot silently\nsubstitute a target. A current dashboard-active `PAUSED` campaign is eligible\nonly when the planner names that exact campaign as start-eligible. Starting it\nmay let the product scheduler schedule/send approved sequence actions and must\nbe reported. DMs are follow-ups, not refill horizon targets. Mixed sequences\nkeep distinct exact target paths; do not choose campaign-union behavior.\n\n## Connection and InMail capacity overlay\n\n```mermaid\nflowchart TD\n S[\"Sender capacity and exact selected days\"] --> C{\"Connection slots available now or later in rolling week?\"}\n S --> F{\"Paid-InMail credit facts fresh?\"}\n F -- No --> RF[\"Refresh exact selected sender once per run, then replan\"]\n RF --> P{\"Credits meet existing threshold, normally 5?\"}\n F -- Yes --> P\n C -- Yes --> INV[\"Enable existing invite lanes\"]\n C -- No --> INVCAP[\"Cap invite lane with timing evidence\"]\n P -- Yes --> MAIL[\"Enable existing paid-InMail or cascade lane\"]\n P -- No --> MAILCAP[\"Skip paid lane; never lower threshold\"]\n INV --> UNION[\"Rank enabled existing lanes per sender\"]\n MAIL --> UNION\n INVCAP --> ALT{\"Paid lane enabled?\"}\n MAILCAP --> ALT2{\"Invite or same-campaign connection fallback enabled?\"}\n ALT -- Yes --> UNION\n ALT -- No --> CAP[\"Output: blocked_retryable / capacity or window\"]\n ALT2 -- Yes --> UNION\n ALT2 -- No --> CAP\n UNION --> POOL[\"Pool shared-campaign prepared inventory; never double-enrich\"]\n```\n\n`rollingWeeklyInvite.capacityFreedDuringWindow:true` means later capacity is\nschedulable; use its timing fields rather than treating the opening gate as a\nfull-day blocker. Credit freshness precedes scheduler wait. Fresh facts below\nthreshold authorize only an already-eligible existing connection fallback or\nanother existing campaign—not a threshold change or new campaign.\n\n## Row lifecycle\n\nFor every selected lane, use the smallest action that can reduce its gap.\n\n```mermaid\nflowchart TD\n A[\"Lane still has projected gap\"] --> ACTIVE{\"Active import, preparation, or stuck work?\"}\n ACTIVE -- \"Healthy active\" --> WAIT[\"Bounded read-only wait; honor wait.deadlineAt\"]\n WAIT --> A\n ACTIVE -- \"Stuck or anomalous\" --> REPAIR[\"Run only planner-bounded repairable cells or return blocker\"]\n REPAIR --> A\n ACTIVE -- No --> APPROVE{\"Generated rows can be approved?\"}\n APPROVE -- Yes --> AP[\"Approve exact bounded cohort with readiness authority\"]\n AP --> REPLAN[\"Record receipt and full authoritative replan\"]\n APPROVE -- No --> ENRICH{\"Existing rows can be enriched or prepared?\"}\n ENRICH -- Yes --> PREP[\"Enrich, generate, or rerun exact bounded cohort\"]\n PREP --> REPLAN\n ENRICH -- No --> SOURCE{\"Selected source can add qualified rows?\"}\n SOURCE -- Yes --> ADD[\"Copy/import bounded rows from exact selected source\"]\n ADD --> REPLAN\n SOURCE -- No --> EXPAND[\"Run source-family acquisition flow\"]\n EXPAND --> REPLAN\n REPLAN --> A\n```\n\nStructural exhaustion requires receipt-proven\n`hasMoreFrontierRows:false`, zero `approvalCandidates`, no fresh active prep,\nno `stuckActiveCells`, and no non-terminal `approvedNotDispatched` work. A dry\npreparation receipt is run-scoped and prevents the identical no-op from\nrepeating. `USER_ADDED_ROWS_LIMIT_EXCEEDED` may use a bounded same-source split\nthrough `load_csv_linkedin_leads` into the exact review batch; a true campaign\ntable hard cap returns a capacity blocker and never deletes rows.\n\n## Sender Post Engagers acquisition\n\n```mermaid\nflowchart TD\n A[\"Sender Post Engagers lane needs rows\"] --> UNUSED{\"Unused selected post/engager rows exist?\"}\n UNUSED -- Yes --> USE[\"Import/copy bounded unused rows\"]\n UNUSED -- No --> REFRESH[\"Refresh this sender's latest recent authored posts\"]\n REFRESH --> SELECT[\"Select new unprocessed relevant high-engagement posts\"]\n SELECT --> FETCH[\"Fetch/import their engagers and dedupe\"]\n FETCH --> YIELD{\"Usable qualified yield?\"}\n YIELD -- Yes --> USE\n YIELD -- No --> EX[\"Exhaust only this Post Engagers lane\"]\n EX --> NEXT[\"Advance to Shared Signal Discovery or next pinned existing lane\"]\n```\n\nThe campaign must be sender-owned: exactly that sender, authored posts only.\nNever invent keywords, search third-party posts, or run general Signal Discovery\nagainst the Post Engagers campaign.\n\n## Shared Signal Discovery acquisition\n\n```mermaid\nflowchart TD\n A[\"Shared Signal lane needs rows\"] --> UNUSED{\"Unused selected rows or unprocessed posts exist?\"}\n UNUSED -- Yes --> USE[\"Import/copy bounded rows\"]\n UNUSED -- No --> STALE[\"Re-search stale existing topics for newly published posts\"]\n STALE --> SY{\"Projected qualified yield meets min remaining gap or 100?\"}\n SY -- Yes --> USE\n SY -- No --> DERIVE[\"Derive up to five concise positive-ICP topics from approved campaign intent\"]\n DERIVE --> DY{\"Projected qualified yield meets floor?\"}\n DY -- Yes --> USE\n DY -- No --> AGENT[\"Request 3-5 new agent-supplied topics through the same fenced continuation\"]\n AGENT --> SEARCH[\"Search once, excluding searchedKeywords, then project actual returned candidates\"]\n SEARCH --> PROVIDER{\"All LinkedIn providers failed?\"}\n PROVIDER -- Yes --> RETRY[\"Retry the same bounded search once\"]\n RETRY --> RECOVER{\"Provider recovered?\"}\n RECOVER -- No --> BLOCK[\"Output: blocked_retryable / provider_unavailable; universeExhausted false\"]\n RECOVER -- Yes --> AY{\"Actual qualified yield meets floor?\"}\n PROVIDER -- No --> AY\n AY -- Yes --> USE\n AY -- No --> EX[\"Receipt-proven signal_yield_below_floor\"]\n EX --> NEXT[\"Advance to next pinned existing lane\"]\n```\n\nProvider outage never consumes a keyword tier or proves exhaustion. Temporary\nderived search state is run-scoped; later runs may rediscover new posts. Agent\nkeywords are supplied only through the exact run continuation, never by user\nsteering or a second run.\n\n## Sales Nav and Prospeo acquisition\n\n```mermaid\nflowchart TD\n A[\"Cold-provider lane needs rows\"] --> UNUSED{\"Unused exact-source rows exist?\"}\n UNUSED -- Yes --> USE[\"Import/copy bounded rows\"]\n UNUSED -- No --> DEEP[\"Continue latest/unfetched pages of exact saved Sales Nav or Prospeo search\"]\n DEEP --> DY{\"Qualified yield?\"}\n DY -- Yes --> USE\n DY -- No --> OPTIONAL{\"Known activity/recency filter exists?\"}\n OPTIONAL -- No --> NEXT[\"Advance to next pinned existing lane\"]\n OPTIONAL -- Yes --> CLONE[\"Clone exact approved search; remove one optional activity/recency filter\"]\n CLONE --> PROOF{\"Original unchanged and every hard-fit filter fingerprint preserved?\"}\n PROOF -- No --> BLOCK[\"Output: blocked_retryable / provider_search_drift\"]\n PROOF -- Yes --> TRIAL[\"Import bounded trial candidates into existing gated source\"]\n TRIAL --> GATE[\"Run current ICP, exclusion, DNC, persona, geography, and company-fit gates\"]\n GATE --> GY{\"Qualified yield?\"}\n GY -- Yes --> USE\n GY -- No --> QUARANTINE[\"Rejects remain unsendable; advance lane\"]\n QUARANTINE --> NEXT\n```\n\nThe original saved search is immutable. An automatic trial may remove only a\nknown activity/recency signal; role, seniority, geography, industry, company\nsize, domain, include/exclude, DNC, and every other hard-fit constraint remain\nbyte-for-byte. Imported candidates are not approvals: current campaign gates\nquarantine bad fits. If rubric rejects dominate — including a receipt-proven\n`low_yield` cohort below the 10% planning floor, not only zero-prepared — enter\nthe bounded sample-quality trial below before another source add. Do not repeat\na spent trial or switch outside planner order.\n\n## Provider prompt before any new provider search\n\nDraining an already-imported source list needs no provider context. But before\nany action that runs a NEW provider search — a `broaden_signal_search` round\n(especially when supplying `agentKeywords`), a Sales Nav or Prospeo cloned-\nsearch broadening, or any source add that dispatches a fresh search — load the\nmatching specialized prompt first with\n`get_provider_prompt({ provider, campaignOfferId })` and apply its discipline:\nsample-first fit checks against the headline ICP criteria, the 10% planning\nfloor, sample math (target ÷ observed pass rate) for sizing, and the keyword-\nquality guidance for Signal Discovery. Inventing broaden keywords or sizing a\nscrape without the provider prompt in context repeats the blind-import failure\nthe sampling discipline exists to prevent. The search tools also enforce this\npreflight server-side; loading it late wastes a fenced round on a typed refusal.\n\n## Rubric sample-quality trial\n\nRubric rejection may mean the source is poor or that one or several required\nchecks are unnecessarily narrow. Decide from an exact sample, not pass-rate alone.\n\n```mermaid\nflowchart TD\n A[\"Rows fail ICP/rubric gate\"] --> STALE{\"Score stale, errored, or computed under mismatched authority?\"}\n STALE -- Yes --> RESCORE[\"Rerun exact bounded cohort under unchanged current rubric\"]\n RESCORE --> RESULT{\"Now qualified?\"}\n RESULT -- Yes --> CONTINUE[\"Continue row lifecycle\"]\n RESULT -- No --> SAMPLE\n STALE -- No --> SAMPLE[\"Take exact representative rejected sample from prep receipt\"]\n SAMPLE --> SNAP[\"Snapshot complete rubric and prior digest\"]\n SNAP --> PROPOSE[\"Propose smallest 1-3 required-to-advisory bundle that creates useful new passes\"]\n PROPOSE --> HARD{\"Touches employment, DNC/opt-out, legal/compliance, or explicit exclusion?\"}\n HARD -- Yes --> REJECT[\"Reject proposal; preserve complete prior rubric\"]\n HARD -- No --> SIM[\"Simulate bundle from recorded per-prospect evaluations; no mutation\"]\n SIM --> DELTA{\"Any newly passing prospects?\"}\n DELTA -- No --> REJECT\n DELTA -- Yes --> QUALITY[\"Review only newly passing profiles in campaign and customer context\"]\n QUALITY --> REPLY{\"If these prospects replied, would the customer be comfortable and consider the replies relevant?\"}\n REPLY -- No --> REJECT\n REPLY -- Yes --> DRIFT{\"Live rubric digest still equals prior digest?\"}\n DRIFT -- No --> BLOCK[\"Output: blocked_retryable / rubric config drift\"]\n DRIFT -- Yes --> APPLY[\"Guarded apply entire required-to-advisory bundle\"]\n APPLY --> EXACT[\"Force exact bounded ICP rescore for accepted sample\"]\n EXACT --> VERIFY{\"Dispatch and accepted quality receipt valid?\"}\n VERIFY -- Yes --> KEEP[\"Keep bundle; receipt before/after digests, changed checks, sample counts, and verdict\"]\n VERIFY -- No --> ROLLBACK[\"Restore complete prior snapshot and receipt rollback\"]\n REJECT --> BETTER[\"Keep rows unsendable; continue better supply or next existing lane\"]\n ROLLBACK --> BETTER\n```\n\n`--yolo` may change more than one required rubric at a time only through this\nsingle bounded reversible bundle. The change demotes selected required checks to\nadvisory scoring; it does not erase their evidence. The acceptance test is the\nnewly passing delta: if any reviewed prospect would make the customer unhappy,\nsurprised, or consider the reply irrelevant, keep the complete prior rubric and\ncontinue the source waterfall. Never expose raw prospect profiles in the public\nreceipt.\n\n## Scheduler and uncertain-receipt recovery\n\n```mermaid\nflowchart TD\n A[\"Ready buffer covers remaining projected gap\"] --> CREDIT{\"Every selected paid lane has fresh credit facts?\"}\n CREDIT -- No --> RF[\"Refresh each exact selected sender once, then full replan\"]\n RF --> A\n CREDIT -- Yes --> DATE{\"Exact targetDate?\"}\n DATE -- Yes --> SWEEP[\"Dispatch one request-scoped product scheduler sweep\"]\n DATE -- No --> WAIT[\"Enter coordinator-owned bounded scheduler wait\"]\n SWEEP --> RECEIPT{\"Receipt state?\"}\n RECEIPT -- Terminal --> READ[\"Canonical target-plan and request/effect readback\"]\n RECEIPT -- Active --> POLL[\"Return in_progress and poll only the same request key\"]\n RECEIPT -- uncertain_outcome --> RECON[\"Reconcile same request key read-only; never redispatch\"]\n POLL --> RECEIPT\n RECON --> TERM[\"Terminal: blocked_retryable with request identity intact\"]\n WAIT --> READ\n READ --> FULL{\"Projected coverage full?\"}\n FULL -- Yes --> COMPLETE[\"Terminal: complete\"]\n FULL -- No --> READY{\"Ready buffer still covers gap?\"}\n READY -- Yes --> OTHER{\"Any other workspace target still needs preparation or an executable gate?\"}\n OTHER -- Yes --> PREP[\"Continue next planner-ranked exact target\"]\n OTHER -- No --> BLOCK[\"Terminal: receipt-backed blocked_retryable scheduler gap\"]\n READY -- No --> PREP[\"Return to row lifecycle\"]\n```\n\nA scheduler sweep is a visible workspace-wide scheduling side effect: existing\nproduct gates may schedule unrelated eligible cells in that workspace/date.\nIt never sends directly or raw-writes scheduler fields. `cellsConsidered is\nallocation-attempt count`; `readyCellsFound` is prefilter inventory. Inspect\n`campaignScopeSummary`, `prefiltered`, `skipped`, and `deferred`. For ready\nclosed-InMail cells with stale paid-credit evidence, use\n`refresh_paid_inmail_credits_then_rerun`. `wait_for_capacity_or_window` means do\nnot source or prep more rows; `no_ready_cells_continue_refill_prep` returns to\nthe row lifecycle. `cellsScheduled:0` alone is not failure. Once a sweep is\ndispatched, a host wait budget yields an `in_progress` continuation carrying\nthe same run identity. Keep polling that request key until its official\nterminal receipt, then reread the full target plan. Never convert an active\nsweep into `loaded_awaiting_scheduler`.\n\n## Explicit message-template revision\n\nOrdinary refill never changes copy. Only a literal user-approved revision\nenvelope may enter this side path.\n\n```mermaid\nflowchart TD\n A[\"Literal messageTemplateRevision with approved markdown, digests, 1-500 row IDs, request/effect IDs\"] --> DIGEST{\"Current prior authority digest present?\"}\n DIGEST -- No --> FENCE[\"Acquire exact run and read reportingContext source templateAuthorityDigest\"]\n FENCE --> DG{\"Digest returned?\"}\n DG -- No --> BLOCK[\"Terminal: blocked_retryable / template_authority_missing\"]\n DG -- Yes --> REVISE[\"Apply revision to exact cohort\"]\n DIGEST -- Yes --> REVISE\n REVISE --> AUDIT[\"select_campaign_cells in batches <=20 with includeGeneratedMessageReview:true\"]\n AUDIT --> MATCH{\"Every authoritativeGeneratedMessageReview complete, exact text/digest, matchesCurrentTemplateAuthority true?\"}\n MATCH -- No --> FAIL[\"Stop before approval: regenerated_copy_integrity_failed\"]\n MATCH -- Yes --> APPROVE[\"Approve only exact rowIds using compiled readiness authority\"]\n APPROVE --> RECEIPT{\"Bounded preparation receipt includes laneScope?\"}\n RECEIPT -- No --> FAIL\n RECEIPT -- Yes --> PLAN[\"Return to canonical refill plan\"]\n```\n\nFormula Message/Subject columns, previews, exports, and counts are not copy\nauthority. `forceRerun:true` never implies a revision or approval.\n\n## Manual approval and `--yolo`\n\n```mermaid\nflowchart TD\n A[\"Render fresh bounded packet in normal chat as Markdown\"] --> MODE{\"--yolo present?\"}\n MODE -- Yes --> AUTO[\"Auto-accept all planner-ranked transitions among existing campaigns, lanes, sources, and safe refill primitives\"]\n MODE -- No --> ASK[\"Open host-native structured question with exactly Accept and Decline\"]\n ASK --> DECISION{\"Operator choice?\"}\n DECISION -- Accept --> RUN[\"Execute only rendered envelope\"]\n DECISION -- Decline --> STOP[\"Stop with no mutation\"]\n AUTO --> RUN\n```\n\nUse `plain chat` in Codex and `plain chat` in Claude Code. The\nfull packet belongs in the normal chat message immediately before the question:\nworkspace, sender scope, campaign-by-campaign plan table, action, target/cap,\nsource, blocker/skip reason, exact IDs, expected side effects, forbidden actions,\nand stop condition. The question body must be compact and refer back to the\nposted packet instead of duplicating it. `--yolo` may switch among every fresh\nplanner-ranked existing campaign/lane/source family and start the exact selected\n`PAUSED` campaign. It does not create campaigns, direct-send, archive/delete,\nchange sender limits or paid-InMail thresholds, reassign senders, or invent\nsource selection outside the planner.\n\n## Typed outputs\n\n```mermaid\nflowchart TD\n A[\"Fresh canonical state\"] --> C{\"Terminal classification\"}\n C -- \"sent + scheduled meets target\" --> COMPLETE[\"complete: report saturation ledger\"]\n C -- \"all remaining exact targets scheduler-owned and workspace ready-or-projected gap is zero\" --> LOADED[\"loaded_awaiting_scheduler: report expected pickup and stop\"]\n C -- \"recoverable external, capacity, active-work, or receipt condition\" --> BLOCKED[\"blocked_retryable: exact blocker, receipt, and safe retry condition\"]\n C -- \"current lane spent but another existing target remains\" --> EX[\"lanes_exhausted internally; continue next_exact_target\"]\n C -- \"every existing campaign/lane/source spent or infeasible\" --> NEW[\"new_campaign_required: propose missing shape and ask whether to create it\"]\n C -- \"scope/config/readiness changed\" --> DRIFT[\"blocked_retryable: typed drift; never guess\"]\n```\n\nOne scheduler-loaded exact lane is not a workspace terminal: skip it and\ncontinue other planner-ranked lanes. Workspace `loaded_awaiting_scheduler` is\nadmissible only when no refill-owned scheduler request is active. After refill\ndispatches a sweep, keep the same fence alive until the official terminal\nreceipt; then return `complete` from the post-receipt readback or a concrete\nreceipt-backed retryable scheduler blocker if coverage remains short. The sole\nrefill-ladder expansion\nthat asks the user in `--yolo` is `new_campaign_required`; refill itself never\ncreates that campaign. `new_campaign_required` is also the truthful terminal\nwhen receipts prove every existing lane is spent but the planner has no\nautomatic cold rung to propose (Signal Discovery workspaces): report the\nremaining gap and ask the user; a future handler may automate the creation. A\n`actionable_supply_not_queued` terminal means actionable row frontiers\n(approval/generate/enrich/rubric or unprocessed frontier rows) still exist but\nno executable exact edge surfaced: retry once with a fresh command, and if it\nrepeats report it as a planner-exposure defect instead of treating the\nworkspace as exhausted. That census counts CONVERTIBLE rows only, de-duplicated\nper campaign/table lane — a frontier whose own preparation receipt carries a\nnon-retryable `icp_or_rubric_rejection` diagnosis is proven unable to convert,\nso it never inflates the census. When such receipts are all that remain, the\nterminal is `source_supply_exhausted_at_rubric`: a truthful source exhaustion,\nnot a defect and not retryable. Report the per-lane evidence from the note and\ntell the user that widening the rubric or adding fresh source rows is the only\nremaining fill path. Whenever a terminal reports a non-empty census, it also\nnames every exact edge the run refused (`Exact edges this run refused: ...`) —\nsurface those named blockers rather than describing the workspace as having no\navailable work.\n\n## Non-negotiable authority and proof\n\n- Before preparation, approval, or exact-date scheduling, require a validated\n compiled campaign and positive exact target readiness identity from the\n backend compiler: `profileSchemaVersion`, `compilerVersion`,\n `campaignDigest`, `actionColumnId`, action, `pathDigest`,\n `dependsOnColumnIds`, `runCondition`, the selected target's `capabilities`,\n `requestId`, `effectId`, and `dateGuards`. Never infer no-message behavior\n from a missing Generate Message column. Prepare rows according to the\n persisted sequence; bounded enrichment and LLM prerequisite calls are\n allowed only when authorized by the exact readiness packet and receipted.\n- Refuse approval outside the bounded authorized cohort. The exact selected\n target path controls message, subject, comment, reaction, and row approval.\n For exact dates, require the date strictly after sender-local today and inside\n the fill horizon. Prepared, approved, and ready rows remain intermediate\n evidence; completion requires request/effect-attributed scheduler-owned\n scheduled readback.\n- Execute one bounded primitive, then perform a full authoritative reread.\n Never call a LinkedIn outreach/provider-send surface from refill. No direct\n sends, raw scheduler writes, broad approval, threshold/limit changes,\n sender reassignment, destructive cleanup, or new campaign creation.\n- Maintain the target-window saturation ledger per sender: selected days,\n gross capacity, actual sent, future scheduler-owned scheduled with non-null\n `scheduledFor`, projected coverage (`sent + scheduled`), ready buffer,\n remaining gap, paid-InMail feasibility, `targetShapeRevision`, and\n `stateRevision`. Future scheduled coverage and already sent actions are\n distinct.\n- Carry canonical `refill_reporting.v2` unchanged through progress,\n continuation, replay, and terminal output. Completion proof is Sellable MCP\n evidence only: target plan, campaign refill state, scheduler capacity,\n sweep/status, and bounded receipts. Never use individual cell ids, Prisma,\n SQL, direct database access, or production-environment scripts as completion\n proof. Redact raw copy and prospect fields.\n\n## Refill V3\n\nThis is the DEFAULT route whenever `refill_v3_advance` is exposed (see\n[Route selection](#route-selection--do-this-first)). `refill_v3_advance` is then\nthe only execution owner and `refill-sends-workflow` plus its `core/flow.v3.json`\nasset is the contract to load — load the prompt and that asset, verify the `v3`\ncompatible range, and report the version before the first call. Start from the\nbase request `{workspaceId, scope}`, add `yolo:true` by default, and call it\nagain after each `advanced` or\nsettled `campaign_attention_required` result. A `run_step_pending` result means\nthe server is still completing the already-consumed step: wait its\n`retryAfterMs`, then call advance with the same public inputs. The MCP retains\nthe identical token internally; never copy a token, route to AI, or execute an\nauthority for this transport-reconciliation wait. `refill_v3_continue` itself\nsettles the exact packet action before it returns. Bounded enrichment and an\nalready-active preparation job use the shared Create Campaign waiter and\ndurable preparation owner; directly queued row repair uses the campaign waiter.\nSynchronous source, configuration, rubric, and exhaustion authorities already\nreturn after their own exact reread, so they return `settlement.ready:true` from\nthat bounded authority receipt and never wait on unrelated campaign-wide\nprocessing cells.\n\nWhen an explicit `yolo:false` request names a campaign, resolve that visible name with one\nauthorized bounded `get_campaigns` call carrying an explicit `limit`. Require\nexactly one case-insensitive exact match; if none or more than one match, stop\nwithout preview or mutation. Retain only the returned stable campaign ID. Call\n`refill_v3_world_state({workspaceId, scope, campaignId})`, render that exact\ncampaign's two-lane readiness and its explicit zero product side effects, then\nstop at the product-native question with exactly Accept and Decline. Do not call\n`refill_v3_advance` before Accept. Accept calls\n`refill_v3_advance({workspaceId, scope, campaignId})`; Decline stops. Carry the\nsame campaignId through every advance, continue, replay, partial-wait, and\npost-wait repeat. Display-name changes never alter this retained identity, and\nno sibling campaign may replace it.\nCall the next advance only when `settlement.ready` is true. When it is false,\ncall `wait_for_campaign_processing` with `settlement.resumeInput` **unchanged**;\nthat carries the exact `preparationJobId`, `requirePreparationTerminal:true`,\nand `requireIdle:true`. Repeat the returned `resumeInput` until ready; never\nfall back to a stats-only campaign wait for this settlement. An\n`awaiting_external_change` result with\n`deferral.code:\"campaign_work_in_flight\"` and a campaign id is a bounded\nread-only continuation, not permission to walk the next campaign: call\n`wait_for_campaign_processing({ workspaceId, campaignId, requireIdle:true })`,\nthen call `refill_v3_advance` again with the identical scope and yolo grant.\nThis reuses Create Campaign's campaign-table waiter and guarantees the same\ncampaign is freshly replanned after its cohort settles. If the bounded wait\nreturns a partial timeout, surface that checkpoint and make the fresh advance;\nif it reports the same live campaign, repeat the bounded wait. Stop on every\nother `awaiting_external_change`, `complete`, or `blocked` result. For each of\nthose terminal results, report **every** entry in `terminalEvidence.rows`, one\nper scoped sender/date/lane—not only the headline deferral or blocker. Include\n`targetSlots`, `takenSlots`, `remainingTargetGap`, `fillableSlotsNow`,\n`blockedGap`, `terminalClassification`, `reasonCodes`, `approvedDelta`, and\n`scheduledDelta`. When `reasonCodes` contains\n`paid_inmail_credit_refresh_failed`, also report `paidCreditRefreshAttempt`\nexactly: `attemptedAt`, `outcome`, `errorClass`, `errorDetail`, and `durationMs`.\nA cumulative observation, vague \"credit refresh\" label, or one surfaced blocker\nis never a row-complete terminal summary.\n\n`terminalEvidence.rows` covers exactly two Refill V3 lanes:\n`connection_invite` and closed/paid InMail. It does **not** report Open InMail.\nCampaign `supply.readyToSchedule` is a broad first-touch table count and can\ninclude Open InMail rows that the normal scheduler can place independently.\nNever present that broad count as connection or paid inventory, never infer\nOpen InMail is empty or unscheduled from a Refill V3 row, and never explain the\ndifference as sender affinity unless exact lane evidence proves it. If asked\nwhether Open InMail is maxed, say the two-lane refill receipt cannot answer that\nquestion and obtain an action-type-specific scheduled readback before answering.\n\nLead every row-complete terminal summary by stating that all scoped\nsender/date/lane rows were explored. Never say the workspace \"stopped on\" one\nsender or headline blocker: that blocker classifies one row after independent\nsibling work was explored; it is not the traversal stop.\n\nResolve the workspace BEFORE the first call, exactly as the V1 route already\nrequires. `workspaceId` must be an exact id on every automation call: when the\noperator names a workspace, call `list_workspaces` first and match that name to\nits id. Prefer one case-insensitive exact name match; if none exists, accept one\ncase-insensitive prefix match (so `Damiano` resolves `Damiano R`). Use the\nconfigured or active workspace only when the operator named none. If zero or\nmultiple prefix matches remain, stop and say so — do not fall back to the\nconfigured workspace — and never change the shared active workspace to steer\nan automation.\n\nThe command-shaped form is unambiguous: in `refill sends <name> [flags]`,\n`<name>` is the workspace override, never a sender name. A sender restriction\nmust be explicit through `--sender`/`senderIds`/`senderNames` or prose that says\n“sender.” Therefore call `list_workspaces` and resolve `<name>` first. Do not\nlist configured-workspace senders before that workspace match; doing so is both\nscope drift and avoidable latency.\n\nMap the rest of the request onto those keys and nothing else: the sender/date\nenvelope becomes `scope`. `sender_local_horizon` (1-3 days) is ONLY for\nrequests with no date control at all (\"refill sends X\"); the moment the\noperator names any date — `--target-date`, `--until-date`, or dated prose —\nthe scope is `exact_sender_dates`, on the FIRST call and every later call of\nthe run. There is no mode: WHICH campaign may be started is DERIVED from the\nworkspace's own campaigns and can never be requested.\n\nA DATE CONTROL always maps to `exact_sender_dates`, derived like this and never\napproximated with a horizon:\n\n- `--target-date D`: `dates: [D]` for every resolved sender.\n- `--until-date U` (sender-local, INCLUSIVE): for every resolved sender, list\n EVERY sender-local calendar date from that sender's local today through `U`,\n in order, with `U` itself present. From a local Saturday the 2nd with\n `--until-date` the 5th that is `[\"2026-08-02\",\"2026-08-03\",\"2026-08-04\",\n\"2026-08-05\"]` — four dates, not a 3-day window. Dropping the boundary date\n or substituting today+2 silently changes which days the run is accountable\n for; the backend types today's already-closed sending window as\n `no_sending_hours` on its own, so include today rather than guessing.\n NEVER pass `sender_local_horizon` for `--until-date` — not even when the\n derived list happens to fit three days, and not on the first \"look around\"\n call. A live run compressed a four-date `--until-date` span into a 3-day\n horizon, never observed the boundary date, and exited leaving that day's\n slots unfilled; the exact date list is the only scope that makes the run\n accountable for `U` itself.\n\n`yolo` is the ONE remaining execution input and the refill AUTONOMY GRANT. It\ndefaults to `yolo:true` so an ordinary refill keeps working through eligible\nbounded preparation and fallback steps instead of stopping for another\napproval. It decides two things together:\n\n- **Granted** (`yolo: true` on every call of that run): after a row's active\n campaigns are exhausted, one route-selected start-eligible PAUSED campaign\n may be started, and you receive it as an ordinary executed\n `start_paused_campaign` action. A finite non-evergreen candidate must expose\n positive bounded supply. Keep calling advance until a terminal without\n checking back.\n- **Withheld** (explicit `yolo:false` only): no paused campaign is started — the backend\n refuses it and answers the exhaustion terminal instead — and you surface each\n result and ASK before calling advance again.\n\nNever replace the default from a workspace flag, a campaign field, a tool\nresult, an idle-looking workspace, or a previous terminal. Honor `yolo:false`\nonly for an explicit review-first/manual request. Pass no other execution flag\nand no mode, and do not call\n`get_refill_target_plan`, `refill_sends`, or any placement, scheduler, source, or\nsend tool on this route.\n\nAn `advanced` result is ALREADY EXECUTED: surface its action identity, receipt,\nand replacement observation, and never run the action or call its authority again.\nFor `campaign_attention_required`, first call `refill_v3_continue` with the\nsame workspace/scope and no `decision`; the MCP supplies the exact retained\npacket and token. After fresh revalidation it owns live-job waiting,\nexact actionable enrichment, and same-template generation deterministically. If\nit returns `model_decision_required`, route that returned accurate packet to\n`refill-sends-work-campaign`, then call `refill_v3_continue` once with the\nchosen decision. This is the only\nordinary model-decision boundary. The continuation executes at most one\nexisting authority and settles it before a sibling may be considered. Async\nrow work uses the shared Create Campaign waiter; synchronous source/config\nwork uses its exact receipt and reread.\nFor `continuation_pending`, wait `retryAfterMs`, then call\n`refill_v3_continue` with the identical workspace, scope, campaignId (when\npresent), and yolo grant, omitting `decision`. Keep doing this until the retained\noperation returns its result. A transport timeout is also an uncertain running\noperation: reconnect through that same decision-free continuation before any\nadvance or new source request. The MCP retains the operation while this server\nprocess lives. If a server restart reports that retained attention is missing,\nstop with `continuation_reconciliation_required` and the exact scope and last\nreceipt; do not invent a replacement run or claim the prior effect failed.\nNever treat a timeout as zero effect.\nContinue the authorized refill across every connected sender and requested\nlane until the coordinator returns row-complete terminal evidence. Preserve the\nrubric, message, caps, and exclusions; pending work needs no renewed approval.\n\nInterpret continuation world wrappers by their outer kind: `world_terminal`\nmeans `advanceResult` is already the canonical `awaiting_external_change`,\n`complete`, or `blocked` terminal, so report that nested terminal and stop;\nnever call advance again. `world_step_pending` means wait the nested\n`retryAfterMs` and then call advance with the same public inputs.\n`world_advanced` means the nested action already ran, so surface it and call\nadvance again. For `attention_refresh_required`, continue from its refreshed\npacket rather than opening another run.\nIf it returns `attention_correction_required` with\n`correction.kind:\"signal_keyword_collision\"`, route the returned same packet\nand exact correction through `refill-sends-work-campaign` once, then call\n`refill_v3_continue` with that revised decision. Exclude every returned searched\nkeyword and use the required request-fingerprint prefix. This is one refused,\nzero-effect Signal correction; a second collision is terminal and must not loop.\n\nThis skill chooses no sender, date, lane, campaign, or action, holds no counter or\ncursor between calls, and declares no terminal, exhaustion verdict, or health\nclassification of its own. V1 `refill_sends` behavior is unchanged.\n"
|
|
25
25
|
},
|
|
26
26
|
{
|
|
27
27
|
"id": "campaign-daily-review",
|
|
@@ -826,8 +826,23 @@ it returns `model_decision_required`, route that returned accurate packet to
|
|
|
826
826
|
`refill-sends-work-campaign`, then call `refill_v3_continue` once with the
|
|
827
827
|
chosen decision. This is the only
|
|
828
828
|
ordinary model-decision boundary. The continuation executes at most one
|
|
829
|
-
existing authority and settles
|
|
830
|
-
|
|
829
|
+
existing authority and settles it before a sibling may be considered. Async
|
|
830
|
+
row work uses the shared Create Campaign waiter; synchronous source/config
|
|
831
|
+
work uses its exact receipt and reread.
|
|
832
|
+
For `continuation_pending`, wait `retryAfterMs`, then call
|
|
833
|
+
`refill_v3_continue` with the identical workspace, scope, campaignId (when
|
|
834
|
+
present), and yolo grant, omitting `decision`. Keep doing this until the retained
|
|
835
|
+
operation returns its result. A transport timeout is also an uncertain running
|
|
836
|
+
operation: reconnect through that same decision-free continuation before any
|
|
837
|
+
advance or new source request. The MCP retains the operation while this server
|
|
838
|
+
process lives. If a server restart reports that retained attention is missing,
|
|
839
|
+
stop with `continuation_reconciliation_required` and the exact scope and last
|
|
840
|
+
receipt; do not invent a replacement run or claim the prior effect failed.
|
|
841
|
+
Never treat a timeout as zero effect.
|
|
842
|
+
Continue the authorized refill across every connected sender and requested
|
|
843
|
+
lane until the coordinator returns row-complete terminal evidence. Preserve the
|
|
844
|
+
rubric, message, caps, and exclusions; pending work needs no renewed approval.
|
|
845
|
+
|
|
831
846
|
Interpret continuation world wrappers by their outer kind: `world_terminal`
|
|
832
847
|
means `advanceResult` is already the canonical `awaiting_external_change`,
|
|
833
848
|
`complete`, or `blocked` terminal, so report that nested terminal and stop;
|
|
@@ -43,7 +43,7 @@ ARG STRIPE_CLI_PACKAGE=@stripe/cli-linux-x64@1.45.0
|
|
|
43
43
|
ARG STRIPE_CLI_INTEGRITY=sha512-1ZhoPpoweYfynqsvhCLlTjZ7lPz5IKtxqAMT5MBy6zrwLRTP9x0T6r8h/jLYL8lRH1c7zC/6X6/XUu2V+r9Bog==
|
|
44
44
|
ARG DEFAULT_PROFILE_BUNDLE_FIXTURE_VERSION=1
|
|
45
45
|
ARG DEFAULT_PROFILE_BUNDLE_VERSION=4
|
|
46
|
-
ARG DEFAULT_PROFILE_BUNDLE_DIGEST=
|
|
46
|
+
ARG DEFAULT_PROFILE_BUNDLE_DIGEST=4ac98653f04e0c12b6947f4406326c3e6bf3ad1e90fdefcd4f6d8a3075ccfe74
|
|
47
47
|
|
|
48
48
|
COPY --from=slack-pp-cli-builder --chmod=0555 /out/slack-pp-cli /usr/local/bin/slack-pp-cli
|
|
49
49
|
|
|
@@ -21,7 +21,7 @@ ARG PLAYWRIGHT_BROWSER_REVISION=1234
|
|
|
21
21
|
ARG TIRITH_ARCHIVE_SHA256=6cdbe35e8f9ccf42e70ad95b501c93cd218ac18201c3df958d54f6ba0d995ce2
|
|
22
22
|
ARG DEFAULT_PROFILE_BUNDLE_FIXTURE_VERSION=1
|
|
23
23
|
ARG DEFAULT_PROFILE_BUNDLE_VERSION=4
|
|
24
|
-
ARG DEFAULT_PROFILE_BUNDLE_DIGEST=
|
|
24
|
+
ARG DEFAULT_PROFILE_BUNDLE_DIGEST=3b397ed1e16a1521f9026ae5de53fa345aeed938cf6842c989234b35a121e4be
|
|
25
25
|
|
|
26
26
|
RUN --mount=type=secret,id=mcp_trust_root,required=true \
|
|
27
27
|
test -s /run/secrets/mcp_trust_root \
|
|
@@ -57,6 +57,6 @@
|
|
|
57
57
|
},
|
|
58
58
|
{
|
|
59
59
|
"path": "skills/sellable/sellable-refill-sends/SKILL.md",
|
|
60
|
-
"content": "---\nname: sellable-refill-sends\ndescription: Refill projected sends across a workspace or selected senders through the canonical fenced coordinator.\nvisibility: public\nallowed-tools:\n - mcp_sellable_refill_sends\n - mcp_sellable_get_auth_status\n - mcp_sellable_start_cli_login\n - mcp_sellable_wait_for_cli_login\n - mcp_sellable_get_active_workspace\n - mcp_sellable_list_workspaces\n - mcp_sellable_set_active_workspace\n - mcp_sellable_get_subskill_prompt\n - mcp_sellable_get_subskill_asset\n - mcp_sellable_search_subskill_prompts\n - mcp_sellable_get_scheduler_fill_capacity\n - mcp_sellable_run_scheduler_sweep\n - mcp_sellable_refresh_paid_inmail_credits\n - mcp_sellable_list_senders\n - mcp_sellable_get_sender_routing\n - mcp_sellable_get_campaign_waterfall\n - mcp_sellable_resolve_campaign_fill_route\n - mcp_sellable_get_campaign_refill_state\n - mcp_sellable_get_refill_target_plan\n - mcp_sellable_fill_campaign_horizon\n - mcp_sellable_get_campaign\n - mcp_sellable_get_campaign_context\n - mcp_sellable_update_campaign\n - mcp_sellable_get_provider_prompt\n - mcp_sellable_get_campaign_message_preparation_status\n - mcp_sellable_start_campaign_message_preparation\n - mcp_sellable_cancel_campaign_message_preparation\n - mcp_sellable_import_leads\n - mcp_sellable_wait_for_lead_list_ready\n - mcp_sellable_confirm_lead_list\n - mcp_sellable_search_signals\n - mcp_sellable_select_promising_posts\n - mcp_sellable_fetch_post_engagers\n - mcp_sellable_search_sales_nav\n - mcp_sellable_lookup_sales_nav_filter\n - mcp_sellable_search_prospeo\n - mcp_sellable_search_prospeo_companies\n - mcp_sellable_confirm_prospeo_company_accounts\n - mcp_sellable_load_csv_linkedin_leads\n - mcp_sellable_load_csv_domains\n - mcp_sellable_list_dnc_entries\n - mcp_sellable_load_csv_dnc_entries\n - mcp_sellable_get_rows\n - mcp_sellable_get_rows_minimal\n - mcp_sellable_get_table_rows\n - mcp_sellable_get_campaign_table_schema\n - mcp_sellable_select_campaign_cells\n - mcp_sellable_queue_campaign_cells\n - mcp_sellable_wait_for_campaign_processing\n - mcp_sellable_get_sender\n---\n\n# Refill Sends\n\n## Installed Host Contract\n\nThis installed skill is running in Hermes Agent. When the shared workflow body\nor fallback text mentions Claude Code, Codex, or Hermes for internal parity,\nchoose the Hermes instruction for customer-facing language and host functions.\n\n- Customer-facing command: `/sellable-refill-sends`\n- MCP tool naming: Hermes exposes Sellable tools as `mcp_sellable_<tool>`;\n when shared instructions show `mcp_sellable_<tool>`, call the matching\n `mcp_sellable_<tool>` tool instead.\n- Structured questions: ask plainly in chat unless a Hermes-native approval or\n question tool is visible in the current session.\n- Bootstrap host label: `host: \"Hermes\"`\n- Install/reload blocker label: Hermes install/reload problem\n- Reload instruction: restart Hermes, or run `/reload-mcp` in the active\n Hermes session after install\n\nDo not tell Hermes users to run Codex or Claude command forms, use Codex/Claude structured-question APIs, or restart Codex Desktop or Claude Code. Do not describe this run as Claude Code or Codex.\n\nUse this skill for “fill”, “refill sends”, “max out sends”, “load everyone up”,\nor “fill horizon sends”. Exactly one coordinator owns execution: `refill_v3_advance`\non the V3 route, `refill_sends` on the V1 route. The host resolves the request,\ninvokes that coordinator, and follows its exact continuation; it never\nreconstructs the refill ladder from low-level tools.\n\nHost commands:\n\n- Claude Code: `/sellable-refill-sends`\n- Codex: `/sellable-refill-sends`\n\n## Scheduled customer-program entry\n\nA scheduled invocation is one downstream action of the existing customer\nprogram. It does not create a second refill loop or choose a new campaign. The\nprogram wrapper supplies one already-claimed home workspace plus its exact\ncampaign/sender cohort and one to three sender-local dates. Use that exact scope,\npass `yolo:true` to the same canonical Refill V3 advance/continue flow below,\nand retain the server-issued run continuity until the run settles. Never switch\nan Admin runtime to another workspace, widen the cohort, add dates, or create a\nchild schedule.\n\nReuse a persisted refill enrollment and its approved campaign, exclusion,\nsource, message, and sender rules. A human pause, a missing enrollment, a\nnever-launched campaign, legacy PAUSED state with no provenance, or generation\ndrift is a hold. Return the one exact decision or action the customer must take;\ndo not restart the campaign, invent permission, or ask for the same permission\nevery morning. An explicit authenticated Start/resume remains human-owned.\n\nScheduled results use five product meanings:\n\n- `settled`: independent readback proves the exact scheduled additions.\n- `partial`: some additions are proven and the remaining exact gaps/blockers are\n named.\n- `pending`: the same run or scheduler receipt is still active; retain and poll\n that identity.\n- `blocked`: no allowed next mutation exists; name the precise human or provider\n action and safe retry condition.\n- `quiet`: coverage was already healthy or routine maintenance settled with no\n customer action. Make the result available to the daily review; do not post a\n second routine message.\n\nInteractive `refill-sends --yolo` always receives its actual result immediately.\nState connection invitations and paid InMail separately: invitation capacity is\nnot paid InMail credit, and paid InMail coverage is never proof of invitation\ncoverage. “Added” means scheduler-owned rows with a non-null scheduled time; it\nnever means LinkedIn delivered them.\n\n## Route selection — do this FIRST\n\nDecide the route before parsing scope, before loading any flow asset, and before\nany tool call other than auth/workspace resolution. The predicate is\nMECHANICAL and observable in the connected Sellable MCP tool list:\n\n> **Is `refill_v3_advance` one of the tools this server exposes?**\n\n- **Yes → take the Refill V3 route.** This is the default for every workspace on\n a server that exposes the tool. Go to [Refill V3](#refill-v3) and follow it;\n the V1 ladder in the rest of this document does not apply.\n- **No → take the V1 route.** The installed server predates Refill V3, so\n `refill_sends` is the only coordinator available. Follow this document from\n [Entry and exact scope](#entry-and-exact-scope) onward.\n\nNever infer the route from a workspace flag, a campaign field, a tool result, or\nthe operator's wording: no such cutover signal exists, and guessing at one is\nwhat makes an ordinary refill request silently take the wrong route. Report the\nselected route explicitly before the first coordinator call.\n\n## Entry and exact scope\n\nEverything from here down to [Refill V3](#refill-v3) is the **V1 route**. Skip it\nentirely when route selection chose V3. On this route `refill_sends` is the only\nexecution owner and the host follows its exact continuation; it never\nreconstructs the refill ladder from low-level tools.\n\nAccepted request fields are `--yolo`, `workspaceId`, `--sender`/`senderIds`/\n`senderNames`, `actionTypes`, `--until`/`untilDate`, `--target-date`/\n`targetDate`, and compatibility `horizonSendDays`. Omitted dates mean the\nscheduler-forward 48-hour window. `untilDate` is sender-local and inclusive;\n`targetDate` is one sender-local scheduler-fillable date. Skip no-send days and\nnever extend beyond the requested date. Finish the full D1 reread before D2.\nOrdinary refill defaults to `yolo:true`; only an explicit `yolo:false` or a\nclear request for review-first/manual execution opts out.\n\n```text\nrefill_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\", runHandle?: RefillRunHandleV1, targetConfig?: RefillTargetConfigV1, reportingContext?: RefillReportingContextV2, messageTemplateRevision?: MessageTemplateRevisionV1 })\n```\n\n```mermaid\nflowchart TD\n A[\"Parse the operator request\"] --> AUTH{\"Sellable auth valid?\"}\n AUTH -- No --> LOGIN[\"Run the returned login flow and wait\"]\n LOGIN --> AUTH\n AUTH -- Yes --> WS[\"Resolve exact workspace by ID, exact name, or install mapping\"]\n WS --> WSG{\"One accessible workspace match?\"}\n WSG -- No --> WB[\"Output: blocked_retryable / WORKSPACE_REQUIRED or workspace_ambiguous\"]\n WSG -- Yes --> SENDERS[\"Resolve each sender inside that workspace by ID, exact name, or unambiguous prefix\"]\n SENDERS --> SG{\"Every selector resolves exactly?\"}\n SG -- No --> SB[\"Output: blocked_retryable / sender_selector_unresolved with candidates\"]\n SG -- Yes --> DATE[\"Normalize 48h, exact targetDate, or inclusive untilDate in sender-local time\"]\n DATE --> ROUTE{\"Does this server expose refill_v3_advance?\"}\n ROUTE -- Yes --> V3[\"Refill V3 route: load core/flow.v3.json and call refill_v3_advance\"]\n ROUTE -- No --> D1[\"D1: call get_refill_target_plan read-only with exact scope\"]\n D1 --> RENDER[\"Render sender/campaign waterfall, coverage ledger, first action, side effects, forbidden actions, and stop condition\"]\n RENDER --> D2[\"D2: call refill_sends with workspaceCoordinator true plus displayed targetShapeRevision and actionKey\"]\n```\n\nScheduled and `--yolo` execution require an explicit `workspaceId` on every\ncall. Never change the shared active workspace to control an automation, never\nfall back to its full fleet, and never mutate the workspace that merely happens\nto be active. If the native tool is unavailable, use only the host’s exact\nconfigured Sellable MCP transport; otherwise stop with `sellable_mcp_unavailable`\ninstead of manually reproducing the workflow.\n\nBefore product work, load the closed workflow asset completely and verify it:\n\n```text\nget_subskill_prompt({ subskillName: \"refill-sends-workflow\" })\nget_subskill_asset({ subskillName: \"refill-sends-workflow\", assetPath: \"core/flow.v1.json\" })\n```\n\nContinue chunks until `hasMore:false`; require `workflow:\"refill-sends-workflow\"`\nand a COMPATIBLE version: same major (`v1`) and minor at or above the minimum\n`v1.9` — so `v1.9`, `v1.10` pass while `v1.8` and `v2.x` do not. Report the\nverified version before D1. A missing, unparseable, wrong-major, or\nbelow-minimum version is `workflow_version_mismatch`: stop before\n`get_refill_target_plan` or mutation. Do NOT require exact string equality: the\nflow asset ships in the npm package while this skill is installed separately,\nso an exact pin makes every additive contract change a breaking one.\nRoute intent is immutable: ordinary refill uses `intent:\"auto\"` from first plan\nthrough terminal; explicit `yolo:false` uses the review-first path.\n\n## Mandatory visible plan before execution\n\nEvery refill in every mode begins with D1, a read-only\n`get_refill_target_plan` with the exact workspace, sender/action selectors, and\ndate envelope. For default yolo execution, the first D1 call must explicitly pass\n`approvalMode:\"approve\"`; never rely on the planner's `mark_ready` default and\nthen discover the scope mismatch at D2. Invoke D1 exactly once, retain and parse\nthat response in the same host composition, and never call D1 again only to\nformat or render it. Render its plan in normal chat before any mutation. At minimum,\nshow one row per selected sender/campaign lane with sender, campaign, lane/source\nfamily, planned first action, target/cap, sent, scheduled, ready, still needing\npreparation, fallback order, and blocker/skip reason. Then show the bounded side\neffects, forbidden actions, stop condition, `targetShapeRevision`, and first\n`globalActionQueue[0].actionKey`.\n\nIf a stale or missing paid-credit fact prevents a certified fillable cap, show\n`pending credit refresh`, never bare `unknown`. The target remains visible and\nyolo executes the displayed refresh action before replanning the numeric cap.\n\nAfter rendering D1, explicit `yolo:false` asks Accept or Decline and invokes\nonly the returned `planned_manual_run` after Accept. Default `yolo:true` does\nnot ask: call\n`refill_sends` D2 with `workspaceCoordinator:true`, the identical scope, and\nboth `expectedTargetShapeRevision` and `expectedActionKey` copied from the\ndisplayed packet. The server may itself return `status:\"plan_ready\"`; render\nthat returned plan before invoking `planned_manual_run` or\n`planned_workspace_run`. Thus the modes share the exact same visible plan and\nrevision fence. The only difference is that non-yolo pauses for decisions while\n`--yolo` auto-accepts the displayed packet and autonomously traverses every\nplanner-ranked existing campaign, lane, source, safe rubric trial, and scheduler\nhandoff until terminal. If either pin drifts, render the fresh read-only\nreplacement packet; do not mutate from the stale plan. No credit refresh, fence,\nor product mutation may exist before this render.\n\n## Coordinator lifecycle\n\n```mermaid\nflowchart TD\n A[\"Fresh read-only workspace refill plan rendered to the user\"] --> FULL{\"Projected coverage sent + scheduled is full?\"}\n FULL -- Yes --> COMPLETE[\"Terminal: complete\"]\n FULL -- No --> ACTIVE{\"Active exact fenced run exists?\"}\n ACTIVE -- Yes --> RESUME[\"Resume only issued runId, fence, targetConfig, reportingContext\"]\n ACTIVE -- No --> PICK[\"Select globalActionQueue 0\"]\n PICK --> PREFLIGHT[\"Exact campaign, table, sender, action, lane preflight\"]\n PREFLIGHT --> ACT[\"Execute one bounded planner action\"]\n RESUME --> ACT\n ACT --> OUTCOME{\"Canonical outcome?\"}\n OUTCOME -- \"Committed or canonical no-op\" --> A\n OUTCOME -- \"Still running\" --> WAIT[\"Bounded read-only wait or receipt reconciliation\"]\n WAIT --> A\n OUTCOME -- \"Source exhausted\" --> NEXT{\"Another planner-ranked existing target?\"}\n NEXT -- Yes --> HANDOFF[\"Terminalize exact fence as next_exact_target\"]\n HANDOFF --> A\n NEXT -- No --> NC[\"Terminal: new_campaign_required; ask whether to create it\"]\n OUTCOME -- \"Provider unavailable after one retry\" --> RETRY[\"Terminal: blocked_retryable; universeExhausted false\"]\n OUTCOME -- \"Scope, config, readiness, or receipt drift\" --> BLOCK[\"Terminal: blocked_retryable with exact blocker\"]\n OUTCOME -- \"Planner marker done\" --> DONE[\"Terminalize marker; never dispatch it\"]\n```\n\nIf `status:\"plan_ready\"`, render its full plan packet first. Non-yolo asks for\nAccept or Decline before `planned_manual_run`; `--yolo` invokes\n`planned_workspace_run` automatically. If `status:\"in_progress\"`, invoke only the returned\n`continuation.arguments`. `targetConfig` and `runHandle` are separate and remain\nunchanged except for a server-issued takeover fence. `active_exact_run` resumes\nthat fence; `next_exact_target` carries no stale run fence. Never open a second\nor overlapping run, ask the user to type “continue”, redispatch a control marker, or\nturn `done`, `next_campaign`, or a continuation object into a product action.\n\n## Per-sender campaign and lane waterfall\n\nUse managed evergreen order when healthy. Otherwise build the same waterfall\non the fly from existing eligible campaigns the sender is already attached to.\nThis makes regular and evergreen campaigns differ only in where ordering comes\nfrom, not in how refill proceeds.\n\n```mermaid\nflowchart TD\n A[\"All existing campaign-backed sequences attached to one sender\"] --> FILTER[\"Exclude wrong workspace/sender, archived, completed, direct, disconnected, or sequence-invalid targets\"]\n FILTER --> STALE{\"Managed waterfall complete and live?\"}\n STALE -- Yes --> MANAGED[\"Use configured priority order\"]\n STALE -- No --> DERIVE[\"Derive deterministic order from dashboard-active campaigns\"]\n DERIVE --> P1[\"Prefer canonical source/lane priority\"]\n P1 --> P2[\"Then future scheduled and ready inventory\"]\n P2 --> P3[\"Then recent successful sends and source health\"]\n P3 --> P4[\"Then active before exact start-eligible paused, recency, stable ID\"]\n MANAGED --> PIN[\"Pin exact per-sender and per-action lane chain for this run\"]\n P4 --> PIN\n PIN --> LANE[\"Select highest-priority non-exhausted lane\"]\n LANE --> REFILL[\"Run row lifecycle\"]\n REFILL --> EX{\"Lane structurally exhausted?\"}\n EX -- No --> REFILL\n EX -- Yes --> MORE{\"Another pinned existing lane or source family?\"}\n MORE -- Yes --> LANE\n MORE -- No --> END[\"Output: lanes_exhausted, then new_campaign_required if coverage still short\"]\n```\n\nCampaign enrollment/removal, missing pinned targets, or loss of eligibility is\ntyped scope drift; a fresh planner may rederive, but the host cannot silently\nsubstitute a target. A current dashboard-active `PAUSED` campaign is eligible\nonly when the planner names that exact campaign as start-eligible. Starting it\nmay let the product scheduler schedule/send approved sequence actions and must\nbe reported. DMs are follow-ups, not refill horizon targets. Mixed sequences\nkeep distinct exact target paths; do not choose campaign-union behavior.\n\n## Connection and InMail capacity overlay\n\n```mermaid\nflowchart TD\n S[\"Sender capacity and exact selected days\"] --> C{\"Connection slots available now or later in rolling week?\"}\n S --> F{\"Paid-InMail credit facts fresh?\"}\n F -- No --> RF[\"Refresh exact selected sender once per run, then replan\"]\n RF --> P{\"Credits meet existing threshold, normally 5?\"}\n F -- Yes --> P\n C -- Yes --> INV[\"Enable existing invite lanes\"]\n C -- No --> INVCAP[\"Cap invite lane with timing evidence\"]\n P -- Yes --> MAIL[\"Enable existing paid-InMail or cascade lane\"]\n P -- No --> MAILCAP[\"Skip paid lane; never lower threshold\"]\n INV --> UNION[\"Rank enabled existing lanes per sender\"]\n MAIL --> UNION\n INVCAP --> ALT{\"Paid lane enabled?\"}\n MAILCAP --> ALT2{\"Invite or same-campaign connection fallback enabled?\"}\n ALT -- Yes --> UNION\n ALT -- No --> CAP[\"Output: blocked_retryable / capacity or window\"]\n ALT2 -- Yes --> UNION\n ALT2 -- No --> CAP\n UNION --> POOL[\"Pool shared-campaign prepared inventory; never double-enrich\"]\n```\n\n`rollingWeeklyInvite.capacityFreedDuringWindow:true` means later capacity is\nschedulable; use its timing fields rather than treating the opening gate as a\nfull-day blocker. Credit freshness precedes scheduler wait. Fresh facts below\nthreshold authorize only an already-eligible existing connection fallback or\nanother existing campaign—not a threshold change or new campaign.\n\n## Row lifecycle\n\nFor every selected lane, use the smallest action that can reduce its gap.\n\n```mermaid\nflowchart TD\n A[\"Lane still has projected gap\"] --> ACTIVE{\"Active import, preparation, or stuck work?\"}\n ACTIVE -- \"Healthy active\" --> WAIT[\"Bounded read-only wait; honor wait.deadlineAt\"]\n WAIT --> A\n ACTIVE -- \"Stuck or anomalous\" --> REPAIR[\"Run only planner-bounded repairable cells or return blocker\"]\n REPAIR --> A\n ACTIVE -- No --> APPROVE{\"Generated rows can be approved?\"}\n APPROVE -- Yes --> AP[\"Approve exact bounded cohort with readiness authority\"]\n AP --> REPLAN[\"Record receipt and full authoritative replan\"]\n APPROVE -- No --> ENRICH{\"Existing rows can be enriched or prepared?\"}\n ENRICH -- Yes --> PREP[\"Enrich, generate, or rerun exact bounded cohort\"]\n PREP --> REPLAN\n ENRICH -- No --> SOURCE{\"Selected source can add qualified rows?\"}\n SOURCE -- Yes --> ADD[\"Copy/import bounded rows from exact selected source\"]\n ADD --> REPLAN\n SOURCE -- No --> EXPAND[\"Run source-family acquisition flow\"]\n EXPAND --> REPLAN\n REPLAN --> A\n```\n\nStructural exhaustion requires receipt-proven\n`hasMoreFrontierRows:false`, zero `approvalCandidates`, no fresh active prep,\nno `stuckActiveCells`, and no non-terminal `approvedNotDispatched` work. A dry\npreparation receipt is run-scoped and prevents the identical no-op from\nrepeating. `USER_ADDED_ROWS_LIMIT_EXCEEDED` may use a bounded same-source split\nthrough `load_csv_linkedin_leads` into the exact review batch; a true campaign\ntable hard cap returns a capacity blocker and never deletes rows.\n\n## Sender Post Engagers acquisition\n\n```mermaid\nflowchart TD\n A[\"Sender Post Engagers lane needs rows\"] --> UNUSED{\"Unused selected post/engager rows exist?\"}\n UNUSED -- Yes --> USE[\"Import/copy bounded unused rows\"]\n UNUSED -- No --> REFRESH[\"Refresh this sender's latest recent authored posts\"]\n REFRESH --> SELECT[\"Select new unprocessed relevant high-engagement posts\"]\n SELECT --> FETCH[\"Fetch/import their engagers and dedupe\"]\n FETCH --> YIELD{\"Usable qualified yield?\"}\n YIELD -- Yes --> USE\n YIELD -- No --> EX[\"Exhaust only this Post Engagers lane\"]\n EX --> NEXT[\"Advance to Shared Signal Discovery or next pinned existing lane\"]\n```\n\nThe campaign must be sender-owned: exactly that sender, authored posts only.\nNever invent keywords, search third-party posts, or run general Signal Discovery\nagainst the Post Engagers campaign.\n\n## Shared Signal Discovery acquisition\n\n```mermaid\nflowchart TD\n A[\"Shared Signal lane needs rows\"] --> UNUSED{\"Unused selected rows or unprocessed posts exist?\"}\n UNUSED -- Yes --> USE[\"Import/copy bounded rows\"]\n UNUSED -- No --> STALE[\"Re-search stale existing topics for newly published posts\"]\n STALE --> SY{\"Projected qualified yield meets min remaining gap or 100?\"}\n SY -- Yes --> USE\n SY -- No --> DERIVE[\"Derive up to five concise positive-ICP topics from approved campaign intent\"]\n DERIVE --> DY{\"Projected qualified yield meets floor?\"}\n DY -- Yes --> USE\n DY -- No --> AGENT[\"Request 3-5 new agent-supplied topics through the same fenced continuation\"]\n AGENT --> SEARCH[\"Search once, excluding searchedKeywords, then project actual returned candidates\"]\n SEARCH --> PROVIDER{\"All LinkedIn providers failed?\"}\n PROVIDER -- Yes --> RETRY[\"Retry the same bounded search once\"]\n RETRY --> RECOVER{\"Provider recovered?\"}\n RECOVER -- No --> BLOCK[\"Output: blocked_retryable / provider_unavailable; universeExhausted false\"]\n RECOVER -- Yes --> AY{\"Actual qualified yield meets floor?\"}\n PROVIDER -- No --> AY\n AY -- Yes --> USE\n AY -- No --> EX[\"Receipt-proven signal_yield_below_floor\"]\n EX --> NEXT[\"Advance to next pinned existing lane\"]\n```\n\nProvider outage never consumes a keyword tier or proves exhaustion. Temporary\nderived search state is run-scoped; later runs may rediscover new posts. Agent\nkeywords are supplied only through the exact run continuation, never by user\nsteering or a second run.\n\n## Sales Nav and Prospeo acquisition\n\n```mermaid\nflowchart TD\n A[\"Cold-provider lane needs rows\"] --> UNUSED{\"Unused exact-source rows exist?\"}\n UNUSED -- Yes --> USE[\"Import/copy bounded rows\"]\n UNUSED -- No --> DEEP[\"Continue latest/unfetched pages of exact saved Sales Nav or Prospeo search\"]\n DEEP --> DY{\"Qualified yield?\"}\n DY -- Yes --> USE\n DY -- No --> OPTIONAL{\"Known activity/recency filter exists?\"}\n OPTIONAL -- No --> NEXT[\"Advance to next pinned existing lane\"]\n OPTIONAL -- Yes --> CLONE[\"Clone exact approved search; remove one optional activity/recency filter\"]\n CLONE --> PROOF{\"Original unchanged and every hard-fit filter fingerprint preserved?\"}\n PROOF -- No --> BLOCK[\"Output: blocked_retryable / provider_search_drift\"]\n PROOF -- Yes --> TRIAL[\"Import bounded trial candidates into existing gated source\"]\n TRIAL --> GATE[\"Run current ICP, exclusion, DNC, persona, geography, and company-fit gates\"]\n GATE --> GY{\"Qualified yield?\"}\n GY -- Yes --> USE\n GY -- No --> QUARANTINE[\"Rejects remain unsendable; advance lane\"]\n QUARANTINE --> NEXT\n```\n\nThe original saved search is immutable. An automatic trial may remove only a\nknown activity/recency signal; role, seniority, geography, industry, company\nsize, domain, include/exclude, DNC, and every other hard-fit constraint remain\nbyte-for-byte. Imported candidates are not approvals: current campaign gates\nquarantine bad fits. If rubric rejects dominate — including a receipt-proven\n`low_yield` cohort below the 10% planning floor, not only zero-prepared — enter\nthe bounded sample-quality trial below before another source add. Do not repeat\na spent trial or switch outside planner order.\n\n## Provider prompt before any new provider search\n\nDraining an already-imported source list needs no provider context. But before\nany action that runs a NEW provider search — a `broaden_signal_search` round\n(especially when supplying `agentKeywords`), a Sales Nav or Prospeo cloned-\nsearch broadening, or any source add that dispatches a fresh search — load the\nmatching specialized prompt first with\n`get_provider_prompt({ provider, campaignOfferId })` and apply its discipline:\nsample-first fit checks against the headline ICP criteria, the 10% planning\nfloor, sample math (target ÷ observed pass rate) for sizing, and the keyword-\nquality guidance for Signal Discovery. Inventing broaden keywords or sizing a\nscrape without the provider prompt in context repeats the blind-import failure\nthe sampling discipline exists to prevent. The search tools also enforce this\npreflight server-side; loading it late wastes a fenced round on a typed refusal.\n\n## Rubric sample-quality trial\n\nRubric rejection may mean the source is poor or that one or several required\nchecks are unnecessarily narrow. Decide from an exact sample, not pass-rate alone.\n\n```mermaid\nflowchart TD\n A[\"Rows fail ICP/rubric gate\"] --> STALE{\"Score stale, errored, or computed under mismatched authority?\"}\n STALE -- Yes --> RESCORE[\"Rerun exact bounded cohort under unchanged current rubric\"]\n RESCORE --> RESULT{\"Now qualified?\"}\n RESULT -- Yes --> CONTINUE[\"Continue row lifecycle\"]\n RESULT -- No --> SAMPLE\n STALE -- No --> SAMPLE[\"Take exact representative rejected sample from prep receipt\"]\n SAMPLE --> SNAP[\"Snapshot complete rubric and prior digest\"]\n SNAP --> PROPOSE[\"Propose smallest 1-3 required-to-advisory bundle that creates useful new passes\"]\n PROPOSE --> HARD{\"Touches employment, DNC/opt-out, legal/compliance, or explicit exclusion?\"}\n HARD -- Yes --> REJECT[\"Reject proposal; preserve complete prior rubric\"]\n HARD -- No --> SIM[\"Simulate bundle from recorded per-prospect evaluations; no mutation\"]\n SIM --> DELTA{\"Any newly passing prospects?\"}\n DELTA -- No --> REJECT\n DELTA -- Yes --> QUALITY[\"Review only newly passing profiles in campaign and customer context\"]\n QUALITY --> REPLY{\"If these prospects replied, would the customer be comfortable and consider the replies relevant?\"}\n REPLY -- No --> REJECT\n REPLY -- Yes --> DRIFT{\"Live rubric digest still equals prior digest?\"}\n DRIFT -- No --> BLOCK[\"Output: blocked_retryable / rubric config drift\"]\n DRIFT -- Yes --> APPLY[\"Guarded apply entire required-to-advisory bundle\"]\n APPLY --> EXACT[\"Force exact bounded ICP rescore for accepted sample\"]\n EXACT --> VERIFY{\"Dispatch and accepted quality receipt valid?\"}\n VERIFY -- Yes --> KEEP[\"Keep bundle; receipt before/after digests, changed checks, sample counts, and verdict\"]\n VERIFY -- No --> ROLLBACK[\"Restore complete prior snapshot and receipt rollback\"]\n REJECT --> BETTER[\"Keep rows unsendable; continue better supply or next existing lane\"]\n ROLLBACK --> BETTER\n```\n\n`--yolo` may change more than one required rubric at a time only through this\nsingle bounded reversible bundle. The change demotes selected required checks to\nadvisory scoring; it does not erase their evidence. The acceptance test is the\nnewly passing delta: if any reviewed prospect would make the customer unhappy,\nsurprised, or consider the reply irrelevant, keep the complete prior rubric and\ncontinue the source waterfall. Never expose raw prospect profiles in the public\nreceipt.\n\n## Scheduler and uncertain-receipt recovery\n\n```mermaid\nflowchart TD\n A[\"Ready buffer covers remaining projected gap\"] --> CREDIT{\"Every selected paid lane has fresh credit facts?\"}\n CREDIT -- No --> RF[\"Refresh each exact selected sender once, then full replan\"]\n RF --> A\n CREDIT -- Yes --> DATE{\"Exact targetDate?\"}\n DATE -- Yes --> SWEEP[\"Dispatch one request-scoped product scheduler sweep\"]\n DATE -- No --> WAIT[\"Enter coordinator-owned bounded scheduler wait\"]\n SWEEP --> RECEIPT{\"Receipt state?\"}\n RECEIPT -- Terminal --> READ[\"Canonical target-plan and request/effect readback\"]\n RECEIPT -- Active --> POLL[\"Return in_progress and poll only the same request key\"]\n RECEIPT -- uncertain_outcome --> RECON[\"Reconcile same request key read-only; never redispatch\"]\n POLL --> RECEIPT\n RECON --> TERM[\"Terminal: blocked_retryable with request identity intact\"]\n WAIT --> READ\n READ --> FULL{\"Projected coverage full?\"}\n FULL -- Yes --> COMPLETE[\"Terminal: complete\"]\n FULL -- No --> READY{\"Ready buffer still covers gap?\"}\n READY -- Yes --> OTHER{\"Any other workspace target still needs preparation or an executable gate?\"}\n OTHER -- Yes --> PREP[\"Continue next planner-ranked exact target\"]\n OTHER -- No --> BLOCK[\"Terminal: receipt-backed blocked_retryable scheduler gap\"]\n READY -- No --> PREP[\"Return to row lifecycle\"]\n```\n\nA scheduler sweep is a visible workspace-wide scheduling side effect: existing\nproduct gates may schedule unrelated eligible cells in that workspace/date.\nIt never sends directly or raw-writes scheduler fields. `cellsConsidered is\nallocation-attempt count`; `readyCellsFound` is prefilter inventory. Inspect\n`campaignScopeSummary`, `prefiltered`, `skipped`, and `deferred`. For ready\nclosed-InMail cells with stale paid-credit evidence, use\n`refresh_paid_inmail_credits_then_rerun`. `wait_for_capacity_or_window` means do\nnot source or prep more rows; `no_ready_cells_continue_refill_prep` returns to\nthe row lifecycle. `cellsScheduled:0` alone is not failure. Once a sweep is\ndispatched, a host wait budget yields an `in_progress` continuation carrying\nthe same run identity. Keep polling that request key until its official\nterminal receipt, then reread the full target plan. Never convert an active\nsweep into `loaded_awaiting_scheduler`.\n\n## Explicit message-template revision\n\nOrdinary refill never changes copy. Only a literal user-approved revision\nenvelope may enter this side path.\n\n```mermaid\nflowchart TD\n A[\"Literal messageTemplateRevision with approved markdown, digests, 1-500 row IDs, request/effect IDs\"] --> DIGEST{\"Current prior authority digest present?\"}\n DIGEST -- No --> FENCE[\"Acquire exact run and read reportingContext source templateAuthorityDigest\"]\n FENCE --> DG{\"Digest returned?\"}\n DG -- No --> BLOCK[\"Terminal: blocked_retryable / template_authority_missing\"]\n DG -- Yes --> REVISE[\"Apply revision to exact cohort\"]\n DIGEST -- Yes --> REVISE\n REVISE --> AUDIT[\"select_campaign_cells in batches <=20 with includeGeneratedMessageReview:true\"]\n AUDIT --> MATCH{\"Every authoritativeGeneratedMessageReview complete, exact text/digest, matchesCurrentTemplateAuthority true?\"}\n MATCH -- No --> FAIL[\"Stop before approval: regenerated_copy_integrity_failed\"]\n MATCH -- Yes --> APPROVE[\"Approve only exact rowIds using compiled readiness authority\"]\n APPROVE --> RECEIPT{\"Bounded preparation receipt includes laneScope?\"}\n RECEIPT -- No --> FAIL\n RECEIPT -- Yes --> PLAN[\"Return to canonical refill plan\"]\n```\n\nFormula Message/Subject columns, previews, exports, and counts are not copy\nauthority. `forceRerun:true` never implies a revision or approval.\n\n## Manual approval and `--yolo`\n\n```mermaid\nflowchart TD\n A[\"Render fresh bounded packet in normal chat as Markdown\"] --> MODE{\"--yolo present?\"}\n MODE -- Yes --> AUTO[\"Auto-accept all planner-ranked transitions among existing campaigns, lanes, sources, and safe refill primitives\"]\n MODE -- No --> ASK[\"Open host-native structured question with exactly Accept and Decline\"]\n ASK --> DECISION{\"Operator choice?\"}\n DECISION -- Accept --> RUN[\"Execute only rendered envelope\"]\n DECISION -- Decline --> STOP[\"Stop with no mutation\"]\n AUTO --> RUN\n```\n\nUse `plain chat` in Codex and `plain chat` in Claude Code. The\nfull packet belongs in the normal chat message immediately before the question:\nworkspace, sender scope, campaign-by-campaign plan table, action, target/cap,\nsource, blocker/skip reason, exact IDs, expected side effects, forbidden actions,\nand stop condition. The question body must be compact and refer back to the\nposted packet instead of duplicating it. `--yolo` may switch among every fresh\nplanner-ranked existing campaign/lane/source family and start the exact selected\n`PAUSED` campaign. It does not create campaigns, direct-send, archive/delete,\nchange sender limits or paid-InMail thresholds, reassign senders, or invent\nsource selection outside the planner.\n\n## Typed outputs\n\n```mermaid\nflowchart TD\n A[\"Fresh canonical state\"] --> C{\"Terminal classification\"}\n C -- \"sent + scheduled meets target\" --> COMPLETE[\"complete: report saturation ledger\"]\n C -- \"all remaining exact targets scheduler-owned and workspace ready-or-projected gap is zero\" --> LOADED[\"loaded_awaiting_scheduler: report expected pickup and stop\"]\n C -- \"recoverable external, capacity, active-work, or receipt condition\" --> BLOCKED[\"blocked_retryable: exact blocker, receipt, and safe retry condition\"]\n C -- \"current lane spent but another existing target remains\" --> EX[\"lanes_exhausted internally; continue next_exact_target\"]\n C -- \"every existing campaign/lane/source spent or infeasible\" --> NEW[\"new_campaign_required: propose missing shape and ask whether to create it\"]\n C -- \"scope/config/readiness changed\" --> DRIFT[\"blocked_retryable: typed drift; never guess\"]\n```\n\nOne scheduler-loaded exact lane is not a workspace terminal: skip it and\ncontinue other planner-ranked lanes. Workspace `loaded_awaiting_scheduler` is\nadmissible only when no refill-owned scheduler request is active. After refill\ndispatches a sweep, keep the same fence alive until the official terminal\nreceipt; then return `complete` from the post-receipt readback or a concrete\nreceipt-backed retryable scheduler blocker if coverage remains short. The sole\nrefill-ladder expansion\nthat asks the user in `--yolo` is `new_campaign_required`; refill itself never\ncreates that campaign. `new_campaign_required` is also the truthful terminal\nwhen receipts prove every existing lane is spent but the planner has no\nautomatic cold rung to propose (Signal Discovery workspaces): report the\nremaining gap and ask the user; a future handler may automate the creation. A\n`actionable_supply_not_queued` terminal means actionable row frontiers\n(approval/generate/enrich/rubric or unprocessed frontier rows) still exist but\nno executable exact edge surfaced: retry once with a fresh command, and if it\nrepeats report it as a planner-exposure defect instead of treating the\nworkspace as exhausted. That census counts CONVERTIBLE rows only, de-duplicated\nper campaign/table lane — a frontier whose own preparation receipt carries a\nnon-retryable `icp_or_rubric_rejection` diagnosis is proven unable to convert,\nso it never inflates the census. When such receipts are all that remain, the\nterminal is `source_supply_exhausted_at_rubric`: a truthful source exhaustion,\nnot a defect and not retryable. Report the per-lane evidence from the note and\ntell the user that widening the rubric or adding fresh source rows is the only\nremaining fill path. Whenever a terminal reports a non-empty census, it also\nnames every exact edge the run refused (`Exact edges this run refused: ...`) —\nsurface those named blockers rather than describing the workspace as having no\navailable work.\n\n## Non-negotiable authority and proof\n\n- Before preparation, approval, or exact-date scheduling, require a validated\n compiled campaign and positive exact target readiness identity from the\n backend compiler: `profileSchemaVersion`, `compilerVersion`,\n `campaignDigest`, `actionColumnId`, action, `pathDigest`,\n `dependsOnColumnIds`, `runCondition`, the selected target's `capabilities`,\n `requestId`, `effectId`, and `dateGuards`. Never infer no-message behavior\n from a missing Generate Message column. Prepare rows according to the\n persisted sequence; bounded enrichment and LLM prerequisite calls are\n allowed only when authorized by the exact readiness packet and receipted.\n- Refuse approval outside the bounded authorized cohort. The exact selected\n target path controls message, subject, comment, reaction, and row approval.\n For exact dates, require the date strictly after sender-local today and inside\n the fill horizon. Prepared, approved, and ready rows remain intermediate\n evidence; completion requires request/effect-attributed scheduler-owned\n scheduled readback.\n- Execute one bounded primitive, then perform a full authoritative reread.\n Never call a LinkedIn outreach/provider-send surface from refill. No direct\n sends, raw scheduler writes, broad approval, threshold/limit changes,\n sender reassignment, destructive cleanup, or new campaign creation.\n- Maintain the target-window saturation ledger per sender: selected days,\n gross capacity, actual sent, future scheduler-owned scheduled with non-null\n `scheduledFor`, projected coverage (`sent + scheduled`), ready buffer,\n remaining gap, paid-InMail feasibility, `targetShapeRevision`, and\n `stateRevision`. Future scheduled coverage and already sent actions are\n distinct.\n- Carry canonical `refill_reporting.v2` unchanged through progress,\n continuation, replay, and terminal output. Completion proof is Sellable MCP\n evidence only: target plan, campaign refill state, scheduler capacity,\n sweep/status, and bounded receipts. Never use individual cell ids, Prisma,\n SQL, direct database access, or production-environment scripts as completion\n proof. Redact raw copy and prospect fields.\n\n## Refill V3\n\nThis is the DEFAULT route whenever `refill_v3_advance` is exposed (see\n[Route selection](#route-selection--do-this-first)). `refill_v3_advance` is then\nthe only execution owner and `refill-sends-workflow` plus its `core/flow.v3.json`\nasset is the contract to load — load the prompt and that asset, verify the `v3`\ncompatible range, and report the version before the first call. Start from the\nbase request `{workspaceId, scope}`, add `yolo:true` by default, and call it\nagain after each `advanced` or\nsettled `campaign_attention_required` result. A `run_step_pending` result means\nthe server is still completing the already-consumed step: wait its\n`retryAfterMs`, then call advance with the same public inputs. The MCP retains\nthe identical token internally; never copy a token, route to AI, or execute an\nauthority for this transport-reconciliation wait. `refill_v3_continue` itself\nsettles the exact packet action before it returns. Bounded enrichment and an\nalready-active preparation job use the shared Create Campaign waiter and\ndurable preparation owner; directly queued row repair uses the campaign waiter.\nSynchronous source, configuration, rubric, and exhaustion authorities already\nreturn after their own exact reread, so they return `settlement.ready:true` from\nthat bounded authority receipt and never wait on unrelated campaign-wide\nprocessing cells.\n\nWhen an explicit `yolo:false` request names a campaign, resolve that visible name with one\nauthorized bounded `get_campaigns` call carrying an explicit `limit`. Require\nexactly one case-insensitive exact match; if none or more than one match, stop\nwithout preview or mutation. Retain only the returned stable campaign ID. Call\n`refill_v3_world_state({workspaceId, scope, campaignId})`, render that exact\ncampaign's two-lane readiness and its explicit zero product side effects, then\nstop at the product-native question with exactly Accept and Decline. Do not call\n`refill_v3_advance` before Accept. Accept calls\n`refill_v3_advance({workspaceId, scope, campaignId})`; Decline stops. Carry the\nsame campaignId through every advance, continue, replay, partial-wait, and\npost-wait repeat. Display-name changes never alter this retained identity, and\nno sibling campaign may replace it.\nCall the next advance only when `settlement.ready` is true. When it is false,\ncall `wait_for_campaign_processing` with `settlement.resumeInput` **unchanged**;\nthat carries the exact `preparationJobId`, `requirePreparationTerminal:true`,\nand `requireIdle:true`. Repeat the returned `resumeInput` until ready; never\nfall back to a stats-only campaign wait for this settlement. An\n`awaiting_external_change` result with\n`deferral.code:\"campaign_work_in_flight\"` and a campaign id is a bounded\nread-only continuation, not permission to walk the next campaign: call\n`wait_for_campaign_processing({ workspaceId, campaignId, requireIdle:true })`,\nthen call `refill_v3_advance` again with the identical scope and yolo grant.\nThis reuses Create Campaign's campaign-table waiter and guarantees the same\ncampaign is freshly replanned after its cohort settles. If the bounded wait\nreturns a partial timeout, surface that checkpoint and make the fresh advance;\nif it reports the same live campaign, repeat the bounded wait. Stop on every\nother `awaiting_external_change`, `complete`, or `blocked` result. For each of\nthose terminal results, report **every** entry in `terminalEvidence.rows`, one\nper scoped sender/date/lane—not only the headline deferral or blocker. Include\n`targetSlots`, `takenSlots`, `remainingTargetGap`, `fillableSlotsNow`,\n`blockedGap`, `terminalClassification`, `reasonCodes`, `approvedDelta`, and\n`scheduledDelta`. When `reasonCodes` contains\n`paid_inmail_credit_refresh_failed`, also report `paidCreditRefreshAttempt`\nexactly: `attemptedAt`, `outcome`, `errorClass`, `errorDetail`, and `durationMs`.\nA cumulative observation, vague \"credit refresh\" label, or one surfaced blocker\nis never a row-complete terminal summary.\n\n`terminalEvidence.rows` covers exactly two Refill V3 lanes:\n`connection_invite` and closed/paid InMail. It does **not** report Open InMail.\nCampaign `supply.readyToSchedule` is a broad first-touch table count and can\ninclude Open InMail rows that the normal scheduler can place independently.\nNever present that broad count as connection or paid inventory, never infer\nOpen InMail is empty or unscheduled from a Refill V3 row, and never explain the\ndifference as sender affinity unless exact lane evidence proves it. If asked\nwhether Open InMail is maxed, say the two-lane refill receipt cannot answer that\nquestion and obtain an action-type-specific scheduled readback before answering.\n\nLead every row-complete terminal summary by stating that all scoped\nsender/date/lane rows were explored. Never say the workspace \"stopped on\" one\nsender or headline blocker: that blocker classifies one row after independent\nsibling work was explored; it is not the traversal stop.\n\nResolve the workspace BEFORE the first call, exactly as the V1 route already\nrequires. `workspaceId` must be an exact id on every automation call: when the\noperator names a workspace, call `list_workspaces` first and match that name to\nits id. Prefer one case-insensitive exact name match; if none exists, accept one\ncase-insensitive prefix match (so `Damiano` resolves `Damiano R`). Use the\nconfigured or active workspace only when the operator named none. If zero or\nmultiple prefix matches remain, stop and say so — do not fall back to the\nconfigured workspace — and never change the shared active workspace to steer\nan automation.\n\nThe command-shaped form is unambiguous: in `refill sends <name> [flags]`,\n`<name>` is the workspace override, never a sender name. A sender restriction\nmust be explicit through `--sender`/`senderIds`/`senderNames` or prose that says\n“sender.” Therefore call `list_workspaces` and resolve `<name>` first. Do not\nlist configured-workspace senders before that workspace match; doing so is both\nscope drift and avoidable latency.\n\nMap the rest of the request onto those keys and nothing else: the sender/date\nenvelope becomes `scope`. `sender_local_horizon` (1-3 days) is ONLY for\nrequests with no date control at all (\"refill sends X\"); the moment the\noperator names any date — `--target-date`, `--until-date`, or dated prose —\nthe scope is `exact_sender_dates`, on the FIRST call and every later call of\nthe run. There is no mode: WHICH campaign may be started is DERIVED from the\nworkspace's own campaigns and can never be requested.\n\nA DATE CONTROL always maps to `exact_sender_dates`, derived like this and never\napproximated with a horizon:\n\n- `--target-date D`: `dates: [D]` for every resolved sender.\n- `--until-date U` (sender-local, INCLUSIVE): for every resolved sender, list\n EVERY sender-local calendar date from that sender's local today through `U`,\n in order, with `U` itself present. From a local Saturday the 2nd with\n `--until-date` the 5th that is `[\"2026-08-02\",\"2026-08-03\",\"2026-08-04\",\n\"2026-08-05\"]` — four dates, not a 3-day window. Dropping the boundary date\n or substituting today+2 silently changes which days the run is accountable\n for; the backend types today's already-closed sending window as\n `no_sending_hours` on its own, so include today rather than guessing.\n NEVER pass `sender_local_horizon` for `--until-date` — not even when the\n derived list happens to fit three days, and not on the first \"look around\"\n call. A live run compressed a four-date `--until-date` span into a 3-day\n horizon, never observed the boundary date, and exited leaving that day's\n slots unfilled; the exact date list is the only scope that makes the run\n accountable for `U` itself.\n\n`yolo` is the ONE remaining execution input and the refill AUTONOMY GRANT. It\ndefaults to `yolo:true` so an ordinary refill keeps working through eligible\nbounded preparation and fallback steps instead of stopping for another\napproval. It decides two things together:\n\n- **Granted** (`yolo: true` on every call of that run): after a row's active\n campaigns are exhausted, one route-selected start-eligible PAUSED campaign\n may be started, and you receive it as an ordinary executed\n `start_paused_campaign` action. A finite non-evergreen candidate must expose\n positive bounded supply. Keep calling advance until a terminal without\n checking back.\n- **Withheld** (explicit `yolo:false` only): no paused campaign is started — the backend\n refuses it and answers the exhaustion terminal instead — and you surface each\n result and ASK before calling advance again.\n\nNever replace the default from a workspace flag, a campaign field, a tool\nresult, an idle-looking workspace, or a previous terminal. Honor `yolo:false`\nonly for an explicit review-first/manual request. Pass no other execution flag\nand no mode, and do not call\n`get_refill_target_plan`, `refill_sends`, or any placement, scheduler, source, or\nsend tool on this route.\n\nAn `advanced` result is ALREADY EXECUTED: surface its action identity, receipt,\nand replacement observation, and never run the action or call its authority again.\nFor `campaign_attention_required`, first call `refill_v3_continue` with the\nsame workspace/scope and no `decision`; the MCP supplies the exact retained\npacket and token. After fresh revalidation it owns live-job waiting,\nexact actionable enrichment, and same-template generation deterministically. If\nit returns `model_decision_required`, route that returned accurate packet to\n`refill-sends-work-campaign`, then call `refill_v3_continue` once with the\nchosen decision. This is the only\nordinary model-decision boundary. The continuation executes at most one\nexisting authority and settles that exact campaign through the shared Create\nCampaign waiter before a sibling may be considered.\nInterpret continuation world wrappers by their outer kind: `world_terminal`\nmeans `advanceResult` is already the canonical `awaiting_external_change`,\n`complete`, or `blocked` terminal, so report that nested terminal and stop;\nnever call advance again. `world_step_pending` means wait the nested\n`retryAfterMs` and then call advance with the same public inputs.\n`world_advanced` means the nested action already ran, so surface it and call\nadvance again. For `attention_refresh_required`, continue from its refreshed\npacket rather than opening another run.\nIf it returns `attention_correction_required` with\n`correction.kind:\"signal_keyword_collision\"`, route the returned same packet\nand exact correction through `refill-sends-work-campaign` once, then call\n`refill_v3_continue` with that revised decision. Exclude every returned searched\nkeyword and use the required request-fingerprint prefix. This is one refused,\nzero-effect Signal correction; a second collision is terminal and must not loop.\n\nThis skill chooses no sender, date, lane, campaign, or action, holds no counter or\ncursor between calls, and declares no terminal, exhaustion verdict, or health\nclassification of its own. V1 `refill_sends` behavior is unchanged.\n"
|
|
60
|
+
"content": "---\nname: sellable-refill-sends\ndescription: Refill projected sends across a workspace or selected senders through the canonical fenced coordinator.\nvisibility: public\nallowed-tools:\n - mcp_sellable_refill_sends\n - mcp_sellable_get_auth_status\n - mcp_sellable_start_cli_login\n - mcp_sellable_wait_for_cli_login\n - mcp_sellable_get_active_workspace\n - mcp_sellable_list_workspaces\n - mcp_sellable_set_active_workspace\n - mcp_sellable_get_subskill_prompt\n - mcp_sellable_get_subskill_asset\n - mcp_sellable_search_subskill_prompts\n - mcp_sellable_get_scheduler_fill_capacity\n - mcp_sellable_run_scheduler_sweep\n - mcp_sellable_refresh_paid_inmail_credits\n - mcp_sellable_list_senders\n - mcp_sellable_get_sender_routing\n - mcp_sellable_get_campaign_waterfall\n - mcp_sellable_resolve_campaign_fill_route\n - mcp_sellable_get_campaign_refill_state\n - mcp_sellable_get_refill_target_plan\n - mcp_sellable_fill_campaign_horizon\n - mcp_sellable_get_campaign\n - mcp_sellable_get_campaign_context\n - mcp_sellable_update_campaign\n - mcp_sellable_get_provider_prompt\n - mcp_sellable_get_campaign_message_preparation_status\n - mcp_sellable_start_campaign_message_preparation\n - mcp_sellable_cancel_campaign_message_preparation\n - mcp_sellable_import_leads\n - mcp_sellable_wait_for_lead_list_ready\n - mcp_sellable_confirm_lead_list\n - mcp_sellable_search_signals\n - mcp_sellable_select_promising_posts\n - mcp_sellable_fetch_post_engagers\n - mcp_sellable_search_sales_nav\n - mcp_sellable_lookup_sales_nav_filter\n - mcp_sellable_search_prospeo\n - mcp_sellable_search_prospeo_companies\n - mcp_sellable_confirm_prospeo_company_accounts\n - mcp_sellable_load_csv_linkedin_leads\n - mcp_sellable_load_csv_domains\n - mcp_sellable_list_dnc_entries\n - mcp_sellable_load_csv_dnc_entries\n - mcp_sellable_get_rows\n - mcp_sellable_get_rows_minimal\n - mcp_sellable_get_table_rows\n - mcp_sellable_get_campaign_table_schema\n - mcp_sellable_select_campaign_cells\n - mcp_sellable_queue_campaign_cells\n - mcp_sellable_wait_for_campaign_processing\n - mcp_sellable_get_sender\n---\n\n# Refill Sends\n\n## Installed Host Contract\n\nThis installed skill is running in Hermes Agent. When the shared workflow body\nor fallback text mentions Claude Code, Codex, or Hermes for internal parity,\nchoose the Hermes instruction for customer-facing language and host functions.\n\n- Customer-facing command: `/sellable-refill-sends`\n- MCP tool naming: Hermes exposes Sellable tools as `mcp_sellable_<tool>`;\n when shared instructions show `mcp_sellable_<tool>`, call the matching\n `mcp_sellable_<tool>` tool instead.\n- Structured questions: ask plainly in chat unless a Hermes-native approval or\n question tool is visible in the current session.\n- Bootstrap host label: `host: \"Hermes\"`\n- Install/reload blocker label: Hermes install/reload problem\n- Reload instruction: restart Hermes, or run `/reload-mcp` in the active\n Hermes session after install\n\nDo not tell Hermes users to run Codex or Claude command forms, use Codex/Claude structured-question APIs, or restart Codex Desktop or Claude Code. Do not describe this run as Claude Code or Codex.\n\nUse this skill for “fill”, “refill sends”, “max out sends”, “load everyone up”,\nor “fill horizon sends”. Exactly one coordinator owns execution: `refill_v3_advance`\non the V3 route, `refill_sends` on the V1 route. The host resolves the request,\ninvokes that coordinator, and follows its exact continuation; it never\nreconstructs the refill ladder from low-level tools.\n\nHost commands:\n\n- Claude Code: `/sellable-refill-sends`\n- Codex: `/sellable-refill-sends`\n\n## Scheduled customer-program entry\n\nA scheduled invocation is one downstream action of the existing customer\nprogram. It does not create a second refill loop or choose a new campaign. The\nprogram wrapper supplies one already-claimed home workspace plus its exact\ncampaign/sender cohort and one to three sender-local dates. Use that exact scope,\npass `yolo:true` to the same canonical Refill V3 advance/continue flow below,\nand retain the server-issued run continuity until the run settles. Never switch\nan Admin runtime to another workspace, widen the cohort, add dates, or create a\nchild schedule.\n\nReuse a persisted refill enrollment and its approved campaign, exclusion,\nsource, message, and sender rules. A human pause, a missing enrollment, a\nnever-launched campaign, legacy PAUSED state with no provenance, or generation\ndrift is a hold. Return the one exact decision or action the customer must take;\ndo not restart the campaign, invent permission, or ask for the same permission\nevery morning. An explicit authenticated Start/resume remains human-owned.\n\nScheduled results use five product meanings:\n\n- `settled`: independent readback proves the exact scheduled additions.\n- `partial`: some additions are proven and the remaining exact gaps/blockers are\n named.\n- `pending`: the same run or scheduler receipt is still active; retain and poll\n that identity.\n- `blocked`: no allowed next mutation exists; name the precise human or provider\n action and safe retry condition.\n- `quiet`: coverage was already healthy or routine maintenance settled with no\n customer action. Make the result available to the daily review; do not post a\n second routine message.\n\nInteractive `refill-sends --yolo` always receives its actual result immediately.\nState connection invitations and paid InMail separately: invitation capacity is\nnot paid InMail credit, and paid InMail coverage is never proof of invitation\ncoverage. “Added” means scheduler-owned rows with a non-null scheduled time; it\nnever means LinkedIn delivered them.\n\n## Route selection — do this FIRST\n\nDecide the route before parsing scope, before loading any flow asset, and before\nany tool call other than auth/workspace resolution. The predicate is\nMECHANICAL and observable in the connected Sellable MCP tool list:\n\n> **Is `refill_v3_advance` one of the tools this server exposes?**\n\n- **Yes → take the Refill V3 route.** This is the default for every workspace on\n a server that exposes the tool. Go to [Refill V3](#refill-v3) and follow it;\n the V1 ladder in the rest of this document does not apply.\n- **No → take the V1 route.** The installed server predates Refill V3, so\n `refill_sends` is the only coordinator available. Follow this document from\n [Entry and exact scope](#entry-and-exact-scope) onward.\n\nNever infer the route from a workspace flag, a campaign field, a tool result, or\nthe operator's wording: no such cutover signal exists, and guessing at one is\nwhat makes an ordinary refill request silently take the wrong route. Report the\nselected route explicitly before the first coordinator call.\n\n## Entry and exact scope\n\nEverything from here down to [Refill V3](#refill-v3) is the **V1 route**. Skip it\nentirely when route selection chose V3. On this route `refill_sends` is the only\nexecution owner and the host follows its exact continuation; it never\nreconstructs the refill ladder from low-level tools.\n\nAccepted request fields are `--yolo`, `workspaceId`, `--sender`/`senderIds`/\n`senderNames`, `actionTypes`, `--until`/`untilDate`, `--target-date`/\n`targetDate`, and compatibility `horizonSendDays`. Omitted dates mean the\nscheduler-forward 48-hour window. `untilDate` is sender-local and inclusive;\n`targetDate` is one sender-local scheduler-fillable date. Skip no-send days and\nnever extend beyond the requested date. Finish the full D1 reread before D2.\nOrdinary refill defaults to `yolo:true`; only an explicit `yolo:false` or a\nclear request for review-first/manual execution opts out.\n\n```text\nrefill_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\", runHandle?: RefillRunHandleV1, targetConfig?: RefillTargetConfigV1, reportingContext?: RefillReportingContextV2, messageTemplateRevision?: MessageTemplateRevisionV1 })\n```\n\n```mermaid\nflowchart TD\n A[\"Parse the operator request\"] --> AUTH{\"Sellable auth valid?\"}\n AUTH -- No --> LOGIN[\"Run the returned login flow and wait\"]\n LOGIN --> AUTH\n AUTH -- Yes --> WS[\"Resolve exact workspace by ID, exact name, or install mapping\"]\n WS --> WSG{\"One accessible workspace match?\"}\n WSG -- No --> WB[\"Output: blocked_retryable / WORKSPACE_REQUIRED or workspace_ambiguous\"]\n WSG -- Yes --> SENDERS[\"Resolve each sender inside that workspace by ID, exact name, or unambiguous prefix\"]\n SENDERS --> SG{\"Every selector resolves exactly?\"}\n SG -- No --> SB[\"Output: blocked_retryable / sender_selector_unresolved with candidates\"]\n SG -- Yes --> DATE[\"Normalize 48h, exact targetDate, or inclusive untilDate in sender-local time\"]\n DATE --> ROUTE{\"Does this server expose refill_v3_advance?\"}\n ROUTE -- Yes --> V3[\"Refill V3 route: load core/flow.v3.json and call refill_v3_advance\"]\n ROUTE -- No --> D1[\"D1: call get_refill_target_plan read-only with exact scope\"]\n D1 --> RENDER[\"Render sender/campaign waterfall, coverage ledger, first action, side effects, forbidden actions, and stop condition\"]\n RENDER --> D2[\"D2: call refill_sends with workspaceCoordinator true plus displayed targetShapeRevision and actionKey\"]\n```\n\nScheduled and `--yolo` execution require an explicit `workspaceId` on every\ncall. Never change the shared active workspace to control an automation, never\nfall back to its full fleet, and never mutate the workspace that merely happens\nto be active. If the native tool is unavailable, use only the host’s exact\nconfigured Sellable MCP transport; otherwise stop with `sellable_mcp_unavailable`\ninstead of manually reproducing the workflow.\n\nBefore product work, load the closed workflow asset completely and verify it:\n\n```text\nget_subskill_prompt({ subskillName: \"refill-sends-workflow\" })\nget_subskill_asset({ subskillName: \"refill-sends-workflow\", assetPath: \"core/flow.v1.json\" })\n```\n\nContinue chunks until `hasMore:false`; require `workflow:\"refill-sends-workflow\"`\nand a COMPATIBLE version: same major (`v1`) and minor at or above the minimum\n`v1.9` — so `v1.9`, `v1.10` pass while `v1.8` and `v2.x` do not. Report the\nverified version before D1. A missing, unparseable, wrong-major, or\nbelow-minimum version is `workflow_version_mismatch`: stop before\n`get_refill_target_plan` or mutation. Do NOT require exact string equality: the\nflow asset ships in the npm package while this skill is installed separately,\nso an exact pin makes every additive contract change a breaking one.\nRoute intent is immutable: ordinary refill uses `intent:\"auto\"` from first plan\nthrough terminal; explicit `yolo:false` uses the review-first path.\n\n## Mandatory visible plan before execution\n\nEvery refill in every mode begins with D1, a read-only\n`get_refill_target_plan` with the exact workspace, sender/action selectors, and\ndate envelope. For default yolo execution, the first D1 call must explicitly pass\n`approvalMode:\"approve\"`; never rely on the planner's `mark_ready` default and\nthen discover the scope mismatch at D2. Invoke D1 exactly once, retain and parse\nthat response in the same host composition, and never call D1 again only to\nformat or render it. Render its plan in normal chat before any mutation. At minimum,\nshow one row per selected sender/campaign lane with sender, campaign, lane/source\nfamily, planned first action, target/cap, sent, scheduled, ready, still needing\npreparation, fallback order, and blocker/skip reason. Then show the bounded side\neffects, forbidden actions, stop condition, `targetShapeRevision`, and first\n`globalActionQueue[0].actionKey`.\n\nIf a stale or missing paid-credit fact prevents a certified fillable cap, show\n`pending credit refresh`, never bare `unknown`. The target remains visible and\nyolo executes the displayed refresh action before replanning the numeric cap.\n\nAfter rendering D1, explicit `yolo:false` asks Accept or Decline and invokes\nonly the returned `planned_manual_run` after Accept. Default `yolo:true` does\nnot ask: call\n`refill_sends` D2 with `workspaceCoordinator:true`, the identical scope, and\nboth `expectedTargetShapeRevision` and `expectedActionKey` copied from the\ndisplayed packet. The server may itself return `status:\"plan_ready\"`; render\nthat returned plan before invoking `planned_manual_run` or\n`planned_workspace_run`. Thus the modes share the exact same visible plan and\nrevision fence. The only difference is that non-yolo pauses for decisions while\n`--yolo` auto-accepts the displayed packet and autonomously traverses every\nplanner-ranked existing campaign, lane, source, safe rubric trial, and scheduler\nhandoff until terminal. If either pin drifts, render the fresh read-only\nreplacement packet; do not mutate from the stale plan. No credit refresh, fence,\nor product mutation may exist before this render.\n\n## Coordinator lifecycle\n\n```mermaid\nflowchart TD\n A[\"Fresh read-only workspace refill plan rendered to the user\"] --> FULL{\"Projected coverage sent + scheduled is full?\"}\n FULL -- Yes --> COMPLETE[\"Terminal: complete\"]\n FULL -- No --> ACTIVE{\"Active exact fenced run exists?\"}\n ACTIVE -- Yes --> RESUME[\"Resume only issued runId, fence, targetConfig, reportingContext\"]\n ACTIVE -- No --> PICK[\"Select globalActionQueue 0\"]\n PICK --> PREFLIGHT[\"Exact campaign, table, sender, action, lane preflight\"]\n PREFLIGHT --> ACT[\"Execute one bounded planner action\"]\n RESUME --> ACT\n ACT --> OUTCOME{\"Canonical outcome?\"}\n OUTCOME -- \"Committed or canonical no-op\" --> A\n OUTCOME -- \"Still running\" --> WAIT[\"Bounded read-only wait or receipt reconciliation\"]\n WAIT --> A\n OUTCOME -- \"Source exhausted\" --> NEXT{\"Another planner-ranked existing target?\"}\n NEXT -- Yes --> HANDOFF[\"Terminalize exact fence as next_exact_target\"]\n HANDOFF --> A\n NEXT -- No --> NC[\"Terminal: new_campaign_required; ask whether to create it\"]\n OUTCOME -- \"Provider unavailable after one retry\" --> RETRY[\"Terminal: blocked_retryable; universeExhausted false\"]\n OUTCOME -- \"Scope, config, readiness, or receipt drift\" --> BLOCK[\"Terminal: blocked_retryable with exact blocker\"]\n OUTCOME -- \"Planner marker done\" --> DONE[\"Terminalize marker; never dispatch it\"]\n```\n\nIf `status:\"plan_ready\"`, render its full plan packet first. Non-yolo asks for\nAccept or Decline before `planned_manual_run`; `--yolo` invokes\n`planned_workspace_run` automatically. If `status:\"in_progress\"`, invoke only the returned\n`continuation.arguments`. `targetConfig` and `runHandle` are separate and remain\nunchanged except for a server-issued takeover fence. `active_exact_run` resumes\nthat fence; `next_exact_target` carries no stale run fence. Never open a second\nor overlapping run, ask the user to type “continue”, redispatch a control marker, or\nturn `done`, `next_campaign`, or a continuation object into a product action.\n\n## Per-sender campaign and lane waterfall\n\nUse managed evergreen order when healthy. Otherwise build the same waterfall\non the fly from existing eligible campaigns the sender is already attached to.\nThis makes regular and evergreen campaigns differ only in where ordering comes\nfrom, not in how refill proceeds.\n\n```mermaid\nflowchart TD\n A[\"All existing campaign-backed sequences attached to one sender\"] --> FILTER[\"Exclude wrong workspace/sender, archived, completed, direct, disconnected, or sequence-invalid targets\"]\n FILTER --> STALE{\"Managed waterfall complete and live?\"}\n STALE -- Yes --> MANAGED[\"Use configured priority order\"]\n STALE -- No --> DERIVE[\"Derive deterministic order from dashboard-active campaigns\"]\n DERIVE --> P1[\"Prefer canonical source/lane priority\"]\n P1 --> P2[\"Then future scheduled and ready inventory\"]\n P2 --> P3[\"Then recent successful sends and source health\"]\n P3 --> P4[\"Then active before exact start-eligible paused, recency, stable ID\"]\n MANAGED --> PIN[\"Pin exact per-sender and per-action lane chain for this run\"]\n P4 --> PIN\n PIN --> LANE[\"Select highest-priority non-exhausted lane\"]\n LANE --> REFILL[\"Run row lifecycle\"]\n REFILL --> EX{\"Lane structurally exhausted?\"}\n EX -- No --> REFILL\n EX -- Yes --> MORE{\"Another pinned existing lane or source family?\"}\n MORE -- Yes --> LANE\n MORE -- No --> END[\"Output: lanes_exhausted, then new_campaign_required if coverage still short\"]\n```\n\nCampaign enrollment/removal, missing pinned targets, or loss of eligibility is\ntyped scope drift; a fresh planner may rederive, but the host cannot silently\nsubstitute a target. A current dashboard-active `PAUSED` campaign is eligible\nonly when the planner names that exact campaign as start-eligible. Starting it\nmay let the product scheduler schedule/send approved sequence actions and must\nbe reported. DMs are follow-ups, not refill horizon targets. Mixed sequences\nkeep distinct exact target paths; do not choose campaign-union behavior.\n\n## Connection and InMail capacity overlay\n\n```mermaid\nflowchart TD\n S[\"Sender capacity and exact selected days\"] --> C{\"Connection slots available now or later in rolling week?\"}\n S --> F{\"Paid-InMail credit facts fresh?\"}\n F -- No --> RF[\"Refresh exact selected sender once per run, then replan\"]\n RF --> P{\"Credits meet existing threshold, normally 5?\"}\n F -- Yes --> P\n C -- Yes --> INV[\"Enable existing invite lanes\"]\n C -- No --> INVCAP[\"Cap invite lane with timing evidence\"]\n P -- Yes --> MAIL[\"Enable existing paid-InMail or cascade lane\"]\n P -- No --> MAILCAP[\"Skip paid lane; never lower threshold\"]\n INV --> UNION[\"Rank enabled existing lanes per sender\"]\n MAIL --> UNION\n INVCAP --> ALT{\"Paid lane enabled?\"}\n MAILCAP --> ALT2{\"Invite or same-campaign connection fallback enabled?\"}\n ALT -- Yes --> UNION\n ALT -- No --> CAP[\"Output: blocked_retryable / capacity or window\"]\n ALT2 -- Yes --> UNION\n ALT2 -- No --> CAP\n UNION --> POOL[\"Pool shared-campaign prepared inventory; never double-enrich\"]\n```\n\n`rollingWeeklyInvite.capacityFreedDuringWindow:true` means later capacity is\nschedulable; use its timing fields rather than treating the opening gate as a\nfull-day blocker. Credit freshness precedes scheduler wait. Fresh facts below\nthreshold authorize only an already-eligible existing connection fallback or\nanother existing campaign—not a threshold change or new campaign.\n\n## Row lifecycle\n\nFor every selected lane, use the smallest action that can reduce its gap.\n\n```mermaid\nflowchart TD\n A[\"Lane still has projected gap\"] --> ACTIVE{\"Active import, preparation, or stuck work?\"}\n ACTIVE -- \"Healthy active\" --> WAIT[\"Bounded read-only wait; honor wait.deadlineAt\"]\n WAIT --> A\n ACTIVE -- \"Stuck or anomalous\" --> REPAIR[\"Run only planner-bounded repairable cells or return blocker\"]\n REPAIR --> A\n ACTIVE -- No --> APPROVE{\"Generated rows can be approved?\"}\n APPROVE -- Yes --> AP[\"Approve exact bounded cohort with readiness authority\"]\n AP --> REPLAN[\"Record receipt and full authoritative replan\"]\n APPROVE -- No --> ENRICH{\"Existing rows can be enriched or prepared?\"}\n ENRICH -- Yes --> PREP[\"Enrich, generate, or rerun exact bounded cohort\"]\n PREP --> REPLAN\n ENRICH -- No --> SOURCE{\"Selected source can add qualified rows?\"}\n SOURCE -- Yes --> ADD[\"Copy/import bounded rows from exact selected source\"]\n ADD --> REPLAN\n SOURCE -- No --> EXPAND[\"Run source-family acquisition flow\"]\n EXPAND --> REPLAN\n REPLAN --> A\n```\n\nStructural exhaustion requires receipt-proven\n`hasMoreFrontierRows:false`, zero `approvalCandidates`, no fresh active prep,\nno `stuckActiveCells`, and no non-terminal `approvedNotDispatched` work. A dry\npreparation receipt is run-scoped and prevents the identical no-op from\nrepeating. `USER_ADDED_ROWS_LIMIT_EXCEEDED` may use a bounded same-source split\nthrough `load_csv_linkedin_leads` into the exact review batch; a true campaign\ntable hard cap returns a capacity blocker and never deletes rows.\n\n## Sender Post Engagers acquisition\n\n```mermaid\nflowchart TD\n A[\"Sender Post Engagers lane needs rows\"] --> UNUSED{\"Unused selected post/engager rows exist?\"}\n UNUSED -- Yes --> USE[\"Import/copy bounded unused rows\"]\n UNUSED -- No --> REFRESH[\"Refresh this sender's latest recent authored posts\"]\n REFRESH --> SELECT[\"Select new unprocessed relevant high-engagement posts\"]\n SELECT --> FETCH[\"Fetch/import their engagers and dedupe\"]\n FETCH --> YIELD{\"Usable qualified yield?\"}\n YIELD -- Yes --> USE\n YIELD -- No --> EX[\"Exhaust only this Post Engagers lane\"]\n EX --> NEXT[\"Advance to Shared Signal Discovery or next pinned existing lane\"]\n```\n\nThe campaign must be sender-owned: exactly that sender, authored posts only.\nNever invent keywords, search third-party posts, or run general Signal Discovery\nagainst the Post Engagers campaign.\n\n## Shared Signal Discovery acquisition\n\n```mermaid\nflowchart TD\n A[\"Shared Signal lane needs rows\"] --> UNUSED{\"Unused selected rows or unprocessed posts exist?\"}\n UNUSED -- Yes --> USE[\"Import/copy bounded rows\"]\n UNUSED -- No --> STALE[\"Re-search stale existing topics for newly published posts\"]\n STALE --> SY{\"Projected qualified yield meets min remaining gap or 100?\"}\n SY -- Yes --> USE\n SY -- No --> DERIVE[\"Derive up to five concise positive-ICP topics from approved campaign intent\"]\n DERIVE --> DY{\"Projected qualified yield meets floor?\"}\n DY -- Yes --> USE\n DY -- No --> AGENT[\"Request 3-5 new agent-supplied topics through the same fenced continuation\"]\n AGENT --> SEARCH[\"Search once, excluding searchedKeywords, then project actual returned candidates\"]\n SEARCH --> PROVIDER{\"All LinkedIn providers failed?\"}\n PROVIDER -- Yes --> RETRY[\"Retry the same bounded search once\"]\n RETRY --> RECOVER{\"Provider recovered?\"}\n RECOVER -- No --> BLOCK[\"Output: blocked_retryable / provider_unavailable; universeExhausted false\"]\n RECOVER -- Yes --> AY{\"Actual qualified yield meets floor?\"}\n PROVIDER -- No --> AY\n AY -- Yes --> USE\n AY -- No --> EX[\"Receipt-proven signal_yield_below_floor\"]\n EX --> NEXT[\"Advance to next pinned existing lane\"]\n```\n\nProvider outage never consumes a keyword tier or proves exhaustion. Temporary\nderived search state is run-scoped; later runs may rediscover new posts. Agent\nkeywords are supplied only through the exact run continuation, never by user\nsteering or a second run.\n\n## Sales Nav and Prospeo acquisition\n\n```mermaid\nflowchart TD\n A[\"Cold-provider lane needs rows\"] --> UNUSED{\"Unused exact-source rows exist?\"}\n UNUSED -- Yes --> USE[\"Import/copy bounded rows\"]\n UNUSED -- No --> DEEP[\"Continue latest/unfetched pages of exact saved Sales Nav or Prospeo search\"]\n DEEP --> DY{\"Qualified yield?\"}\n DY -- Yes --> USE\n DY -- No --> OPTIONAL{\"Known activity/recency filter exists?\"}\n OPTIONAL -- No --> NEXT[\"Advance to next pinned existing lane\"]\n OPTIONAL -- Yes --> CLONE[\"Clone exact approved search; remove one optional activity/recency filter\"]\n CLONE --> PROOF{\"Original unchanged and every hard-fit filter fingerprint preserved?\"}\n PROOF -- No --> BLOCK[\"Output: blocked_retryable / provider_search_drift\"]\n PROOF -- Yes --> TRIAL[\"Import bounded trial candidates into existing gated source\"]\n TRIAL --> GATE[\"Run current ICP, exclusion, DNC, persona, geography, and company-fit gates\"]\n GATE --> GY{\"Qualified yield?\"}\n GY -- Yes --> USE\n GY -- No --> QUARANTINE[\"Rejects remain unsendable; advance lane\"]\n QUARANTINE --> NEXT\n```\n\nThe original saved search is immutable. An automatic trial may remove only a\nknown activity/recency signal; role, seniority, geography, industry, company\nsize, domain, include/exclude, DNC, and every other hard-fit constraint remain\nbyte-for-byte. Imported candidates are not approvals: current campaign gates\nquarantine bad fits. If rubric rejects dominate — including a receipt-proven\n`low_yield` cohort below the 10% planning floor, not only zero-prepared — enter\nthe bounded sample-quality trial below before another source add. Do not repeat\na spent trial or switch outside planner order.\n\n## Provider prompt before any new provider search\n\nDraining an already-imported source list needs no provider context. But before\nany action that runs a NEW provider search — a `broaden_signal_search` round\n(especially when supplying `agentKeywords`), a Sales Nav or Prospeo cloned-\nsearch broadening, or any source add that dispatches a fresh search — load the\nmatching specialized prompt first with\n`get_provider_prompt({ provider, campaignOfferId })` and apply its discipline:\nsample-first fit checks against the headline ICP criteria, the 10% planning\nfloor, sample math (target ÷ observed pass rate) for sizing, and the keyword-\nquality guidance for Signal Discovery. Inventing broaden keywords or sizing a\nscrape without the provider prompt in context repeats the blind-import failure\nthe sampling discipline exists to prevent. The search tools also enforce this\npreflight server-side; loading it late wastes a fenced round on a typed refusal.\n\n## Rubric sample-quality trial\n\nRubric rejection may mean the source is poor or that one or several required\nchecks are unnecessarily narrow. Decide from an exact sample, not pass-rate alone.\n\n```mermaid\nflowchart TD\n A[\"Rows fail ICP/rubric gate\"] --> STALE{\"Score stale, errored, or computed under mismatched authority?\"}\n STALE -- Yes --> RESCORE[\"Rerun exact bounded cohort under unchanged current rubric\"]\n RESCORE --> RESULT{\"Now qualified?\"}\n RESULT -- Yes --> CONTINUE[\"Continue row lifecycle\"]\n RESULT -- No --> SAMPLE\n STALE -- No --> SAMPLE[\"Take exact representative rejected sample from prep receipt\"]\n SAMPLE --> SNAP[\"Snapshot complete rubric and prior digest\"]\n SNAP --> PROPOSE[\"Propose smallest 1-3 required-to-advisory bundle that creates useful new passes\"]\n PROPOSE --> HARD{\"Touches employment, DNC/opt-out, legal/compliance, or explicit exclusion?\"}\n HARD -- Yes --> REJECT[\"Reject proposal; preserve complete prior rubric\"]\n HARD -- No --> SIM[\"Simulate bundle from recorded per-prospect evaluations; no mutation\"]\n SIM --> DELTA{\"Any newly passing prospects?\"}\n DELTA -- No --> REJECT\n DELTA -- Yes --> QUALITY[\"Review only newly passing profiles in campaign and customer context\"]\n QUALITY --> REPLY{\"If these prospects replied, would the customer be comfortable and consider the replies relevant?\"}\n REPLY -- No --> REJECT\n REPLY -- Yes --> DRIFT{\"Live rubric digest still equals prior digest?\"}\n DRIFT -- No --> BLOCK[\"Output: blocked_retryable / rubric config drift\"]\n DRIFT -- Yes --> APPLY[\"Guarded apply entire required-to-advisory bundle\"]\n APPLY --> EXACT[\"Force exact bounded ICP rescore for accepted sample\"]\n EXACT --> VERIFY{\"Dispatch and accepted quality receipt valid?\"}\n VERIFY -- Yes --> KEEP[\"Keep bundle; receipt before/after digests, changed checks, sample counts, and verdict\"]\n VERIFY -- No --> ROLLBACK[\"Restore complete prior snapshot and receipt rollback\"]\n REJECT --> BETTER[\"Keep rows unsendable; continue better supply or next existing lane\"]\n ROLLBACK --> BETTER\n```\n\n`--yolo` may change more than one required rubric at a time only through this\nsingle bounded reversible bundle. The change demotes selected required checks to\nadvisory scoring; it does not erase their evidence. The acceptance test is the\nnewly passing delta: if any reviewed prospect would make the customer unhappy,\nsurprised, or consider the reply irrelevant, keep the complete prior rubric and\ncontinue the source waterfall. Never expose raw prospect profiles in the public\nreceipt.\n\n## Scheduler and uncertain-receipt recovery\n\n```mermaid\nflowchart TD\n A[\"Ready buffer covers remaining projected gap\"] --> CREDIT{\"Every selected paid lane has fresh credit facts?\"}\n CREDIT -- No --> RF[\"Refresh each exact selected sender once, then full replan\"]\n RF --> A\n CREDIT -- Yes --> DATE{\"Exact targetDate?\"}\n DATE -- Yes --> SWEEP[\"Dispatch one request-scoped product scheduler sweep\"]\n DATE -- No --> WAIT[\"Enter coordinator-owned bounded scheduler wait\"]\n SWEEP --> RECEIPT{\"Receipt state?\"}\n RECEIPT -- Terminal --> READ[\"Canonical target-plan and request/effect readback\"]\n RECEIPT -- Active --> POLL[\"Return in_progress and poll only the same request key\"]\n RECEIPT -- uncertain_outcome --> RECON[\"Reconcile same request key read-only; never redispatch\"]\n POLL --> RECEIPT\n RECON --> TERM[\"Terminal: blocked_retryable with request identity intact\"]\n WAIT --> READ\n READ --> FULL{\"Projected coverage full?\"}\n FULL -- Yes --> COMPLETE[\"Terminal: complete\"]\n FULL -- No --> READY{\"Ready buffer still covers gap?\"}\n READY -- Yes --> OTHER{\"Any other workspace target still needs preparation or an executable gate?\"}\n OTHER -- Yes --> PREP[\"Continue next planner-ranked exact target\"]\n OTHER -- No --> BLOCK[\"Terminal: receipt-backed blocked_retryable scheduler gap\"]\n READY -- No --> PREP[\"Return to row lifecycle\"]\n```\n\nA scheduler sweep is a visible workspace-wide scheduling side effect: existing\nproduct gates may schedule unrelated eligible cells in that workspace/date.\nIt never sends directly or raw-writes scheduler fields. `cellsConsidered is\nallocation-attempt count`; `readyCellsFound` is prefilter inventory. Inspect\n`campaignScopeSummary`, `prefiltered`, `skipped`, and `deferred`. For ready\nclosed-InMail cells with stale paid-credit evidence, use\n`refresh_paid_inmail_credits_then_rerun`. `wait_for_capacity_or_window` means do\nnot source or prep more rows; `no_ready_cells_continue_refill_prep` returns to\nthe row lifecycle. `cellsScheduled:0` alone is not failure. Once a sweep is\ndispatched, a host wait budget yields an `in_progress` continuation carrying\nthe same run identity. Keep polling that request key until its official\nterminal receipt, then reread the full target plan. Never convert an active\nsweep into `loaded_awaiting_scheduler`.\n\n## Explicit message-template revision\n\nOrdinary refill never changes copy. Only a literal user-approved revision\nenvelope may enter this side path.\n\n```mermaid\nflowchart TD\n A[\"Literal messageTemplateRevision with approved markdown, digests, 1-500 row IDs, request/effect IDs\"] --> DIGEST{\"Current prior authority digest present?\"}\n DIGEST -- No --> FENCE[\"Acquire exact run and read reportingContext source templateAuthorityDigest\"]\n FENCE --> DG{\"Digest returned?\"}\n DG -- No --> BLOCK[\"Terminal: blocked_retryable / template_authority_missing\"]\n DG -- Yes --> REVISE[\"Apply revision to exact cohort\"]\n DIGEST -- Yes --> REVISE\n REVISE --> AUDIT[\"select_campaign_cells in batches <=20 with includeGeneratedMessageReview:true\"]\n AUDIT --> MATCH{\"Every authoritativeGeneratedMessageReview complete, exact text/digest, matchesCurrentTemplateAuthority true?\"}\n MATCH -- No --> FAIL[\"Stop before approval: regenerated_copy_integrity_failed\"]\n MATCH -- Yes --> APPROVE[\"Approve only exact rowIds using compiled readiness authority\"]\n APPROVE --> RECEIPT{\"Bounded preparation receipt includes laneScope?\"}\n RECEIPT -- No --> FAIL\n RECEIPT -- Yes --> PLAN[\"Return to canonical refill plan\"]\n```\n\nFormula Message/Subject columns, previews, exports, and counts are not copy\nauthority. `forceRerun:true` never implies a revision or approval.\n\n## Manual approval and `--yolo`\n\n```mermaid\nflowchart TD\n A[\"Render fresh bounded packet in normal chat as Markdown\"] --> MODE{\"--yolo present?\"}\n MODE -- Yes --> AUTO[\"Auto-accept all planner-ranked transitions among existing campaigns, lanes, sources, and safe refill primitives\"]\n MODE -- No --> ASK[\"Open host-native structured question with exactly Accept and Decline\"]\n ASK --> DECISION{\"Operator choice?\"}\n DECISION -- Accept --> RUN[\"Execute only rendered envelope\"]\n DECISION -- Decline --> STOP[\"Stop with no mutation\"]\n AUTO --> RUN\n```\n\nUse `plain chat` in Codex and `plain chat` in Claude Code. The\nfull packet belongs in the normal chat message immediately before the question:\nworkspace, sender scope, campaign-by-campaign plan table, action, target/cap,\nsource, blocker/skip reason, exact IDs, expected side effects, forbidden actions,\nand stop condition. The question body must be compact and refer back to the\nposted packet instead of duplicating it. `--yolo` may switch among every fresh\nplanner-ranked existing campaign/lane/source family and start the exact selected\n`PAUSED` campaign. It does not create campaigns, direct-send, archive/delete,\nchange sender limits or paid-InMail thresholds, reassign senders, or invent\nsource selection outside the planner.\n\n## Typed outputs\n\n```mermaid\nflowchart TD\n A[\"Fresh canonical state\"] --> C{\"Terminal classification\"}\n C -- \"sent + scheduled meets target\" --> COMPLETE[\"complete: report saturation ledger\"]\n C -- \"all remaining exact targets scheduler-owned and workspace ready-or-projected gap is zero\" --> LOADED[\"loaded_awaiting_scheduler: report expected pickup and stop\"]\n C -- \"recoverable external, capacity, active-work, or receipt condition\" --> BLOCKED[\"blocked_retryable: exact blocker, receipt, and safe retry condition\"]\n C -- \"current lane spent but another existing target remains\" --> EX[\"lanes_exhausted internally; continue next_exact_target\"]\n C -- \"every existing campaign/lane/source spent or infeasible\" --> NEW[\"new_campaign_required: propose missing shape and ask whether to create it\"]\n C -- \"scope/config/readiness changed\" --> DRIFT[\"blocked_retryable: typed drift; never guess\"]\n```\n\nOne scheduler-loaded exact lane is not a workspace terminal: skip it and\ncontinue other planner-ranked lanes. Workspace `loaded_awaiting_scheduler` is\nadmissible only when no refill-owned scheduler request is active. After refill\ndispatches a sweep, keep the same fence alive until the official terminal\nreceipt; then return `complete` from the post-receipt readback or a concrete\nreceipt-backed retryable scheduler blocker if coverage remains short. The sole\nrefill-ladder expansion\nthat asks the user in `--yolo` is `new_campaign_required`; refill itself never\ncreates that campaign. `new_campaign_required` is also the truthful terminal\nwhen receipts prove every existing lane is spent but the planner has no\nautomatic cold rung to propose (Signal Discovery workspaces): report the\nremaining gap and ask the user; a future handler may automate the creation. A\n`actionable_supply_not_queued` terminal means actionable row frontiers\n(approval/generate/enrich/rubric or unprocessed frontier rows) still exist but\nno executable exact edge surfaced: retry once with a fresh command, and if it\nrepeats report it as a planner-exposure defect instead of treating the\nworkspace as exhausted. That census counts CONVERTIBLE rows only, de-duplicated\nper campaign/table lane — a frontier whose own preparation receipt carries a\nnon-retryable `icp_or_rubric_rejection` diagnosis is proven unable to convert,\nso it never inflates the census. When such receipts are all that remain, the\nterminal is `source_supply_exhausted_at_rubric`: a truthful source exhaustion,\nnot a defect and not retryable. Report the per-lane evidence from the note and\ntell the user that widening the rubric or adding fresh source rows is the only\nremaining fill path. Whenever a terminal reports a non-empty census, it also\nnames every exact edge the run refused (`Exact edges this run refused: ...`) —\nsurface those named blockers rather than describing the workspace as having no\navailable work.\n\n## Non-negotiable authority and proof\n\n- Before preparation, approval, or exact-date scheduling, require a validated\n compiled campaign and positive exact target readiness identity from the\n backend compiler: `profileSchemaVersion`, `compilerVersion`,\n `campaignDigest`, `actionColumnId`, action, `pathDigest`,\n `dependsOnColumnIds`, `runCondition`, the selected target's `capabilities`,\n `requestId`, `effectId`, and `dateGuards`. Never infer no-message behavior\n from a missing Generate Message column. Prepare rows according to the\n persisted sequence; bounded enrichment and LLM prerequisite calls are\n allowed only when authorized by the exact readiness packet and receipted.\n- Refuse approval outside the bounded authorized cohort. The exact selected\n target path controls message, subject, comment, reaction, and row approval.\n For exact dates, require the date strictly after sender-local today and inside\n the fill horizon. Prepared, approved, and ready rows remain intermediate\n evidence; completion requires request/effect-attributed scheduler-owned\n scheduled readback.\n- Execute one bounded primitive, then perform a full authoritative reread.\n Never call a LinkedIn outreach/provider-send surface from refill. No direct\n sends, raw scheduler writes, broad approval, threshold/limit changes,\n sender reassignment, destructive cleanup, or new campaign creation.\n- Maintain the target-window saturation ledger per sender: selected days,\n gross capacity, actual sent, future scheduler-owned scheduled with non-null\n `scheduledFor`, projected coverage (`sent + scheduled`), ready buffer,\n remaining gap, paid-InMail feasibility, `targetShapeRevision`, and\n `stateRevision`. Future scheduled coverage and already sent actions are\n distinct.\n- Carry canonical `refill_reporting.v2` unchanged through progress,\n continuation, replay, and terminal output. Completion proof is Sellable MCP\n evidence only: target plan, campaign refill state, scheduler capacity,\n sweep/status, and bounded receipts. Never use individual cell ids, Prisma,\n SQL, direct database access, or production-environment scripts as completion\n proof. Redact raw copy and prospect fields.\n\n## Refill V3\n\nThis is the DEFAULT route whenever `refill_v3_advance` is exposed (see\n[Route selection](#route-selection--do-this-first)). `refill_v3_advance` is then\nthe only execution owner and `refill-sends-workflow` plus its `core/flow.v3.json`\nasset is the contract to load — load the prompt and that asset, verify the `v3`\ncompatible range, and report the version before the first call. Start from the\nbase request `{workspaceId, scope}`, add `yolo:true` by default, and call it\nagain after each `advanced` or\nsettled `campaign_attention_required` result. A `run_step_pending` result means\nthe server is still completing the already-consumed step: wait its\n`retryAfterMs`, then call advance with the same public inputs. The MCP retains\nthe identical token internally; never copy a token, route to AI, or execute an\nauthority for this transport-reconciliation wait. `refill_v3_continue` itself\nsettles the exact packet action before it returns. Bounded enrichment and an\nalready-active preparation job use the shared Create Campaign waiter and\ndurable preparation owner; directly queued row repair uses the campaign waiter.\nSynchronous source, configuration, rubric, and exhaustion authorities already\nreturn after their own exact reread, so they return `settlement.ready:true` from\nthat bounded authority receipt and never wait on unrelated campaign-wide\nprocessing cells.\n\nWhen an explicit `yolo:false` request names a campaign, resolve that visible name with one\nauthorized bounded `get_campaigns` call carrying an explicit `limit`. Require\nexactly one case-insensitive exact match; if none or more than one match, stop\nwithout preview or mutation. Retain only the returned stable campaign ID. Call\n`refill_v3_world_state({workspaceId, scope, campaignId})`, render that exact\ncampaign's two-lane readiness and its explicit zero product side effects, then\nstop at the product-native question with exactly Accept and Decline. Do not call\n`refill_v3_advance` before Accept. Accept calls\n`refill_v3_advance({workspaceId, scope, campaignId})`; Decline stops. Carry the\nsame campaignId through every advance, continue, replay, partial-wait, and\npost-wait repeat. Display-name changes never alter this retained identity, and\nno sibling campaign may replace it.\nCall the next advance only when `settlement.ready` is true. When it is false,\ncall `wait_for_campaign_processing` with `settlement.resumeInput` **unchanged**;\nthat carries the exact `preparationJobId`, `requirePreparationTerminal:true`,\nand `requireIdle:true`. Repeat the returned `resumeInput` until ready; never\nfall back to a stats-only campaign wait for this settlement. An\n`awaiting_external_change` result with\n`deferral.code:\"campaign_work_in_flight\"` and a campaign id is a bounded\nread-only continuation, not permission to walk the next campaign: call\n`wait_for_campaign_processing({ workspaceId, campaignId, requireIdle:true })`,\nthen call `refill_v3_advance` again with the identical scope and yolo grant.\nThis reuses Create Campaign's campaign-table waiter and guarantees the same\ncampaign is freshly replanned after its cohort settles. If the bounded wait\nreturns a partial timeout, surface that checkpoint and make the fresh advance;\nif it reports the same live campaign, repeat the bounded wait. Stop on every\nother `awaiting_external_change`, `complete`, or `blocked` result. For each of\nthose terminal results, report **every** entry in `terminalEvidence.rows`, one\nper scoped sender/date/lane—not only the headline deferral or blocker. Include\n`targetSlots`, `takenSlots`, `remainingTargetGap`, `fillableSlotsNow`,\n`blockedGap`, `terminalClassification`, `reasonCodes`, `approvedDelta`, and\n`scheduledDelta`. When `reasonCodes` contains\n`paid_inmail_credit_refresh_failed`, also report `paidCreditRefreshAttempt`\nexactly: `attemptedAt`, `outcome`, `errorClass`, `errorDetail`, and `durationMs`.\nA cumulative observation, vague \"credit refresh\" label, or one surfaced blocker\nis never a row-complete terminal summary.\n\n`terminalEvidence.rows` covers exactly two Refill V3 lanes:\n`connection_invite` and closed/paid InMail. It does **not** report Open InMail.\nCampaign `supply.readyToSchedule` is a broad first-touch table count and can\ninclude Open InMail rows that the normal scheduler can place independently.\nNever present that broad count as connection or paid inventory, never infer\nOpen InMail is empty or unscheduled from a Refill V3 row, and never explain the\ndifference as sender affinity unless exact lane evidence proves it. If asked\nwhether Open InMail is maxed, say the two-lane refill receipt cannot answer that\nquestion and obtain an action-type-specific scheduled readback before answering.\n\nLead every row-complete terminal summary by stating that all scoped\nsender/date/lane rows were explored. Never say the workspace \"stopped on\" one\nsender or headline blocker: that blocker classifies one row after independent\nsibling work was explored; it is not the traversal stop.\n\nResolve the workspace BEFORE the first call, exactly as the V1 route already\nrequires. `workspaceId` must be an exact id on every automation call: when the\noperator names a workspace, call `list_workspaces` first and match that name to\nits id. Prefer one case-insensitive exact name match; if none exists, accept one\ncase-insensitive prefix match (so `Damiano` resolves `Damiano R`). Use the\nconfigured or active workspace only when the operator named none. If zero or\nmultiple prefix matches remain, stop and say so — do not fall back to the\nconfigured workspace — and never change the shared active workspace to steer\nan automation.\n\nThe command-shaped form is unambiguous: in `refill sends <name> [flags]`,\n`<name>` is the workspace override, never a sender name. A sender restriction\nmust be explicit through `--sender`/`senderIds`/`senderNames` or prose that says\n“sender.” Therefore call `list_workspaces` and resolve `<name>` first. Do not\nlist configured-workspace senders before that workspace match; doing so is both\nscope drift and avoidable latency.\n\nMap the rest of the request onto those keys and nothing else: the sender/date\nenvelope becomes `scope`. `sender_local_horizon` (1-3 days) is ONLY for\nrequests with no date control at all (\"refill sends X\"); the moment the\noperator names any date — `--target-date`, `--until-date`, or dated prose —\nthe scope is `exact_sender_dates`, on the FIRST call and every later call of\nthe run. There is no mode: WHICH campaign may be started is DERIVED from the\nworkspace's own campaigns and can never be requested.\n\nA DATE CONTROL always maps to `exact_sender_dates`, derived like this and never\napproximated with a horizon:\n\n- `--target-date D`: `dates: [D]` for every resolved sender.\n- `--until-date U` (sender-local, INCLUSIVE): for every resolved sender, list\n EVERY sender-local calendar date from that sender's local today through `U`,\n in order, with `U` itself present. From a local Saturday the 2nd with\n `--until-date` the 5th that is `[\"2026-08-02\",\"2026-08-03\",\"2026-08-04\",\n\"2026-08-05\"]` — four dates, not a 3-day window. Dropping the boundary date\n or substituting today+2 silently changes which days the run is accountable\n for; the backend types today's already-closed sending window as\n `no_sending_hours` on its own, so include today rather than guessing.\n NEVER pass `sender_local_horizon` for `--until-date` — not even when the\n derived list happens to fit three days, and not on the first \"look around\"\n call. A live run compressed a four-date `--until-date` span into a 3-day\n horizon, never observed the boundary date, and exited leaving that day's\n slots unfilled; the exact date list is the only scope that makes the run\n accountable for `U` itself.\n\n`yolo` is the ONE remaining execution input and the refill AUTONOMY GRANT. It\ndefaults to `yolo:true` so an ordinary refill keeps working through eligible\nbounded preparation and fallback steps instead of stopping for another\napproval. It decides two things together:\n\n- **Granted** (`yolo: true` on every call of that run): after a row's active\n campaigns are exhausted, one route-selected start-eligible PAUSED campaign\n may be started, and you receive it as an ordinary executed\n `start_paused_campaign` action. A finite non-evergreen candidate must expose\n positive bounded supply. Keep calling advance until a terminal without\n checking back.\n- **Withheld** (explicit `yolo:false` only): no paused campaign is started — the backend\n refuses it and answers the exhaustion terminal instead — and you surface each\n result and ASK before calling advance again.\n\nNever replace the default from a workspace flag, a campaign field, a tool\nresult, an idle-looking workspace, or a previous terminal. Honor `yolo:false`\nonly for an explicit review-first/manual request. Pass no other execution flag\nand no mode, and do not call\n`get_refill_target_plan`, `refill_sends`, or any placement, scheduler, source, or\nsend tool on this route.\n\nAn `advanced` result is ALREADY EXECUTED: surface its action identity, receipt,\nand replacement observation, and never run the action or call its authority again.\nFor `campaign_attention_required`, first call `refill_v3_continue` with the\nsame workspace/scope and no `decision`; the MCP supplies the exact retained\npacket and token. After fresh revalidation it owns live-job waiting,\nexact actionable enrichment, and same-template generation deterministically. If\nit returns `model_decision_required`, route that returned accurate packet to\n`refill-sends-work-campaign`, then call `refill_v3_continue` once with the\nchosen decision. This is the only\nordinary model-decision boundary. The continuation executes at most one\nexisting authority and settles it before a sibling may be considered. Async\nrow work uses the shared Create Campaign waiter; synchronous source/config\nwork uses its exact receipt and reread.\nFor `continuation_pending`, wait `retryAfterMs`, then call\n`refill_v3_continue` with the identical workspace, scope, campaignId (when\npresent), and yolo grant, omitting `decision`. Keep doing this until the retained\noperation returns its result. A transport timeout is also an uncertain running\noperation: reconnect through that same decision-free continuation before any\nadvance or new source request. The MCP retains the operation while this server\nprocess lives. If a server restart reports that retained attention is missing,\nstop with `continuation_reconciliation_required` and the exact scope and last\nreceipt; do not invent a replacement run or claim the prior effect failed.\nNever treat a timeout as zero effect.\nContinue the authorized refill across every connected sender and requested\nlane until the coordinator returns row-complete terminal evidence. Preserve the\nrubric, message, caps, and exclusions; pending work needs no renewed approval.\n\nInterpret continuation world wrappers by their outer kind: `world_terminal`\nmeans `advanceResult` is already the canonical `awaiting_external_change`,\n`complete`, or `blocked` terminal, so report that nested terminal and stop;\nnever call advance again. `world_step_pending` means wait the nested\n`retryAfterMs` and then call advance with the same public inputs.\n`world_advanced` means the nested action already ran, so surface it and call\nadvance again. For `attention_refresh_required`, continue from its refreshed\npacket rather than opening another run.\nIf it returns `attention_correction_required` with\n`correction.kind:\"signal_keyword_collision\"`, route the returned same packet\nand exact correction through `refill-sends-work-campaign` once, then call\n`refill_v3_continue` with that revised decision. Exclude every returned searched\nkeyword and use the required request-fingerprint prefix. This is one refused,\nzero-effect Signal correction; a second collision is terminal and must not loop.\n\nThis skill chooses no sender, date, lane, campaign, or action, holds no counter or\ncursor between calls, and declares no terminal, exhaustion verdict, or health\nclassification of its own. V1 `refill_sends` behavior is unchanged.\n"
|
|
61
61
|
}
|
|
62
62
|
]
|
package/package.json
CHANGED
|
@@ -775,8 +775,23 @@ it returns `model_decision_required`, route that returned accurate packet to
|
|
|
775
775
|
`refill-sends-work-campaign`, then call `refill_v3_continue` once with the
|
|
776
776
|
chosen decision. This is the only
|
|
777
777
|
ordinary model-decision boundary. The continuation executes at most one
|
|
778
|
-
existing authority and settles
|
|
779
|
-
|
|
778
|
+
existing authority and settles it before a sibling may be considered. Async
|
|
779
|
+
row work uses the shared Create Campaign waiter; synchronous source/config
|
|
780
|
+
work uses its exact receipt and reread.
|
|
781
|
+
For `continuation_pending`, wait `retryAfterMs`, then call
|
|
782
|
+
`refill_v3_continue` with the identical workspace, scope, campaignId (when
|
|
783
|
+
present), and yolo grant, omitting `decision`. Keep doing this until the retained
|
|
784
|
+
operation returns its result. A transport timeout is also an uncertain running
|
|
785
|
+
operation: reconnect through that same decision-free continuation before any
|
|
786
|
+
advance or new source request. The MCP retains the operation while this server
|
|
787
|
+
process lives. If a server restart reports that retained attention is missing,
|
|
788
|
+
stop with `continuation_reconciliation_required` and the exact scope and last
|
|
789
|
+
receipt; do not invent a replacement run or claim the prior effect failed.
|
|
790
|
+
Never treat a timeout as zero effect.
|
|
791
|
+
Continue the authorized refill across every connected sender and requested
|
|
792
|
+
lane until the coordinator returns row-complete terminal evidence. Preserve the
|
|
793
|
+
rubric, message, caps, and exclusions; pending work needs no renewed approval.
|
|
794
|
+
|
|
780
795
|
Interpret continuation world wrappers by their outer kind: `world_terminal`
|
|
781
796
|
means `advanceResult` is already the canonical `awaiting_external_change`,
|
|
782
797
|
`complete`, or `blocked` terminal, so report that nested terminal and stop;
|