Fusion Tables, internal only
What the six-deck pack contains, the five live measurement defects behind it, the ordered fix plan, and what still cannot be sourced. This deck also carries the self-QA and acceptance results for the whole pack.
This run
Why this deck exists
| ID | Severity | Defect |
|---|---|---|
| F-21 | Critical | A cached page has served one visitor's UTM and Google click ID inside live form action URLs to the next visitor since a clean HIT was graded on 2026-07-30. Never fixed. |
| F-02 | Critical | The armed "Submit lead form" Google Ads conversion action fires on a URL that returns HTTP 404. A separate "Purchase" action sits on a URL that returns 200 and has not fired yet. |
| F-04 | Critical | The CRM source column is null for every enquiry row, so no submitted enquiry can be joined back to the ad that produced it. |
| F-03 | Critical | Google Ads conversion_value carries the conversion count under unit "huf", producing a ROAS of 0.0005 with no real revenue behind it. |
| Windows | High | The five data sources behind the internal reporting pipeline cover three different date ranges, so a single report can mix incompatible windows under one "current" label. |
Fix plan, step 1 of 5
1
Symptom. A clean cache HIT on the billiard-table landing page serves one visitor's UTM parameters and gclid inside the three rendered CF7 form action URLs to the next visitor who hits the same cache entry.
2
Root cause. The production cache layer, owner not yet identified, caches query-derived personalization fields as part of the static HTML instead of stripping them before the page is cached.
3
Fix. Exclude query-derived click IDs and UTM values from cached HTML. Generate attribution fields per request after the cache layer. Never cache a personalized form action.
4
Who. Site or cache owner, currently unassigned.
Proof it is fixed
An automated clean HIT/MISS matrix using two distinct synthetic visitor IDs shows neither visitor receives the other's values, the page stays at HTTP 200, and every CF7 form action contains only current-request values. No live form submit required.
Fix plan, step 2 of 5
1
Symptom. The Google Ads "Submit lead form" conversion action is a page-load trigger on a URL that returns 404. A separate "Purchase" action sits on a URL that returns 200 and is armed but silent.
2
Root cause. Form start stayed Primary and counted Every in Google Ads while the real submission-confirmation URL was never wired to a working conversion action, so both spend and bidding optimize on a page load, not a submission.
3
Fix. Generate one lead_id on server-accepted CF7 success, map it to one canonical GTM and GA4 event, then make the deduplicated submitted-lead action Primary, count once, and move form start and the dead Purchase action to Secondary or retire them.
4
Who. Site or GTM owner for the event, Google Ads account owner for the conversion action change. Both currently unassigned.
Proof it is fixed
Google Ads change preview shows the exact action IDs, Primary or Secondary status, count and value settings. GTM Preview and GA4 DebugView show exactly one start event and one submission event per test action, with matching IDs.
Fix plan, step 3 of 5
1
Symptom. crm.source_column is null on every enquiry row in the form register. No submitted enquiry can be traced back to Google or Meta spend.
2
Root cause. The form register headers never included source, campaign, click-ID or landing-page fields, so a submission lands with no attribution even where a click ID was technically available upstream.
3
Fix. Add lead_id, source, medium, campaign, content, term, landing URL and every click ID to the Sheet, populated from the fields the EDIT-02 payload already captures at submission time.
4
Who. Sales or CRM owner for the sheet schema, coordinated with the site owner who ships EDIT-02. Both currently unassigned.
Proof it is fixed
Schema readback confirms the new columns exist. An aggregate completeness report shows fill rate by field. The ten historical rows remain intact, and one synthetic test row flows through the new columns with no personal data.
Fix plan, step 4 of 5
1
Symptom. The Google Ads conversion_value field carries the raw conversion count tagged with unit "huf", producing a ROAS of 0.0005 that reads as a real return-on-spend figure.
2
Root cause. No verified revenue figure exists anywhere in the stack. The CRM schema has quote and payment fields, but no filled Fusion outcome value, so the count was left in the value field as a placeholder.
3
Fix. Remove the forint-labelled value from the conversion action now. Report spend, clicks and enquiries only, never a computed ROAS, until offline enhanced conversions import a real quote or purchase value from the CRM.
4
Who. Ads account owner for the immediate removal. Sales or CRM owner for the eventual real-value import. Both currently unassigned.
Proof it is fixed
Google Ads readback shows the conversion action carrying no value, or an explicitly disabled value field. No pack deck or client report prints a ROAS number until the real-value import is live.
Fix plan, step 5 of 5
1
Symptom. One report run pulls Google Ads and Meta Ads on 2026-07-25 to 08-23, BigQuery on 2026-07-24 to 08-22, the CRM sheet on 2026-07-26 to 08-24, and work evidence on 2026-06-23 to 08-23.
2
Root cause. Each collector pulls its own trailing window independently, driven by per-source lag and API history limits, and the report assembler merges them without normalizing to one canonical window.
3
Fix. Pick one canonical window per report run. Have every collector clip or pad to it, or return UNAVAILABLE for that source. Treat source_health.range as a gate a report cannot pass with mismatched ranges.
4
Who. The reporting-pipeline owner, the same code line that writes report_data.json.
Proof it is fixed
A rerun of the collector shows every source_health.range entry equal for one report_id, or an explicit UNAVAILABLE for any source that cannot supply that exact window.
Dependencies
| Step | Fix | Depends on | Blocks |
|---|---|---|---|
| 1 | F-21, cache stops leaking click IDs | none | 2, 3, 4, 5 |
| 2 | F-02, conversion action repointed, Purchase retired | 1 | 3 |
| 3 | F-04, CRM source and click-ID columns added | 1, 2 | 4, 5 |
| 4 | F-03, mislabeled value removed, real-value import planned | 3 | 5 |
| 5 | Report windows normalized to one canonical range | 1, 2, 3, 4 | none |
Where the numbers came from
| File | Window | Rows | Consumed by |
|---|---|---|---|
| .tmp/overnight-2026-08-10/data/meta_ads.json | no window field, account-level creative export | 39 ads | kreativ-teljesitmeny |
| .tmp/overnight-2026-08-10/data/meta_ad_insights.json | 2026-07-11..2026-08-09 | 20 rows | kreativ-teljesitmeny |
| .tmp/fusion-ppc-2026-08-06/breakdowns.json | 2026-07-08..2026-08-06 | Google: 4 breakdown sets. Meta: 4 breakdown sets, 15 adsets | riport-30-nap |
| outputs/loop-runs/2026-08-28-fusiontables-report/report_data.json | 5 source windows, 3 distinct ranges, see next slide | 7 source_health entries | riport-30-nap, belso-anyagok |
Defect detail
| Source | Current window | Status |
|---|---|---|
| google_ads | 2026-07-25 .. 2026-08-23 | degraded, change-event history before 07-26 unavailable |
| meta_ads | 2026-07-25 .. 2026-08-23 | degraded, results field is a form-start signal, not a verified enquiry |
| search_console | not available | absent, no property configured for this client |
| ga4 | not available | absent, no measurement configured for this client |
| bigquery | 2026-07-24 .. 2026-08-22 | disabled, no verified GA4 BigQuery export configured |
| crm_sheet | 2026-07-26 .. 2026-08-24 | degraded, blank legacy date header, 7 QA rows excluded |
| work_evidence | 2026-06-23 .. 2026-08-23 | degraded, Activity Log skipped, no CRM page ID configured |
Gaps
| Metric | Why not available | What would fix it |
|---|---|---|
| Cost-per-enquiry, ad-attributed ROI | Enquiries carry no source column, F-04 | Ship the fix-plan step 3 CRM columns |
| Enquiry source breakdown by channel | Same source-column gap, F-04 | Same as above, then a backfill window |
| Qualified lead, quote acceptance, purchase, revenue | No structured qualification field exists in the form register or CRM for either channel | EDIT-06 sheet fields, then EDIT-07 offline conversion import |
| GA4 landing-page funnel | No GA4 measurement configured for this client | Configure a GA4 property and link it in client config |
| Search Console organic figures | No Search Console property available to this client | Grant Search Console access and link it in client config |
| Fresh Meta account and dataset readback | The configured Meta API session is invalid, error 190/467, no authorized token | Re-authorize a live Meta access token for the ad account |
| Verified combined monthly Meta plus Google budget baseline (B) | T4A and T4B, the tasks that were to resolve baseline B, never ran, both stayed WAITING_DEPENDENCY | Run T4A/T4B against a fresh authenticated account readback |
Traceability
Acceptance
| Task | Originally asked for | This pack delivers | Still open |
|---|---|---|---|
| T4A | Decision-level Meta and Google strategy for the single pool-table landing page, allocated against a verified monthly budget baseline B | hirdetesi-strategia deck's single-offer scenario, built without a confirmed B | Baseline B verification, WAITING_DEPENDENCY, NOT STARTED at source |
| T4B | Full six-offer-group strategy at or below 1.5x baseline B | hirdetesi-strategia deck's second scenario, same baseline gap | Same baseline B verification, WAITING_DEPENDENCY, NOT STARTED at source |
| T7 | Source-traceable Google and Meta targeting and campaign pack for both scenarios, keyword-measured under a USD 3 DataForSEO cap | persona and hirdetesi-strategia decks carry targeting and audience detail. No DataForSEO keyword run occurred in this pack | Depended on accepted T4A and T4B, both still WAITING_DEPENDENCY at source |
Fusion Pulse, layer 1 of 10
1
What it is. Four registries plus one A/Z test ledger, rebuilt every month from the raw Meta, Google and leads-sheet pull by a single script. It turns the month-end report into a decision list instead of a description.
2
What it answers. Which creatives to change, alter or keep. Which copy to cut, alter or keep. Which audiences to exclude or double down on. What was tested and what the test decided.
3
What it never does. No Meta or Google writes. It reads, ranks and recommends. Changes are applied by hand in Ads Manager after the recommendation is accepted.
4
How to re-run. Pull the new month with the three scripts in qa/data/, then run _registry.py. The four CSVs are rewritten in place next to docs/fusion-pulse/README.md.
Registry 1 of 4
| Ad | Format | Spend HUF | Link clicks | CPC HUF | Leads | Cost per lead |
|---|---|---|---|---|---|---|
| belga_biliard_carousel_1 | carousel | 55 888 | 420 | 119.67 | 5 | 11 178 |
| belga_biliard_carousel_4 | carousel | 22 962 | 157 | 129.73 | 2 | 11 481 |
| belga_biliard_carousel_elenk-meleg | carousel | 2 933 | 12 | 195.53 | n.a. | n.a. |
| belga_biliard_carousel_pergola_1 | carousel | 2 847 | 14 | 167.47 | n.a. | n.a. |
| belga_biliard_carousel_fa-meleg | carousel | 1 603 | 10 | 160.30 | n.a. | n.a. |
| belga_biliard_carousel_2 | carousel | 1 539 | 4 | 307.80 | 1 | 1 539 |
| belga_biliard_carousel_elegans | carousel | 1 292 | 8 | 117.45 | n.a. | n.a. |
| belga_biliard_carousel_3 | carousel | 800 | 7 | 114.29 | n.a. | n.a. |
Registry 2 of 4
| ID | Hook | Ads | Shared spend HUF | Shared CPC HUF | Chars |
|---|---|---|---|---|---|
| C01 | Nem kell választania stílus és szórakozás között | 17 | 88 977 | 143.51 | 411 |
| C02 | Egy igazán sokoldalú asztal | 17 | 88 977 | 143.51 | 384 |
| C03 | Étkezőasztal nappal, tárgyalóasztal az üzleti megbeszélésekre | 17 | 88 977 | 143.51 | 425 |
| C04 | Van egy többfunkciós biliárdasztal, melyet a hölgyek is szeretnek | 17 | 88 977 | 143.51 | 768 |
| C05 | Egyedi. Exkluzív. Többfunkciós. | 5 | 82 148 | 139.47 | 333 |
| C06 | Fúziós biliárdasztalok, három funkció egyben | 12 | 6 829 | 220.29 | 572 |
| C07 | Szeretné a maximumot kihozni a pergolájából | 3 | 4 104 | 256.50 | 544 |
| C08 | A legjobb pergolák titka | 3 | 4 104 | 256.50 | 319 |
| C09 | Egy pergola rengeteg lehetőséget teremt | 3 | 4 104 | 256.50 | 550 |
Registry 3 of 4
| Window | Ad set | Age | Geo | Platforms | Spend HUF | CPC HUF | Cost per lead |
|---|---|---|---|---|---|---|---|
| aug | 2026_2_IG_mixed-interest_2_belga_biliard | 25-65 | HU | instagram, threads | 93 081 | 130.18 | 11 635 |
| jul | 2026_2_IG_mixed-interest_2_belga_biliard | 25-65 | HU | instagram, threads | 49 776 | 83.80 | 4 525 |
| jul | 2026_1_mixed-interest_1_belga_biliard | 25-65 | HU | 1 188 | 56.57 | n.a. |
The blocking fact
One ad set carried 100 percent of august spend, with 20 broad interests, all genders, ages 25 to 65, Hungary, Advantage audience on. There is no audience split inside august to compare, which is why the account cannot answer which audience to double down on yet.
Registry 4 of 4
| ID | Hypothesis | Metric | Result | Decision |
|---|---|---|---|---|
| AB-01 | Neutral tone carousel beats the colour variants | CPC | A 140, B 203 HUF, A cheaper by 45 percent | keep A, change B |
| AB-02 | Pergola hook beats the dining-table hook | CPC | A 140, B 256 HUF, A cheaper by 83 percent | keep A, change B |
| AB-03 | Instagram plus Threads beats Instagram only | CPC | A 84, B 57 HUF in july, under 30 clicks on arm B | signal only, not decisive |
| AB-04 | The 1AB and 2AB duplicates match the originals | CPC | A 86, B 171 HUF on 342 HUF of spend | rerun with real budget or close |
| AB-05 | Cost per lead replaces CPC as the deciding metric | cost per lead | measurement staged, not live yet | evaluate end of september |
How a decision is made
Every month
Measurement
1
Browser side, verified on the local staging copy. ViewContent per product category from the URL slug, Contact on mailto clicks, matching view_item and contact_click dataLayer pushes, and form actions rewritten at runtime so a cached page cannot pass one visitor's click ID to the next.
2
Lead with a shared event id. The id lead_email_date is stamped onto the Lead the existing GTM container already fires, so the Conversions API copy deduplicates instead of double counting. PageView, telefon Contact and a second Lead are deliberately not re-fired.
3
Server side, read back from Meta. Conversions API from the Apps Script for Lead, QuoteSent and Purchase, all events_received 1 under test event code TEST_FUSION_E6, fbtrace ids in qa/measurement/capi-readback.txt. Google Ads values moved from 1 HUF to 0 on 6 actions, two offline actions created for the quote and order path.
4
Score. 4 of the 5 audited defects fixed, the fifth partial. Snippet 3101 is staged with the two command deploy path quoted below and goes live on deploy. Until then every cost per lead outside Meta's own lead surfaces stays not available.
Two human gates, none of them code
1. WordPress login for the 3101 deploy: python3 landing/billiardasztal-v2/pw/login.py then python3 landing/billiardasztal-v2/pw/deploy_snip.py 3101. 2. One time Apps Script authorization click, run setupCapi once in the editor and approve the external_request scope. Done already: the two dead UA goal conversion actions 382354946 and 382741653 were removed in the Ads UI on 2026-09-03, API readback REMOVED, their replacement was already live.
September, part 1 of 2
September, part 2 of 2
Nothing is excluded and nothing is doubled down on this month, because one ad set carried 100 percent of august spend and there is no contrast to act on. Split the 20 interest set into two ad sets for september, billiard and cue sports against interior design and luxury furniture, so october has a real comparison. Keep age 25 to 65, Hungary, all genders.
PMax search category impressions fall from 1 791 in july to 47 in august while cost nearly doubles, and july's categories were real intent terms while august is mostly the unlabelled bucket plus the brand term. Recommend re-enabling the paused 2605-Fusion-Tables_Search campaign on biliárd asztal, biliárd asztal ár and használt biliárd asztal.
The honest august headline
83 percent more spend bought 22 percent more link clicks and fewer leads, 8 against 11. Cost per lead went from 4 633 to 11 635 HUF. Until the Lead event is live that number covers Meta's own lead surfaces only, and the 21 sheet leads cannot be attributed to a channel because the sheet has no source column.
QA
| Deck | Slides | Local QA | Live HTTP |
|---|---|---|---|
| 30 napos eredmények | 13 | PASS | 200 |
| Hirdetéskreatívok teljesítménye | 13 | PASS | 200 |
| Versenytársak hirdetései | 14 | PASS | 200 |
| Hirdetési és célzási stratégia | 35 | PASS | 200 |
| Persona elemzés | 22 | PASS | 200 |
| Belső anyagok és QA | 24 | PASS | 200 |
QA
| Check | Result |
|---|---|
| Deck is slides | PASS |
| Arrow key turns the page | PASS |
| On-screen back arrow works | PASS |
| On-screen forward arrow works | PASS |
| Navigation returns to slide 1 | PASS |
| No page scroll at 1280x900 | PASS |
| No slides-app chrome, 2 nav buttons only | PASS |
| No slide overflows its 1280x900 frame | PASS |
| 0 em-dashes in rendered text | PASS |
| 0 semicolons in rendered text | PASS |
| 0 console errors, 0 page errors | PASS |
| Live HTTP status | 200 |
| Comment layer present in fetched HTML | yes |
QA
| Check | Result |
|---|---|
| Deck is slides | PASS |
| Arrow key turns the page | PASS |
| On-screen back arrow works | PASS |
| On-screen forward arrow works | PASS |
| Navigation returns to slide 1 | PASS |
| No page scroll at 1280x900 | PASS |
| No slides-app chrome, 2 nav buttons only | PASS |
| No slide overflows its 1280x900 frame | PASS |
| 0 em-dashes in rendered text | PASS |
| 0 semicolons in rendered text | PASS |
| 0 console errors, 0 page errors | PASS |
| Live HTTP status | 200 |
| Comment layer present in fetched HTML | yes |
QA
| Check | Result |
|---|---|
| Deck is slides | PASS |
| Arrow key turns the page | PASS |
| On-screen back arrow works | PASS |
| On-screen forward arrow works | PASS |
| Navigation returns to slide 1 | PASS |
| No page scroll at 1280x900 | PASS |
| No slides-app chrome, 2 nav buttons only | PASS |
| No slide overflows its 1280x900 frame | PASS |
| 0 em-dashes in rendered text | PASS |
| 0 semicolons in rendered text | PASS |
| 0 console errors, 0 page errors | PASS |
| Live HTTP status | 200 |
| Comment layer present in fetched HTML | yes |
QA
| Check | Result |
|---|---|
| Deck is slides | PASS |
| Arrow key turns the page | PASS |
| On-screen back arrow works | PASS |
| On-screen forward arrow works | PASS |
| Navigation returns to slide 1 | PASS |
| No page scroll at 1280x900 | PASS |
| No slides-app chrome, 2 nav buttons only | PASS |
| No slide overflows its 1280x900 frame | PASS |
| 0 em-dashes in rendered text | PASS |
| 0 semicolons in rendered text | PASS |
| 0 console errors, 0 page errors | PASS |
| Live HTTP status | 200 |
| Comment layer present in fetched HTML | yes |
QA
| Check | Result |
|---|---|
| Deck is slides | PASS |
| Arrow key turns the page | PASS |
| On-screen back arrow works | PASS |
| On-screen forward arrow works | PASS |
| Navigation returns to slide 1 | PASS |
| No page scroll at 1280x900 | PASS |
| No slides-app chrome, 2 nav buttons only | PASS |
| No slide overflows its 1280x900 frame | PASS |
| 0 em-dashes in rendered text | PASS |
| 0 semicolons in rendered text | PASS |
| 0 console errors, 0 page errors | PASS |
| Live HTTP status | 200 |
| Comment layer present in fetched HTML | yes |
QA
| Check | Result |
|---|---|
| Deck is slides | PASS |
| Arrow key turns the page | PASS |
| On-screen back arrow works | PASS |
| On-screen forward arrow works | PASS |
| Navigation returns to slide 1 | PASS |
| No page scroll at 1280x900 | PASS |
| No slides-app chrome, 2 nav buttons only | PASS |
| No slide overflows its 1280x900 frame | PASS |
| 0 console errors, 0 page errors | PASS |
| Live HTTP status | 200 |
| Comment layer present in fetched HTML | yes |
Acceptance
| Row | Requirement | Status | Evidence file |
|---|---|---|---|
| A1 | Six decks plus the index are live on review.clientsflow.hu | PASS | qa/a1-live.md |
| A2 | Every deck is slides: arrow key and on-screen arrows turn the page, no page scroll at 1280x900, no app chrome | PASS | qa/a2-slides.md, qa/shots/ |
| A3 | 0 em-dashes and 0 semicolons in client copy, 0 console errors per deck | PASS | qa/a3-copy.md, qa/a3-console.md |
| A4 | Every number traces to a source file and window, unavailable is labelled | PASS | qa/a4-provenance.md |
| A5 | The creative deck extends the 2026-08-24 report rather than rebuilding it | PASS | qa/a5-extend.md |
| A6 | Gist exists and the strategy deck cites the T4A, T4B and T7 contract items | PASS | qa/a6-contracts.md |
| A7 | Work committed on a branch, nothing on main, no secrets | PASS | qa/a7-git.md |
| A8 | Index cards with status, slide count and what to check, plus the round 2 handoff | PASS | round-2-handoff.md |
Acceptance
Sources