Every outbound integration that receives personal data in the arguments of its calls is listed in a sub-processor or third-party inventory entry that names the fields sent and references a processor agreement. No AI engine is involved: the verdict is reproducible from the source alone.
Inputs
Non-test code files of the checkout (JavaScript, TypeScript, Python, PHP) analysed statically (tokens, function units, calls, imports) plus Markdown, text, YAML, JSON, TOML and CSV documents. A call site is an integration when its callee is bound to a provider SDK (e-mail, SMS, CRM, support, analytics, error tracking, AI, storage, payment, notifications, identity: by the callee's own name, by the import its root is bound to, or by the expression the root variable was built from) or when it is an HTTP client call (fetch, axios, got, ky, superagent, requests, httpx, urlopen, Guzzle, Http::) whose URL literal, URL variable or client base URL names an external host. The personal data sent is read from the call's arguments: identifiers and object keys of the personal-data vocabulary outside string literals (a key whose value is a literal does not count), template and f-string interpolations, and one level of expansion of a variable passed as argument and assigned earlier in the same function; strong fields (e-mail, phone, names, birth date, identifiers, address, financial, health, location) and contextual ones (name, username, city, country, ip, user agent…) are told apart. Inventory documents are found by name (sub-processors, third parties, processors, data flows, DPA, vendors, integrations, privacy) or by content, and parsed into entries: Markdown table rows, list items and sections, YAML and JSON mapping nodes, CSV rows; the provider's entry is the one whose name (or text) names the provider or the host's domain. Paths listed in excludes are never analysed. Nothing of the checkout is executed.
Decision rule
Not applicable when no outbound integration exists, or when no call towards one carries personal-data vocabulary in its arguments (an SDK that is only imported or called with opaque identifiers is listed, not judged). FAIL (HIGH) when integrations receive strong personal data and no inventory document exists (MEDIUM when only contextual data is sent), and for each provider receiving strong personal data that no inventory entry or mention names; a provider receiving contextual data and not named is MEDIUM. For a named provider: an entry that declares no personal-data field or category, or that omits a strong field the code sends (by name, by a normalised variant, or by a category word such as contact, identity, address, payment, location, device), is MEDIUM (fields-not-declared); an entry without a DPA, processor terms, standard contractual clauses, contract or legal/terms link is MEDIUM (agreement-not-referenced). MEDIUM blocks in Extended suites. PASS when every integration receiving personal data has an entry with fields and agreement; the summary names the entry per provider (file, line). Not judged by this check (declared): an object passed whole to the SDK (`send(user)`, `...profile`) or built outside the calling function beyond one assignment, data reaching a provider through a client-side snippet loaded from HTML, whether the agreement referenced is signed or current, the lawfulness of the transfer, and what the provider does with the data.
Type
deterministic
1.1.1: a callee whose root is a name that `Object.prototype` also carries (`build().toString()` tokenizes to the bare callee `toString`; also `constructor`, `valueOf`, `hasOwnProperty`) was looked up in the plain object that holds the imported names, so it resolved to the INHERITED FUNCTION instead of to nothing and the whole check died with "name.includes is not a function". Only a real binding counts now, and the name of a unit is always read as a string. Found on a 1 319-file checkout (2fa-available and session-expiry-rotation, 2026-09-24); the same line was in the 15 scripts that walk the call graph, so all fifteen ship the fix. (1.1.0: deterministic: the rule runs over the static analysis kit (tokens, function units, calls, imports, routes) with no AI engine; exact decisionRule and languages published; not-applicable with the reason when the checkout gives nothing to evaluate. Integrations are CALL SITES (a callee bound to a provider SDK by import, initialiser or name, or an HTTP client call whose URL or base URL names an external host) and the personal data sent is read from the call ARGUMENTS (vocabulary outside string literals, template and f-string interpolations, one assignment followed); the inventory is parsed into entries (markdown tables/lists/sections, YAML, JSON, CSV) that must declare the sent fields (name or category word) and an agreement. Not judged: objects passed whole beyond one assignment, client-side snippets inside HTML, validity of the agreement, lawfulness of the transfer. (1.0.2: never analyses temporary files (*.tmp.*; spec.excludes follows AUDITOR_ANALYSIS_EXCLUDES). (1.0.1: never analyses test, spec, fixture and mock paths nor the auditor's own scripts (spec.excludes = AUDITOR_ANALYSIS_EXCLUDES); a fixture-looking secret (sk_test_, example, dummy) in real code is LOW, informative; every model call stays under the engine prompt cap (spec.promptMaxChars = AUDITOR_AI_PROMPT_MAX_CHARS): assess mode sends the candidate set in parts and aggregates the verdicts (a HIGH in any part is a FAIL, an unsatisfied part is a FAIL).)))
// integration = CALL SITE: callee bound to a provider SDK (import, variable built from it, or its own name) or an HTTP client call whose URL / base URL names an external host
// personal data sent = identifiers and object keys of the vocabulary in the ARGUMENTS (outside string literals; `${…}` read; one assignment of an argument variable followed)
// inventory entries: markdown table rows / list items / sections, YAML-JSON mapping nodes, CSV rows -> the provider's entry must declare the sent fields (name or category) and an agreement (DPA, processor terms, SCCs, legal link)
// no inventory -> HIGH (strong) / MEDIUM (contextual); provider not named -> HIGH / MEDIUM; entry without fields or agreement -> MEDIUM
The full script is disclosed on request in a read-only viewer (never published on GitHub); the attestation binds to this exact hash.