Seven layers sit between your raw ad logs and AI agent answers you can trust.
Trusting the answers from an AI agent that you point at your log level data needs it to go through seven layers: ingestion, enrichment, unification, semantics, governed access, security and compliance, and consistency across users. Skip on just one and the agent always answer but the answer won't be based on anything that you can trust.
Your business wants to leverage AI to unlock all the insights in all the data it has stored on your ad stack. At first glance the route looks quick and obvious: Land the FreeWheel and Google Ad Manager files in the SQL warehouse, let an agent write SQL and hey presto the agent provides a pretty compelling answer.
The problem though is how it gets there. It does so by guessing, each and every time, what each value of data means and what the IDs stand for. It’s brimming with ignorant confidence. Nothing crashes, nothing complains. It’s dangerous to say the least.
If the raw data is akin to crude oil and your agents your hyper car engines, you need to properly extract, refine, enrich and deliver the data in the right amounts to make the agent the most effective it can be.
1. Ingestion: files arrive late, corrected and sometimes twice
An agent is only as good as the data it consumes, and ad-server files can keep changing after they are first published. Google says most Data Transfer data arrives 5 to 15 hours after the hour it records, with delayed events taking up to eight days. And in that case a corrected file is posted with _corrected in its name beside the original, so an unaware loader may create duplicate values, or just miss them altogether.
So a naive agent asked at breakfast about last night may end up reading a partial data as a fall in revenue, and blame a partner for a drop that never happened.
Not only does your ingestion step need to continuously work to keep the data up to date, but your agents need to know that data is very likely to keep changing well after the fact.
2. Enrichment: the agent needs names as they were on the day
Log level data is simply a record of output - typically denoted as events with a data record for that moment in time. By design they only store relevant fields and for compression and efficiency purposes they will store IDs rather than full text strings. Not only that they do not have any metadata of the state of the systems at those moments or indeed how they connect to all the other components in the stack.
So an agent, that thrives on context, can only do so much with just log data. To be fully contextualised IDs need to be resolved into metadata. Local system data sets need to be joined up into a holistic superset. Events need to be joined up to their sessions.
Metadata is also constantly in flux, so last month’s report needs every version of a setting kept with the dates it applied, which data modellers call a type 2 slowly changing dimension. An agent that joins to today’s metadata files September’s revenue under October’s campaigns, and nothing in the answer shows the switch. Even named, the rows are too scattered to count.
3. Unification: one long-form view is about a hundred rows
What’s in a view? Piecing together just one video view might seem simple and straightforward. But it rarely is because the implications are more nuanced - Videos can play back over 2hrs, live streams even longer. Events are scattered across large timespans and each has significant context that is needed to piece it all together. This leads into trawling hundreds of rows of complex relationships and metadata.
This requires highly sophisticated SQL query building, extensive knowledge of the data schema and knowing how to join between disparate data sets to get the unified data view that provides the full picture
Building this data is precise work, because a careless join returns a result that looks right. For example on Google Ad Manager, a very specialised data field called KeyPart identifies a bid auction in the Bids file and a query in the other files, this level of specialist knowledge is the difference between getting the right record of fact vs a hallucination. And a naive agent left to do this on its own, in its non-deterministic way, rebuilds the SQL on every question, a little differently each time.
4. Semantics: the agent guesses what your fields mean
When is an impression, not an impression, not an impression? FreeWheel, Google Ad Manager and your SSP reports each have something they call an impression but all are different and unique to their local points of view. Ask your agent for your total impressions for yesterday and without proper semantics you’ll get all sorts of crazy numbers.
Each data feed should provide a schema overlay to help with its own data but it won’t map a FreeWheel ad to the SpringServe supply tag, or to the SSP report that paid for it. Putting the meanings in the prompt fails too, since the IFScale benchmark found that even the best frontier models stop following instructions reliably once a prompt gets overwhelmed by long lists and data.
So the meaning has to sit in the data, defined once, where the agent can ask for a metric by name and get the same calculation every time.
5. Governed access: left alone, an agent scans a month of impressions
Ask a naive agent for all impressions last month and it may write SELECT * FROM impressions with no limit. On billions of rows, that query slows the warehouse for everyone, or autoscaling adds nodes and the cost arrives at the end of the month.
The bigger data set returned to the agent, the less accurate and attentive it becomes. Chroma found that a short, focused input beat the same question wrapped in a long one, and that even one distractor lowered performance.
The fix is to stop the agent writing SQL on the raw store. Pipe it through an MCP server that works like a linter instead. The agent sends a structured request (data source, dates, metrics, groupings, filters), and the server checks it against what exists, writes the query and/or holds a cache and returns only the answer.
6. Security and compliance: permissions follow the person
Not only can three people ask the same question three different ways but they have three different levels of rights to even ask the question: one may see revenue by advertiser, another only delivery. An agent on one shared service account sees everything that account can see, so all three get the same view breaking all the security and compliance in one go.
Leveraging an MCP server will enforce security policies and provide audit level controls. Each agent has their own login, through single sign-on if you use it, so there are no API keys to hand out. The agent sees only what that login sees in the web app, and every tool is read-only, so it can’t create or change reports, monitors or settings.
7. Consistency: three phrasings, one answer
With the right data in front of each person, two people asking the same question on the same day must still get the same number. Agents are non-deterministic by design, so on raw logs each one writes its SQL a little differently and the same question can come back as two stories.
The six layers below fix that, with each session built once, each metric given one meaning and each request compiled to the same query. Ad ops in Claude, the revenue lead in ChatGPT and an engineer in your own agent then get the same number. The agent keeps the work it is good at, understanding the question and explaining the answer.
Hold any build, ours included, to a test at every layer
Whoever builds it, the layer should give everyone the same answer within their own permissions, stay read-only and show numbers anyone can check. Those guarantees are won or lost one layer at a time, so test each layer on your own data before anyone acts on an answer.
| What breaks without it | What guards it | How to test it | |
|---|---|---|---|
| Ingestion | A late, empty or _corrected file reads as a revenue drop or a double count | Collect every feed as it lands, and alert when one breaks before any agent reads it | Compare one hour from the files with the ad server's own report for that hour a day later |
| Enrichment | Answers in IDs, or last month's revenue filed under this month's names | Look up every ID in the source system's API, and keep each name with the dates it applied | After a campaign is renamed, ask for last month's revenue by campaign. It should show the old name |
| Unification | About a hundred rows per view, rebuilt differently on every query | One session per view, counted once, joined across ad servers and SSPs | Count one view's ads by hand from the raw rows, then ask the agent for the same count |
| Semantics | The agent picks one of several impression or revenue fields and doesn't say which | Each metric and dimension defined once, in ad-ops terms, and asked for by name | Ask which data source, dates and metrics it used, then open the same cut yourself and compare |
| Governed access | A SELECT * over a month of impressions slows the warehouse or scales up the bill | Structured requests, checked against what exists, compiled the same way every time | Ask for all impressions last month, then look at the query it ran and the rows it read |
| Security and compliance | One shared service account sees everything, and an agent with write access can change settings | Read-only tools on each person's own login, scoped to what that login can see | Have two people with different rights ask for revenue by advertiser, then list every tool the agent can call. Each tool should only read |
| Consistency | Two people ask the same question on the same day and get two numbers | Meaning and query fixed below the agent, so the agent only phrases the answer | Two people ask ten revenue questions you know from the ad server's reports, twice each. The numbers should match |
Build the refinery, or plug into one that already runs
Could your team build all seven layers? Given enough time, probably. It takes engineers who know FreeWheel’s event types and Google’s corrected files, and someone keeping every ID lookup and name history current. It takes a semantic model for every metric, query governance, per-person access, and alerts that catch a broken feed before your agents do. Then you have to keep every one of them current whenever an ad server changes its log files, on its own schedule and without warning.
You would need a permanent data platform team, and the business’s questions would wait while it maintains the plumbing. Most broadcasters and publishers have it harder: they run FreeWheel alongside SpringServe or Google Ad Manager, plus SSP reports, bid-level logs and SSAI logs.
That is exactly the crude Watching That was built to refine. The seven layers already run every day for our customers, and A+E Networks cut ad errors 70% in its first quarter on Watching That. When an ad server changes its log files, we update the connector.
So plug your own Claude or ChatGPT into the read-only Watching That MCP server, each person on their own login. Your agents run on refined data from the first question. Your data team spends its time on the questions the business is asking and on the agents that answer them.
Bring three of your own questions and see the layers on your own data
In 30 minutes we'll put three of your revenue questions to an agent connected through the Watching That MCP server, on your own ad stack, and show you each layer at work.
Can the agent change anything through the Watching That MCP server?
No. All six tools read data, and none of them can create or change reports, monitors or settings.
How far back can the agent look?
Detailed data covers about the last seven days. For older periods the agent uses daily rollups, and a tool tells it first which dimension combinations those allow.
How do we test the difference on our own data?
Pick ten revenue questions whose answers you know from the ad server's own reports, and have two people ask each one twice, once through your raw-log agent and once through a governed layer. Compare the numbers and the token counts.