taketomarket 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.
Files changed (123) hide show
  1. package/.claude-plugin/plugin.json +10 -0
  2. package/LICENSE +21 -0
  3. package/README.md +419 -0
  4. package/agents/ttm-producer.md +53 -0
  5. package/bin/lib/campaign.cjs +553 -0
  6. package/bin/lib/commit.cjs +105 -0
  7. package/bin/lib/core.cjs +172 -0
  8. package/bin/lib/deviation.cjs +149 -0
  9. package/bin/lib/drift-log.cjs +219 -0
  10. package/bin/lib/health.cjs +438 -0
  11. package/bin/lib/slug.cjs +59 -0
  12. package/bin/lib/state.cjs +96 -0
  13. package/bin/ttm-tools.cjs +157 -0
  14. package/gates/base-gates.md +266 -0
  15. package/gates/discipline/.gitkeep +0 -0
  16. package/gates/gate-evaluation.md +341 -0
  17. package/gates/meta-gates.md +19 -0
  18. package/install.js +307 -0
  19. package/package.json +53 -0
  20. package/playbooks/.gitkeep +0 -0
  21. package/playbooks/aeo.md +223 -0
  22. package/playbooks/affiliate.md +272 -0
  23. package/playbooks/base.md +110 -0
  24. package/playbooks/email.md +306 -0
  25. package/playbooks/events.md +320 -0
  26. package/playbooks/linkedin.md +263 -0
  27. package/playbooks/paid-ads.md +318 -0
  28. package/playbooks/pr-media.md +296 -0
  29. package/playbooks/seo.md +284 -0
  30. package/playbooks/social.md +305 -0
  31. package/playbooks/youtube.md +325 -0
  32. package/references/context-loading.md +107 -0
  33. package/references/learnings-extraction.md +94 -0
  34. package/references/measurement-template.md +48 -0
  35. package/references/meta-gate-evaluation.md +169 -0
  36. package/references/positioning-check-report.md +197 -0
  37. package/references/review-checklist.md +78 -0
  38. package/references/ship-checklist-items.md +94 -0
  39. package/settings.json +4 -0
  40. package/skills/ttm-aeo-check/SKILL.md +20 -0
  41. package/skills/ttm-affiliate-kit/SKILL.md +19 -0
  42. package/skills/ttm-archive/SKILL.md +13 -0
  43. package/skills/ttm-brand-refresh/SKILL.md +19 -0
  44. package/skills/ttm-brief/SKILL.md +14 -0
  45. package/skills/ttm-competitor-scan/SKILL.md +19 -0
  46. package/skills/ttm-email-preflight/SKILL.md +19 -0
  47. package/skills/ttm-fix/SKILL.md +13 -0
  48. package/skills/ttm-health/SKILL.md +12 -0
  49. package/skills/ttm-icp-refresh/SKILL.md +19 -0
  50. package/skills/ttm-init/SKILL.md +12 -0
  51. package/skills/ttm-keyword-map/SKILL.md +19 -0
  52. package/skills/ttm-learn/SKILL.md +14 -0
  53. package/skills/ttm-measure/SKILL.md +14 -0
  54. package/skills/ttm-new-campaign/SKILL.md +13 -0
  55. package/skills/ttm-next/SKILL.md +12 -0
  56. package/skills/ttm-positioning-check/SKILL.md +19 -0
  57. package/skills/ttm-positioning-shift/SKILL.md +19 -0
  58. package/skills/ttm-produce/SKILL.md +14 -0
  59. package/skills/ttm-repurpose/SKILL.md +20 -0
  60. package/skills/ttm-research/SKILL.md +13 -0
  61. package/skills/ttm-resume/SKILL.md +13 -0
  62. package/skills/ttm-review/SKILL.md +13 -0
  63. package/skills/ttm-seo-audit/SKILL.md +20 -0
  64. package/skills/ttm-ship/SKILL.md +13 -0
  65. package/skills/ttm-state/SKILL.md +13 -0
  66. package/skills/ttm-verify/SKILL.md +14 -0
  67. package/templates/agents-md.md +65 -0
  68. package/templates/campaign-brief.md +74 -0
  69. package/templates/campaign-research.md +39 -0
  70. package/templates/campaign-state.md +40 -0
  71. package/templates/claude-md.md +65 -0
  72. package/templates/deviation-log.md +12 -0
  73. package/templates/drift-log.md +17 -0
  74. package/templates/fix-brief.md +59 -0
  75. package/templates/fix-log.md +22 -0
  76. package/templates/measurement-report.md +75 -0
  77. package/templates/migration-plan.md +24 -0
  78. package/templates/production-manifest.json +20 -0
  79. package/templates/reference-files/brand.md +45 -0
  80. package/templates/reference-files/calendar.md +30 -0
  81. package/templates/reference-files/channels.md +40 -0
  82. package/templates/reference-files/competitors.md +40 -0
  83. package/templates/reference-files/icp.md +50 -0
  84. package/templates/reference-files/learnings.md +40 -0
  85. package/templates/reference-files/metrics.md +42 -0
  86. package/templates/reference-files/positioning.md +38 -0
  87. package/templates/reference-files/state.md +27 -0
  88. package/templates/verification-report.md +59 -0
  89. package/workflows/discipline/.gitkeep +0 -0
  90. package/workflows/discipline/aeo-check.md +180 -0
  91. package/workflows/discipline/affiliate-kit.md +147 -0
  92. package/workflows/discipline/email-preflight.md +150 -0
  93. package/workflows/discipline/keyword-map.md +125 -0
  94. package/workflows/discipline/repurpose.md +329 -0
  95. package/workflows/discipline/seo-audit.md +169 -0
  96. package/workflows/lifecycle/.gitkeep +0 -0
  97. package/workflows/lifecycle/brief-positioning-check.md +90 -0
  98. package/workflows/lifecycle/brief.md +355 -0
  99. package/workflows/lifecycle/fix.md +495 -0
  100. package/workflows/lifecycle/learn.md +405 -0
  101. package/workflows/lifecycle/measure.md +379 -0
  102. package/workflows/lifecycle/produce.md +383 -0
  103. package/workflows/lifecycle/research.md +264 -0
  104. package/workflows/lifecycle/review.md +432 -0
  105. package/workflows/lifecycle/ship.md +521 -0
  106. package/workflows/lifecycle/verify.md +507 -0
  107. package/workflows/reference-mgmt/.gitkeep +0 -0
  108. package/workflows/reference-mgmt/brand-refresh.md +193 -0
  109. package/workflows/reference-mgmt/competitor-scan.md +228 -0
  110. package/workflows/reference-mgmt/icp-refresh.md +200 -0
  111. package/workflows/reference-mgmt/positioning-check.md +339 -0
  112. package/workflows/reference-mgmt/positioning-shift.md +368 -0
  113. package/workflows/setup/.gitkeep +0 -0
  114. package/workflows/setup/init-questions.md +225 -0
  115. package/workflows/setup/init-validation.md +155 -0
  116. package/workflows/setup/init.md +449 -0
  117. package/workflows/setup/new-campaign.md +134 -0
  118. package/workflows/utility/.gitkeep +0 -0
  119. package/workflows/utility/archive.md +334 -0
  120. package/workflows/utility/health.md +166 -0
  121. package/workflows/utility/next.md +187 -0
  122. package/workflows/utility/resume.md +249 -0
  123. package/workflows/utility/state.md +207 -0
@@ -0,0 +1,379 @@
1
+ <purpose>
2
+ Measurement workflow for /ttm-measure. Accepts analytics data via 3 pathways
3
+ (MCP tools, CSV/Markdown paste, structured batch questions). Applies 3 attribution
4
+ models (last-touch, linear, time-decay). Generates an outcome-first measurement
5
+ report. Updates campaign state. Use after a campaign has been shipped and analytics
6
+ data is available for the measurement window.
7
+ </purpose>
8
+
9
+ <required_reading>
10
+ @${CLAUDE_PLUGIN_ROOT}/references/context-loading.md
11
+ @${CLAUDE_PLUGIN_ROOT}/references/measurement-template.md
12
+ @${CLAUDE_PLUGIN_ROOT}/templates/measurement-report.md
13
+ </required_reading>
14
+
15
+ <constraints>
16
+
17
+ ## Positioning Constraint (Read-Only)
18
+
19
+ `.marketing/POSITIONING.md` is loaded for context only. This workflow MUST NOT modify
20
+ POSITIONING.md. Positioning changes require `/ttm-positioning` -- never alter positioning
21
+ as a side effect of measurement.
22
+
23
+ ## Text-Mode Detection
24
+
25
+ **Text mode (`--text` flag):** Set `TEXT_MODE=true` if `--text` is present in `$ARGUMENTS`
26
+ or if the runtime is not Claude Code. When TEXT_MODE is active, replace every
27
+ `AskUserQuestion` call with a plain-text numbered list.
28
+
29
+ Detection:
30
+ ```bash
31
+ if echo "$ARGUMENTS" | grep -q -- '--text'; then TEXT_MODE=true; fi
32
+ ```
33
+
34
+ If `AskUserQuestion` tool is not available in the current runtime, set `TEXT_MODE=true`.
35
+
36
+ When TEXT_MODE is active, replace each AskUserQuestion with a plain-text numbered list:
37
+ ```
38
+ [HEADER]
39
+ [QUESTION]
40
+ 1. [OPTION_1_LABEL] -- [OPTION_1_DESCRIPTION]
41
+ 2. [OPTION_2_LABEL] -- [OPTION_2_DESCRIPTION]
42
+ ...
43
+ Type the number of your choice:
44
+ ```
45
+
46
+ </constraints>
47
+
48
+ <process>
49
+
50
+ ## Step 1: Load Context
51
+
52
+ ```
53
+ takeToMarket > LOADING CONTEXT
54
+ ```
55
+
56
+ Extract SLUG from $ARGUMENTS (strip `--text` flag if present):
57
+ ```bash
58
+ SLUG=$(echo "$ARGUMENTS" | sed 's/--text//g' | xargs)
59
+ ```
60
+
61
+ If SLUG is empty, error: "Usage: /ttm-measure [campaign-slug]. Provide a campaign slug." Exit.
62
+
63
+ Read Tier 1 summary blocks (content between `<!-- _SUMMARY -->` and `<!-- END_SUMMARY -->`)
64
+ from all 9 `.marketing/` reference files:
65
+
66
+ - `.marketing/POSITIONING.md` (lines 1 to `<!-- END_SUMMARY -->`)
67
+ - `.marketing/BRAND.md` (lines 1 to `<!-- END_SUMMARY -->`)
68
+ - `.marketing/ICP.md` (lines 1 to `<!-- END_SUMMARY -->`)
69
+ - `.marketing/CHANNELS.md` (lines 1 to `<!-- END_SUMMARY -->`)
70
+ - `.marketing/STATE.md` (frontmatter only)
71
+ - `.marketing/CALENDAR.md` (lines 1 to `<!-- END_SUMMARY -->`)
72
+ - `.marketing/COMPETITORS.md` (lines 1 to `<!-- END_SUMMARY -->`)
73
+ - `.marketing/METRICS.md` (lines 1 to `<!-- END_SUMMARY -->`)
74
+ - `.marketing/LEARNINGS.md` (lines 1 to `<!-- END_SUMMARY -->`)
75
+
76
+ Read Tier 2 (full content) for:
77
+ - `.marketing/METRICS.md` (needed for metric definitions and outcome/output classification)
78
+ - `.marketing/CHANNELS.md` (needed for channel attribution mapping)
79
+
80
+ Read campaign-specific files (always full-load per context-loading.md rule 4):
81
+ - `.marketing/CAMPAIGNS/${SLUG}/STATE.md`
82
+ - `.marketing/CAMPAIGNS/${SLUG}/BRIEF.md`
83
+
84
+ Extract from brief:
85
+ - **Outcome metric:** name, target value, measurement window, data source
86
+ - **Output metrics:** asset counts, intermediate indicators
87
+ - **Channel mix:** channels used in campaign (for attribution)
88
+
89
+ ---
90
+
91
+ ## Step 2: Validate Campaign State
92
+
93
+ ```bash
94
+ node "${CLAUDE_PLUGIN_ROOT}/bin/ttm-tools.cjs" campaign state ${SLUG} --raw
95
+ ```
96
+
97
+ Verify campaign is in `shipped` or `measured` phase (re-measurement is allowed).
98
+
99
+ **If NOT shipped or measured:**
100
+ ```
101
+ takeToMarket > ERROR
102
+
103
+ Campaign must be shipped before measuring.
104
+ Current phase: ${PHASE}
105
+ Run /ttm-ship first.
106
+ ```
107
+ Exit -- do not continue.
108
+
109
+ **If shipped or measured:** Continue to Step 3.
110
+
111
+ If phase is `measured`, inform the user:
112
+ ```
113
+ takeToMarket > RE-MEASUREMENT
114
+
115
+ Campaign '${SLUG}' has already been measured.
116
+ Running measurement again will generate a new MEASUREMENT.md.
117
+ Previous measurement data will be overwritten.
118
+ ```
119
+
120
+ Wait for user confirmation before continuing.
121
+
122
+ ---
123
+
124
+ ## Step 3: Detect Analytics Source
125
+
126
+ Attempt detection in priority order per D-01 and D-04.
127
+
128
+ ### Priority 1: MCP Analytics Tools (ANALYTICS_MODE=mcp)
129
+
130
+ Check for analytics MCP tools by attempting tool availability detection:
131
+ - PostHog MCP tools (posthog_*, *posthog*)
132
+ - Amplitude MCP tools (amplitude_*, *amplitude*)
133
+ - GA4 / Google Analytics MCP tools (ga4_*, google_analytics_*, *ga4*)
134
+ - Mixpanel MCP tools (mixpanel_*, *mixpanel*)
135
+ - Any tool matching pattern *analytics*, *metric*, *event*
136
+
137
+ If any analytics MCP tool is detected:
138
+ ```
139
+ takeToMarket > ANALYTICS MODE: MCP
140
+
141
+ Detected analytics tools: ${TOOL_NAMES}
142
+ Collecting data via MCP integration.
143
+ ```
144
+ Set ANALYTICS_MODE=mcp. Proceed to Step 4 with MCP collection.
145
+
146
+ ### Priority 2: CSV/Markdown Paste (ANALYTICS_MODE=paste)
147
+
148
+ If no MCP tools detected, prompt user:
149
+ ```
150
+ takeToMarket > NO ANALYTICS MCP TOOLS DETECTED
151
+
152
+ You can paste your analytics data directly. We accept:
153
+ - CSV data (comma or tab separated)
154
+ - Markdown tables
155
+ - Plain text with metric labels and values
156
+
157
+ Here's what we need (paste all available data):
158
+ ```
159
+
160
+ Display the contents of `${CLAUDE_PLUGIN_ROOT}/references/measurement-template.md`.
161
+
162
+ Set ANALYTICS_MODE=paste.
163
+
164
+ Wait for the user to paste data. If the user pastes data, proceed to Step 4.
165
+
166
+ ### Priority 3: Structured Batch Questions (ANALYTICS_MODE=batch)
167
+
168
+ If user indicates they cannot paste bulk data (e.g., "I don't have a spreadsheet",
169
+ "can you ask me questions?", or pastes insufficient data), switch to batch mode:
170
+
171
+ ```
172
+ takeToMarket > ANALYTICS MODE: GUIDED
173
+
174
+ I'll ask for your data in 4 batches.
175
+ ```
176
+
177
+ Set ANALYTICS_MODE=batch.
178
+
179
+ **Batch 1 -- Outcome Metrics:**
180
+ "What are your results for the campaign's outcome metric(s)?
181
+ [List outcome metrics from brief with their targets]:
182
+ - ${OUTCOME_METRIC_NAME}: target was ${OUTCOME_TARGET}. What was the actual result?"
183
+
184
+ **Batch 2 -- Traffic & Engagement:**
185
+ "Paste your traffic and engagement metrics (any you have):
186
+ - Page views, sessions, unique visitors
187
+ - Bounce rate, average time on page, pages per session"
188
+
189
+ **Batch 3 -- Conversion & Revenue:**
190
+ "Paste your conversion and revenue metrics (any you have):
191
+ - Conversions (signups, purchases, form fills)
192
+ - Conversion rate
193
+ - Revenue or pipeline value"
194
+
195
+ **Batch 4 -- Channel Attribution:**
196
+ "For each channel used in this campaign, share what you have:
197
+
198
+ | Channel | Touches/Impressions | Conversions | Revenue |
199
+ |---------|---------------------|-------------|---------|
200
+ [Pre-fill channel names from brief's channel mix]"
201
+
202
+ Proceed to Step 4 after collecting all batch responses.
203
+
204
+ ---
205
+
206
+ ## Step 4: Collect and Parse Data
207
+
208
+ Based on ANALYTICS_MODE:
209
+
210
+ ### MCP Mode
211
+ Use detected MCP tools to query analytics data for the campaign's measurement window
212
+ (from brief: measurement window start to current date or window end).
213
+
214
+ Map tool output to expected metric fields:
215
+ - Outcome metrics (from brief definition)
216
+ - Traffic metrics (page views, sessions, visitors)
217
+ - Engagement metrics (bounce rate, time on page)
218
+ - Conversion metrics (conversions, rate, revenue)
219
+ - Channel attribution data (per-channel touches, conversions, revenue)
220
+
221
+ ### Paste Mode
222
+ Parse pasted CSV, Markdown tables, or plain text. Map columns/rows to expected
223
+ metric fields.
224
+
225
+ If unmapped columns exist (per D-03), ask the user:
226
+ ```
227
+ I found data I couldn't automatically map:
228
+ - [COLUMN_1]: What does this represent?
229
+ - [COLUMN_2]: What does this represent?
230
+
231
+ You can skip any that aren't relevant.
232
+ ```
233
+
234
+ ### Batch Mode
235
+ Collect responses from all 4 batches. Structure into the same internal format as
236
+ paste and MCP modes.
237
+
238
+ ### Data Validation (all modes)
239
+ After parsing, verify minimum data requirements:
240
+ - Outcome metric actual value (REQUIRED -- cannot generate report without this)
241
+ - At least one traffic or engagement metric (WARN if missing)
242
+ - Channel data for attribution (WARN if missing -- will note single-channel)
243
+
244
+ If outcome metric actual value is missing, ask:
245
+ "I need the actual result for your outcome metric (${OUTCOME_METRIC_NAME}) to generate
246
+ the measurement report. What was the actual value?"
247
+
248
+ ---
249
+
250
+ ## Step 5: Apply Attribution Models
251
+
252
+ Calculate all 3 models from channel attribution data:
253
+
254
+ ### Last-Touch Attribution
255
+ Assign 100% credit to the last touchpoint before each conversion.
256
+ - If conversion path data is available: use actual last touch
257
+ - If only aggregate channel data: assign 100% to highest-converting channel
258
+
259
+ ### Linear Attribution
260
+ Distribute credit equally across all touchpoints in each conversion path.
261
+ - If conversion path data is available: divide equally per path
262
+ - If only aggregate channel data: distribute proportional to touch count
263
+
264
+ ### Time-Decay Attribution (DEFAULT DISPLAY per D-05)
265
+ Weight credit exponentially toward the most recent touchpoint.
266
+ Half-life: 7 days.
267
+ - Recent touches receive higher weight using formula: weight = 2^(-days_since_touch / 7)
268
+ - Normalize weights to sum to 100%
269
+
270
+ If channel attribution data is insufficient (single channel only), note:
271
+ "Single-channel campaign -- attribution models show identical results."
272
+
273
+ If no channel attribution data at all, note:
274
+ "Channel attribution data not available. Attribution analysis skipped.
275
+ To include attribution, re-run /ttm-measure with per-channel data."
276
+
277
+ ---
278
+
279
+ ## Step 6: Generate Measurement Report (Outcome-First per D-05, D-06, LIFE-15)
280
+
281
+ ```
282
+ takeToMarket > GENERATING MEASUREMENT REPORT
283
+ ```
284
+
285
+ Generate MEASUREMENT.md using the `${CLAUDE_PLUGIN_ROOT}/templates/measurement-report.md`
286
+ template structure.
287
+
288
+ **CRITICAL: Outcome Assessment section MUST be first.**
289
+
290
+ Fill template fields:
291
+ - `${SLUG}`: campaign slug
292
+ - `${ISO_DATE}`: current timestamp via `node "${CLAUDE_PLUGIN_ROOT}/bin/ttm-tools.cjs" timestamp --raw`
293
+ - `${ANALYTICS_SOURCE}`: mcp, paste, or batch
294
+ - `${OUTCOME_MET}`: YES or NO (did actual meet or exceed target?)
295
+ - `${OUTCOME_DELTA}`: percentage difference from target (e.g., "+15%" or "-8%")
296
+ - `${CAMPAIGN_NAME}`: from campaign STATE.md
297
+
298
+ ### Outcome Assessment (FIRST section)
299
+ Open with: **Did we hit the target? YES/NO**
300
+
301
+ Fill the metrics table with outcome metric FIRST, then output metrics:
302
+ - Compare actual values against targets from brief
303
+ - Calculate delta as percentage: ((actual - target) / target) * 100
304
+ - Status: HIT (met or exceeded), MISS (below target), PARTIAL (within 10% of target)
305
+
306
+ ### Attribution Analysis
307
+ Display time-decay attribution as default (per D-05).
308
+ Note that last-touch and linear are available on request.
309
+
310
+ ### Channel Performance
311
+ One subsection per channel with key metrics.
312
+
313
+ ### Signals for Learn Phase
314
+ Identify:
315
+ - **Overperformance:** channels or metrics that exceeded expectations
316
+ - **Underperformance:** channels or metrics that fell short
317
+ - **Unexpected patterns:** anomalies or surprises in the data
318
+ - **Hypothesis validation:** did the campaign's positioning hypothesis hold?
319
+
320
+ ### Raw Data
321
+ Preserve the original pasted/collected data for audit trail.
322
+
323
+ Write completed report to:
324
+ ```
325
+ .marketing/CAMPAIGNS/${SLUG}/MEASUREMENT.md
326
+ ```
327
+
328
+ ---
329
+
330
+ ## Step 7: Update Campaign State
331
+
332
+ ```bash
333
+ node "${CLAUDE_PLUGIN_ROOT}/bin/ttm-tools.cjs" campaign update ${SLUG} phase measured
334
+ ```
335
+
336
+ ```bash
337
+ TIMESTAMP=$(node "${CLAUDE_PLUGIN_ROOT}/bin/ttm-tools.cjs" timestamp --raw)
338
+ ```
339
+
340
+ ```bash
341
+ # Read current run count (default to 0 if first measurement)
342
+ CURRENT_STATE=$(node "${CLAUDE_PLUGIN_ROOT}/bin/ttm-tools.cjs" campaign state ${SLUG} --raw)
343
+ # Increment run count
344
+ RUN_COUNT=$((PREVIOUS_RUN_COUNT + 1))
345
+
346
+ node "${CLAUDE_PLUGIN_ROOT}/bin/ttm-tools.cjs" campaign update ${SLUG} measure.run_count ${RUN_COUNT}
347
+ node "${CLAUDE_PLUGIN_ROOT}/bin/ttm-tools.cjs" campaign update ${SLUG} measure.last_run ${TIMESTAMP}
348
+ node "${CLAUDE_PLUGIN_ROOT}/bin/ttm-tools.cjs" campaign update ${SLUG} measure.outcome_result ${YES_OR_NO}
349
+ node "${CLAUDE_PLUGIN_ROOT}/bin/ttm-tools.cjs" campaign update ${SLUG} measure.outcome_delta ${DELTA_PERCENT}
350
+ node "${CLAUDE_PLUGIN_ROOT}/bin/ttm-tools.cjs" campaign update ${SLUG} measure.analytics_source ${ANALYTICS_MODE}
351
+ ```
352
+
353
+ ---
354
+
355
+ ## Step 8: Display Summary and Next Steps
356
+
357
+ Display the Outcome Assessment section inline (the metrics table from Step 6).
358
+
359
+ ```
360
+ takeToMarket > MEASUREMENT COMPLETE
361
+
362
+ Report written to: .marketing/CAMPAIGNS/${SLUG}/MEASUREMENT.md
363
+ Analytics source: ${ANALYTICS_MODE}
364
+ Outcome metric: ${OUTCOME_METRIC_NAME}
365
+ Result: ${OUTCOME_MET} (${OUTCOME_DELTA} from target)
366
+
367
+ Next: Run /ttm-learn ${SLUG} to extract lessons and improve future campaigns.
368
+ ```
369
+
370
+ </process>
371
+
372
+ <checklist>
373
+ - [ ] Campaign is in shipped or measured phase
374
+ - [ ] Analytics data collected via one of 3 pathways (MCP/paste/batch)
375
+ - [ ] Outcome metric compared against target value from brief
376
+ - [ ] 3 attribution models calculated (time-decay shown as default)
377
+ - [ ] MEASUREMENT.md written with outcome-first ordering
378
+ - [ ] Campaign state updated with measure.* fields
379
+ </checklist>