Loading
Preparing your report
insights-progress.brentneale.au · drift-prevention surfaceBuild progress
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.
31/55 tasks complete56%
Current stagePhase 2.5 — Causal Study Engine v1
We are preserving the live Phase 2 measurement loop, then adding the trust layer Brent now needs: explicit study configuration, optional-source readiness, safe covariate selection, model-table generation, pre-flight validation, supporting studies, diagnostics, and report warnings.
Phase 2.5 completion8/17 tasks
Causal Study Engine v1 pipeline defined; study config, paid-media controls, Klaviyo controls, and per-study audit snapshots landed.
Live nowExisting measurement looplive
Queue, manual investigations, saved reports, responses, and change log stay live while the engine is upgraded.
Outcome-based studieslive
Campaign and channel studies now model a business outcome rather than proving spend changed.
Scoped experimentslive
Whole-store, geo-holdout, product-category, and paid-media change contexts are runnable against Rover data.
Report surfacelive
Saved study pages show actual vs expected, pointwise effect, summary stats, saved model inputs, and validation warnings.
Phase treeWhere the build is up to
Each phase has its own task list. Quality scores show against completed tasks (composite from QUALITY_LOG.md).
Single-tenant Phase 1 closed 2026-05-07. Daily Google Ads + Meta Ads + Shopify ingestion into BigQuery, modelled in dbt, surfaced via the operator dashboard at insights.brentneale.au. 7-day observation window proved the alerter resilience: 2 caught-and-resolved incidents (Meta dedup + alerter false-positive) plus 1 self-recovered transient (shopify_fulfillments stream skip). All 6 Validator criteria passed (criterion #3 via PM-D-034 substantive interpretation). Tagged `phase-1-complete`.
- ●T1.1q 1.00
- ●T1.2
GCP infra setup
Project, BQ datasets, service accounts, AUD $300/mo budget alerts
Live data freshnessPipeline health right now
22 ingestion sources monitored. Updated every 5 minutes from `_meta.freshness_check` — refresh the page to re-query.
- ●google_ads_dts_account_basic4,784 rows1d lag
- ●google_ads_dts_adgroup_basic17,543 rows1d lag
- ●google_ads_dts_campaign_basic14,649 rows1d lag
- ●google_ads_dts_keyword_basic35,743 rows1d lag
Locked decisionsWhat is settled
Each entry below is closed to debate. New evidence can re-open one, but a preference or aesthetic argument cannot.
- PM-D-001
Single-tenant Phase 1, multi-tenant refactor at Phase 2
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.
- PM-D-002
Multi-tenancy approach: dataset-per-client
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.
- PM-D-003
Detection engine ruleset config-driven from day one
Detection thresholds live in versioned config, not hardcoded.
Quarterly tuning is the platform's primary calibration loop; hardcoded thresholds would kill the feedback cadence.
- PM-D-004
Anti-goalsWhat this is not
A bounded scope is what makes the in-scope work tractable. Each item below is a rejection — not a backlog candidate.
- AG-1
Not a Google Ads management tool
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.
- AG-2
Not real-time
Daily refresh cadence by design. Real-time adds infrastructure cost without changing the underlying decisions (which are weekly-to-monthly in scope).
- AG-3
Not a multi-touch attribution platform
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.
- AG-4
Not a public marketing surface
Operator-facing only. No public landing page describing the platform's capabilities to non-clients. robots noindex, nofollow.
Marketing with Brent · Insights Platform · Internal build status
source: STATE.md / QUALITY_LOG.mdData-source settingslive
Data Sources now exposes the Causal Study Engine v1 integration contract and routes each integration action to a real setup page.
Ready to testRover sanity checksready
Continue using completed studies, but treat confidence claims as v0 until source readiness and pre-flight checks land.
Source completenessready
Klaviyo email importer scaffold is now in place; confirm which remaining optional inputs Rover actually uses: SMS, promos, stock, inventory, and calendar flags.
Study auditabilityready
Use the data-used table to compare included controls with the operator's knowledge of what changed.
Blocking closureModel table generatorpending
Need one explicit daily modelling table per study with outcome, treatment, controls, calendar, and diagnostics.
Pre-flight validationpending
Need errors/warnings before model fit: missing data, treatment leakage, outcome leakage, stale sources, and weak treatment.
Supporting studiespending
Primary outcome should run first; supporting outcomes and diagnostics should follow using the same treatment context.
Next focusStudy configready
Create typed config for account, outcome, treatment platform, campaign, intervention, and optional study flags.
Covariate rulesready
Exclude treatment spend from controls and block outcome-family leakage before the model can run.
Optional-source warningsready
Let studies run with missing optional sources, but report the measurement-quality limitation clearly; Klaviyo now has a concrete importer path.
q 0.96
●T1.3dbt project scaffold + GitHub Actions
Daily 22:00 UTC workflow + PR workflow + smoke test
q 0.94 ●T1.4Frontend scaffold + brand tokens + Vercel
Next.js 16 + Tailwind v4 + tokenised proxy + Vercel deploy
q 0.88 ●T1.5Google Ads ingestion
BQ DTS standard reports + custom GAQL Cloud Run service for PMax / channel breakdown
q 0.90 ●T1.6Shopify ingestion via Airbyte
Airbyte Cloud connection — 10 streams, 57k orders backfilled to 2016
q 0.90 ●T1.7Frontend data wiring + KPI views
Dashboard live + KPI strip + trend chart + top-campaigns table + freshness indicator + settlement-window markers + Playwright smoke suite (11/12 passing)
q 0.93 ●T1.8dbt mart models + scheduled run
5 marts materialised, 78 tests pass, daily refresh running
q 0.92 ●T1.9Data Health (reframed per PM-D-018)
Pipeline + freshness + settlement panel; Resend email alerter on Cloud Run; schema-drift detection; original conversion-attribution work disposed of per PM-D-018 strict-interpretation principle
q 0.88 ●Phase ValidatorPhase 1 Validator + 7-day unattended observation
Closed 2026-05-07. All 6 criteria PASS. Observation window 2026-04-30 → 2026-05-06 proved alerter resilience: 2 caught-and-resolved bugs (Meta dedup + alerter false positive), 1 self-recovered transient (shopify_fulfillments). Criterion #3 passed via PM-D-034 substantive interpretation (incident detection + resolution > 7 silent days). Runbook: docs/runbooks/phase_1_validator.md Run 2.
complete 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).
- ●T2.1
Causal engine scaffold (FastAPI + CausalPy + PyMC + Cloud Run)
Scaffold deployed at causal-engine-api-axfj4dtowa-ts.a.run.app — /health + /investigations/_dummy live; T2.2 fills in real BSTS
complete - ●T2.7
Investigation artefact schema + 4-element programmatic check
BQ tables _meta.investigations + _meta.investigation_artefacts; Pydantic mirror with content-quality validators per CONTEXT.md C4.3; 30/31 tests pass
complete - ●T2.10
Meta Ads ingestion (advanced from P3 per PM-D-026)
Airbyte connection live; 8 streams ingested (403k records, 1.2GB); dbt staging + mart_daily_marketing_performance extended with meta_* columns + paid_spend_total. 30-day Meta UI reconciliation pending Brent.
complete - ●T2.2
Frontend → causal_engine API + first real BSTS endpoint
BSTS via CausalPy + PyMC live on Cloud Run. Frontend trigger UI at /investigations/new; locked in BSTS-first per PM-D-031 (synthetic-control deferred). End-to-end verified against real Rover Apr-2 data in 348s.
q 0.89 - ●T2.2.5
Scoped geo/category holdout investigations
PM-D-037 promotes real geo and product-category experiments to runnable scoped BSTS investigations. Operator selects treated segment plus controls; engine models segment Shopify revenue against those controls.
complete - ●T2.4
Detection engine (z-score over 90-day baseline)
Pure-SQL `_meta.flags` view (PM-D-032 — not Cloud Run). Whole-store dimensions now spend/net_revenue/new_customer_orders/returning_customer_orders after PM-D-035 replaced NvR-ratio detection. PM-D-036 adds a persistence guard: at least 4 of the last 5 settled daily rows must breach the same-direction threshold.
q 0.83 - ●T2.5
Worth-investigating queue UI
/queue reads `_meta.flags`; Investigate button prefills /investigations/new with dimension+date+flag_id. Customer-count flags route to engine revenue impact with an honest label until the causal engine grows native order-count treatment series.
q 0.86 - ●T2.8
Three-state response capture (agree/disagree/dismiss)
_meta.responses table per R2.8; inline controls on every queue card per CONTEXT.md C3.2; Server Action validates required fields per C4.4/C4.5/PM-D-005. Reader SA granted table-scoped dataEditor on _meta.responses only (smallest blast radius). End-to-end smoke test passed.
q 0.87 - ●T2.9
Tracking diagnostics surface
/tracking-diagnostics re-surfaces ConversionActionAudit (kept in repo from T1.9 disposal). Page copy explicitly frames as configuration-integrity check on the 10% layer, not a data-health check (per PM-D-018).
q 0.83 - ●T2.3a
Multi-tenancy refactor — codebase-ready shape
dbt sources + profiles.yml.example templated via var('client'); frontend lib/current-client.ts resolver with allowlist; /queue + / + /tracking-diagnostics threaded through the helper. Onboarding runbook drafted (8 steps). Concession Pass — test coverage gap is by design until T2.3b's pen test against a real second client.
q 0.76 - ■T2.3b
Multi-tenancy refactor — onboard client #2 + pen test
Provisions client #2's BQ dataset, configures ingestion, runs the runbook end-to-end, ships the client-picker UI, runs the cross-client pen test. Blocked on Brent having a second client to onboard.
blocked - ●T2.11a
Disambiguate descriptive ROAS label
ROAS card relabelled 'Revenue ÷ Spend' across the dashboard; closes the immediate misleading-label half of PM-D-012.
q 0.88 - ●T2.6
Change-log table + UI
_meta.change_log table per R2.5's 12-column schema; /change-log route with create/edit/list; auto-link suggestions to same-client flags + investigations from the prior 14 days matching the selected dimension.
q 0.86 - ○T2.11b
Modelled ROAS batch column from causal engine
Substantial — needs the causal engine to emit a batch column comparing observed vs modelled ROAS. Closes the second half of PM-D-012.
pending - ●T2.4.5
Multi-dim detection (geo / category / channel_mix)
_meta.flags now includes dimension_value and emits geo, category, and channel_mix flags alongside whole-store flags. Last-30-day smoke query shows live rows for AU regions, product categories, and Google Ads channel types.
q 0.88 - ○Phase 2 Validator
Phase 2 Validator + 7-day observation
Detection engine produces non-empty queue ≥1 day (✓ achieved, now includes multi-dim flags); manual investigation < 10 min (✓ T2.2 verified at 348s); artefact 4-element check (✓ T2.7); responses captured (✓ T2.8); change log live (✓ T2.6); second client onboarded (T2.3b — blocked); multi-tenancy live (T2.3a ✓ codebase / T2.3b end-to-end).
pending
Incremental engine upgrade from the Causal Study Engine v1 spec. Existing Phase 2 investigations stay live; this phase adds the data contract and trust layer: client channel settings, optional-source handling, campaign/channel treatment mapping, leakage-safe covariates, pre-flight validation, primary/supporting/diagnostic study runners, standard report output, and audit logging.
- ●CSE1.1
Study config schema + client channel settings contract
Backend Pydantic contract added for account, outcome, treatment, campaign/change, date windows, v1 exclusions, and optional source statuses.
complete - ◐CSE1.2
Source table schemas and optional-source contract
Data Sources UI exposes the optional-source contract. Klaviyo raw/staging/mart schemas are scaffolded and disabled until first import; remaining optional-source schemas still need to land.
in progress - ●CSE1.3
Campaign/channel type mapping
Backend now normalises Google Ads, Meta Ads, Google channel, legacy channel keys, and campaign-specific treatment segments.
complete - ○CSE1.4
Shopify daily outcome aggregation
Formalise daily Shopify outcomes: orders, net sales, new/returning customers, AOV, discounts, refunds, and diagnostic fields.
pending - ◐CSE1.5
Google Ads daily aggregation
Current marts provide campaign/channel spend; v1 needs an explicit treatment/control extraction contract with treatment exclusion.
in progress - ◐CSE1.6
Meta Ads daily aggregation
Current Meta spend is available; v1 needs source-status driven inclusion, freshness checks, and campaign-level treatment support.
in progress - ◐CSE1.7
EDM/SMS daily aggregation
Klaviyo email importer is deployed, health-checked, and 12-month backfilled into mart_lifecycle_marketing_daily. Email recipients, campaign count, and flow-message count now feed studies as lifecycle-pressure controls. SMS remains separate.
in progress - ○CSE1.8
Promo/discount daily table
Manual or integrated promo calendar plus Shopify discount controls so sales events do not masquerade as media impact.
pending - ◐CSE1.9
Calendar and market seasonality table
Generated day-of-week, month-end, Black Friday, Christmas, and EOFY controls now feed every study. Manual holiday/override table still needs to land.
in progress - ●CSE1.10
Study model table generator
Each new investigation persists `_meta.investigation_model_daily`: exact daily outcome, treatment spend context, included/excluded covariates, period flags, and row hashes used by BSTS.
complete - ●CSE1.11
Covariate eligibility and leakage rules
Paid-media control defaults now live in the API, with tests for treatment exclusion and outcome-family leakage rejection.
complete - ◐CSE1.12
Validation and pre-flight checks
Run-level validation now persists date continuity, row counts, covariate signal, treatment movement, treatment exclusion, lifecycle inclusion, and known missing-source warnings. Pre-flight UX still needs to consume the same contract before model fit.
in progress - ●CSE1.13
Primary study runner
Primary studies run against business outcomes, include selected paid-media controls, Klaviyo lifecycle controls, generated calendar controls, and persist the post-period posterior path for the report chart.
complete - ●CSE1.14
Supporting study runner
Primary runs now create a study suite and run supporting business outcomes separately with the same treatment/control structure. Supporting results persist as linked investigations and suite members.
complete - ◐CSE1.15
Diagnostics runner
Study-suite diagnostics now persist validation status, treatment movement, control contamination checks, and supporting-outcome alignment. Broader sessions, inventory, discount, and margin diagnostics remain.
in progress - ●CSE1.16
Standard report output
Branded report output includes business takeaway, model stats, posterior-path charts, supporting-study sense checks, diagnostics, validation warnings, and the full audit/model table.
complete - ●CSE1.17
Audit logging
Investigations now persist exact model-input rows, posterior daily path columns, validation issue rows, audit summaries, suite-member rows, and diagnostic rows. Broader source lineage grows as promo/inventory/SMS inputs come online.
complete
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.
- ○T3.1
Outcome verification automation (R1.10)
pending - ○T3.2
Clerk auth + client-facing dashboard (R1.11–R1.13)
pending - ○T3.3
Storefront gclid snippet (R3.5)
pending - ○T3.4
Full token expiry alert matrix (R3.6 — Meta tokens, Shopify, etc.)
pending - ○T3.5
Schema-drift email alerts + full notification matrix (R3.7, R5.5 full)
pending - ○T3.6
Per-client query scoping at API layer (R2.9) + penetration test
pending - ○T3.7
Data export per-client (R2.10)
pending - ○T3.8
RUNBOOK.md consolidation + operator playbook (R5.6)
pending - ○Phase 3 Validator
Phase 3 Validator + Validation Gate 1
pending
No code work. Pricing, onboarding playbook, client success. Commercial readiness only — closure at Brent's discretion.
- ○T4.1
Pricing + commercial model
pending - ○T4.2pending
- ○T4.3
Validation Gate (4 weeks post-launch)
pending
●
google_ads_gaql_channel
161 rows
1d lag
●google_ads_gaql_pmax2,425 rows1d lag●klaviyo_campaign_activity95 rowstoday●klaviyo_flow_activity11,140 rowstoday●meta_ads682 rowstoday●meta_ads_insights35,231 rowstoday●meta_ads_insights_country27,103 rowstoday●meta_ads_insights_region171,863 rowstoday●meta_campaigns66 rowstoday●shopify_customers83,274 rowstoday●shopify_fulfillments58,426 rowstoday●shopify_inventory_items629 rowstoday●shopify_inventory_levels1,514 rowstoday●shopify_locations1 rowstoday●shopify_orders59,187 rowstoday●shopify_product_variants1,617 rowstoday●shopify_products1,498 rowstoday●shopify_shop1 rowstodayOutcome verification reuses the main causal engine
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.
PM-D-005Free-text on disagree is required, not optional
Disagree responses require a one-line reason.
Optional fields degrade to empty; disagreements are the highest-value signal in the system.
PM-D-006Default verification window = 14 days, configurable per change
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.
PM-D-007Investigation artefact format conformance is a build-time check
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.
PM-D-008Mobile responsiveness is a Phase 1 baseline
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.
PM-D-009Token rotation deferred to Phase 3
Phase 1 access via single long-lived tokenised URL.
Single user (Brent); threat model is accidental URL sharing, not credential theft.
PM-D-010Data export format chosen at Phase 3
CSV vs Parquet vs JSON deferred to implementation time.
Format depends on what tools clients use; locking now is a guess.
PM-D-011T1.9 originally implemented as conversion-attribution reconciliation
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.
PM-D-012ROAS as whole-store revenue ÷ Google spend (descriptive, not causal)
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.
PM-D-013Google in-platform conversion metrics not surfaced as primary KPIs
Available in customisation panel for diagnostics; removed from default selection.
10% sanity layer in the convergent-evidence model; not platform measurement.
PM-D-014Search-term-level data dropped from ingestion
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.
PM-D-015gclid_from_url regex extraction in stg_shopify__orders
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.
PM-D-016stg_shopify__orders deduped on id by Airbyte extract timestamp
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.
PM-D-017Light-theme dashboard background #F1F1F1
Page background #F1F1F1 (replacing #ffffff). Disposition in PM-D-020.
Brent verbal direction mid-session for visual contrast against dark cards.
PM-D-018Data health = integrity of representation, not attribution agreement
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.
PM-D-019T1.7 reservations folded into T1.9 build
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.
PM-D-020#F1F1F1 added to locked palette as --bg-soft
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.
PM-D-021Phase 1 data-health pipeline state derived from BQ signals
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.
PM-D-022Token expiry / connection failure alert via Resend Cloud Function
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.
PM-D-023Top-campaigns table columns honour strict-interpretation
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.
PM-D-024Phase 1 Validator criterion #4 reframed
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.
PM-D-025Phase 2 architectural shape: frontend → causal_engine → marts
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.
PM-D-026Meta ingestion advanced from Phase 3 to Phase 2
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.
PM-D-027Multi-tenancy approach confirmed: dataset-per-client
Reconfirms PM-D-002. dbt Core's existing var-based templating handles per-client cleanly.
No reason to reopen the original directional choice.
PM-D-028Detection engine scope: 6 dimensions, z-score over 90-day baseline
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.
PM-D-029Phase 2 build begins during Phase 1 observation window
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.
PM-D-030meta_reach column dropped from mart_daily_marketing_performance
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.
PM-D-031T2.2 first method: BSTS at account level, synthetic-control deferred
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.
PM-D-032Detection engine = `_meta` BigQuery view, not Cloud Run
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.
PM-D-033Per-source freshness tolerance
`_meta.freshness_check` and `_meta.connection_health` subtract per-source `tolerance_days` before classifying freshness.
Google Ads and Meta have structural 24-48h lag profiles; treating every source like Shopify caused false-positive health alerts and would train the operator to ignore real warnings.
PM-D-034Phase 1 Validator criterion #3 substantive pass
Criterion #3 passed via substantive interpretation: incidents detected, diagnosed, resolved, and fixes held.
A 7-day window with caught-and-resolved incidents proved the observability and resilience layer better than a silent period would have.
PM-D-035NvR-ratio detection replaced by absolute cohort counts
Detection drops `nvr_ratio` and monitors `new_customer_orders` lower-direction plus `returning_customer_orders` both-directions.
The ratio can false-positive when returning-customer orders spike and false-negative when both cohorts collapse together; absolute counts preserve the actual acquisition and retention signals.
PM-D-036Detection flags require sustained same-direction movement
`_meta.flags` only emits when the same dimension/value breaches the configured threshold in the same direction on at least 4 of the last 5 settled daily rows.
One-day fluctuations are not recommendations. The queue should surface sustained disruption, not train the operator to triage daily noise.
PM-D-037Geo/category holdouts become runnable scoped investigations
`POST /investigations` supports geo and product-category treatment keys with operator-selected control segments.
A QLD or product-category pause should be measured on the affected segment against comparable controls, not diluted into whole-store revenue.
AG-5No Slack / push / SMS notifications
Email + in-dashboard only. Notification proliferation creates fatigue without improving signal.
AG-6No HTML emails
Plain text only. HTML email infrastructure costs days for zero functional value.
AG-7No guided onboarding tour
Empty states and labels do the explaining. Operator built the tool; clients are onboarded verbally.
AG-8Search-term operational hygiene out of scope
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.
AG-9Google's reported conversions are not the measurement
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.