marketing: MMM calibration launch carousel (Signal palette) + claims-sync guard - #781
Conversation
…sync guard
New LinkedIn launch deck for the diff_diff.mmm interop, following the
generate_cic_carousel.py architecture (magazine sidebar, split logo, one
dark slide, footer wordmark, phone type floors) with a new "Signal"
palette: violet = calibrated, coral = uncalibrated, amber reserved for
ground truth in every chart.
Ease-first narrative (Tutorial 30 / Meridian is the spine, Tutorial 29 /
PyMC-Marketing the secondary beat): cover hook with the two-posterior
motif ("the true ROI (simulated)" + illustrative tag) -> the
hand-derivation pain -> the three-line handshake (dark code slide) ->
the generated to_code() snippet shown verbatim -> the payoff interval
chart (default 3.29 [3.02, 3.57] vs truth 2.5; calibrated 2.54
[2.47, 2.62]) -> the aggregation schematic -> estimand-rigor cards ->
the PyMC lift-test beat (3.52 -> 2.21 vs truth 2.0, executable
keyword-only call) -> a capabilities slide -> CTA carrying the single
tutorial mention and the full simulation-provenance statement.
Claim posture (documented in the module docstring + DEFERRED.md decision
record): capabilities over validation; guardrail copy scoped, never
absolute ("the easy mistakes fail loudly", "you own the design, it owns
the math") with the retired absolutes ban-listed; truth provenance
concentrated into the cover/chart "(simulated)" labels and the CTA line;
slide 8 carries no on-slide linearity qualifier - the staggered-boost
compression's linear-channel scoping is tutorial 29's job.
tests/test_mmm_carousel_claims.py (18 tests, normal suite, skips when
carousel/ or docs/ absent) syncs the deck to the committed executed
notebooks: every constant is located on the tutorial output surface, the
slide-4 snippet lines must be byte-verbatim from the committed to_code()
output, the confidently-wrong interval structure and 6x-narrower ratio
are recomputed from constants, slide-8 call arguments are re-derived
from tutorial 29's DGP, the four named aggregate('total') adopters are
pinned against each results class's _AGGREGATE_SUPPORTED, the "Zero new
dependencies" strip is backed by an mmm.py import scan plus a
pyproject.toml requirement scan, the version strip is derived from the
tutorials' own requirement pins, and competitive claims plus unqualified
guardrail absolutes are ban-listed.
Tracking: TODO.md gains the deck-agnostic PDF-vs-generator drift-guard
row (fpdf date metadata makes byte-compare nontrivial); DEFERRED.md's
decision record documents the marketing-surface claim posture.
The committed PDF is the generator's build artifact, regenerated with
the final source per carousel/README.md.
Overall assessmentExecutive summary
MethodologyP1 — [Newly identified] Required Meridian scope arguments are omitted
prior.to_code(
channel="search",
media_channels=["search", "tv"],
roi_calibration_period=mask,
)The tracked omission of slide-8’s linearity qualifier is P3-informational under Code QualityNo additional findings. PerformanceNo findings. MaintainabilityNo findings. Tech DebtP3 — PDF/source drift guard is tracked
SecurityNo findings. No secrets or suspicious PDF metadata were identified. Documentation/TestsP2 — Claim guard does not validate the displayed invocation
Validation: both Python files compiled successfully; all 18 claim assertions passed; the committed PDF reports 10 pages. Full pytest was unavailable in the review environment. Path to Approval
|
to_code() deliberately fails closed without channel + time scope, so the 'Paste and Run' slide now shows the tutorial's actual call (channel/media_channels/roi_calibration_period) instead of a bare prior.to_code() that would raise ValueError. New regression assertion pins the scoping kwargs on the displayed call, bans the bare form, and confirms the same kwargs in tutorial 30's to_code() cell. PDF regenerated.
|
🔁 AI review rerun (requested by @igerber) Head SHA: Overall assessment✅ Looks good — the prior P1 is resolved; no unmitigated P0/P1 findings remain. Executive summary
MethodologyThe prior P1 is fixed at P3 — Documented marketing-surface scoping
Code QualityNo findings. PerformanceNo findings. MaintainabilityNo findings. Tech DebtP3 — PDF/source drift guard is tracked
SecurityNo findings. No secrets or unsafe externally controlled operations identified. Documentation/TestsNo findings. The new regression directly covers the previously invalid displayed invocation. Full |
Summary
diff_diff.mmminterop:carousel/generate_mmm_carousel.pyrenderscarousel/diff-diff-mmm-carousel.pdf(10 slides, 4:5), following thegenerate_cic_carousel.pyarchitecture with a new "Signal" palette (violet = calibrated, coral = uncalibrated, amber reserved for ground truth in every chart).to_code()snippet, the default-vs-calibrated payoff interval chart (3.29 [3.02, 3.57] vs truth 2.5 -> 2.54 [2.47, 2.62]), and a capabilities slide.tests/test_mmm_carousel_claims.py(18 tests, normal suite): every deck number is located on the committed executed notebook surfaces; slide-4 snippet lines must be byte-verbatim from the committedto_code()output; the confidently-wrong interval structure and 6x-narrower ratio are recomputed from the deck's own constants; slide-8 call arguments re-derive from tutorial 29's DGP; the four namedaggregate('total')adopters are pinned against each results class's_AGGREGATE_SUPPORTED; the "Zero new dependencies" strip is backed by anmmm.pyimport scan plus apyproject.tomlrequirement scan; the version strip derives from the tutorials' own requirement pins; competitive claims and unqualified guardrail absolutes are ban-listed.Methodology references (required if estimator / math changes)
to_meridian_roi_prior/meridian_calibration_mask/to_pymc_marketing_lift_test/aggregate('total')states committed-tutorial facts only.Validation
tests/test_mmm_carousel_claims.py(new, 18 tests; skips cleanly whencarousel/ordocs/is absent, matchingtest_cic_carousel_claims.py).Security / privacy