What integration verification proves and what it does not
The stages between your code and stored evidence, what a verified sample establishes, the exact limits and known gaps of the verification reads, how long to wait, and what has been run.
On this page
After your agent integrates feature flags or product events, three reads ask Anectico whether the exact samples of a controlled test arrived. This page is the one place that says what their answers establish, which limits bound them, how long to wait before trusting a negative answer, and what has and has not been run. The request and answer fields are on the pages for each read.
| Read | REST | MCP action | CLI | Fields and states |
|---|---|---|---|---|
| One job, one verdict | POST /api/v1/instrumentation/verify |
verify_integration |
anectico doctor integration |
Integration job verification |
| Exact product events | POST /api/v1/instrumentation/events/verify |
verify_integration_events |
anectico doctor events |
Integration event verification |
| Exact flag exposures | POST /api/v1/instrumentation/flags/verify |
verify_flag_integration |
anectico doctor flags |
Feature-flag exposure verification |
All three are reads. They send nothing, change nothing, store no report, run no model and open no
proof page: links is always empty. Their states (observed_match, mismatch, not_observed,
withheld, unavailable, ambiguous) mean the same thing on every surface, and a REST, MCP or CLI
call with the same request returns the same answer.
Six stages, and which one a read can establish
A test passes through six stages. Each one is evidence of itself and of nothing after it.
| Stage | What it is | Who reports it | Does a verification establish it? |
|---|---|---|---|
| Configuration | The flag, keys, project and tracking-plan revision you approved through a preview and a confirmation | The confirmation receipt | No. A receipt shows a setting exists, never that your application uses it. |
| Application execution and local outcome | Your application ran, served a branch, and its SDK or code reported success or failure | Your application's own record | No. Anectico does not see your run. Keep the clocks, message IDs and served branch from your application's record. |
| Queue acceptance | Capture answered CAPTURE_DELIVERY_QUEUED for the item |
The capture acknowledgement | No. It does not mean the event is stored, readable, or that an identity update has finished. |
| Retained evidence | A stored event with that name, message ID and admitting source matches your selection | The verification read | Yes, for the selected samples only. |
| Identity | The distinct_id your application declared resolves to a person |
The identity check, with persons:read |
Yes, with persons:read. The declared ID is your application's own assertion; Anectico does not authenticate your end users. |
| Verification | Every required check of every selected sample is observed_match |
The verdict |
It is the sum of the checks above and no more. |
What a verified sample proves
verified_sample means: for the up to 20 samples you selected, inside the window and before the
read_cutoff the answer states, every required check was observed_match. For product events that
is the event name, message ID and admitting source, the declared identity, the session if you
asked, the person the declared identity resolves to, and, with a pinned tracking-plan revision, that
the revision declares the event and the property types match. For flags it is the value, definition
version, evaluation status, fallback flag, evaluation mode and input context that your application
recorded.
It does not prove:
- that any other event, flag, person or code path is instrumented;
- that everything your application sent arrived.
upstream_completenessis alwaysunknown: SDK configuration, sampling, consent, client-side loss and an accepted intake request are not observed; - that errors, traces, logs or replay work. They are neither required nor checked;
- that a person saw a treatment. A flag exposure is application-reported use;
- that your application authenticated its inputs. An
input_bindingis a declaration by the sender, never recomputed or authenticated, and a remote decision that used stored person, group, cohort or audience context iscontext_not_established; - that the people in the test are real people;
- that the project's measurements are healthy. Verification checks your selected samples and nothing else, so another person's correct events neither help nor hide a wrong one.
Bounds on every request
| Bound | Value |
|---|---|
| Event-time window | At most 1 hour, [start, end), millisecond precision |
| Samples or exposures | 1 to 20, answered in the order sent |
| Property checks per sample | At most 20 |
| Whole job call | Stops after 20 seconds |
| Concurrent verifications per project | 2; a third is refused with HTTP 429 |
The product-event read behind both jobs also stops at these limits, returned in every answer under
limits:
| Read limit | Value |
|---|---|
| Rows scanned | 10,000,000 |
| Bytes scanned | 1 GiB |
| Memory | 512 MiB |
| Candidate events returned | 200 |
| Returned bytes | 4 MiB |
| Execution time | 8 seconds |
A reached limit makes every sample unavailable with a reason that begins limit_, and
limits.limit_reached is true. It never produces not_observed. Normal rate limits and agent budgets
apply to these reads; there is no separate fee.
Two known gaps in the event read
Both are open and both are stated in every answer's limitations.
The read is not narrowed by date. It reads every retained event of the selected event names in
the project, not only those of the window's day, and keeps the ones inside the window. The cost
therefore grows with the project's history of those names, not with your test. On a local
deployment holding 100,000 retained events of the 20 selected names across 30 days, one 20-sample
verification read about 100,000 rows, 27 MB, in about 50 ms. At that row width the 1 GiB byte limit
binds near 3.9 million retained events of the selected names, before the row limit. A busy project
can therefore answer unavailable for an event that exists. Select fewer distinct event names per
request, and treat unavailable with a limit_ reason as unknown, never as absent.
The stored event has no source in its key. Two sources in one project that send the same event
name, timestamp, distinct ID and message ID keep one stored event. Verifying one source can then
report not_observed because the other source's copy was kept. Ordinary traffic rarely collides,
because SDK message IDs are random, but a replayed fixture, a copied payload, or two servers
forwarding one upstream event can. Use a message ID that is unique to the source in every test,
and never reuse a fixture across sources. Nothing in the answer tells you a collision happened.
How long to wait, and when to stop
Queue acceptance is not readability. In the local runs described below, stored events became readable about 20 to 35 seconds after the application sent them; the slowest run needed its fourth read, about 65 seconds after the exercise. How long a hosted deployment takes has not been measured, so do not hard-code a delay.
- The first one or two reads after a test can answer
failedbecause every check isnot_observed. That is delay, not a defect. Amismatchis different: the event was read and it differs from what you asked for. Read the checks, not only the verdict. - Read again with the same request. The runnable examples read at most four times, after waiting
5, 10, 20 and 30 seconds in turn, and re-read only while a required check is
not_observedorunavailable. Then they report what is unresolved. Your agent decides the schedule; Anectico does not poll for you. - Do not resend an acknowledged event to make it appear, do not widen the window or change the selectors to get a better verdict, and do not create another resource after an ambiguous answer.
- A call that fails with 409, 429 or 503 released no answer. Retry the same request shortly.
- If a scope, the project's content policy or the selected events change while a read runs, no answer is released. Start a fresh read.
Scopes decide how much of the answer you see
| Scope | Needed for | Without it |
|---|---|---|
mcp:read |
Calling a read over MCP | The MCP call is refused. |
query:read |
The one-verdict job read | The job read is refused (403) before anything is read. |
analytics:read |
Every product-event and flag-exposure read | The read is refused (403). |
flags:read |
The flags job and the exposure read |
The read is refused (403). |
persons:read |
The identity check |
The check is withheld; a stored identity that differs from the declared one is reported only as a mismatch. |
tracking_plans:read |
The plan and its declarations | They are withheld. |
agents:content:read |
Property checks and recorded flag fields | Every such check is withheld. |
A withheld check never lets a sample verify. It is not a sign that the application is wrong or the
event is absent: ask for the scope, or report that part as not checked.
Time, history and population
- Windows are event time as your application stamped it.
read_cutoffis the receipt time after which nothing was read; it is not a snapshot or a delivery watermark.effective_start_timeandeffective_end_timeare the part of the window the read covered after the project's readable history, and are empty when nothing was read. population.basisis alwaysexplicitly_selected_application_samples: only the samples you selected were checked.- Anectico does not yet reserve a population for verification traffic. Test events are ordinary
events in the project: they count in its measurements and in its event allocation, and they are
retained, exported and erased like any other event. Use clearly synthetic identities such as
anectico-verification-user-a, tell the person who owns the project, and never erase a person merely to tidy up. - Identify and group-identify calls store no event row, so no read can select them. Their outcome is the acknowledgement. Verify the events that follow them.
Jobs not covered yet
errors, traces_logs, replay, surveys and experiments are refused by name. For an error or
trace story use the setup check in verify your setup.
What has been run
On 15 October 2026 the runnable examples were driven against a local test deployment on one macOS machine, each by a script that exercised the application like a visitor's browser and then asked Anectico to verify the samples:
| Example | Runtime | Result |
|---|---|---|
| Node checkout, remote flag decisions | Node 22.22.0, SDK built from the repository; and from a packed tarball | Product events and flags verified_sample; the people behind the events resolved as expected |
| Node checkout, remote flag decisions | Node 24.21.0, packed tarball | The same |
| Node checkout, local flag evaluation | Node 22.22.0, SDK built from the repository | The same |
| Ruby checkout over HTTP, no SDK | Ruby 2.6.10, standard library | The same, with session checks |
Against the verified Ruby run's own requests, a wrong selection failed as it should: another source,
identity, session, expected value or definition version each produced failed, and another project
was refused.
On 16 October 2026 an independent coding agent was asked, on the same local test deployment, to
integrate product events or a server-side flag into the uninstrumented Node 24 and Ruby 2.6
checkouts from scratch, four times in all. In every run, its changed application, exercised again by
the test harness as two visitors the agent had never seen, produced exactly the events and exposures
that the verification reads then confirmed: the events, the anonymous-to-identified joins, a numeric
property, the served branch and the versioned exposures, and on Node an established, agreeing
local-versus-remote comparison. None of the four counts as a qualification: each final report left
out a fact the check requires (an event name, the test people, the message IDs or the flag key). The
agents' own check of $groups as an event property came back missing, so account attribution was
not confirmed through event verification.
Not run: a passed qualification of the workflow by an independent agent; a hosted or shared deployment; Ruby 3; Linux or Windows hosts; a browser; and any other language. Nothing on this page is a promise for those. See Ask your agent to integrate Anectico for what is covered and Runnable integration examples for the code that was run.