Marketing with Brentinsights
ClientInternal — build status
Last refreshupdated on each request
insights-progress.brentneale.au · drift-prevention surface

Build 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.

19/37 tasks complete51%
Phase tree

Where the build is up to

Each phase has its own task list. Quality scores show against completed tasks (composite from QUALITY_LOG.md).


Phase 1

Single-client proof of concept

Rover Pet Products — daily ingestion, modelling, dashboard

9/10 complete

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.

  • T1.1
    Repo + monorepo scaffold
    q 1.00
  • T1.2
    GCP infra setup
    Project, BQ datasets, service accounts, AUD $300/mo budget alerts
    q 0.96
  • T1.3
    dbt project scaffold + GitHub Actions
    Daily 22:00 UTC workflow + PR workflow + smoke test
    q 0.94
  • T1.4
    Frontend scaffold + brand tokens + Vercel
    Next.js 16 + Tailwind v4 + tokenised proxy + Vercel deploy
    q 0.88
  • T1.5
    Google Ads ingestion
    BQ DTS standard reports + custom GAQL Cloud Run service for PMax / channel breakdown
    q 0.90
  • T1.6
    Shopify ingestion via Airbyte
    Airbyte Cloud connection — 10 streams, 57k orders backfilled to 2016
    q 0.90
  • T1.7
    Frontend 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.8
    dbt mart models + scheduled run
    5 marts materialised, 78 tests pass, daily refresh running
    q 0.92
  • T1.9
    Data 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 Validator
    Phase 1 Validator + 7-day unattended observation
    Day 2 of 7 captured 2026-05-01; runbook at docs/runbooks/phase_1_validator.md. 4 of 6 criteria pass; criterion #2 (30-day reconciliation) blocked on 12-month Ads backfill draining (~5 hrs); criterion #3 (7-day observation) earliest 2026-05-07.
    in progress
Phase 2

Detection + causal investigations + multi-tenancy

Worth-investigating queue + agree/disagree workflow + 2nd client

10/15 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.4
    Detection engine (z-score over 90-day baseline)
    Pure-SQL `_meta.flags` view (PM-D-032 — not Cloud Run). Whole-store dimensions (spend/net_revenue/nvr_ratio); multi-dim (geo/category/channel_mix) deferred to T2.4.5. Settlement-window guard caught + filtered an Apr-30 false-positive before commit.
    q 0.83
  • T2.5
    Worth-investigating queue UI
    /queue route renders 5 NvR-drop flags from last 30 days; Investigate button prefills /investigations/new with dimension+date+flag_id. NvR-ratio fallback maps to engine's revenue dimension with honest 'Investigate revenue impact' label until T2.2.5 adds native NvR.
    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
    Per-client log per R2.5 schema (12 cols); auto-link suggestions to flags + investigations within prior 14 days (R1.8). Unblocked by T2.3a.
    pending
  • 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)
    Deferred from T2.4 — needs per-instance row in flags table (one z-score per AU state per day, etc). Schema change + UNION expansion in flags.sql. Estimated ~2 hours.
    pending
  • Phase 2 Validator
    Phase 2 Validator + 7-day observation
    Detection engine produces non-empty queue ≥1 day (✓ already 5 flags); manual investigation < 10 min (✓ T2.2 verified at 348s); artefact 4-element check (✓ T2.7); responses captured (✓ T2.8); second client onboarded (T2.3b — blocked); multi-tenancy live (T2.3a ✓ codebase / T2.3b end-to-end).
    pending
Phase 3

Outcome verification + client dashboard + productisation

Auth + per-client surfaces + R3.5–R3.8 hardening

0/9 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
Phase 4

Commercial rollout

Productisation + onboarding playbook

0/3 complete

No code work. Pricing, onboarding playbook, client success. Commercial readiness only — closure at Brent's discretion.

  • T4.1
    Pricing + commercial model
    pending
  • T4.2
    Onboarding playbook
    pending
  • T4.3
    Validation Gate (4 weeks post-launch)
    pending
Live data freshness

Pipeline health right now

20 ingestion sources monitored. Updated every 5 minutes from `_meta.freshness_check` — refresh the page to re-query.

  • shopify_fulfillments57,920 rows2d lag
  • google_ads_dts_account_basic4,728 rows2d lag
  • google_ads_dts_adgroup_basic17,460 rows2d lag
  • google_ads_dts_campaign_basic14,489 rows2d lag
  • google_ads_dts_keyword_basic35,696 rows2d lag
  • google_ads_gaql_channel108 rows2d lag
  • google_ads_gaql_pmax1,777 rows2d lag
  • meta_ads676 rows1d lag
  • meta_ads_insights29,047 rows1d lag
  • meta_ads_insights_country22,424 rows1d lag
  • meta_ads_insights_region141,539 rows1d lag
  • meta_campaigns65 rows1d lag
  • shopify_customers82,811 rows1d lag
  • shopify_inventory_items643 rows1d lag
  • shopify_inventory_levels1,530 rows1d lag
  • shopify_locations1 rows1d lag
  • shopify_orders58,134 rows1d lag
  • shopify_product_variants1,617 rows1d lag
  • shopify_products1,498 rows1d lag
  • shopify_shop1 rows1d lag
Locked decisions

What is settled

Each entry below is closed to debate. New evidence can re-open one, but a preference or aesthetic argument cannot.

  1. 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.

  2. 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.

  3. 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.

  4. PM-D-004
    Outcome 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.

  5. PM-D-005
    Free-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.

  6. PM-D-006
    Default 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.

  7. PM-D-007
    Investigation 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.

  8. PM-D-008
    Mobile 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.

  9. PM-D-009
    Token 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.

  10. PM-D-010
    Data 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.

  11. PM-D-011
    T1.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.

  12. PM-D-012
    ROAS 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.

  13. PM-D-013
    Google 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.

  14. PM-D-014
    Search-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.

  15. PM-D-015
    gclid_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.

  16. PM-D-016
    stg_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.

  17. PM-D-017
    Light-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.

  18. PM-D-018
    Data 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.

  19. PM-D-019
    T1.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.

  20. 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.

  21. PM-D-021
    Phase 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.

  22. PM-D-022
    Token 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.

  23. PM-D-023
    Top-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.

  24. PM-D-024
    Phase 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.

  25. PM-D-025
    Phase 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.

  26. PM-D-026
    Meta 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.

  27. PM-D-027
    Multi-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.

  28. PM-D-028
    Detection 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.

  29. PM-D-029
    Phase 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.

  30. PM-D-030
    meta_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.

  31. PM-D-031
    T2.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.

  32. PM-D-032
    Detection 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.

Anti-goals

What 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.

  • AG-5
    No Slack / push / SMS notifications

    Email + in-dashboard only. Notification proliferation creates fatigue without improving signal.

  • AG-6
    No HTML emails

    Plain text only. HTML email infrastructure costs days for zero functional value.

  • AG-7
    No guided onboarding tour

    Empty states and labels do the explaining. Operator built the tool; clients are onboarded verbally.

  • AG-8
    Search-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-9
    Google'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.


Marketing with Brent · Insights Platform · Internal build status

source: STATE.md / QUALITY_LOG.md