Auditor
Message routes and storage only handle ciphertext; no server code path decrypts message content.
1.0.11: SPEED PASS: each file goes to the model as the EXCERPT around the lines the deterministic part marked relevant to THIS requirement (decryptions, ciphertext and message content, per-room access checks, and the notification, log, search and webhook paths that carry a message), 12 lines on each side (the whole file when that is most of it); the omitted spans are marked in place and a finding on a line that was not sent is dropped. A server file of the server-managed group class with none of them (a file that only shares the messaging vocabulary) is not sent and the trace names it; a group scope left with nothing to assess keeps its deterministic verdict; the device-to-device class never drops a file; message schemas always go whole. Up to 48 files, most relevant first, instead of 24 whole ones. STABLE PARTS: the files are packed by path with content-defined part boundaries (decided by the path, never by the content) and the repository context lists no files, so an unchanged file lands in a byte-identical part the engine may answer from its verdict cache (per organisation, declared in the trace and in the attestation). The parts are sent in parallel up to what the engine admits (ctx.ai.maxConcurrentCalls) and aggregated in part order, so the verdict never depends on which answer arrives first. The assessment reason is ONE sentence of at most 30 words (the platform GPU spends 46 ms per output token and the reason was most of every answer). Requirement, categories and decision rule unchanged. (1.0.10: the operational-notification exclusion of 1.0.9 was vetoed whenever the file named "members" or "contacts", so an alert fanned out to the members of an organisation was still judged as person-to-person messaging. The veto is now conversation addressing only (a recipient or sender id, the participants of a room, a conversation, room, thread or chat id): a file that addresses a conversation is still the messaging feature and still fails in plain text. (1.0.9: an OPERATIONAL incident/alert notification system — opening an internal incident, notifying a dispute, delivering account-lifecycle notices, counting webhook deliveries — was classified as part of the messaging feature just because it reuses the same coarse vocabulary ("inbox", "channel", "message", "push", "send"): its audience is an operator or a third-party integration, never a person-to-person conversation. Excluded before the file is added to the messaging feature at all, unless it also addresses a person (recipient, sender, participant, member). (1.0.8: `followerCount`/`follower_count` dropped from the public-broadcast vocabulary: "follower" is a universal social-graph relationship (who follows whose profile), not a stream's audience, and it fired on an ordinary follow-count feature unrelated to messaging — a real checkout with a follow feature and a private group chat would have had that group misclassified as a public channel it never was. `viewerCount`/`subscriberCount` are unchanged: they name a stream's audience specifically. (1.0.7: the check now classifies every messaging file or schema into up to three CLASSES before any decryption analysis, each with its own verdict in result.scopes: public-broadcast (a many-to-many, audience-facing channel, detected by shape, never by whether the server can decrypt) is excluded from this requirement entirely, not-applicable, because no confidentiality is promised there (local to the chat-e2ee suite: the same channel keeps its normal verdict in every other suite); server-managed-group (a symmetric key tied to the room/group's own identity, decryption gated to that room's own membership or an assigned bot/participant) reports a real, HIGH finding when the decryption is unrestricted — this class can never come out clean without a restriction — and otherwise is judged under its OWN distinct guarantee, worded as confidential group messaging and never as end-to-end or point-to-point; device-to-device is the strict default for everything else, and only this class may pass under the device end-to-end guarantee. The check's own aggregate status is the worst of the published classes (ERROR > FAIL > PASS > NOT_APPLICABLE): a clean device-to-device class next to a legitimate server-managed-group class is PASS, never a fail borrowed from a class that never promised end-to-end, and never a pass that hides a class that does not qualify. (1.0.6: WHERE A FILE RUNS is decided from the FILE (and, when the file alone does not say, from the import graph of the checkout), never from a list of folder names of one particular repository, and a file whose server nature is UNPROVEN is never reported as server code. A monorepo has a SHARED layer — a package the browser bundle and the services both import — and the old rule read every ambiguous file as server: WebCrypto of the browser (`crypto.subtle` in a shared e2ee service that a client component imports) came out as "key generation in server code", once per product sharing the layer. The evidence is now, strongest first: the language (Python, PHP); a `server-only`/`client-only` import or a `'use server'`/`'use client'` directive; a location the framework declares as server (route.ts, middleware, pages/api, app/api, *.server.*, +server, wsgi/asgi); a browser runtime in the code (DOM member, Web Worker scope, `new Worker(`, a React client hook, a browser-environment polyfill such as fake-indexeddb or jsdom); a server runtime in the code (Node built-in, server-only package such as express/mongodb/winston/@aws-sdk, HTTP response sink, Lambda handler export); the IMPORT GRAPH (a module a client-declared file imports runs in the browser, a module that imports a server-proven module runs on a server); the folder convention (`workers/` is no longer one of them: a worker folder is a browser convention as often as a server one); a universal Web API of the browser with no server evidence at all; otherwise unproven, which is never server. Found by the attestation campaign of the platform (2026-09-25): 73 of the 252 high findings of every project were this one classification. A decryption is a CALL (`decrypt…(`, `.decrypt(`): an identifier that merely starts with the word (`decryptError`, a field naming a failure) and the import or re-export line of a decrypt function are references, never a server decrypting a message. (1.0.5: `assess` mode cuts the candidate set to what the chosen ENGINE serves in ONE call (`ctx.ai.maxInputChars`, published by the engine per its catalogue budget; `ENGINE_CALL_MAX_CHARS` = 32 000 when an older sandbox does not publish it), instead of filling the call up to the TRANSPORT cap of the proxy (`spec.promptMaxChars`, unchanged at 120 000). On a 1 319-file checkout the old packing produced single prompts of 17 672 / 26 709 / 29 351 tokens and the platform GPU answered "CUDA out of memory": the check ended in `error`. Every call of the same run under ~24 000 characters was answered normally. The part aggregation of 1.0.1 is unchanged: a HIGH in any part is a FAIL, an unsatisfied part is a FAIL, undecided never passes. (1.0.4: the browser asset folders of the server-rendered frameworks (static/, wwwroot/ and Laravel resources/js/) are classified as browser code, like public/ and assets/ already were: browser JavaScript of a Django, Flask or Go application was being analysed as server code (false positive found by the control bench of the audit scripts). (1.0.3: requires an AI engine (spec.requiresEngine: true): the check needs judgement and is executed only when the organisation provides an engine; the core catalogue runs without one. 1.0.2: applies only to a real messaging feature: a message or conversation model, a chat transport (socket, channel or pub/sub events of a conversation), a messaging protocol library (Signal, MLS, Olm/Megolm, XMPP) or a chat UI; messaging vocabulary alone (an error message pushed to a queue, a notification channel, a case signal route) is not-applicable with the reason; 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).)))))))))
| const BROADCAST_VOCAB = /\b(?:broadcast|live[-_]?stream|viewerCount|subscriberCount)\b/i; // checked FIRST -> scope 'public-broadcast', NOT_APPLICABLE, never evaluated |
| const ROOM_ACCESS_GUARD = /\bresolveRoomBot\(|\bgetBotByRoom\(|\bisRoomMember\(/; // a server decrypt found WITH this nearby -> scope 'server-managed-group' PASS candidate (its own certificate, never end-to-end); WITHOUT it -> HIGH, never clean |
| // device-to-device: a recognised protocol reference with NO decrypt call in the same file -> its own scope, its own certificate |
The full script is disclosed on request in a read-only viewer (never published on GitHub); the attestation binds to this exact hash.