Verify a bounded run
Prepare canary evidence, review backfill bounds, and compare stable history.
This guide is for an Ads Sync operator who already has an operator runner built around the public package. The Ads Sync Reference Deployment ships POST /runs for one scheduled Sync Connection (see the quickstart); it does not ship canary or backfill endpoints, so these steps do not claim that POST /backfill-plans exists there.
prepare one canary
Start with one exact connection and a positive window no longer than 24 hours:
const request = parseAdsSyncCanaryRequest({
connectionId: "meta_ads_performance",
provider: "meta_ads",
windowStart: "2026-05-01T00:00:00.000Z",
windowEnd: "2026-05-02T00:00:00.000Z",
});
Hash the canonical request with adsSyncCanaryRequestSha256(). Bind that hash to the operator runner’s reviewed request and evidence. The package parser rejects extra keys, unsupported providers, invalid connection ids, reversed windows, and windows over 24 hours.
Run the detailed prepare-bounded-run.ts source tutorial. It prints the canonical request hash, curated Meta backfill policy, and deterministic R2 artifact keys.
bound the backfill
Use the curated provider defaults as a starting policy:
| provider | window step | maximum windows per run |
|---|---|---|
google_ads |
7 days | 8 |
meta_ads |
3 days | 4 |
The package exposes these values through supportedProviderDefinitions. Durable backfill_plans and sync_run_windows tables are part of controlSchemaSql, but plan creation, leases, scheduling, retries, and HTTP operations belong to the operator runner. Keep windows idempotent and serialize work that shares a connection lease.
inspect stored evidence
artifactKeys() partitions replay data by provider, stream, and run id. An operator runner can use those keys for configured catalog, source output, state input, destination input and output, stderr logs, and summary data.
R2 object persistence and retention are deployment responsibilities. Postgres is runtime authority for connections, plans, run windows, committed state, artifact metadata, and leases. Commit state only after a successful destination write.
compare stable history
Use runHistoricalComparisonGate() after warehouse rows exist. Its provider and warehouse adapters read the same bounded half-open window [startDate, endDate) at the entity grain the provider declares. Google Ads needs a window at least 30 days behind stableAsOf; Meta Ads needs at least 28 days.
const artifact = await runHistoricalComparisonGate({
provider: "meta_ads",
window: {
startDate: "2026-04-01",
endDate: "2026-04-02",
stableAsOf: "2026-07-25",
},
readProviderRows,
readWarehouseRows,
});
Google Search Console compares the query_page grain instead. Pass a queryPageScope naming the exact property and search type, and needs a window at least 7 days behind stableAsOf:
const artifact = await runHistoricalComparisonGate({
provider: "google_search_console",
queryPageScope: { property: "sc-domain:example.org", searchType: "web" },
window: {
startDate: "2026-04-01",
endDate: "2026-04-02",
stableAsOf: "2026-07-25",
},
readProviderRows,
readWarehouseRows,
});
Accept the gate only when summary.passed is true and readinessRecommendation is "ready". An adapter that could not return the complete bounded result must say so in limitations; a declared limitation always lands the gate on "review". Preserve the resulting Source Comparison Artifact without exposing account data or credentials.
Run run-historical-comparison.ts for a complete in-memory adapter example:
pnpm --filter @patronage/ads-sync build
node --experimental-strip-types packages/ads-sync/src/tutorials/run-historical-comparison.ts