The Insights Platform enables Brent to identify, investigate, and explain Google Ads campaign impact with sufficient confidence and clarity that (a) it becomes his primary tool for optimisation decisions across active Shopify clients, and (b) every shared finding stands on its own as a structured story with a clear takeaway.
Each phase has its own task list. Quality scores show against completed tasks (composite from QUALITY_LOG.md).
Rover Pet Products — daily ingestion, modelling, dashboard
Prove the platform end-to-end with one client. Ingest Google Ads + Shopify daily into BigQuery, model the data layer in dbt, surface the operator dashboard. Build tasks complete; pending the Phase 1 Validator + 7-day unattended observation window before formal closure.
Worth-investigating queue + agree/disagree workflow + 2nd client
Phase 2 produces the platform's measurement surface: a Bayesian causal engine for lift estimation, an anomaly-detection engine that surfaces flagged candidates daily, an investigation-artefact format with a 4-element programmatic check, and an agree/disagree feedback loop. Plus the multi-tenancy refactor that makes a second client possible. Locked + active 2026-04-30 per PM-D-029 (begins during Phase 1's observation window rather than after gate close).
Auth + per-client surfaces + R3.5–R3.8 hardening
Phase 3 takes the operator-only Phase 2 output and productises it: Clerk org-aware auth + per-client dashboards (R1.11–R1.13), automated outcome verification when change-log windows close (R1.10), gclid storefront snippet (R3.5), full token-expiry alerting (R3.6), schema-drift email alerts (R3.7), and the security hardening for client-data isolation (R4.x, R2.9, R2.10). Causal inference itself moved to Phase 2 per PM-D-026.
Productisation + onboarding playbook
No code work. Pricing, onboarding playbook, client success. Commercial readiness only — closure at Brent's discretion.
20 ingestion sources monitored. Updated every 5 minutes from `_meta.freshness_check` — refresh the page to re-query.
Each entry below is closed to debate. New evidence can re-open one, but a preference or aesthetic argument cannot.
Phase 1 builds with hardcoded paths; Phase 2 forces the refactor by onboarding client #2.
Premature multi-tenancy is the highest-risk failure mode for a one-person build per Core Principle 3.1.
One BigQuery dataset per client (e.g. client_rover, client_<second>) within a single GCP project.
Cleanest row-level isolation; simpler IAM; easier per-client export. Reconfirmed in PM-D-027.
Detection thresholds live in versioned config, not hardcoded.
Quarterly tuning is the platform's primary calibration loop; hardcoded thresholds would kill the feedback cadence.
Outcome verification (R1.10) is a scheduled invocation of the same engine, not a separate service.
Same methodology, same controls; separate engine doubles maintenance for zero benefit.
Disagree responses require a one-line reason.
Optional fields degrade to empty; disagreements are the highest-value signal in the system.
Outcome verification window defaults to 14 days; Brent can override per change-log entry.
Long enough for most Google Ads optimisations to express; short enough to keep the feedback loop tight.
The 4-element rule is enforced at INSERT/render time, not via post-hoc audit.
100% conformance is the metric; the only way to hit it reliably is to make non-conformance impossible.
375px legible from Phase 1; refined in Phase 3.
Brent will check on mobile in week 1; poor early UX biases his agree/disagree behaviour.
Phase 1 access via single long-lived tokenised URL.
Single user (Brent); threat model is accidental URL sharing, not credential theft.
CSV vs Parquet vs JSON deferred to implementation time.
Format depends on what tools clients use; locking now is a guess.
Logged retrospectively; the work was disposed of per PM-D-018 (see below).
Conflated 'data quality' with 'conversion accuracy'; should have read R1.4 more carefully.
Renamed to revenue_to_spend_ratio in T2.10; modelled_roas lands from causal engine in T2.11.
Original calculation implied 100% Google attribution; misleading. Replaced cleanly in Phase 2.
Available in customisation panel for diagnostics; removed from default selection.
10% sanity layer in the convergent-evidence model; not platform measurement.
Custom GAQL no longer pulls search_term_view; restorable from git history at commit 132016e.
Operational data, not strategic. Platform's purpose is strategic decision support, not keyword management.
Extract gclid from landing_site URL via regex alongside the storefront-snippet path.
Storefront snippet is Phase 3; URL extraction unblocks Phase 1+2 attribution-confidence work today.
qualify row_number() partition by id order by _airbyte_extracted_at desc.
Airbyte writes a row per cursor-bump (refunds, fulfilment); 39 dupes found on first staging build.
Page background #F1F1F1 (replacing #ffffff). Disposition in PM-D-020.
Brent verbal direction mid-session for visual contrast against dark cards.
Three pillars only — pipeline health, freshness, settlement. No platform-vs-platform attribution checks.
Strict-interpretation principle: any future spec ambiguity defaults to the strict interpretation. The original T1.9 commit (63ee6bf) was disposed of under this rule.
Top-campaigns table, FreshnessIndicator, 375px verification, Playwright — all addressed in the T1.9 reframe rather than as a discrete T1.7-amendment task.
Both touch DashboardShell; splitting would mean editing twice.
CONTEXT.md C1.1 extended; existing dashboard usage is the canonical example.
Reverting would lose the design intent; adding a defined fourth surface tier preserves the locked-palette discipline.
No dedicated polling service in P1; derive connection state from existing freshness + raw-table activity.
Phase 1 operator-confidence question is 'is the data current?', not 'is the pipeline running this second?'. Dedicated poller is the right Phase 3 design alongside R3.6 full token expiry.
Cloud Run service triggered daily 23:00 UTC; emails Brent on any failed/overdue source or schema drift.
Dashboard catches issues at next load; email backstop covers the >24h-no-check case.
Spend / Clicks / Impressions / CTR (hard data) + Convs / Conv value (Google-reported, labelled with ⓖ). No Revenue / ROAS / Orders columns.
Per-campaign Revenue/ROAS requires attribution we don't have until the Phase 2 causal engine.
From 'reconciliation panel shows raw vs platform-reported figures' to 'Data Health panel shows pipeline / freshness / settlement and flags failed/overdue/broken'.
Original wording tested a panel PM-D-018 explicitly dropped.
Causal engine is the single place measurement claims (lift, CIs, attribution) are produced. Frontend stays direct-to-BigQuery only for descriptive surfaces.
Architectural embodiment of PM-D-018's strict-interpretation principle.
R3.4 phase tag updated 3 → 2.
Without Meta data the causal engine systematically over-credits Google. Known-bias-from-day-one shipping is an own-goal.
Reconfirms PM-D-002. dbt Core's existing var-based templating handles per-client cleanly.
No reason to reopen the original directional choice.
Spend / revenue / NvR / channel mix / geo / category. Per-keyword + per-creative explicitly out. Cross-platform-divergence detection out per PM-D-018.
Maps cleanly to existing marts; config-driven thresholds per R2.7.
Task queue moved from DRAFT to ACTIVE 2026-04-30. Phase 1 gate ceremony still on 2026-05-07 as planned.
7-day observation watches the pipeline, not blocks code. Tasks without runtime-pipeline deps can execute in parallel.
Reach not summed daily — it's non-additive (deduped per period in Meta UI, summing inflates by ~240%).
Brent's 30-day reconciliation caught the bug. Cleanest fix is to drop the column entirely until Phase 3 adds proper period-level reach modelling.
BSTS via CausalPy ships first; synthetic-control-across-regions deferred to Phase 2.5 follow-up.
5-question PM probe answers: campaign-level interventions / whole-business framing / rare regional isolation / national clients / soft 'must always work' constraint all point to BSTS not synthetic control. Methodology choice must fit the workflow, not the strategic positioning language.
T2.4 ships as `_meta.flags` view (read-on-query) backed by `_meta.detection_config` table; not a dedicated Cloud Run job + Scheduler.
Detection logic is pure SQL. The data_health_alerter Cloud Run pattern (T1.9) was justified because the alerter sends email; SQL alone can't. T2.4 has no outbound calls — it produces a queue T2.5 reads. View-on-read means zero scheduling complexity, zero deployment surface, mart freshness == view freshness for free.
A bounded scope is what makes the in-scope work tractable. Each item below is a rejection — not a backlog candidate.
Bid changes, negative keyword management, and tactical campaign hygiene live in Google Ads (or Optmyzr / Adalysis). The platform surfaces strategic decisions; the operator executes in Google Ads.
Daily refresh cadence by design. Real-time adds infrastructure cost without changing the underlying decisions (which are weekly-to-monthly in scope).
Per Brent 2026-04-30: 'we are not trying to stitch journeys together. That is not our job here.' Platform produces convergent-evidence lift estimates, not per-touchpoint credit assignment. PM-D-018 codifies this.
Operator-facing only. No public landing page describing the platform's capabilities to non-clients. robots noindex, nofollow.
Email + in-dashboard only. Notification proliferation creates fatigue without improving signal.
Plain text only. HTML email infrastructure costs days for zero functional value.
Empty states and labels do the explaining. Operator built the tool; clients are onboarded verbally.
Negative keyword discovery and n-gram analysis are tactical workflows that don't drive strategic decisions. Removed from the data layer 2026-04-29 per PM-D-014.
Google's metrics.conversions / conversion_value sit in the 10% layer of the convergent-evidence model — informational, not authoritative. The 70% layer is spend × clicks × Shopify-side revenue with causal lift modelling.
Marketing with Brent · Insights Platform · Internal build status
source: STATE.md / QUALITY_LOG.md