The account-deletion flow hard-deletes or anonymises every store that holds the person's data; a soft-delete flag alone is not deletion. 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) plus Prisma and SQL files, analysed statically with the tokens, function units, calls, imports and route registrations of the static analysis kit. Schema files yield the personal-data stores (one block per model, table or collection) and the user/account store; a file with NO store declaration yields one store named after it only when its form declares a schema (a .prisma or .sql file, a models, schemas, entities or prisma folder), so an imperative migration or seed script that only writes data declares no store. Entry points of the deletion flow are functions named like an account deletion (deleteAccount, destroy_user, closeAccount, gdprErase, rightToErasure…), DELETE routes of users/accounts/me/profile (Next route exports, Express/Fastify/Koa/Hono, Nest @Delete, Django delete and perform_destroy views, Laravel Route::delete and destroy actions of user controllers) and routes named like a deletion (delete-account, erasure, gdpr); listeners of a deletion event (Mongoose pre/post remove hooks, @OnEvent user.deleted, Django post_delete signals, Laravel observers, TypeORM @AfterRemove) join the flow. From each entry the call graph is followed through same-file functions and functions imported by name (at most 3 module hops); every reached function is read for hard deletes, anonymisations and soft-delete flags, and each is attributed to the store its statement NAMES (prisma.user.delete, User.deleteMany, $user->forceDelete(), Order.objects.filter(...).delete(), DELETE FROM orders; a domain deletion helper of the application, a method whose name begins with a deletion verb and carries more words such as deleteUserAndRelatedData or purgeCustomerRecords, is a hard delete of the store its own NAME names and of no other; anonymize/scrub/redact calls; e-mail, phone or other personal fields set to null, empty or a placeholder). Paths listed in excludes (test, spec and tmp files, __tests__, __mocks__, fixtures, test, tests and audit-scripts folders) are never analysed. Nothing of the checkout is executed.
Decision rule
A file that declares no store block yields no store unless its form declares a schema: an imperative migration or seed script that only writes data (a client seeded from environment variables) is not the user table of the product. A unit of a user-interface file (a Next route segment page, layout, template, loading, error or not-found; a component, view, screen or page folder; a .jsx, .tsx, .vue or .svelte file) that RENDERS MARKUP and calls nothing named like a deletion or an anonymisation is a confirmation or notice screen, never an entry point of the deletion flow however its name reads (AccountDeletedPage): the trace names it. A screen that does call a deletion (a button wired to deleteAccountAction) is an entry like any other. Not applicable when no user or account store with personal-data fields is declared. FAIL (HIGH) when such stores exist and no entry point of an account deletion is found. FAIL (HIGH) when the flow reaches no hard delete and no anonymisation of any personal-data store: soft-delete-only when it sets a flag (deletedAt, is_deleted, SoftDeletes, paranoid, status deleted, active false), deletion-missing otherwise. FAIL (HIGH) when the user store itself is neither hard-deleted nor anonymised by the flow. Every other personal-data store is COVERED by a hard delete or an anonymisation naming it in the flow or in a deletion listener, or by a cascade declared in its schema block (onDelete: Cascade, on_delete=models.CASCADE, ON DELETE CASCADE, cascadeOnDelete, cascade: true) that references the user store while the user store is hard-deleted; a store not covered is MEDIUM (blocks only inside Extended suites). PASS when every store is covered; the summary names each store with what covers it (file, line, kind). Not judged by this check (declared): backups, replicas, caches, search indexes and third-party processors (the matter of deletion-propagation); a deletion delegated to a queue or job by NAME (queue.add('delete-user'), dispatch(new DeleteUserJob) resolved only when the job class is imported by name; otherwise the trace says the job is not followed); stores kept under a legal obligation (invoices, accounting records), which are reported MEDIUM for the organisation to document the basis; and whether the anonymised values are truly irreversible.
Type
deterministic
1.1.3: 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.2: false positive of the attestation of platform/apps/auth (2026-09-24), fixed in the script: dos correcciones más del mismo checkout. (a) Un SCRIPT IMPERATIVO de migración o semilla NO es un esquema: la regla de respaldo «un fichero de esquema sin declaración de tienda es una tienda con el nombre del fichero» sólo se aplica a un fichero cuya FORMA declara esquema (.prisma, .sql, carpeta models/schemas/entities/prisma); src/migrations/init-client.js, que siembra UN cliente de plataforma desde variables de entorno, se leía como la tienda de USUARIOS del producto (su name, phone y email como columnas de datos personales) y todo el flujo de borrado se juzgaba contra ella. (b) Un MÉTODO DE BORRADO DE DOMINIO es un borrado duro: un método cuyo nombre empieza por un verbo de borrado y lleva más palabras (authDao.users.deleteUserAndRelatedData(id), removeUserData, purgeCustomerRecords) cuenta como borrado duro de la tienda que NOMBRA su propio nombre —nunca del resto de la sentencia—, así que un flujo que borra por el helper de acceso a datos de la propia aplicación deja de reportarse como «no llega a ningún borrado duro». (1.1.1: una PANTALLA no es el flujo de borrado: una unidad de un fichero de interfaz que pinta marcado y no llama a nada con nombre de borrado o anonimización es una pantalla de confirmación o aviso, se nombra en la traza y nunca es punto de entrada; una pantalla que SÍ llama al borrado sigue siéndolo. 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. Unidades de entrada + listeners, grafo de llamadas 3 saltos, borrado duro o anonimización atribuidos a la tienda que NOMBRA la sentencia.))
// entries = function units named like an account deletion | DELETE routes of users/accounts/me | destroy of a user controller; listeners of user.deleted / post_delete / pre('remove') join the flow
// deletionOf(entries): breadth-first over the call graph (<= 3 module hops); each reached function yields hard deletes / anonymisations attributed to the store its statement NAMES, and soft flags
// no entry -> HIGH; flag only -> HIGH; user store untouched -> HIGH; other store without delete, anonymisation or cascade -> MEDIUM
The full script is disclosed on request in a read-only viewer (never published on GitHub); the attestation binds to this exact hash.