Skip to content

docs: hold DLEAPP artifact claims to the sourced-evidence standard - #48

Merged
abrignoni merged 1 commit into
mainfrom
fix/doc-claims-dleapp
Aug 1, 2026
Merged

docs: hold DLEAPP artifact claims to the sourced-evidence standard#48
abrignoni merged 1 commit into
mainfrom
fix/doc-claims-dleapp

Conversation

@abrignoni

Copy link
Copy Markdown
Owner

Applies fixes from an audit of all 34 DLEAPP artifact files (43 findings: 17 moderate, 26 minor). Citations were added only where a source was verified to support the specific claim; everything unverifiable was reworded to what the code and data show.

The main finding was not what the scan predicted

A vocabulary scan had flagged 10 completeness claims ("Every Discord account…", "All structured Roblox Player log events…"). On reading the code, only two were indefensible — the rest are scoped to a container and accurate. The larger and more repeated problem was ELSE-branch assertion: stating a specific meaning for a missing, NULL or unresolved value.

Three of the four conversation views asserted a message direction on rows where none was established:

  • discordMessages labeled every message "Received" whenever the signed-in account id could not be resolved (no Sentry scope, no Local Storage).
  • whatsappMessages labeled system entries "Incoming".
  • wireIndexedDb labeled sender-less events (conversation-created, member events — kinds the artifact deliberately includes) as received.

All three now emit a blank direction. signalMessages already did this correctly and was the in-repo model.

signalMessages reported "File not in extraction" for what are eight distinct failure paths in decrypt_attachment — including a missing decryption key. Only four are distinguishable from the call site, so it now reports those four ("Attachments folder not in extraction", "No key recorded", "No stored path recorded", "File not in extraction") and collapses the indistinguishable remainder into "Could not decrypt" rather than asserting a cause.

Verified empirically rather than assumed

  • The WhatsApp system-message discriminator was validated against the local corpus: ZMESSAGETYPE 6 is 265 rows, all with ZISFROMME clear and all in group chats. An alternative discriminator (ZGROUPEVENTTYPE) was tested and rejected — it is populated on ordinary messages too.
  • Wire's created_at for MLS identity was checked against sample data (10-digit value resolving to 2026, not 1970). It was already correct; no change made, unit recorded.

Other corrections

Roblox UDMUX Address/Port no longer labeled "Public Server"/"Public Port" (the file's own notes decline to guarantee that relationship); Roblox log timestamps no longer asserted as UTC when the parser returns naive datetimes for lines without an offset; a Roblox WebView2 column no longer claims "DPAPI Header" without validating the provider GUID; the WebView2 user-id attribution fallback (which can misattribute on account-switched profiles) is now disclosed on all three affected artifacts; wireCookies switched from a hand-built read-only URI to the repo's open_sqlite_db_readonly helper; the Wire service-worker encryption note is applied only to rows with a resolved asset URL instead of unconditionally.

Citations added (verified)

Discord Snowflake ID format, Microsoft DPAPI, Chromium page-transition types and History schema, AWS CloudFront signed-URL expiry. Two claims could not be sourced and were reworded rather than cited: Discord's per-message attachment cap (absent from the Message resource docs) and the Wire AVS call end-reason enum — both now state the limitation instead of implying authority.

Compiles clean; lint gate passes with zero new warnings; all 17 tests pass.

🤖 Generated with Claude Code

Applies fixes from an audit of all 34 artifact files (43 findings).
Citations were added only where a source was verified to support the
specific claim; everything else was reworded to what the code shows.

The dominant defect was ELSE-branch assertion: stating a specific
meaning for a missing, NULL or unresolved value. Three of the four
conversation views asserted a message direction on rows where none was
established:
- discordMessages labeled every message 'Received' whenever the
  signed-in account id could not be resolved.
- whatsappMessages labeled system entries 'Incoming'.
- wireIndexedDb labeled sender-less events (conversation-created,
  member events) as received.
All three now emit a blank direction, matching signalMessages, which
already handled this correctly.

signalMessages reported 'File not in extraction' for what are eight
distinct failure paths in decrypt_attachment. Only four are
distinguishable from the call site, so it now reports those four and
collapses the rest into 'Could not decrypt' rather than asserting a
cause it cannot tell apart.

Completeness claims were corrected where the code contradicted them
(discordCacheRecords excludes bundle assets; discordUsers only sees
accounts in the endpoints it decodes) and left where they are scoped
to a container and accurate.

Also: UDMUX addresses no longer labeled 'Public Server'; Roblox log
timestamps no longer asserted as UTC; a DPAPI header no longer claimed
without validating the provider GUID; Roblox WebView2 user-id
attribution fallback disclosed; wireCookies switched to the read-only
sqlite helper; Wire service-worker encryption note applied only to
resolved asset rows.

Verified empirically rather than assumed: the WhatsApp system-message
discriminator against the local corpus (an alternative candidate was
tested and rejected), and Wire's MLS created_at unit, which was already
correct and needed no change.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@abrignoni
abrignoni merged commit b43456c into main Aug 1, 2026
5 checks passed
@abrignoni
abrignoni deleted the fix/doc-claims-dleapp branch August 1, 2026 06:02
stark4n6 pushed a commit to stark4n6/DLEAPP that referenced this pull request Aug 5, 2026
Adds admin/scripts/check_claim_language.py, ported from the canonical
iLEAPP implementation, and wires it into the existing lint workflow as
an added step in the same job.

The check reads each scripts/artifacts/*.py module with ast, evaluates
its __artifacts_v2__ literal, and matches the name and description of
every entry against a vocabulary of phrasing that past audits found to
assert what the parsed data does not establish: completeness words,
attributions of an act to "the user", certainty words. Those two fields
reach the examiner through the HTML report and the LAVA manifest, so a
claim there is quoted in casework; PR abrignoni#48 fixed them by hand and nothing
has watched them since.

It also fails on a stale allowlist entry, so an entry cannot outlive the
description it was written for and silently shield the next claim under
the same key, and prints NOT CHECKED modules on every run so the
coverage hole stays visible rather than being assumed empty.

Ten fields fired on first run. Nine are reworded to what the data shows;
in each the trigger word was removable without losing information --
three cases of "complete <value>" describing one column, six leading
"All"/"Every" over a set the following clause already scopes. The tenth
is allowlisted: discordCacheRecords' match is inside its own hedge
("a partial record ... rather than a complete one").

Known coverage gap, documented in the docstring: robloxWindows.py builds
__artifacts_v2__ through a helper rather than a literal, so its four
Windows artifacts are not read. Their descriptions are inherited from
the macOS modules, which are checked.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant