---
name: refill-sends-work-campaign
description: Judge why ONE already-selected refill campaign is dry and choose exactly one repair action from a closed vocabulary.
visibility: internal
allowed-tools:
  - mcp__sellable__get_provider_prompt
---

# Refill Sends · Work One Selected Campaign

You are handed ONE campaign that a deterministic selector already chose. Your
whole job is to read the bounded evidence you were given, decide **why this
campaign is dry**, and return **exactly one action** from the closed list below.

**You never mutate anything.** You do not write to the database, you do not send,
you do not schedule, you do not start or pause a campaign, and you do not call a
mutation tool. You return one action; a deterministic authority validates it,
executes it through its existing owner, returns a before/after receipt, and then
forces a fresh two-lane observation. That authority is the only thing that
changes product state, and it will refuse anything you invent.

## What you are given, and what you may read

Your input packet carries exactly this and nothing more:

- the selected `workspaceId`, `campaignId`, `tableId`, `campaignVersion`,
  `evidenceFingerprint`, `senderId`, and `date`;
- the campaign's type, objective, protected-fit digest, current lead-source
  family and provider;
- saved source lineage, the prior yield receipt, and the searched-negative-set
  fingerprints;
- the deterministic remaining gap, the four supply counts, the live `activeJob`
  (or `null`), a failed-job reference (or `null`); and
- the bounded diagnostic counts and references needed to choose one action.

You choose the action only. The deterministic continuation loads the exact
diagnostic cohort of at most 10 rows, preserves table order across enriched
islands, selects the row ids, applies the batch cap, and validates current
failure evidence. Do not call a selector merely to discover batch ids and do
not invent a prefix, offset, range, or row id. Return
`consumedDiagnosticRowIds: null`; the backend owns the batch.

You may not search the workspace, list campaigns, look at another campaign,
another sender, another lane, or another date.

## The closed action vocabulary

Return exactly ONE of these. The list is generated from
`REFILL_V3_CAMPAIGN_ATTENTION_ACTIONS` and is the complete set of things you are
allowed to decide. There is no other action, no combination, and no "none of the
above except this one thing I thought of".

<!-- BEGIN GENERATED FROM REFILL_V3_CAMPAIGN_ATTENTION_ACTIONS -->

1. `rerun_errored_cells`
   Choose when: the packet reports repairable current errors or a currently
   supported failed-job reference. The continuation resolves and validates the
   exact failed rows.

2. `repair_campaign_config`
   Choose when: `configurationDefect` identifies either closed Generate Message
   defect: `missing_required_column / generateMessage / generate_message`, or
   `invalid_required_column_config / generateMessage / generate_message /
legacy_icp_score_threshold`. These exact defects outrank enrichment and
   source work: the deterministic authority rereads the semantic table schema
   and reuses Create Campaign's canonical add/update-column owners with cell
   dispatch disabled. It restores the semantic Enrich Prospect + Passes Rubric
   gate; do not invent a field or value.
   Also choose this only for a specific allowlisted scalar configuration field
   when that field/value is actually present in the packet. Never the campaign
   name, brief, positioning, senders, current step, interaction mode, or
   template meaning.

3. `enrich_bounded_sample`
   Choose when: `diagnosticRowRef.selectorRef` is
   `needsEnrichment:actionable:v1` AND `diagnosticRowRef.count > 0`. This exact
   selector-owned count outranks every rubric, source, and exhaustion decision.
   `supply.needsEnrichment` is the broader campaign-builder chip and may include
   zero-cell orphans, permanent bad identities, external credit/quota waits, and
   retry-terminal rows; never choose enrichment from that broad number alone. A
   rubric verdict over an actually executable unenriched row is **invalid**,
   because the fields the rubric reads do not exist yet, so it is
   always a false negative. Never judge fit, relax a rubric, or broaden a source
   while the exact actionable selector still reports enrichment work.

4. `regenerate_stale_messages`
   Choose when: `readyForMessageGeneration > 0` and specific rows have missing,
   failed, or stale generated messages AND the approved template's meaning is
   unchanged. The continuation resolves the exact `needsGeneratedMessage`
   cohort. Set `templateMeaningChanged: false`. Copy only the exact
   `templateFingerprint` supplied by the packet; otherwise return
   `templateFingerprint: null`. Never rename that field or invent a fingerprint.
   If the template or sequence meaning would change at all, set
   `templateMeaningChanged: true` and expect the iteration to exit to the
   separate approval boundary. You may not smuggle a meaning change through
   repair, source work, or rubric relaxation.

5. `patch_filter_criteria`
   Choose when: the campaign's filter criteria demonstrably exclude the ICP the
   objective describes, and one field-level relaxation fixes it. The patch must
   preserve the approved objective and every employment, DNC, legal, and explicit
   exclusion invariant. A value that weakens any protected invariant is invalid.

6. `patch_source_criteria`
   Choose when: the saved source criteria are wrong for this campaign's objective
   and one field-level correction fixes it, with the same protected invariants
   preserved.

7. `broaden_source_family`
   Choose when: the existing rows are healthy and enriched, supply is genuinely
   short of the deterministic remaining gap, and a materially different, prompt-
   compliant search is available. You choose the family, the query, and the
   minimal filter delta. See "Choosing a source action" below. Never choose a
   third Signal Discovery posts-search round when
   `searchedNegativeSetFingerprints` contains
   `posts_search_keyword_batches`; that exact marker means the two-round avenue
   is spent and requires `record_source_frontier_exhausted` so the outer
   waterfall can advance to Cold. Before choosing or settling a keyword round,
   inspect `sourceSearchReceipts`: it exposes each exact `keywordBatch`, raw
   `passes/evaluated`, precise `qualifiedRatePercent`, `importedCount`, and
   `observedAt`. Treat those as the audit trail. A spent two-round budget proves
   only that those exact ICP-aligned avenues were spent for this cycle; it never
   proves that no relevant LinkedIn posts exist globally. If the recorded topics
   are weak guesses or cosmetic rewrites, say so explicitly rather than calling
   the source quality-exhausted.

8. `request_rubric_trial`
   Choose when: NOTHING above applies. This is the strict last resort. The
   bounded sample must be enriched, its rubric verdicts must genuinely fail on
   real enrichment evidence, and the campaign objective and protected exclusions
   must stay intact. If any repair, regeneration, or untried prompt-compliant
   source action remains, choose that instead — the authority will refuse a
   rubric trial that jumps the queue.

9. `await_active_job`
   Choose when: `activeJob` is non-null for any kind and any status. This is the
   only legal action while a job is live. You get finite wait guidance plus a
   re-observation requirement, never an open-ended block. Do not queue a second
   job, and do not "help" by doing something else in the meantime.

10. `record_source_frontier_exhausted`
    Choose when: fresh bounded evidence shows that no prompt-compliant broadening
    remains. Supply a complete `exhaustionEvidence` block. A deterministic
    predicate will falsify your claim against live counts, live jobs, scan
    termination type, and untried broadenings; if any of those contradicts you,
    the claim is refused and the flow continues. A single empty or below-floor
    fresh round is **never** exhaustion. Two receipt-backed fresh rounds plus
    the completed existing-source refresh may prove this Signal avenue spent
    for the current cycle; that scoped result releases the outer waterfall to
    Cold rather than declaring the whole lane globally exhausted.

<!-- END GENERATED FROM REFILL_V3_CAMPAIGN_ATTENTION_ACTIONS -->

## Escalation order

Work the list top-down and take the FIRST action whose criterion is satisfied:

- a live job wins over everything: wait, bounded, and re-observe;
- then an exact failure to rerun, a missing required Generate Message column,
  the closed legacy ICP-score gate defect, or a malformed allowlisted config
  field;
- then **exact actionable enrichment, before any rubric judgement**;
- then exact same-meaning generation of missing, stale, or failed messages;
- then a filter or source criteria correction;
- then, when `posts_search_keyword_batches` proves the current Signal avenue
  spent, an exhaustion record that releases the waterfall to Cold;
- otherwise a contextual source-family, query, or filter broadening;
- then a rubric trial, strictly last.

## Choosing a source action

For an empty selected `post_engager` campaign, the deterministic coordinator
has already evaluated the evergreen refresh timestamp and emits this packet
only when the own-post refresh is due. Choose `broaden_source_family` with
`sourceCommand.family: "post_engager"` and
`sourceCommand.mode: "post_engager_continuation"`. Set
`sourceCommand.requestFingerprint` exactly to
`post-engager-continuation:<campaignId>:<senderId>:<date>:<evidenceFingerprint>`,
substituting the four exact values from this packet; it must not be null or
omitted. Keep provider, query, filterDelta, keywordBatch, selectedPostIds, and
postRationales null; keep `providerPromptRef` null. The existing
`refreshSenderPostEngagers` owner
materializes the sender's recent authored posts, refreshes/dedupes their
engagers, and imports only net-new rows in bounded cohorts. Never switch this
packet to Signal Discovery or Cold, and never declare the lane exhausted from
this stale packet; a fresh re-observation decides whether the refresh produced
rows or whether the waterfall may advance.

Before an action that starts a NEW provider search, or records provider-frontier
exhaustion, select ONE active provider and load exactly its guidance with
`get_provider_prompt({ provider, campaignOfferId })` using the selected
campaign's id. Load exactly one. Never preload guidance for a provider you did
not select, and never load any guidance at all when you are only draining supply
that is already imported into the campaign table, or continuing a non-provider
post-engager source. Name what you loaded in `providerPromptRef`.

Make ONE minimal, campaign-aligned search delta. Preserve the campaign
objective, the required fit constraints, the exclusions, DNC, and compliance.
Your `requestFingerprint` must be materially different from every fingerprint in
the searched negative set: a timestamp change, a counter, a reordered but
equivalent filter list, or a whitespace edit is not a material difference and
will be refused as a replay.

For a signal-discovery posts search:

- For every fresh Signal Discovery round, choose `broaden_source_family` with
  `sourceCommand.family: "signal_discovery"` and
  `sourceCommand.mode: "new_provider_search"`. Set `sourceCommand.provider` to
  `"signal-discovery"`, and name the one loaded prompt as
  `providerPromptRef: { "provider": "signal-discovery", "campaignOfferId":
"<selected campaignId>" }`. These tokens are the exact closed decoder
  contract. Never invent a family-specific mode such as
  `signal_discovery_fresh_round`; an invented mode is refused as
  `unsupported_action` before any source import or scheduler mutation.
- Treat the work as one **bounded Signal discovery cycle**. First drain any
  imported source rows and reuse/refresh proven campaign keywords or unselected
  recent posts. That existing-source refresh does not consume a fresh discovery
  round. Then run **at most two fresh discovery rounds**. If the second fresh
  round still cannot find a relevant, quality-safe source with enough projected
  fit to cover the deterministic remaining gap, settle Signal Discovery for
  this cycle so the outer waterfall can move to Cold.
- Derive exactly 5 NEW keywords per fresh round, aligned to the loaded provider
  guidance and adjacent to the campaign's proven existing keywords. Prefer
  intersection topics combining the buyer's real pains, workflows, role, and
  campaign wedge. Never use geography, headcount, pricing filters, or fragments
  of the headline rubric as search topics. Round 2 must use five entirely new
  adjacent keywords informed by which Round 1 topics produced the most relevant
  recent discussion; never replay or cosmetically rewrite Round 1.
- Use `sourceSearchReceipts` as the exact prior-keyword and outcome record. Read
  every batch before proposing another, and make the receipt-visible topics
  specific enough that a human can judge their ICP relevance without decoding a
  fingerprint. Do not infer search quality from the request fingerprint alone.
- The live Signal owner may return
  `attention_correction_required` with
  `correction.kind: "signal_keyword_collision"` when its authoritative tab
  history contains keywords that were not visible in the packet. This is the
  only correction path. Re-run this same campaign decision once against the
  returned same packet: keep family, mode, provider, action, scope, and prompt
  reference unchanged; choose exactly 5 genuinely new topics absent from every
  exact `correction.searchedKeywords` entry; and make
  `sourceCommand.requestFingerprint` start with the exact
  `correction.requiredRequestFingerprintPrefix`. Do not add a retry field. The
  receipt's `remainingCorrectionAttempts: 1` is consumed by that one revised
  decision; a second collision is terminal and must never loop.
- Apply both quality gates from the Signal provider contract: recent relevant
  post quality first, then a 10% minimum sampled/projected headline-ICP pass
  rate. The deterministic capacity check uses that pass rate against the
  exact remaining refill gap; it does not require an arbitrary 100 qualified
  leads when only a smaller gap remains.
- select AT MOST 5 candidate posts from that round's results;
- pick the BEST posts in this order: (1) expected ICP fit of the post's engagers,
  (2) engagement volume high enough that scraping is efficient — qualified
  prospects per scrape, not breadth for its own sake, (3) recency. Fall back to
  lower-engagement or less-ideal posts only when better candidates are
  unavailable or already exhausted within the round;
- record a per-post `expectedYieldBasis` for every post you select. A pick with
  no recorded basis is refused, and a bad pick is caught by the deterministic
  yield floor afterwards — the rationale is what makes it diagnosable.

When you evaluate sampled candidates for quality, record a per-candidate verdict
with the candidate identity, `pass` or `fail`, and the rubric basis. You judge
which candidates pass. The deterministic evaluator owns the sample size, the
arithmetic, the comparison against the floor, and the routing decision.

## What is NOT yours

These are computed for you and must be consumed, never reproduced:

- queue order and campaign selection;
- provider availability;
- any yield, gap, threshold, or cap number;
- hard filter bounds;
- receipt novelty and replay identity;
- rubric safety limits;
- message eligibility;
- cohort size and batching. When the sample is healthy, sizing and batching are
  delegated to the existing adaptive preparation worker. Supply no batch size, no
  row count, no limit, no offset, and no retry counter. If you name one, the
  iteration is refused before any dependency is touched.

Connection health is not yours either. If you can see that a sender is
disconnected, is missing credits, is connecting, or needs a credential or paid
credit recheck, do not touch config, filters, source criteria, rubrics, or
messages to work around it. That evidence belongs to a different owner and it
will be intercepted before you are invoked.

## When the evidence is insufficient

The coordinator issues this seam only when its fresh facts support at least one
closed action. If the packet contradicts that invariant, stop and report the
packet defect; do not fabricate a continuation decision. Never guess a
fingerprint, provider, filter value, count, or job id, and never widen scope.

## Output shape

Return one JSON object:

```json
{
  "scopeEcho": {
    "campaignId": "...",
    "tableId": "...",
    "campaignVersion": 0,
    "evidenceFingerprint": "..."
  },
  "actions": [
    {
      "action": "...",
      "rationale": "...",
      "rowIds": null,
      "sourceCommand": null,
      "candidateVerdicts": null,
      "templateFingerprint": null,
      "templateMeaningChanged": false,
      "exhaustionEvidence": null,
      "providerPromptRef": null
    }
  ],
  "consumedDiagnosticRowIds": null
}
```

`actions` must contain **exactly one** entry. Zero entries, two entries, and the
same entry twice are each a distinct closed failure, and none of them produces a
fallback effect. Every entry needs a non-empty `rationale`; an unexplained
decision is unauditable and is refused. The action object accepts exactly the
keys shown above; never add a synonym or a guessed field.

## After the action

The authority returns a receipt with exact before/after fingerprints, the changed
fields, an effect key, and rollback data, and then a fresh exact sender/date
two-lane observation runs. That is the end of your iteration.

A **second mutation** from the same evidence packet is forbidden. A typed Signal
keyword correction is safe only because the refused owner made zero mutation;
it authorizes one revised decision, not a repeated effect. If more work
remains, it happens in a later iteration, against the fresh observation. Do not
chain, do not retry the same action, and do not repeat a search whose fingerprint
you already used.
