# Martech stack audit: Acme Cloud, as of 2026-11-01

Fictional example. Acme Cloud, its people, tools, IDs and amounts are invented to show a finished report. Abbreviated: the full finding list is in the script outputs reproduced in references/worked-example.md.

## Header

- Prepared by: Marketing ops lead. FAILs reviewed with: Head of Growth, Data lead, Lifecycle lead, Web lead, IT admin.
- Trigger: stack inherited from the agency; four renewals inside 90 days; request to connect HubSpot and Snowflake to an AI assistant.
- Workflows traced: W1 lead to opportunity; W2 trial to activation; W3 subscription to renewal.
- Sources: AP, card and expense lines (finance, exported 2026-10-28); Okta Application Usage, Google accessed apps and the identity provider user list (IT admin, 2026-10-29); user exports from HubSpot, GA4, GTM, Amplitude, Customer.io, Snowflake and Metabase (tool admins, 2026-10-28 to 2026-10-30); connection register (technical owners, 2026-10-31); AI connection inventory (team leads, 2026-10-30); billing accounts and CRM companies key lists (Data lead, 2026-10-30).
- Scripts run from the audit folder with `--as-of 2026-11-01`:
  - stack_inventory.py: 16 FAIL, 24 WARN, 5 PASS, 10 NOT CHECKED
  - connection_map.py: 4 FAIL, 11 WARN, 5 PASS, 0 NOT CHECKED
  - key_match.py (billing accounts against CRM companies on account_id): 1 FAIL, 2 WARN, 3 PASS
- Test actions on live systems: the reject and accept clicks on the consent banner for the pricing and sign-up pages, approved by the Web lead on 2026-10-30. No record was created, updated or unsubscribed; the four-case evidence came from records that had already been through each case.
- Nothing was changed by this audit. Every change below is a proposal for its owner.

## Act now (sent to the user on 2026-11-01)

- Example Notes AI holds restricted Gmail and Drive scopes with no register row: IT security today.
- Unbounce: review-by passed on 2026-10-26; the notice boundary is 2026-11-11.
- HubSpot: review-by is today; the renewal work starts now.
- Segment: review-by 2026-11-06; the notice boundary is 2026-11-20.

## Decisions needed, with deadlines

- Example Notes AI, today: an unverified app holds Gmail, Drive and Calendar access for 7 people.
  - Owner: IT admin. Options: block and revoke, or register with an owner and a DPA. Evidence: F02.
- Unbounce, decide now (review-by 2026-10-26 passed; notice boundary 2026-11-11).
  - Owner: Growth marketer. Options: retire with written notice before 2026-11-11, or keep. Evidence: F06.
- HubSpot renewal, start today (review-by 2026-11-01), decide by 2027-01-01 (14 days before the account-toggle boundary on 2027-01-15).
  - Owner: Head of Growth. Options: right-size 4 seats at renewal, renegotiate with an alternative priced, or keep. The discount ends with the term. Evidence: CON05, USE02.
- Segment renewal, decide by 2026-11-06 (boundary 2026-11-20).
  - Owner: Product lead. Options: keep (current disposition) or renegotiate the MTU commitment.
- Metabase seats, decide by 2026-11-17 (boundary 2026-12-01).
  - Owner: Data lead. Options: right-size from 10 to 4 or 5 seats at the 2026-12-31 renewal. Evidence: USE02.

Amplitude (decide by 2026-12-15) and Cookiebot (by 2026-12-18) follow in the 31 to 60 day window.

## Stack map

From connection_map.py. Solid arrows are observed with dated evidence, dotted arrows are proposed or lack that evidence (C03 has no evidence reference, FLW06), and a check ID in a label marks a FAIL.

```mermaid
flowchart LR
  subgraph layer_collect["collect"]
    T03["T03 Google Tag Manager<br/>Web lead"]
    T04["T04 Segment<br/>Product lead"]
    T14["T14 Microsoft Clarity<br/>Web lead"]
    T18["T18 Cookiebot<br/>Privacy lead"]
  end
  subgraph layer_store["store"]
    T01["T01 HubSpot<br/>Head of Growth"]
    T09["T09 Stripe<br/>Finance lead"]
    T10["T10 Snowflake<br/>Data lead"]
    T11["T11 Fivetran<br/>Data lead"]
  end
  subgraph layer_measure["measure"]
    T02["T02 Google Analytics 4<br/>Growth analyst"]
    T05["T05 Mixpanel<br/>Product lead"]
    T06["T06 Amplitude<br/>Product lead"]
    T13["T13 Metabase<br/>Data lead"]
  end
  subgraph layer_activate["activate"]
    T12["T12 Hightouch<br/>Data lead"]
    T16["T16 Zapier<br/>RevOps lead"]
  end
  subgraph layer_engage["engage"]
    T07["T07 Customer.io<br/>Lifecycle lead"]
    T15["T15 Calendly<br/>Sales lead"]
    T17["T17 Unbounce<br/>Growth marketer"]
    T19["T19 Google Ads<br/>Paid media lead"]
  end
  subgraph layer_support["support"]
    T08["T08 Intercom<br/>Support lead"]
  end
  subgraph layer_unregistered["not in the register"]
    X01["X01 not in the register"]
  end
  T03 -->|C01 tag| T02
  T04 -->|C02 cdp| T05
  T04 -.->|C03 cdp no dated evidence| T06
  T04 -->|C04 cdp| T07
  T09 -->|C05 elt via T11 Fivetran| T10
  T01 -->|C06 elt via T11 Fivetran| T10
  T10 -->|C07 FLW01 reverse_etl via T12 Hightouch| T01
  X01 -->|C08 FLW05 FLW09 ipaas via T16 Zapier| T01
  T07 -->|C09 FLW02 native| T01
  T08 -->|C10 native| T01
  T01 -->|C11 native| T19
  T10 -->|C12 native| T13
  T10 -->|C13 manual_csv| T07
  T04 -.->|C14 cdp proposed| T05
  classDef unregistered stroke-dasharray: 5 5
  class X01 unregistered
```

- X01 is the Typeform account found in card spend; it is being registered as T21 (forms).
- T18 Cookiebot has no mapped connection yet (FLW11): its consent signal to GTM and Segment needs a row.

## Register summary

- Tools in scope: 20. Seen in one channel only: T02, T03 (seats), T08 (spend), T17 (contract fields), T19, T20 (spend). Seen in no channel: T09 Stripe (fees netted), T14 Microsoft Clarity (free).
- Unregistered: Typeform (card spend and OAuth, register); Hotjar (expense claims, register or retire); Notion (SSO, out_of_scope: general workspace tool with no marketing data flow); Example Notes AI (OAuth, IT security decision).
- 12-month tool spend: USD 159,416.00, of which 1,292.00 unregistered; EUR 1,800.00. Never added together.
- Reported apart: media USD 60,000.00 (Google Ads); agency services USD 48,000.00.
- Top 80% of USD tool spend: T01, T10, T06, T04, T08, T07, T11 (83.1% of the cost basis).

## Renewal calendar

- 2026-10-26 overdue: T17 Unbounce, term ends 2026-11-25, notice 14 days by written notice, boundary 2026-11-11, no disposition. Owner: Growth marketer.
- 2026-11-01 days 0-30: T01 HubSpot, term ends 2027-01-15, account toggle, discount ends the same day, right-size on the largest contract (lead 75), decision target 2027-01-01. Owner: Head of Growth.
- 2026-11-06 days 0-30: T04 Segment, term ends 2026-12-20, notice 30 days, boundary 2026-11-20, keep. Owner: Product lead.
- 2026-11-17 days 0-30: T13 Metabase, term ends 2026-12-31, notice 30 days, boundary 2026-12-01, right-size. Owner: Data lead.
- 2026-12-15 days 31-60: T06 Amplitude, term ends 2027-02-28, notice 45 days, boundary 2027-01-14, consolidate (lead 75). Owner: Product lead.
- 2026-12-18 days 31-60: T18 Cookiebot (EUR), term ends 2027-01-31, boundary 2027-01-01, keep. Owner: Privacy lead.
- Later: T11 Fivetran 2027-02-15; T10 Snowflake 2027-04-17 (auto-renew off).
- Locked: T12 Hightouch, boundary passed 2026-10-16, term ends 2026-11-15; recertify by 2027-07-18.
- Unknown terms: T07 Customer.io (notice days, mechanism, reduction rule); T08 Intercom (term end, notice, auto-renew, pricing, reduction rule). Order forms requested 2026-11-02.
- Monthly, reducible any time: T05 Mixpanel, T15 Calendly, T16 Zapier.

## Key findings

- F01 FLW02 FAIL, class 1
  - Condition and dated evidence: unsubscribes from Customer.io reach HubSpot after 1,440 minutes against a 15-minute requirement (connection C09, four-case test AUD-C09, 2026-10-31).
  - Affected workflow and population: W2; every person who unsubscribes in Customer.io and is in a HubSpot email list.
  - Consequence: people who opted out can receive HubSpot marketing email the next morning.
  - Proposed change: interim suppression list shared by both tools now; then move the sync to near-real-time or webhook.
  - Owner and dependencies: Lifecycle lead; none.
  - Acceptance test: an unsubscribe in either tool reaches the other within 15 minutes in three of three tests.
  - Rollback or recovery: remove the interim list after the fix passes; sends already made cannot be recalled.
  - Target window: days 0 to 30. Owner response: agreed.
- F02 INV02 FAIL, class 1
  - Condition: "Example Notes AI", unverified, 7 users, restricted gmail.readonly and drive.readonly scopes plus calendar.readonly, no register row (accessed apps CSV, row 6, 2026-10-29).
  - Consequence: mail, calendars and files readable by an app with no owner, no DPA and no off switch.
  - Proposed change: IT security decides today; the audit drafted the revocation list.
  - Owner: IT admin. Acceptance test: the app is absent from a fresh accessed apps download, or registered with an owner and a DPA. Target window: today, outside the plan.
- F03 OVL02 FAIL and point-of-action FAIL, class 1 if confirmed
  - Condition: email:trial_onboarding is listed by both HubSpot and Customer.io (register rows 2 and 8). HubSpot's onboarding workflow has no goal or exit rule, so trials that activate during a delay keep getting activation emails (workflow settings and enrolment history, 2026-10-31).
  - Proposed change: compare one week of both send logs for the same trial accounts; keep one sender, which exits on activation.
  - Owner: Lifecycle lead. Acceptance test: no trial account receives onboarding email from both tools in a seven-day sample, and no activated account receives an activation email. Target window: days 0 to 30.
- F04 FLW05 and FLW09 FAIL, class 2
  - Condition: the form-to-CRM zap (C08) runs on a departed person's credential and starts in an unregistered form tool (X01, Typeform).
  - Consequence: the lead flow stops the day that user is removed; leads match on email only (FLW03).
  - Proposed change: register Typeform; rebuild the zap under a company service identity with the RevOps lead as named owner.
  - Acceptance test: the four-case test passes three times on the new identity. Target window: days 0 to 30.
- F05 INV05, ACC01 and ACC02 FAIL, class 2
  - Condition: GA4 sits in an agency-owned account with one company admin; GTM's only admin is on example.net (seats rows 15 to 19).
  - Proposed change: add a second company admin to GA4 and two to GTM, then the agency transfers ownership.
  - Owner: Web lead. Acceptance test: fresh access exports show 2 to 4 company admins and no agency-held ownership. Target window: days 0 to 30.
- F06 CON04 FAIL, class 2
  - Condition: Unbounce review-by 2026-10-26 passed; boundary 2026-11-11; no charges, SSO users or seats found (INV06).
  - Proposed change: list live landing pages; if none, the contract owner sends written notice before 2026-11-11.
  - Owner: Growth marketer. Acceptance test: written acknowledgement filed and no renewal invoice after 2026-11-25. Target window: days 0 to 30.
- F07 FLW01 FAIL, class 2
  - Condition: the warehouse writes contact.lifecycle_stage through Hightouch (C07, no field authority) while HubSpot is its recorded system of record; rejected rows are not visible (FLW07).
  - Proposed change: decide one authority, or split into lifecycle_stage (CRM) and product_stage (warehouse); record it in decisions.md.
  - Owner: Head of Growth with the Data lead. Dependencies: none. Target window: days 31 to 60.
- F08 KEY02 FAIL and KEY01 WARN, class 3
  - Condition: 6 excess CRM company rows on 6 account IDs (2.33%); 241 of 250 paid billing accounts found (96.4%); 11 unexpected keys are trials and churned accounts, explained.
  - Proposed change: duplicate review queue in the CRM; no new account-based segments until KEY02 passes.
  - Owner: RevOps lead. Acceptance test: re-run shows excess duplicates at or below 0.5% and coverage at 98% or more. Target window: days 31 to 60.
- F09 AI connection FAIL, class 2
  - Condition: the HubSpot remote MCP server is connected in one assistant on a Super Admin login, with all tools allowed and no off switch recorded (AI connection inventory, 2026-10-30). That is a personal admin login with write access and no approval step.
  - Proposed change: disconnect it, or reconnect under a least-privilege user with only read tools allowed in the client.
  - Owner: Head of Growth. Acceptance test: the inventory shows a non-admin identity, read tools only and a named off switch. Target window: days 0 to 30.
- F10 ACC04 and ACC05 FAIL, class 2
  - Condition: HubSpot does not require two-factor authentication, so its four Super Admins sign in with a password alone (seats rows 2 to 5). A person whose identity provider user was deactivated in July keeps enabled HubSpot and Metabase accounts (seats rows 13 and 51).
  - Proposed change: replace the shared marketing login with named users, then require two-factor authentication; move what the leaver's accounts own to named owners, then disable both accounts.
  - Owner and dependencies: Head of Growth (HubSpot), Data lead (Metabase); required MFA depends on the shared login being replaced (ACC03).
  - Acceptance test: a fresh user export shows MFA enforced for every HubSpot admin and no enabled account whose identity provider user is deactivated. Target window: days 0 to 30.

Also open: USE01 FAIL (dormant Snowflake ACCOUNTADMIN), ACC03 FAIL (shared HubSpot Super Admin login), CON01 FAIL (Customer.io and Intercom order forms), INV04 FAIL (Hightouch technical owner), ACC06 WARN (HubSpot's Google grant holds gmail.readonly for 12 users; Zapier's holds gmail.modify and full Drive for 2), FLW08 WARN (C10 and C11 people flows with no consent rule, for the privacy owner), FLW04 WARN (C05 alert owner, C10 replay method).

## Tracking screen

- W2 trial to activation: GA4 sign_up over backend registrations, 28 completed days to 2026-10-28, past GA4's late-data window, stayed inside its band (0.92 to 0.97) every day. PASS.
- Page senders, fresh profile, 2026-10-30, in three consent states (no choice, rejected, accepted; the clicks approved by the Web lead): with consent rejected, a Hotjar script loads from the site theme on the pricing page. Handed to consent-debugging on 2026-10-31; verdict pending, listed under not checked.
- Consent default owner: the Cookiebot template in GTM only. PASS.

## Dispositions per tool

- Keep: T02, T03, T04, T05, T07, T09, T10, T11, T12, T14, T16, T18, T19, T20.
- Right-size: T01 HubSpot (4 seats at renewal; the contact tier stays at the owner's 15% growth forecast; an alternative priced before the 2027-01-01 decision); T13 Metabase (10 to 4 or 5 seats).
- Consolidate: T06 Amplitude into T05 Mixpanel. Owner Product lead; acceptance test: the five weekly product reports reproduce in Mixpanel within 2% on the same date range; commercial deadline 2027-01-14 (notice); dependencies: reroute C03 events (C14), export saved charts, remove the Segment destination. T15 Calendly into T01 HubSpot meetings. Owner Sales lead; acceptance test: every booking link reproduces with round-robin and reminders; deadline: any time (monthly); dependencies: embedded booking links on the website and in email signatures.
- Investigate: T08 Intercom (question: what job does it do that HubSpot chat does not; owner Support lead; answer by 2026-12-01). T17 Unbounce (question: which pages are live and who pays; owner Growth marketer; answer by 2026-11-07).
- Register: Typeform as T21 (forms). Register or retire: Hotjar (overlaps T14 Clarity). Out of scope: Notion.

## AI connections and readiness

- AI connections: HubSpot remote MCP server in one assistant, connected by a Super Admin, all tools allowed, no central off switch recorded (F09). Example Notes AI (F02). No others reported by team leads.
- Tracking accuracy: partly. Written plan exists; last end-to-end test February 2026; W2 ratio inside its band.
- Identity resolution: fix. No shared user ID between product analytics and the CRM; 2.33% duplicate account IDs.
- Warehouse models: partly. Scheduled loads with owners; joins have no duplicate tests.
- Metric definitions: fix. No written definition of revenue or of a customer; MQL differs between the CRM report and the BI dashboard.
- Context docs: partly. ICP and naming written; no compliance rules document.
- Access and permissions: fix. The HubSpot MCP connection on a Super Admin login, the unverified AI notes app, the shared CRM admin login, CRM admins without enforced MFA, the agency-only GTM admin.
- MCP readiness: partly. One connection made on purpose, by a named owner; not read-only; no single off switch.
- Blocking statements: no AI answers on CAC or pipeline by channel until identity and metric definitions pass. No write-capable AI connection until access passes. First step: reconnect HubSpot under a least-privilege user with read tools only, tested on five questions with known answers.

## 30, 60, 90 day plan

Days 0 to 30 (to 2026-12-01):

- P1 Contain Example Notes AI (IT admin; today; F02).
- P2 Interim suppression for C09, then the sync fix (Lifecycle lead; acceptance as F01).
- P3 Compare onboarding send logs and keep one sender, which exits on activation (Lifecycle lead; F03).
- P4 Decide Unbounce before 2026-11-11 (Growth marketer; F06).
- P5 Start the HubSpot renewal work: decompose the renewal into discount, unit price and quantity, size the seats and price an alternative (Head of Growth; CON05, USE02).
- P6 Decide Segment by 2026-11-06 and Metabase seats by 2026-11-17 (Product lead; Data lead).
- P7 Company admins for GTM and GA4, then the agency ownership transfer (Web lead; F05).
- P8 Access clean-up: grant Snowflake ACCOUNTADMIN to a second active owner, then remove it from the dormant account; replace the shared HubSpot admin login with named users, then require two-factor authentication; disable the leaver's HubSpot and Metabase accounts after their assets move (Data lead; Head of Growth; F10).
- P9 Disconnect the HubSpot MCP connection, or reconnect it under a least-privilege user with read tools only (Head of Growth; F09).
- P10 Rebuild C08 under a service identity and register Typeform (RevOps lead; F04).
- P11 Obtain the Customer.io and Intercom order forms (contract owner; CON01).
- P12 Quick wins after owner checks: cancel the duplicate Calendly subscription on Card B; add an alert owner to C05 and a replay method to C10; name Hightouch's technical owner.

Days 31 to 60 (to 2026-12-31):

- P13 Lifecycle stage authority decision for C07 (F07; dependency for any new lifecycle workflow).
- P14 CRM duplicate review queue (F08; dependency for new account segments).
- P15 Amplitude to Mixpanel replacement test, sends and writes off, finished by 2026-12-15.
- P16 Consent rules for C10 and C11 from the privacy owner; map Cookiebot's connection; decide Cookiebot by 2026-12-18.
- P17 Owners confirm the restricted Google scopes: HubSpot inbox logging for 12 users, Zapier mail and Drive for 2 users (ACC06).
- P18 Re-test the tracking plan end to end for W1 and W3.

Days 61 to 90 (to 2027-01-30):

- P19 HubSpot renewal decision by 2027-01-01, from P5's decomposition and alternative price.
- P20 If P15 passed: Amplitude notice before 2027-01-14, export, Segment destination removed, access removed.
- P21 Calendly into HubSpot meetings; cancel the remaining subscription after the cutover.
- P22 New-tool intake rule adopted.
- P23 Re-test every closed FAIL; re-run the three scripts on fresh exports.
- P24 Read-only AI connection tested on five questions with known answers, once the access check is ready.

Roadmap: Fivetran review by 2027-02-15; Snowflake review by 2027-04-17 with the 15% overage explained; Hightouch recertification by 2027-07-18; shared user ID across product analytics and CRM (Q1 2027 gate: KEY02 passes); one metric definition layer (Q1 2027 gate: MQL agreed).

## Savings

- Cash through 2027-01-31: USD 538 to 588 after owner checks (Calendly duplicate 288; Metabase January instalment 250 to 300). Up to USD 2,697 more is conditional: Hotjar 297 if retired, Unbounce 2,400 if Acme pays it at all.
- Run-rate once commitments end: USD 22,152 to 22,752 a year (Calendly duplicate 1,152; Metabase 3,000 to 3,600 from 2027-01-01 at the 600 per seat-year average implied by the contract, confirm in the order; Amplitude 18,000 from 2027-03-01 less any added Mixpanel cost, which the owner will quote). Up to USD 3,588 more is conditional (Hotjar 1,188; Unbounce 2,400).
- Released capacity: none assumed. The weekly churn-risk CSV upload (C13) takes about an hour by the RevOps lead's estimate; verify before counting.
- Not counted: Amplitude cash before 2027-02-28 (prepaid term); HubSpot seat savings until the renewal decomposition is done.

## Not checked

- Admin counts for T04, T09, T11, T12, T16, T18, T19: user exports with roles requested from each tool admin.
- Dormancy for GA4 and GTM: their access lists carry no login dates.
- MFA for the agency admin on GA4 and GTM: the agency confirms it, or the admin is removed after the transfer.
- Hotjar script with consent rejected: consent-debugging verdict pending since 2026-10-31.
- Customer.io dormancy for two accounts: the tool's own team list requested.
- Change history older than each tool's retention window.

## Evidence index

- example-acme-spend.csv: AP, cards and expenses, exported 2026-10-28, supplied by the Finance lead.
- example-acme-okta-app-usage.csv and example-acme-google-accessed-apps.csv: exported 2026-10-29, supplied by the IT admin.
- example-acme-seats.csv: seven tool exports normalised 2026-10-30, with MFA from each tool's security settings and identity provider status joined from the IT admin's user list.
- example-acme-connections.csv: connection register with four-case test references, 2026-10-31.
- AI connection inventory: team leads, 2026-10-30.
- example-acme-billing-accounts.csv and example-acme-crm-companies.csv: key lists, 2026-10-30, supplied by the Data lead.

## Proposed martech-context changes (awaiting approval)

- `stack.md`: add T21 Typeform with owners; mark Notion out_of_scope with its reason; record T12's technical owner; correct the GA4 and GTM account ownership after the transfer; record the HubSpot MCP connection's identity and off switch (after P9).
- `decisions.md`: lifecycle stage authority (after P13); onboarding email sender (after P3); Amplitude consolidation decision (after P15); HubSpot renewal decision (after P19).
- `metrics.md`: key coverage lines (98% and 95%) and duplicate line (0.5%) as the agreed data quality thresholds; one MQL definition once agreed.
