AgentLinkOps / Methodology

Methodology.

This page explains how the product reaches each answer it gives: what a check reads, when it refuses to conclude, how a gap report is worded, what a webhook delivery promises, and what retention keeps. Each rule names the source file that enforces it, through a public claims ledger. Nothing here is a measurement. The one dated benchmark has its own account at verifier benchmark, September 11, 2026, with its denominators, and a summary on what your agent can prove.

What the verifier does

A placement check fetches two things: the source page and that host’s robots file. Nothing else is requested. The HTML is parsed and every anchor is extracted as its own occurrence, with the href, the anchor text, the raw rel tokens as the page wrote them, the surrounding context and a locator. Absence is truncation-aware: a page that was cut off before the end is an incomplete read, and an incomplete read never becomes a confirmed absence.

The observation that comes back carries the SHA-256 of the bytes that were read, the byte count, the HTTP status, the final URL after redirects, the robots posture with its reason, whether a browser was used, and a standing warning that JavaScript execution and visual visibility were not checked. The desktop CLI runs the same verifier module the hosted service runs, imported from one file, with tests asserting that both paths return the same shape for the same cases.

The walkthrough shows a real observation from a real page. The verification guide covers how to read one.

What it refuses to do

  • It does not follow a redirect into the target and call that a link. A source that redirects to the destination is refused as a placement; the redirect guard has its own regression tests, written after the September 11, 2026 benchmark found two false presents from exactly that case.
  • It does not count a link it found inside a comment, a script string or on a look-alike host. Those adversarial cases are asserted to return absent.
  • It does not fetch what robots rules disallow. A robots file that answers with a 4xx status other than 429 is read as unavailable, which under RFC 9309 imposes no restriction, and the page is then fetched; a 429 or a 5xx on the robots file, or a robots file served as HTML, still refuses. That 4xx reading was adopted after the September 11, 2026 benchmark measured the cost of the stricter posture it replaced. A refusal is an unknown with a named reason, never a lost link.
  • It does not render JavaScript. A page that needs a browser to show its links reads as unknown, with that reason. Rendered checks exist in source and are switched off in the hosted service.
  • It does not fail a run on unknown. Only an expected link, observed absent, in a complete page, exits with a failure code.

State transitions: current, last known, unknown

Every hosted watch keeps two things apart: the last observation that concluded, with its evidence summary, and the latest attempt, whatever it produced. A blocked or incomplete fetch updates the latest attempt and leaves the last known state alone.

Loss has a clock. A first complete absence after a present observation moves the watch to suspected_missing and schedules one confirmation check 30 minutes later. A second complete absence at least 30 minutes after the first moves it to confirmed_missing and emits a placement_lost event carrying a before summary of the last successful observation and an after summary of the attempt that confirmed it. An unknown between the two does not count toward confirmation. A source that cannot be reached follows a parallel path to source_unavailable, again with its own confirmation, and again without touching the last known state.

The rule this protects: unknown is never reported as lost, and a confirmation retry is one extra check per state change, not a loop.

Source health and destination health are separate

The destination of a placement is its own watch with its own checker, cadence and observations. A destination check fetches only the supplied URL, its robots file and validated redirects. Healthy means a complete, accessible static HTML response. It does not mean indexed, semantically correct or rendered, and it says nothing about whether any backlink points there. A source page can carry the link while the destination fails, or the reverse, and the two records never overwrite each other.

Gap reports state dataset relations only

A competitor gap report compares an approved inventory with the competitor inventories you hold. Its metadata says what it is: absence_claim: not_supported, whole_web_coverage: false, coverage scope selected_inventory_datasets. A gap is worded as not_found_in_customer_dataset, a fact about two datasets. It is never worded as “your competitor has a link you lack”, because no inventory covers the web. When an inventory is partial or failed, the affected groups are reported as comparison_unknown and no gap count is guessed.

The walkthrough shows a full report from synthetic fixtures, and the gap analysis guide explains how to act on one without overreading it.

Freshness gates and immutable revisions

A comparison checks the retrieval window of every selected inventory before it counts anything. When the inventories were retrieved too far apart, or a retrieval time is unknown, or any inventory is incomplete for its query, the report drops to observed_overlap_only mode with the reason named, and no gap is counted, because a difference between a May snapshot and a September snapshot is mostly the calendar. Exclusion rules apply to the request, never to stored evidence: excluding a source host from one report leaves every stored inventory row and every earlier revision as it was. Historical revisions stay immutable.

The exclusion rules guide and backlink data freshness cover the same two rules from the reader’s side.

Anchor terms: one tokenizer, declared in every report

The anchor report for monitored placements and the competitor profile report share one tokenizer, so a term that counts on one report counts the same way on the other. Its rules are plain and are printed in each report that uses them, as tokenization.version: 2: NFKC normalization and Unicode lowercasing, segmentation into letter and number runs with internal apostrophes kept and hyphens split, no stopword removal, no stemming and no language-specific segmentation. Version 2 removes address spans before segmentation, so a URL or an email address inside anchor text does not turn into terms like https or com. A brand name in prose remains a term; its address does not.

Signed, at-least-once webhooks

Every delivery is signed with HMAC-SHA-256 over the timestamp and the raw body. The signing secret is shown once at creation and can be rotated. Deliveries are at-least-once, so a receiver must deduplicate by delivery id, and the feed behind them is resumable by cursor. A receiver that answers 410 is disabled immediately without losing the events it did not take. Delivery diagnostics are readable per endpoint; the service does not resend on request.

Two header sets are sent with identical values during the pilot, AgentLinkOps-* and the compatibility Linktrail-* names, until a dated cutover release. Webhooks deliver single events or periodic digests. The transports exist and are tested; hosted delivery to a customer receiver is gated by environment configuration in the current build, and a page may say so without saying that a receiver gets deliveries in production. The service sends no email.

Retention: archive, verify, then delete

Nothing leaves hot storage until its archived copy has been read back and its digest matched. An unverified archive is treated as no archive, and a row with no verified archive is not deleted. Expiry is visible rather than silent: an event cursor that falls behind the retention floor returns an explicit expired-cursor response with a resync path, so an empty page and an expired cursor can never be confused.

The windows themselves are product configuration, listed with their source on the access and data page. They are not a methodology claim, and they can change with the configuration.

Public contacts are published addresses only

Contact extraction reads the latest saved complete page for a watch and returns the email addresses and contact-page URLs the publisher explicitly published there, each with dated evidence. No address is constructed or guessed. Deliverability is never checked, and the record says so on every contact with deliverability: not_checked. The service never sends outreach; your agent’s own email tools do that, under your review.

Bounded multi-page research follows contact-page links from that saved page with declared ceilings, stops at the first ceiling reached and names it. Only GET requests are made, no form is submitted, and a page behind a login reads as a possible login wall and ends that branch.

The meter: reserved, consumed, released

Every queued check reserves one unit. The unit is consumed only when its observation is saved, including an unknown or an unavailable source. A check that fails for good, or is cancelled, releases its unit. Usage reports the three totals separately; folding reserved into consumed would overstate what happened, and folding released into either would invent a check that never ran. Admission is enforced against the workspace’s monthly check limit; plan allowances appear only in estimates.

What this page does not claim

  • No accuracy percentage. The one dated benchmark keeps its date, its single target domain and its denominators on its own page; no rate from it is repeated here as a property of the product.
  • No ranking effect. A verified placement is a link that exists on a page at a time. Nothing here predicts what a search engine does with it. Reading search trends beside placement dates explains how to compare a chronology with Search Console rows without crediting a link.
  • No rendered-page verification in the hosted service. Rendered checks exist in source and remain switched off.
  • No live discovery. Supplier discovery and new competitor inventories stop with PROVIDER_NOT_CONFIGURED in this build.
  • No verified email addresses, and no sending.

How this page was checked

Written September 15, 2026 against the repository at commit cc2c74f. Each statement quotes a row of the DP-0023 claims ledger: M-01 to M-07, W-01, W-06, W-07, W-11, W-12, P-03, P-05, P-07, A-01, A-02 and B-02. The source files those rows name were re-read on that commit, and the suites they cite were re-run the same day. The robots paragraph was corrected on September 15, 2026 against commit af8f4ba, with rows B-06 and B-07, after the benchmark page was written and the current robots reading was re-read in source. Suites on cc2c74f: verifier 55 of 55, destination verifier 20 of 20, competitor reports 12 of 12, webhooks 27 of 27, retention 18 of 18, contacts 3 of 3, CLI check 13 of 13. The deployed version behind the hosted behavior, and the calls that verify it, are on the status page.

A changed source file voids a claim until it is rechecked. If a rule here no longer matches the product, the ledger is where the correction starts.