@sellable/mcp 0.1.0
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/.claude-plugin/plugin.json +12 -0
- package/.mcp.json +9 -0
- package/README.md +355 -0
- package/dist/api.d.ts +21 -0
- package/dist/api.js +73 -0
- package/dist/auth.d.ts +60 -0
- package/dist/auth.js +246 -0
- package/dist/engage-memory.d.ts +63 -0
- package/dist/engage-memory.js +354 -0
- package/dist/index-dev.d.ts +2 -0
- package/dist/index-dev.js +17 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +8 -0
- package/dist/server.d.ts +1 -0
- package/dist/server.js +499 -0
- package/dist/skills.d.ts +11 -0
- package/dist/skills.js +97 -0
- package/dist/tools/auth.d.ts +30 -0
- package/dist/tools/auth.js +124 -0
- package/dist/tools/blueprint-commit.d.ts +174 -0
- package/dist/tools/blueprint-commit.js +286 -0
- package/dist/tools/bootstrap.d.ts +64 -0
- package/dist/tools/bootstrap.js +246 -0
- package/dist/tools/campaigns.d.ts +589 -0
- package/dist/tools/campaigns.js +892 -0
- package/dist/tools/cells.d.ts +58 -0
- package/dist/tools/cells.js +48 -0
- package/dist/tools/context.d.ts +88 -0
- package/dist/tools/context.js +271 -0
- package/dist/tools/csv-domains.d.ts +73 -0
- package/dist/tools/csv-domains.js +464 -0
- package/dist/tools/csv-linkedin.d.ts +102 -0
- package/dist/tools/csv-linkedin.js +712 -0
- package/dist/tools/direct-campaigns.d.ts +240 -0
- package/dist/tools/direct-campaigns.js +250 -0
- package/dist/tools/engage-bootstrap.d.ts +94 -0
- package/dist/tools/engage-bootstrap.js +205 -0
- package/dist/tools/engage-discovery.d.ts +78 -0
- package/dist/tools/engage-discovery.js +150 -0
- package/dist/tools/engage-memory.d.ts +181 -0
- package/dist/tools/engage-memory.js +143 -0
- package/dist/tools/engage-state.d.ts +72 -0
- package/dist/tools/engage-state.js +62 -0
- package/dist/tools/enrichment.d.ts +167 -0
- package/dist/tools/enrichment.js +174 -0
- package/dist/tools/flow-preflight.d.ts +68 -0
- package/dist/tools/flow-preflight.js +138 -0
- package/dist/tools/framework.d.ts +44 -0
- package/dist/tools/framework.js +153 -0
- package/dist/tools/interaction-mode.d.ts +27 -0
- package/dist/tools/interaction-mode.js +102 -0
- package/dist/tools/leads.d.ts +2417 -0
- package/dist/tools/leads.js +2307 -0
- package/dist/tools/linkedin.d.ts +210 -0
- package/dist/tools/linkedin.js +229 -0
- package/dist/tools/navigation.d.ts +91 -0
- package/dist/tools/navigation.js +381 -0
- package/dist/tools/one-off.d.ts +229 -0
- package/dist/tools/one-off.js +273 -0
- package/dist/tools/processing.d.ts +70 -0
- package/dist/tools/processing.js +56 -0
- package/dist/tools/prompts.d.ts +211 -0
- package/dist/tools/prompts.js +210 -0
- package/dist/tools/provider-preflight.d.ts +21 -0
- package/dist/tools/provider-preflight.js +59 -0
- package/dist/tools/readiness.d.ts +261 -0
- package/dist/tools/readiness.js +510 -0
- package/dist/tools/rows.d.ts +126 -0
- package/dist/tools/rows.js +105 -0
- package/dist/tools/rubrics.d.ts +497 -0
- package/dist/tools/rubrics.js +681 -0
- package/dist/tools/senders.d.ts +44 -0
- package/dist/tools/senders.js +69 -0
- package/dist/tools/sequencer.d.ts +127 -0
- package/dist/tools/sequencer.js +194 -0
- package/dist/tools/tables.d.ts +35 -0
- package/dist/tools/tables.js +36 -0
- package/dist/tools/verify-row.d.ts +36 -0
- package/dist/tools/verify-row.js +38 -0
- package/dist/tools/workspaces.d.ts +140 -0
- package/dist/tools/workspaces.js +139 -0
- package/dist/utils/workspace-root.d.ts +1 -0
- package/dist/utils/workspace-root.js +39 -0
- package/package.json +46 -0
- package/skills/building-gtm-tables/SKILL.md +216 -0
- package/skills/building-gtm-tables/core/auto-execute.yaml +19 -0
- package/skills/building-gtm-tables/core/blueprint-schema.json +72 -0
- package/skills/building-gtm-tables/references/brief-to-blueprint.md +334 -0
- package/skills/building-gtm-tables/references/column-type-catalog.md +318 -0
- package/skills/building-gtm-tables/references/common-blueprints.fixtures.ts +199 -0
- package/skills/building-gtm-tables/references/common-blueprints.md +44 -0
- package/skills/building-gtm-tables/references/failure-taxonomy.md +197 -0
- package/skills/building-gtm-tables/references/uat-seed-prompts.md +37 -0
- package/skills/building-gtm-tables/references/verify-loop.md +74 -0
- package/skills/campaign-messages/SKILL.md +173 -0
- package/skills/campaign-messages/flow.v1.json +75 -0
- package/skills/craft-message/SKILL.md +401 -0
- package/skills/create-campaign/ARCHITECTURE.md +232 -0
- package/skills/create-campaign/DISCUSS.md +296 -0
- package/skills/create-campaign/FLOW_ASCII.md +240 -0
- package/skills/create-campaign/HOST-PARITY-CHECKLIST.md +49 -0
- package/skills/create-campaign/README.md +142 -0
- package/skills/create-campaign/SKILL.md +286 -0
- package/skills/create-campaign/context/README.md +67 -0
- package/skills/create-campaign/context/_TEMPLATE.md +12 -0
- package/skills/create-campaign/context/context.md +35 -0
- package/skills/create-campaign/context/learnings.md +16 -0
- package/skills/create-campaign/context/registry.json +19 -0
- package/skills/create-campaign/core/flow.v1.json +217 -0
- package/skills/create-campaign/core/policy.md +191 -0
- package/skills/create-campaign/core/providers/apollo.json +35 -0
- package/skills/create-campaign/core/providers/prospeo.json +34 -0
- package/skills/create-campaign/core/providers/registry.json +31 -0
- package/skills/create-campaign/core/providers/sales-nav.json +37 -0
- package/skills/create-campaign/core/providers/signal-discovery.json +42 -0
- package/skills/create-campaign/references/brief-template.md +64 -0
- package/skills/create-campaign/references/campaign-quality.md +84 -0
- package/skills/create-campaign/references/copy-calibration-examples.md +120 -0
- package/skills/create-campaign/references/offer-patterns.md +108 -0
- package/skills/create-campaign/references/provider-selection-strategy.md +212 -0
- package/skills/create-campaign/references/question-examples.md +167 -0
- package/skills/create-campaign/references/token-fill-examples.md +81 -0
- package/skills/create-campaign-brief/ARCHITECTURE.md +72 -0
- package/skills/create-campaign-brief/DISCUSS.md +64 -0
- package/skills/create-campaign-brief/README.md +176 -0
- package/skills/create-campaign-brief/SKILL.md +537 -0
- package/skills/create-campaign-brief/references/brief-synthesis-rules.md +100 -0
- package/skills/create-campaign-brief/references/brief-template.md +220 -0
- package/skills/create-campaign-brief/references/campaign-idea-options.md +30 -0
- package/skills/create-campaign-brief/references/copy-appendix-template.md +62 -0
- package/skills/create-campaign-brief/references/draft-lifecycle.md +23 -0
- package/skills/create-campaign-brief/references/examples/MANIFEST.json +89 -0
- package/skills/create-campaign-brief/references/examples/briefs/clover.md +223 -0
- package/skills/create-campaign-brief/references/examples/briefs/galley.md +222 -0
- package/skills/create-campaign-brief/references/examples/briefs/gelee.md +220 -0
- package/skills/create-campaign-brief/references/examples/briefs/hey-digital.md +234 -0
- package/skills/create-campaign-brief/references/examples/briefs/persona.md +231 -0
- package/skills/create-campaign-brief/references/examples/briefs/revvix.md +220 -0
- package/skills/create-campaign-brief/references/examples/briefs/sellable-dev.md +220 -0
- package/skills/create-campaign-brief/references/examples/briefs/superposition.md +233 -0
- package/skills/create-campaign-brief/references/examples/briefs/superpower.md +219 -0
- package/skills/create-campaign-brief/references/examples/briefs/westpark-villas.md +220 -0
- package/skills/create-campaign-brief/references/icp-lock-question-bank.md +43 -0
- package/skills/create-campaign-brief/references/messaging-inputs.md +58 -0
- package/skills/create-campaign-brief/references/output-acceptance-rubric.md +62 -0
- package/skills/create-campaign-brief/references/phase75-active-runtime-message-pack.md +248 -0
- package/skills/create-campaign-brief/references/phase75-canonical-brief-template.md +319 -0
- package/skills/create-campaign-brief/references/phase75-good-brief-and-messaging-examples.md +445 -0
- package/skills/create-campaign-brief/references/quick-research-protocol.md +39 -0
- package/skills/create-campaign-brief/references/reference-sheet-protocol.md +60 -0
- package/skills/create-campaign-brief/references/zero-shot-iteration-rules.md +66 -0
- package/skills/create-campaign-v2/SKILL.md +1619 -0
- package/skills/create-campaign-v2/core/auto-execute.README.md +219 -0
- package/skills/create-campaign-v2/core/auto-execute.yaml +121 -0
- package/skills/create-campaign-v2/core/flow.v2.json +1643 -0
- package/skills/create-campaign-v2/core/policy.md +82 -0
- package/skills/create-campaign-v2/references/ai-tells.md +253 -0
- package/skills/create-campaign-v2/references/approval-gate-framing.md +346 -0
- package/skills/create-campaign-v2/references/draft-lifecycle.md +110 -0
- package/skills/create-campaign-v2/references/escalation-ladder.md +119 -0
- package/skills/create-campaign-v2/references/filter-leads.md +495 -0
- package/skills/create-campaign-v2/references/final-handoff-contract.md +176 -0
- package/skills/create-campaign-v2/references/gold-standard-message-examples.md +394 -0
- package/skills/create-campaign-v2/references/gold-standard-message-patterns.md +314 -0
- package/skills/create-campaign-v2/references/gold-standard-message-validation-example.md +212 -0
- package/skills/create-campaign-v2/references/lead-validation-preview.md +172 -0
- package/skills/create-campaign-v2/references/parallel-critique-protocol.md +368 -0
- package/skills/create-campaign-v2/references/sample-validation-loop.md +289 -0
- package/skills/create-campaign-v2/references/step-13-import-leads.md +151 -0
- package/skills/create-campaign-v2/references/step-15-re-cascade.md +90 -0
- package/skills/create-campaign-v2/references/thomas-revision-filters.md +521 -0
- package/skills/create-campaign-v2/references/thomas-variant-selection.md +202 -0
- package/skills/create-campaign-v2/references/tier-routing-matrix.md +66 -0
- package/skills/create-campaign-v2/references/validation-criteria.md +367 -0
- package/skills/create-campaign-v2/references/watch-link-handoff.md +106 -0
- package/skills/create-campaign-v2-validation/SKILL.md +296 -0
- package/skills/create-post/SKILL.md +1308 -0
- package/skills/create-rubric/SKILL.md +251 -0
- package/skills/engage/SKILL.md +549 -0
- package/skills/engage/core/README.md +23 -0
- package/skills/engage/core/proven-searches.json +11 -0
- package/skills/engage/core/style-guide.template.md +47 -0
- package/skills/engage/core/tracked-people.json +10 -0
- package/skills/enrich-prospects/SKILL.md +97 -0
- package/skills/find-leads/SKILL.md +467 -0
- package/skills/generate-messages/SKILL.md +2361 -0
- package/skills/interview/SKILL.md +132 -0
- package/skills/interview/core/ENGAGE_STYLE_GUIDE.template.md +54 -0
- package/skills/interview/core/ICP.template.md +54 -0
- package/skills/interview/core/VOICE_PROFILE.template.md +101 -0
- package/skills/providers/apollo.md +520 -0
- package/skills/providers/prospeo.md +398 -0
- package/skills/providers/sales-nav.md +372 -0
- package/skills/providers/signal-discovery.md +495 -0
- package/skills/research/SKILL.md +258 -0
- package/skills/research/config.json +9 -0
- package/skills/research/override.md +13 -0
- package/skills/research-prospect/SKILL.md +99 -0
- package/skills/research-sender/SKILL.md +158 -0
- package/skills/workflow-sequences/SKILL.md +85 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Create Campaign v2 Policy
|
|
2
|
+
|
|
3
|
+
This policy is the invariant layer for the from-scratch v2 orchestrator. Follow
|
|
4
|
+
it even if prompt prose is ambiguous.
|
|
5
|
+
|
|
6
|
+
## 1) JSON State Machine First
|
|
7
|
+
|
|
8
|
+
`core/flow.v2.json` is the source of truth for:
|
|
9
|
+
|
|
10
|
+
- stage order
|
|
11
|
+
- required artifacts
|
|
12
|
+
- produced artifacts
|
|
13
|
+
- allowed tools
|
|
14
|
+
- forbidden tools
|
|
15
|
+
- wait events
|
|
16
|
+
- transitions
|
|
17
|
+
|
|
18
|
+
`SKILL.md` explains how to execute the flow. It does not replace the flow.
|
|
19
|
+
|
|
20
|
+
## 2) Net-New Entry Point
|
|
21
|
+
|
|
22
|
+
Net-new v2 campaign creation starts at:
|
|
23
|
+
|
|
24
|
+
```text
|
|
25
|
+
bootstrap -> brief-interview
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Do not start at `validate-artifacts` unless resuming a compatibility run where
|
|
29
|
+
the complete upstream artifact set already exists.
|
|
30
|
+
|
|
31
|
+
## 3) No Mutation Before Approval
|
|
32
|
+
|
|
33
|
+
Before the user explicitly chooses `approve` at the commit gate, do not call:
|
|
34
|
+
|
|
35
|
+
- `create_campaign`
|
|
36
|
+
- `save_rubrics`
|
|
37
|
+
- `import_leads`
|
|
38
|
+
- `confirm_lead_list`
|
|
39
|
+
- `update_campaign`
|
|
40
|
+
- `queue_cells`
|
|
41
|
+
- `start_campaign`
|
|
42
|
+
|
|
43
|
+
Customer roleplay critique is advisory only. It cannot approve a campaign.
|
|
44
|
+
|
|
45
|
+
## 4) Artifact Gates
|
|
46
|
+
|
|
47
|
+
Do not run a downstream stage until the active step's `requiredArtifacts` exist.
|
|
48
|
+
Intermediate user-review gates are interrupt-only: auto-continue when an
|
|
49
|
+
artifact is confirmed and no strategic tradeoff is present. The final commit
|
|
50
|
+
gate is the only mandatory pre-mint approval gate.
|
|
51
|
+
|
|
52
|
+
The minimum pre-approval chain is:
|
|
53
|
+
|
|
54
|
+
```text
|
|
55
|
+
brief-v1.md / brief.md
|
|
56
|
+
lead-review.md
|
|
57
|
+
lead-sample.json
|
|
58
|
+
lead-filter.md
|
|
59
|
+
message-prep.md (optional)
|
|
60
|
+
message-candidate-drafts.md (optional, generated from find-leads basis rows)
|
|
61
|
+
message-validation.md
|
|
62
|
+
approval-packet.md
|
|
63
|
+
commit-gate-decision.md
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## 5) Revision Routing
|
|
67
|
+
|
|
68
|
+
Revision choices route back to the exact upstream stage:
|
|
69
|
+
|
|
70
|
+
- `revise-brief` -> `brief-interview`
|
|
71
|
+
- `revise-leads` -> `find-leads`
|
|
72
|
+
- `revise-rubric` -> `filter-rubric`
|
|
73
|
+
- `revise-messaging` -> `message-generation`
|
|
74
|
+
- `abort` -> stop with zero DB mutation
|
|
75
|
+
|
|
76
|
+
## 6) Post-Approval Tail
|
|
77
|
+
|
|
78
|
+
After `approve`, mint atomically with `create_campaign` and `save_rubrics`.
|
|
79
|
+
Only then surface the watch link and continue the cascade-driven tail.
|
|
80
|
+
|
|
81
|
+
The tail stops at `awaiting-user-greenlight`. Never call `start_campaign`
|
|
82
|
+
inside the autonomous tail.
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
# AI Tells — Canonical List
|
|
2
|
+
|
|
3
|
+
These are the patterns that make a cold message read as AI-generated,
|
|
4
|
+
not human-written. The message-validation Substance Filter 8 enforces
|
|
5
|
+
against this list. Add new tells here as we surface them in UAT — do
|
|
6
|
+
NOT bloat the filter itself.
|
|
7
|
+
|
|
8
|
+
Each tell has:
|
|
9
|
+
|
|
10
|
+
- **Pattern** — what to detect (regex-friendly description)
|
|
11
|
+
- **Why it's an AI tell** — the human-reasoning explanation
|
|
12
|
+
- **Allowed alternative** — what a hand-written message would do
|
|
13
|
+
instead
|
|
14
|
+
- **Severity** — `REJECT` (block message) or `WARN` (surface in
|
|
15
|
+
audit, do not auto-block)
|
|
16
|
+
|
|
17
|
+
## Tell #1 — Body-level self-introduction
|
|
18
|
+
|
|
19
|
+
**Pattern:** `{{sender_first_name}} here.` / `Hey {{first_name}} —
|
|
20
|
+
{{sender_name}} here.` / `I'm {{sender_name}}` / `I'm the founder of
|
|
21
|
+
{{company}}` / sender-identification opening sentences.
|
|
22
|
+
|
|
23
|
+
**Why it's an AI tell:** Recipient sees who sent the message from
|
|
24
|
+
the LinkedIn UI (sender name + photo + headline at the top of the
|
|
25
|
+
thread). Body-level self-intro signals "I'm an automation that
|
|
26
|
+
doesn't know what UI you're reading me in." Real humans don't
|
|
27
|
+
introduce themselves in cold InMail — they open with substance.
|
|
28
|
+
|
|
29
|
+
**Allowed alternative:** Open directly with substance — `"Hey Bonnie
|
|
30
|
+
— pre-Patientdesk we ran our own dental call center for two
|
|
31
|
+
years..."` Or `"Hey Bonnie — building a thing for group dentistry I
|
|
32
|
+
think you'd have an opinion on..."`
|
|
33
|
+
|
|
34
|
+
**Severity:** REJECT
|
|
35
|
+
|
|
36
|
+
## Tell #2 — Explicit recipient-fact reference in opener
|
|
37
|
+
|
|
38
|
+
**Pattern:** `Hey {{first_name}} — saw you posted...` / `Hey
|
|
39
|
+
{{first_name}}, your X is...` / `I noticed your...` / `Saw the X you
|
|
40
|
+
posted...` — opening sentence leads with a recipient-specific
|
|
41
|
+
reference.
|
|
42
|
+
|
|
43
|
+
**Why it's an AI tell:** Talking AT the recipient instead of WITH
|
|
44
|
+
them. Real founders open with their own reality, not by
|
|
45
|
+
interrogating the recipient's data feed. `"I noticed your..."` reads
|
|
46
|
+
as scraped intel.
|
|
47
|
+
|
|
48
|
+
**Allowed alternative:** Open with sender reality (Block 1); let
|
|
49
|
+
recipient gravity show up in Block 3 as a LIGHT callback. Refer to
|
|
50
|
+
their work CASUALLY without `"saw your X"`.
|
|
51
|
+
|
|
52
|
+
**Severity:** REJECT
|
|
53
|
+
|
|
54
|
+
## Tell #3 — Explicit date or duration references about the recipient
|
|
55
|
+
|
|
56
|
+
**Pattern:** `"last month"`, `"yesterday"`, `"X months ago"`, `"six
|
|
57
|
+
months into"`, `"since YYYY"`, verbatim post-dates (`"2026-03-16"`),
|
|
58
|
+
tenure-clocking (`"six months into your CTO seat"`).
|
|
59
|
+
|
|
60
|
+
**Why it's an AI tell:** Humans don't track when someone posted to
|
|
61
|
+
within 30 days. Date precision = data scraping. Tenure clocking is
|
|
62
|
+
creepy.
|
|
63
|
+
|
|
64
|
+
**Allowed alternative:** `"Saw you've been thinking about X
|
|
65
|
+
recently"` (no date); `"you've been at this a while"` (no number);
|
|
66
|
+
skip the timestamp entirely.
|
|
67
|
+
|
|
68
|
+
**Severity:** REJECT
|
|
69
|
+
|
|
70
|
+
## Tell #4 — Block-quoted verbatim recipient phrases
|
|
71
|
+
|
|
72
|
+
**Pattern:** Direct quotation marks around recipient's own words
|
|
73
|
+
longer than 4 words. E.g. `"Built SRE practice from scratch
|
|
74
|
+
supporting $0→$40M ARR growth"` inside the message body.
|
|
75
|
+
|
|
76
|
+
**Why it's an AI tell:** Real humans paraphrase or allude to what
|
|
77
|
+
someone said — they don't quote it back like a citation. Block
|
|
78
|
+
quotes scream "I scraped your profile and pasted the relevant
|
|
79
|
+
phrase."
|
|
80
|
+
|
|
81
|
+
**Allowed alternative:** Paraphrase the gist — `"you've spent years
|
|
82
|
+
building SRE from zero at scaling SaaS"`; reference the IDEA, not
|
|
83
|
+
the wording.
|
|
84
|
+
|
|
85
|
+
**Severity:** REJECT
|
|
86
|
+
|
|
87
|
+
## Tell #5 — Explicit-source-citation phrases
|
|
88
|
+
|
|
89
|
+
**Pattern:** `"your bio says..."`, `"your profile shows..."`, `"the
|
|
90
|
+
post you wrote"`, `"the req you posted"`, `"saw on your LinkedIn"`,
|
|
91
|
+
`"your X-page mentions"`.
|
|
92
|
+
|
|
93
|
+
**Why it's an AI tell:** Hand-writing a message means you mention
|
|
94
|
+
the company or project naturally — you don't cite `"your bio"` as a
|
|
95
|
+
source. Citation-shape phrasing is a template leak.
|
|
96
|
+
|
|
97
|
+
**Allowed alternative:** Refer to their work or company directly
|
|
98
|
+
without naming the source.
|
|
99
|
+
|
|
100
|
+
**Severity:** REJECT
|
|
101
|
+
|
|
102
|
+
## Tell #6 — Stack/feature lists in parentheses
|
|
103
|
+
|
|
104
|
+
**Pattern:** `(Datadog / PagerDuty / GitHub / AWS)` —
|
|
105
|
+
parenthetical-wrapped feature/stack dump.
|
|
106
|
+
|
|
107
|
+
**Why it's an AI tell:** Reads as marketing copy. Real founders
|
|
108
|
+
mention 1-2 named tools casually, in flow, not as a parenthetical
|
|
109
|
+
list.
|
|
110
|
+
|
|
111
|
+
**Allowed alternative:** `"hooks itself into your stack"`
|
|
112
|
+
(mechanism, no list); or weave 1-2 names naturally — `"plugs into
|
|
113
|
+
Datadog and PagerDuty without setup"`.
|
|
114
|
+
|
|
115
|
+
**Severity:** WARN (slashes inline in flow are tolerable;
|
|
116
|
+
parenthetical-wrapped lists are not)
|
|
117
|
+
|
|
118
|
+
## Tell #7 — Over-precise formal numerics
|
|
119
|
+
|
|
120
|
+
**Pattern:** `"2 Q1 2026 pilot partners"`, `"spent the last eight
|
|
121
|
+
years"`, `"over 60+ clinics"`, `"Founded in 2024"`, `"27% of our
|
|
122
|
+
sample"`, `"three failure modes"`.
|
|
123
|
+
|
|
124
|
+
**Why it's an AI tell:** Spec-sheet specificity in a casual message.
|
|
125
|
+
Real humans say `"a couple this quarter"`, `"you've been at this a
|
|
126
|
+
while"`, `"dozens of clinics"`.
|
|
127
|
+
|
|
128
|
+
**Allowed alternative:** Casual quantifiers — `"a couple"`, `"a
|
|
129
|
+
few"`, `"dozens"`, `"a while"`.
|
|
130
|
+
|
|
131
|
+
**Severity:** WARN (REJECT if multiple in one message)
|
|
132
|
+
|
|
133
|
+
## Tell #8 — Hardcoded signoff line
|
|
134
|
+
|
|
135
|
+
**Pattern:** Trailing `— {{sender_name}}` line, `Best, {{sender
|
|
136
|
+
_name}}`, `Cheers, {{sender_name}}`, `{{sender_name}}, co-founder at
|
|
137
|
+
{{company}}` as the last line.
|
|
138
|
+
|
|
139
|
+
**Why it's an AI tell:** Multi-sender pipelines hardcode breaks.
|
|
140
|
+
Recipient sees who sent it from LinkedIn UI. Body signoff is
|
|
141
|
+
redundant + brittle.
|
|
142
|
+
|
|
143
|
+
**Allowed alternative:** No signoff. Message ends with the CTA.
|
|
144
|
+
|
|
145
|
+
**Severity:** REJECT
|
|
146
|
+
|
|
147
|
+
## Tell #9 — Founder-credibility flex without mechanism bridge
|
|
148
|
+
|
|
149
|
+
**Pattern:** Founder-origin sentence (`"I spent two years at X"`)
|
|
150
|
+
that does NOT immediately connect to the product mechanism. Pure
|
|
151
|
+
pedigree-flex.
|
|
152
|
+
|
|
153
|
+
**Why it's an AI tell:** A real founder mentions their background
|
|
154
|
+
only when it directly explains WHY the product works. Pure flex =
|
|
155
|
+
template.
|
|
156
|
+
|
|
157
|
+
**Allowed alternative:** Founder-origin sentence MUST be immediately
|
|
158
|
+
followed by a mechanism explanation — `"Long was on Roblox App/DB
|
|
159
|
+
Infra → that's why IncidentFox auto-builds integrations from your
|
|
160
|
+
codebase"`.
|
|
161
|
+
|
|
162
|
+
**Severity:** REJECT
|
|
163
|
+
|
|
164
|
+
## Tell #10 — Vague-proof brags without named example
|
|
165
|
+
|
|
166
|
+
**Pattern:** `"multi-billion-dollar enterprises"`, `"Fortune 500"`,
|
|
167
|
+
`"leading SaaS"`, `"top scale-ups"`, `"trusted by leaders"` —
|
|
168
|
+
without naming a specific customer.
|
|
169
|
+
|
|
170
|
+
**Why it's an AI tell:** Vapor proof = worse than no proof. Buyers
|
|
171
|
+
immediately think "name one."
|
|
172
|
+
|
|
173
|
+
**Allowed alternative:** Either name a logo (with permission) or
|
|
174
|
+
strip to mechanism-only.
|
|
175
|
+
|
|
176
|
+
**Severity:** REJECT
|
|
177
|
+
|
|
178
|
+
## Tell #11 — Formal CTA phrasing
|
|
179
|
+
|
|
180
|
+
**Pattern:** `"Worth a 20-min walkthrough?"`, `"Open to a brief
|
|
181
|
+
call?"`, `"Could I book some time on your calendar?"`.
|
|
182
|
+
|
|
183
|
+
**Why it's an AI tell:** Corporate cadence. Real founders write
|
|
184
|
+
casually — `"Worth 20?"`, `"Quick call this week or next?"`, `"20
|
|
185
|
+
min sometime?"`.
|
|
186
|
+
|
|
187
|
+
**Allowed alternative:** Casual founder cadence; under 8 words
|
|
188
|
+
preferred.
|
|
189
|
+
|
|
190
|
+
**Severity:** WARN
|
|
191
|
+
|
|
192
|
+
## Tell #12 — Reusable opener that fits any recipient
|
|
193
|
+
|
|
194
|
+
**Pattern:** Opening sentence has zero row-specific detail and could
|
|
195
|
+
be sent unchanged to any of 50 recipients in the sample.
|
|
196
|
+
|
|
197
|
+
**Why it's an AI tell:** Broadcast spam. Real cold InMail earns its
|
|
198
|
+
right to the inbox with at least one row-specific reference.
|
|
199
|
+
|
|
200
|
+
**Allowed alternative:** At least one line in the body must
|
|
201
|
+
reference something verifiable about THIS recipient (project, role,
|
|
202
|
+
company, recent work).
|
|
203
|
+
|
|
204
|
+
**Severity:** REJECT
|
|
205
|
+
|
|
206
|
+
## Tell #13 — Em dash in message body
|
|
207
|
+
|
|
208
|
+
**Pattern:** Any U+2014 em dash character (`—`) anywhere in the
|
|
209
|
+
message body text. Includes em dashes used as parenthetical pauses
|
|
210
|
+
(`"works best for the exact hire you're in the middle of — founding
|
|
211
|
+
engineer, has to ship..."`), em dashes joining two independent
|
|
212
|
+
clauses, and em dashes wrapping an appositive phrase.
|
|
213
|
+
|
|
214
|
+
**Why it's an AI tell:** Em dashes are the single most reliable
|
|
215
|
+
signature of LLM-generated prose in casual-founder text. Real
|
|
216
|
+
founders typing a cold InMail on a phone or desktop almost never
|
|
217
|
+
reach for an em dash — they use commas, periods, parentheses, or
|
|
218
|
+
a hyphen-minus (`-`) when they want a pause. LLMs default to em
|
|
219
|
+
dashes for rhythm because they were trained on edited published
|
|
220
|
+
prose where em dashes are frequent. A message with even ONE em dash
|
|
221
|
+
reads as AI-polished, not hand-typed. Surfaced during Phase 94
|
|
222
|
+
Skillsync run (Plan 07): generator self-declared "NO em dashes" as
|
|
223
|
+
an invariant but still emitted one in the Selected Winner's Block
|
|
224
|
+
2 because the catalog did not yet codify the pattern.
|
|
225
|
+
|
|
226
|
+
**Allowed alternative:** Use commas, periods (break into two
|
|
227
|
+
sentences), parentheses, or a hyphen-minus (`-`) for pauses. If the
|
|
228
|
+
thought needs dashes to feel right, rewrite as two short sentences.
|
|
229
|
+
Example — instead of `"works best for the exact hire you're in the
|
|
230
|
+
middle of — founding engineer, has to ship production day one"`,
|
|
231
|
+
write `"works best for the exact hire you're making. founding
|
|
232
|
+
engineer, ships production day one."`.
|
|
233
|
+
|
|
234
|
+
**Severity:** REJECT
|
|
235
|
+
|
|
236
|
+
**Note:** This tell applies ONLY to the message body. Em dashes in
|
|
237
|
+
reference-file text, brief-template text, prompt text, and audit
|
|
238
|
+
notes are fine — this is a body-level output guard, not a
|
|
239
|
+
general-prose style rule.
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## How to add new tells
|
|
244
|
+
|
|
245
|
+
1. Surface the tell during UAT — it must be a pattern we saw in an
|
|
246
|
+
actual generated message that read as AI-written.
|
|
247
|
+
2. Name it `Tell #N` with a short descriptive title.
|
|
248
|
+
3. Fill in Pattern / Why / Allowed alternative / Severity.
|
|
249
|
+
4. The Filter 8 check automatically picks it up — do not touch
|
|
250
|
+
`thomas-revision-filters.md` Filter 8 spec when adding tells.
|
|
251
|
+
5. Add a corresponding test case in
|
|
252
|
+
`tests/scripts/skill-references-substance-filters.test.ts` if
|
|
253
|
+
the new tell needs regression coverage.
|
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
# Approval Gate Framing
|
|
2
|
+
|
|
3
|
+
This reference governs the commit gate in create-campaign-v2. Load this file
|
|
4
|
+
before showing the user the approval packet at the end of Phase 84 and before
|
|
5
|
+
minting a real `CampaignOffer`.
|
|
6
|
+
|
|
7
|
+
## Purpose
|
|
8
|
+
|
|
9
|
+
The approval gate is the **only** place in create-campaign-v2 where the user
|
|
10
|
+
authorizes a DB mutation. Everything upstream (Phase 83 brief + Phase 84
|
|
11
|
+
validation artifacts) is file-only. Everything downstream (atomic mint +
|
|
12
|
+
autonomous tail) is live campaign state.
|
|
13
|
+
|
|
14
|
+
No campaign row exists until the user picks `approve`.
|
|
15
|
+
|
|
16
|
+
## Preconditions
|
|
17
|
+
|
|
18
|
+
Before showing the commit gate, the draft directory must contain all of:
|
|
19
|
+
|
|
20
|
+
- `brief.md`
|
|
21
|
+
- `lead-review.md`
|
|
22
|
+
- `lead-sample.json`
|
|
23
|
+
- `lead-filter.md`
|
|
24
|
+
- `message-validation.md`
|
|
25
|
+
- `approval-packet.md`
|
|
26
|
+
|
|
27
|
+
The current run must also have retrieved the real message-generation prompt
|
|
28
|
+
through `get_message_prompt({ promptName: "generate-messages" })` or
|
|
29
|
+
`get_subskill_prompt({ subskillName: "generate-messages" })` before
|
|
30
|
+
`message-validation.md`, `approval-packet.md`, or the commit gate is written.
|
|
31
|
+
If the message template was written directly from memory or planning artifacts,
|
|
32
|
+
do not show the commit gate; route back to message generation.
|
|
33
|
+
|
|
34
|
+
`rubric.json` is optional but strongly preferred — when missing, derive it from
|
|
35
|
+
`lead-filter.md` in the atomic mint step.
|
|
36
|
+
|
|
37
|
+
`lead-source-intake.json` is optional for normal discovery and required when
|
|
38
|
+
the user intentionally supplied a source. If present, the approval packet must
|
|
39
|
+
summarize the source type, input mode, supplied profile/domain/list count,
|
|
40
|
+
sampled count, what will be materialized after approval, and that only the
|
|
41
|
+
review batch will be enriched/messaged before greenlight.
|
|
42
|
+
Use the phrase "only the review batch" plainly enough that the operator
|
|
43
|
+
understands approval is not permission to process the full supplied source.
|
|
44
|
+
|
|
45
|
+
If any required artifact is missing, do NOT show the gate. Route back to the
|
|
46
|
+
first missing step instead.
|
|
47
|
+
|
|
48
|
+
### Workspace + sender invariant (Step 0, before any commit-gate action)
|
|
49
|
+
|
|
50
|
+
Before showing the gate OR running any approve-path tool, verify the
|
|
51
|
+
**workspace/sender invariant**:
|
|
52
|
+
|
|
53
|
+
- The sender configured in the committed `CampaignOffer` draft resolves
|
|
54
|
+
inside the currently-authenticated workspace.
|
|
55
|
+
- The active Sellable-auth workspace matches the workspace the draft
|
|
56
|
+
directory was written in (prevents cross-workspace mint drift).
|
|
57
|
+
|
|
58
|
+
This invariant is identical to the Phase 84 "sender/workspace mismatch
|
|
59
|
+
= abort" rule and the global memory rule `CRITICAL: Never Send Messages
|
|
60
|
+
From Wrong Workspace`. If the invariant fails:
|
|
61
|
+
|
|
62
|
+
1. Do NOT show the commit gate.
|
|
63
|
+
2. Do NOT call `bootstrap_create_campaign`, `create_campaign`, or
|
|
64
|
+
`save_rubrics`.
|
|
65
|
+
3. Surface an explicit workspace/sender-mismatch error + the detected
|
|
66
|
+
current-workspace vs expected-workspace diagnostic.
|
|
67
|
+
4. Leave the draft directory intact; a fresh session in the correct
|
|
68
|
+
workspace can resume from where this one aborted.
|
|
69
|
+
|
|
70
|
+
The invariant is a hard stop, not an escalation in the Plan 85-02 sense.
|
|
71
|
+
|
|
72
|
+
## Anchor Validation
|
|
73
|
+
|
|
74
|
+
Before showing the gate, walk the required artifacts and confirm anchors are
|
|
75
|
+
populated:
|
|
76
|
+
|
|
77
|
+
- `brief.md` has a non-empty `## Message Thesis` section
|
|
78
|
+
- `lead-review.md` has a `Status` of `confirmed` (not `rejected` or `unclear`)
|
|
79
|
+
- `lead-sample.json` parses and contains at least one lead row
|
|
80
|
+
- `lead-filter.md` has `Decision`, `Who We'll Keep`, `Who We'll Exclude`,
|
|
81
|
+
`Required Keep Rules`, `Required Exclude Rules`, `Pass Rate`,
|
|
82
|
+
`Recommendation`, and `Implementation Details` sections
|
|
83
|
+
- `message-validation.md` has `Status: confirmed`, `Mode: DRY MODE (no DB mutation)`,
|
|
84
|
+
a `Selected Winner`, and a non-empty `Token Adherence Table`
|
|
85
|
+
|
|
86
|
+
An empty anchor blocks `approve`. The user can still pick a revision choice.
|
|
87
|
+
|
|
88
|
+
## Approval Packet
|
|
89
|
+
|
|
90
|
+
Build the approval packet in user-facing order and write it to
|
|
91
|
+
`approval-packet.md` before the gate is shown. The file is the exact packet the
|
|
92
|
+
user is approving, not a private scratch note.
|
|
93
|
+
|
|
94
|
+
When rendering the approval packet inline for the customer, start it with
|
|
95
|
+
exactly:
|
|
96
|
+
|
|
97
|
+
```text
|
|
98
|
+
Status: approval-packet
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
The same assistant turn must then call `AskUserQuestion` with the six commit
|
|
102
|
+
choices. Do not show a standalone commit-gate question in a later turn without
|
|
103
|
+
the approval packet above it.
|
|
104
|
+
|
|
105
|
+
The packet should read like an AI GTM engineer explaining the campaign, not an
|
|
106
|
+
internal validation report. Start with the practical direction in plain
|
|
107
|
+
language: who we will contact, why this buyer should care, what lead source we
|
|
108
|
+
will use, what the first message says, and what happens if the user approves.
|
|
109
|
+
Keep implementation details available, but move them below the customer-facing
|
|
110
|
+
summary.
|
|
111
|
+
|
|
112
|
+
1. **brief** — `brief.md` thesis, product, ICP, offer
|
|
113
|
+
2. **lead sample** — first 5-10 rows from `lead-sample.json` rendered as
|
|
114
|
+
`Name / Title / Company` lines, plus the `lead-review.md` pass-rate
|
|
115
|
+
and supplied-source framing when `lead-source-intake.json` exists:
|
|
116
|
+
supplied people list, existing Sellable lead list, or supplied account list
|
|
117
|
+
plus people search
|
|
118
|
+
3. **lead filter** — the `Decision`, `Who We'll Keep`, `Who We'll Exclude`,
|
|
119
|
+
`Pass Rate`, and `Recommendation` blocks from `lead-filter.md`; keep
|
|
120
|
+
rubric internals in `Implementation Details` unless the user asks to inspect
|
|
121
|
+
the saved filter criteria
|
|
122
|
+
4. **message validation** — the `Selected Winner` from `message-validation.md`,
|
|
123
|
+
rendered as it will appear in the outbound, plus the `Findings` + `Recommendation`
|
|
124
|
+
|
|
125
|
+
The packet must include a dedicated `## Message Review` section immediately
|
|
126
|
+
before `## Approved Message Template`. This is the customer-facing messaging
|
|
127
|
+
gate. It should not be a raw validation dump; it should answer:
|
|
128
|
+
|
|
129
|
+
- `Verdict:` strong / usable-but-could-improve / needs-revision
|
|
130
|
+
- `What works:` why the message is likely to earn replies
|
|
131
|
+
- `What I would improve before launch:` the biggest remaining concern, or
|
|
132
|
+
`none` if it is ready
|
|
133
|
+
- `Recommendation:` approve-message / revise-messaging
|
|
134
|
+
|
|
135
|
+
If the validation says `revise-message`, do not bury that in caveats. Show the
|
|
136
|
+
draft if useful, mark `Recommendation: revise-messaging`, and route the user to
|
|
137
|
+
the `revise-messaging` commit-gate option instead of implying the campaign is
|
|
138
|
+
ready.
|
|
139
|
+
|
|
140
|
+
If `message-validation.md` has an extractable `Selected Winner`, the packet's
|
|
141
|
+
`## Approved Message Template` must use that winner exactly, except for
|
|
142
|
+
supported prospect-row `{{tokens}}`. Do not write a fresh approval-template
|
|
143
|
+
message from the brief. If no winner/template can be extracted, this exact-match
|
|
144
|
+
gate is skipped, but the packet still needs a usable approved template unless
|
|
145
|
+
the user explicitly chose AI-generated messages.
|
|
146
|
+
|
|
147
|
+
Do NOT render the packet as a bundle of opaque validation anchors or a dump
|
|
148
|
+
of raw JSON. The user is approving a live campaign — they need to see what
|
|
149
|
+
they are approving.
|
|
150
|
+
|
|
151
|
+
Do NOT use opaque words like `anchor`, `chosen lane`, `validation artifact`,
|
|
152
|
+
or `provider path` in the top customer-facing section. Use plain labels:
|
|
153
|
+
target prospects, lead source, expected usable leads, filters, message, risks,
|
|
154
|
+
and next step.
|
|
155
|
+
|
|
156
|
+
If a customer/operator roleplay pass is run before the gate, write its critique
|
|
157
|
+
to `customer-roleplay.md`. That critique is advisory only. A positive roleplay
|
|
158
|
+
result is not approval and must not trigger `create_campaign`,
|
|
159
|
+
`save_rubrics`, or any other DB mutation.
|
|
160
|
+
|
|
161
|
+
After the user/operator chooses, write `commit-gate-decision.md` with exactly
|
|
162
|
+
one of the six allowed choices plus a short reason. This file is the durable
|
|
163
|
+
authorization record for the branch taken. Only `Decision: approve` authorizes
|
|
164
|
+
atomic mint.
|
|
165
|
+
|
|
166
|
+
### Packet framing rule (never say "anchor")
|
|
167
|
+
|
|
168
|
+
The user-visible packet MUST use the product-facing section names:
|
|
169
|
+
|
|
170
|
+
- **brief**
|
|
171
|
+
- **lead sample**
|
|
172
|
+
- **lead filter**
|
|
173
|
+
- **messages** (or **message validation** when emphasizing the validation mode)
|
|
174
|
+
|
|
175
|
+
The internal skill vocabulary uses "anchor validation" to describe the
|
|
176
|
+
presence/non-emptiness checks in §Anchor Validation above — that's fine for
|
|
177
|
+
internal skill state. But the USER-FACING packet MUST NOT use "anchor,"
|
|
178
|
+
"validation anchor," "draft anchor," or any other anchor-prefixed term.
|
|
179
|
+
"Anchor" is an implementation word; it reads as opaque to operators.
|
|
180
|
+
|
|
181
|
+
Example — correct vs incorrect packet headers:
|
|
182
|
+
|
|
183
|
+
| Correct (product-facing) | Incorrect (opaque anchor framing) |
|
|
184
|
+
| ------------------------------------------- | ---------------------------------------------------- |
|
|
185
|
+
| "Here's the **brief** you're about to ship" | "Here's the **brief anchor** in the draft directory" |
|
|
186
|
+
| "The **lead sample** shows 10 top rows" | "The **lead-sample anchor** validates" |
|
|
187
|
+
| "**Messages** — winner from 3 candidates" | "**Message-validation anchor** Status: confirmed" |
|
|
188
|
+
|
|
189
|
+
## Commit Gate Choices
|
|
190
|
+
|
|
191
|
+
The gate offers exactly these 6 choices, in this order:
|
|
192
|
+
|
|
193
|
+
```text
|
|
194
|
+
approve
|
|
195
|
+
revise-brief
|
|
196
|
+
revise-leads
|
|
197
|
+
revise-rubric
|
|
198
|
+
revise-messaging
|
|
199
|
+
abort
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Use `AskUserQuestion` with these 6 options. Do not collapse, reorder, or add
|
|
203
|
+
choices. Do not auto-select.
|
|
204
|
+
|
|
205
|
+
If the host UI limits options per question, preserve all six routes with a
|
|
206
|
+
two-question gate instead of mentioning implementation limits:
|
|
207
|
+
|
|
208
|
+
1. Decision: `approve`, `revise`, `abort`
|
|
209
|
+
2. Revise route: `revise-brief`, `revise-leads`, `revise-rubric`,
|
|
210
|
+
`revise-messaging`
|
|
211
|
+
|
|
212
|
+
In this split form, `revise` is not a seventh route; it is only the parent
|
|
213
|
+
choice that activates the second question.
|
|
214
|
+
|
|
215
|
+
## Choice Semantics
|
|
216
|
+
|
|
217
|
+
### `approve`
|
|
218
|
+
|
|
219
|
+
User authorizes atomic mint. Proceed to the atomic-mint step:
|
|
220
|
+
|
|
221
|
+
0. **verify workspace/sender invariant** (see §Preconditions) — if the
|
|
222
|
+
invariant fails, abort BEFORE `bootstrap_create_campaign`
|
|
223
|
+
1. `bootstrap_create_campaign({ flowVersion: "v2" })`
|
|
224
|
+
2. `create_campaign({ campaignBrief, currentStep: "auto-execute-leads" })`
|
|
225
|
+
→ capture `{ campaignId, watchUrl }` from response
|
|
226
|
+
3. `save_rubrics({ campaignOfferId, rubric })` using `rubric.json` (or derived
|
|
227
|
+
payload from `lead-filter.md`)
|
|
228
|
+
4. flip brief status to `committed`; move draft to `.committed/`
|
|
229
|
+
5. surface the watch link using `watch-link-handoff.md`
|
|
230
|
+
6. hand off to the autonomous tail (Plan 85-02)
|
|
231
|
+
|
|
232
|
+
See `watch-link-handoff.md` for the exact link-surfacing protocol and the
|
|
233
|
+
partial-mint recovery rules.
|
|
234
|
+
|
|
235
|
+
### `save_rubrics` partial-mint recovery preference
|
|
236
|
+
|
|
237
|
+
When `create_campaign` succeeds but `save_rubrics` fails, the recovery
|
|
238
|
+
path preference is **recoverable-failure state + explicit retry**, NOT
|
|
239
|
+
rollback of the CampaignOffer row.
|
|
240
|
+
|
|
241
|
+
Rationale:
|
|
242
|
+
|
|
243
|
+
- `save_rubrics` is idempotent — the operator can retry the same call
|
|
244
|
+
without duplicating state.
|
|
245
|
+
- The operator may want to inspect the in-flight campaign row (via the
|
|
246
|
+
watch link) before deciding whether to retry or abort.
|
|
247
|
+
- Rollback would destroy a useful artifact (the minted campaign row +
|
|
248
|
+
persisted brief) that the operator may want to keep while
|
|
249
|
+
debugging the rubric save.
|
|
250
|
+
|
|
251
|
+
Implementation:
|
|
252
|
+
|
|
253
|
+
1. Do NOT call the delete path on the CampaignOffer row.
|
|
254
|
+
2. Mark the campaign in a `currentStep` state that the skill can
|
|
255
|
+
detect on resume (e.g. `auto-execute-leads-rubric-pending`).
|
|
256
|
+
3. Surface the failure with the specific error + retry instructions.
|
|
257
|
+
4. Do NOT surface the watch link until `save_rubrics` succeeds — per
|
|
258
|
+
`watch-link-handoff.md` §Partial-Mint Recovery, the link points
|
|
259
|
+
at a live, fully-minted campaign; a half-minted one is misleading.
|
|
260
|
+
5. On retry, call `save_rubrics` again with the same payload. If it
|
|
261
|
+
succeeds, the tail resumes normally.
|
|
262
|
+
|
|
263
|
+
Rollback remains available as an operator-driven escape hatch via the
|
|
264
|
+
`abort` gate choice on resume — but the default recovery is NOT
|
|
265
|
+
automatic rollback.
|
|
266
|
+
|
|
267
|
+
### `revise-brief`
|
|
268
|
+
|
|
269
|
+
Route back to Phase 83 or Phase 84 depending on what the user wants to change.
|
|
270
|
+
Do NOT mint a campaign. Do NOT print a watch link.
|
|
271
|
+
|
|
272
|
+
Draft effect: preserve nothing by default; the brief itself is usually
|
|
273
|
+
rewritten upstream. Delete all downstream artifacts so Phase 84 will re-run:
|
|
274
|
+
|
|
275
|
+
- delete `lead-review.md`
|
|
276
|
+
- delete `lead-sample.json`
|
|
277
|
+
- delete `lead-filter.md`
|
|
278
|
+
- delete `message-validation.md`
|
|
279
|
+
- delete `rubric.json` if present
|
|
280
|
+
|
|
281
|
+
### `revise-leads`
|
|
282
|
+
|
|
283
|
+
Route back to Phase 84 `find leads`. Do NOT mint a campaign. Do NOT print a
|
|
284
|
+
watch link.
|
|
285
|
+
|
|
286
|
+
Draft effect:
|
|
287
|
+
|
|
288
|
+
- preserve `brief.md`
|
|
289
|
+
- delete `lead-review.md`
|
|
290
|
+
- delete `lead-sample.json`
|
|
291
|
+
- delete `lead-filter.md`
|
|
292
|
+
- delete `message-validation.md`
|
|
293
|
+
- delete `rubric.json` if present
|
|
294
|
+
|
|
295
|
+
### `revise-rubric`
|
|
296
|
+
|
|
297
|
+
Route back to Phase 84 `filter leads`. Do NOT mint a campaign. Do NOT print a
|
|
298
|
+
watch link.
|
|
299
|
+
|
|
300
|
+
Draft effect:
|
|
301
|
+
|
|
302
|
+
- preserve `brief.md`
|
|
303
|
+
- preserve `lead-review.md`
|
|
304
|
+
- preserve `lead-sample.json`
|
|
305
|
+
- delete `lead-filter.md`
|
|
306
|
+
- delete `message-validation.md`
|
|
307
|
+
- delete `rubric.json` if present
|
|
308
|
+
|
|
309
|
+
### `revise-messaging`
|
|
310
|
+
|
|
311
|
+
Route back to Phase 84 `generate message`. Do NOT mint a campaign. Do NOT
|
|
312
|
+
print a watch link.
|
|
313
|
+
|
|
314
|
+
Draft effect:
|
|
315
|
+
|
|
316
|
+
- preserve `brief.md`
|
|
317
|
+
- preserve `lead-review.md`
|
|
318
|
+
- preserve `lead-sample.json`
|
|
319
|
+
- preserve `lead-filter.md`
|
|
320
|
+
- delete `message-validation.md`
|
|
321
|
+
- preserve `rubric.json` if present
|
|
322
|
+
|
|
323
|
+
### `abort`
|
|
324
|
+
|
|
325
|
+
User cancels the session. Do NOT mint a campaign. Do NOT print a watch link.
|
|
326
|
+
|
|
327
|
+
Draft effect: move the draft directory to
|
|
328
|
+
`.sellable/create-campaign-v2/drafts/{workspace-slug}/.aborted/{campaign-slug}-{timestamp}/`.
|
|
329
|
+
No DB rows touched. No `CampaignOffer` created.
|
|
330
|
+
|
|
331
|
+
## Hard Rules
|
|
332
|
+
|
|
333
|
+
- The user's `approve` choice is the **only** trigger for live DB mutation.
|
|
334
|
+
- A positive `customer-roleplay.md` critique is not approval and produces zero
|
|
335
|
+
DB mutation unless `commit-gate-decision.md` explicitly says
|
|
336
|
+
`Decision: approve`.
|
|
337
|
+
- The commit gate must not call `create_campaign`, `save_rubrics`,
|
|
338
|
+
`import_leads`, `update_campaign`, or any other mutating tool before the
|
|
339
|
+
user picks a choice.
|
|
340
|
+
- `import_leads` is **not** part of atomic mint. Full sourcing/import happens
|
|
341
|
+
in Plan 85-02 Step 13 after mint.
|
|
342
|
+
- Revision choices produce ZERO DB rows.
|
|
343
|
+
- Aborting produces ZERO DB rows.
|
|
344
|
+
- A failed `approve` path (e.g. `create_campaign` errors, or `save_rubrics`
|
|
345
|
+
fails after campaign creation) does NOT surface a watch link. See
|
|
346
|
+
`watch-link-handoff.md` for the partial-mint recovery protocol.
|