LONTA TAP-TO-CALL LAB AND AUDITOR — v1 / 2026-10-24

OPEN WITHOUT INSTALLATION
Save tap-to-call-auditor.html and double-click it in a modern browser.
The tool is self-contained. It makes no external requests and requires no
account. index.html is byte-identical. JavaScript must be enabled locally.

Run full lab produces eight actual DOM snapshots of three call links.
Expand each snapshot for displayed text, accessible label, raw href,
comparable number and result. Save last result JSON exports those records.
The fixture container is inert: rendered links remain readable by the DOM
checker but ordinary keyboard, pointer and auxiliary interaction is disabled.
Browsers without native inert support do not mount the fixture; the lab is
disabled and the observation checker remains available. This is a controlled
fixture behavior, not a guarantee about arbitrary scripted activation or
modified pages. Never dial example numbers.

All fixture numbers and results are synthetic. This is original Lonta
replacement code, NOT CallRail or any other provider's script. The returning
visitor state is an in-memory model. It is not a cookie, browser-restoration
or attribution test. Blocked script means the lab leaves its replacement
function uncalled; it does not emulate a provider's network behavior.

CHECK YOUR OWN PAGE
Only run console code you have reviewed on a page you control. Read
console-snippet.js, optionally set window.tapAuditOptions, then paste the
snippet in developer tools. It reads DOM candidates without network,
clicks, mutations or persistence. It writes tapAuditResult to window and
prints a table. Copy tapAuditResult.rows into the tool's JSON input.

Example configuration (replace with your known setup):
window.tapAuditOptions = {
  country: 'US',
  expected: '+12025550101',
  fallback: '+12025550100'
};

Use country: 'global' to require +country-code input. US mode explicitly
allows NANP 10 digits or leading 1. Number assignment, ownership and country
code allocation are not validated. Syntax comparison is conservative;
unsupported or ambiguous values stay unknown. Extensions, including zero,
remain significant. Short codes, vanity numbers, phone-context, pauses,
isub and multiple displayed numbers require manual inspection.

Paste observations as a JSON array:
[{"id":"mobile-bar","text":"(202) 555-0101",
  "href":"tel:+12025550100","accessible":"Call (202) 555-0101"}]

Only the four fields above are needed; a missing field may be omitted.
The offline tool never parses pasted HTML. Input is rendered with
textContent. Maximum input: 200 rows / 100,000 characters. Clear inputs
resets observations. Load defective sample restores the synthetic example.
Nothing is saved automatically. JSON export contains the observations you
supply. Do not include customer or confidential account data in a report
that you intend to share.

RESULTS
PASS: comparable displayed number and destination agree; any parseable
number in the accessible label also agrees. An explicit numeric accessible
label that cannot be parsed is UNKNOWN. Generic nonnumeric accessible
labels receive NOT_NUMBERED for their label comparison; they do not
prevent a visible-number/link consistency PASS. Expected number, if supplied,
also matches. An empty expectation cannot confirm the intended tracking
number. Attribution and call routing remain UNVERIFIED in every result.
FAIL: observed disagreement, wrong expected destination or missing/non-tel
link on a detected phone CTA. UNKNOWN: insufficient or unsupported input,
invalid expected/fallback number, or no observed CTA.
FALLBACK: displayed number and destination match your declared fallback.
It does not confirm the expected tracking number or that the line works.

SCANNING LIMITS
The DOM snapshot scans visible light-DOM tel anchors, number-labeled
anchors (including anchors missing href), and data-phone-cta elements.
It includes off-screen but rendered elements so scroll to inspect them.
It excludes display:none, visibility:hidden and opacity:0 on the element.
Clipped text, ancestor opacity, overlays, generated text, complete
accessible-name computation, frames, shadow roots, image-only numbers,
buttons without data-phone-cta and custom JavaScript calling are outside
its coverage. Candidate count zero is UNKNOWN, never PASS. Multiple
offices should be audited in separate scopes with their own expectations.
The console snippet installs no observer. Rerun after asynchronous changes,
navigation, Back, revisits and controlled script blocking.

FILES / REPRODUCTION
- audit.js: shared comparison logic and actual DOM reader (MIT).
- fixture.js: controlled deliberate text-only defect and repair (MIT).
- app.js: offline UI and eight-state journey (MIT).
- tool.template.html: HTML and styles used to generate the tool.
- build.mjs: embeds those three scripts into identical HTML files and
  generates the self-contained console snippet. Run: node build.mjs
- audit.test.mjs: dependency-free behavior tests. Run:
  node --test audit.test.mjs
- browser.test.mjs: actual Chromium DOM/file:// tests, 390px viewport,
  input safety, export, reset and zero HTTP requests. Requires existing
  Node + Playwright + its Chromium browser, outside the offline tool.
  Place the extracted directory under a project already providing
  node_modules/playwright, then run: node browser.test.mjs
  No dependency is required merely to open the HTML tool.
- fixture-safety.test.mjs: focus, tab navigation, pointer hit testing,
  ordinary/auxiliary/context event targets and 8-state audits in the
  installed Chromium, Firefox and WebKit engines. The test itself cancels
  phone-target events defensively; no protocol handler is launched.
  Run with existing Playwright browsers: node fixture-safety.test.mjs
- lab-results.json: generated by the browser test from the tool's actual
  JSON download; 8 states / 24 per-CTA snapshots, no customer data.
- package.json: marks audit.js as CommonJS for the standalone Node tests.
- make-bundle.py: deterministic zip builder using Python standard library.
  After rebuilding/testing run: python3 make-bundle.py
- LICENSE.txt: license for all original code in this directory.

The bundle contains exact copies of the distributed tool, source, fixture,
tests, this README, license and generated example results. It excludes
itself. No third-party library is redistributed in the tool or bundle.

BACKGROUND SOURCES, READ 2026-10-24
CallRail installation:
https://support.callrail.com/hc/en-us/articles/5711709638541
CallRail DNI overview:
https://support.callrail.com/hc/en-us/articles/5711814948877
CallRail manual testing:
https://support.callrail.com/hc/en-us/articles/5711376255501
CallRail Swap.js documentation (relevant complete section):
https://apidocs.callrail.com/#swap-js
MDN telephone anchors:
https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/a#linking_to_telephone_numbers
MDN history navigation:
https://developer.mozilla.org/en-US/docs/Web/API/History_API/Working_with_the_History_API

No vendor source code is included or executed. Sources explain the
mechanisms; generated results only describe this original synthetic lab.

MDN inert attribute / DOM property (read 2026-10-24):
https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/inert
https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/inert
