MAINTENANCE MODEL
The integration worked the day it was built. Does it work today?
This is the question that decides whether measurement work was worth buying, and it is almost never answered in a proposal. Analytics SDKs update on their own schedule, vendors change field names, and a tracking implementation degrades quietly - the events keep arriving, they are simply wrong. Below is what runs on this property to catch that, what each check cannot catch, and which parts are not built yet.
Read the status tags first
3 of the 4 mitigations below are running in this repository right now, enforced on every pull request. One is scoped: designed, costed, and not built. When this page was written only ONE of the four was real - the other two were closed before publishing it, and the fourth is labelled rather than fudged.
That distinction is the point of the page. A maintenance model is the easiest thing in a proposal to write and the hardest to verify, so most are written as policy. This one is checkable: the checks are in the pipeline configuration, in public, and the section after the table shows one of them catching a real regression.
What catches drift
1. Types as the drift detector
running- Catches
- A breaking field change in any typed SDK fails the build instead of shipping malformed events. Every core SDK here ships TypeScript types, and the canonical event union is the single source those map from.
- Does not catch
- Anything stringly-typed. A vendor that renames a value rather than a field passes the compiler untouched, and so does every hand-written HTTP contract.
- How it is enforced
- tsc --noEmit is a required status check on every pull request. A red check blocks the merge; there is no bypass actor.
2. Contract tests on the vendor mappings
running- Catches
- A mapping change that silently corrupts data. The two warehouse legs deliberately DISAGREE - one needs integers where the other needs booleans, one needs the ISO T and Z stripped where the other requires them kept - so the tests assert that the divergence persists rather than that the mappings match.
- Does not catch
- Everything about the transport. A mapping test proves the row was built correctly, never that it arrived. On this property a destination once reported delivered while zero requests left the browser.
- How it is enforced
- Three mapping surfaces under test: both warehouse legs and the GA4 translation shared by the browser and server legs. Runs on Node’s own test runner, so the check added no dependency to install or keep upgraded - a maintenance mitigation that needs maintaining is a poor trade.
3. Beacon assertions in CI
scoped- Catches
- The gap mitigation 2 leaves open: browser automation drives the store and asserts on the network beacons that actually leave, so a regressed event fails the pipeline instead of the demo.
- Does not catch
- Nothing much - which is why it is the one worth building next. It is also the most expensive to own: a browser in the pipeline is a dependency that breaks on its own schedule.
- How it is enforced
- Not built. Designed, costed, and deliberately not claimed. The honest position today is that a transport regression is caught by a person looking at a vendor debugger.
4. Pinned majors, upgrades as reviewable pull requests
running- Catches
- The slow version of drift. Majors are pinned so an upgrade is never automatic, and upgrades arrive grouped by risk - vendor SDKs separately from framework and tooling - each carrying the full check suite.
- Does not catch
- A vendor breaking change shipped inside a minor or a patch, which does happen. Pinning bounds the blast radius; it does not remove it.
- How it is enforced
- Weekly dependency pull requests, monthly for the pipeline itself, grouped so that a breaking SDK change is reviewed on its own rather than inside a sweep.
A check is worth nothing until you have watched it fail
The two warehouse legs store the same event and need different representations of it. One has no boolean type and takes integers; the other has a real boolean. One rejects the ISO 8601 markers in a timestamp; the other requires them. Both facts were established against the live services, and either mapping copied onto the other corrupts data silently - the write still succeeds.
So the obvious tidy-up - two files that look nearly identical, surely one would do - is a data-loss bug. Here is that exact change being made deliberately, and the pipeline refusing it:
✖ ClickHouse slices the ISO timestamp, BigQuery must not AssertionError: BigQuery accepts ISO 8601 directly - copying the ClickHouse slicing here corrupts the value actual: '2026-08-24 23:59:00.123' expected: '2026-08-24T23:59:00.123Z'
The failure names the service, the cause and the correction. Worth noting what would NOT have caught it: both values are strings, so the compiler is satisfied and the build passes. Type checking and a green build are necessary and they are not sufficient, which is the entire argument for mitigation 2 existing alongside mitigation 1.
Where this model is weak
Stated because a buyer will find these anyway, and finding them unlisted costs more than the admission does.
Three vendor legs are hand-written HTTP, with no types to check
Three of the live server-side legs speak raw HTTP rather than through an SDK - a deliberate choice, because the SDKs batch and would hide each vendor’s per-event answer, which is the thing this property exists to show. The cost is real: no SDK means no types, so mitigation 1 does not apply to them at all. One of the three is checked against the vendor’s own validation endpoint, which returns genuine messages rather than a status code. Nothing catches a change made at the vendor’s end until traffic hits it.
A success report is not a signal
Our own dispatcher once reported a delivery that never happened. Every claim on this property is therefore checked against the vendor’s record rather than against our own optimism, and the inspector shows each vendor’s own answer including the status code it returned. This is a working habit, not a feature, and it is the single most useful thing on the list.
Four mapping surfaces are not yet under contract test
Down from five. The translations that live inside their transport modules rather than in a module of their own cannot be asserted on without loading a client and its credentials. Splitting them is the same one-file change that made the warehouse mapping testable, and it is the roadmap rather than a claim. The one that moved shows how these get paid for: a second transport was built for that vendor, the shared mapping had to exist for the two legs to be comparable at all, and the tests followed from the split rather than from a decision to go and write tests.
None of this is operated by us
The code lives in the client’s own repository and the pipelines in their own cloud accounts. That is deliberate and it is the answer to the boutique-resilience question before it is asked: nothing here depends on Webclat continuing to exist.
Figures and mechanics on this page describe this property, which is a demonstration property: fictional catalogue, simulated checkout, no personal data. It publishes no client outcomes - deliberately, and stated.