chore: check artifact name/description for unsupported claim language - #387
Merged
Conversation
Artifact `name` and `description` are examiner-facing: they render into the HTML report, get written to the LAVA manifest, and are quoted in casework. The project standard is to say what the data is and where it came from, not what it means about the world or who performed an act, unless the data establishes it or a cited source documents it. This adds the check already running in iLEAPP and ALEAPP. It parses each module in scripts/artifacts with `ast`, evaluates the `__artifacts_v2__` literal, and matches both checked fields against a vocabulary of completeness, attribution, and certainty phrasing. Of 164 artifact modules, 155 are statically readable (246 v2 entries) and one match was triaged: takeoutGoogleMail's "All Mail" is Gmail's own system label, shipped by Takeout as a file literally named "All mail Including Spam and Trash.mbox" -- which is the glob the artifact searches for. It names the mailbox being parsed, not a claim of completeness, so it is allowlisted with that reasoning inline. The remaining 9 modules build `__artifacts_v2__` from a helper call or a shared note constant, so their fields never reach ast.literal_eval and are never checked. The run prints them as NOT CHECKED every time, and they are also listed in the script's docstring so the coverage gap is documented rather than implicit. Giving those modules a literal dict is a behaviour change to each module and belongs in its own pull request. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Ports the
check_claim_language.pyguard already running in iLEAPP and ALEAPP into RLEAPP, wired into the existing Python Lint Check workflow as an extra step in the existing job.What it guards
An artifact module's
__artifacts_v2__nameanddescriptionare not developer notes. They render into the HTML report, get written into the LAVA manifest, and from there they are pasted into examination notes and quoted in court. A description that says an artifact holds "every message the user sent" is a statement about a person's conduct that the underlying return does not make.The standard for those two fields:
The failure mode the check exists to stop is the partial fix: someone corrects a module's docstring and the
descriptionfield a few lines above it keeps the original wording, so the claim keeps shipping to reports. Prose fixes go stale exactly where nothing is watching them.How it works
Parses each module under
scripts/artifacts/withast, evaluates the__artifacts_v2__literal, and matchesnameanddescriptionagainst a vocabulary of phrasing that has historically signalled an unsupported claim: completeness (all,every,complete,entire), attribution of an act to a person (the user viewed,user-created,typed by,manually), and certainty or inference (proves,always,reliable,visited,habits).The vocabulary is deliberately blunt. It flags wording that is usually a claim, not wording that is always one, so a match is a prompt to look rather than a verdict.
Every alternative is anchored with an explicit
\b. Expressing the boundary as a trailing space instead (all) matches inside "call log" and "install ", which in an earlier draft of this check turned 35 of 37 raw hits into false positives. Word boundaries also keep hedges quiet: neither "unreliable" nor "incomplete" trips.Result in this repo
164 artifact modules scanned. 155 are statically readable, covering 246 v2 entries. One match, triaged as a legitimate exception; the check exits 0.
The one allowlist entry
takeoutGoogleMail:description— "Parses MBOX mailboxes (All Mail, Deleted) from a Google Takeout export, including attachments.""All Mail" is Gmail's own name for the system label, and Takeout ships it as a file literally called
All mail Including Spam and Trash.mbox— which is the glob this artifact searches for in itspaths. The word names the mailbox being parsed, not a claim that the parse recovered every message the account ever held. This is directly analogous to the Box "All Files" entry in the iLEAPP allowlist: renaming it would make the artifact harder to match to what the examiner sees in the export. The reasoning is written inline next to the entry.Allowlist discipline
A match is resolved one of two ways:
(filename, artifact_key, field)tuple toALLOWLISTwith an inline comment saying why. The allowlist is a record of decisions someone made on purpose; it is not a place to park a description nobody wanted to rewrite.A stale
ALLOWLISTentry — one that no longer matches anything — fails the run. It means the description was reworded or the key changed, and the entry now shields nothing except the next claim that lands under the same key.Documented coverage gap: 9 dynamic modules
Nine modules build
__artifacts_v2__by calling a local helper (_meta(...),_m(...)) or by referencing a shared note constant (_NOTE,_REGEX_NOTE) rather than writing a literal. Their fields never reachast.literal_eval, so no claim language in them is checked:The run prints this set as
NOT CHECKEDon every invocation, so the hole cannot go quiet. It is also written into the script's docstring so the gap is a documented fact rather than something a reader has to rediscover from output. The list is not maintained by hand — the run is the authority if the two ever disagree.Bringing one of these under the check means giving it a literal
__artifacts_v2__, which is a behaviour change to the module and belongs in its own pull request.Verification
python3 admin/scripts/check_claim_language.pyexits 0 (155 checked, 9 NOT CHECKED, 1 allowlisted).accPingerdescriptionto"all records the user viewed"exits 1 and printsscripts/artifacts/accPinger.py:accPinger:descriptionwithmatched: all, the user viewed. Reverted.--listshows the single allowlisted match; a stale entry is reported and exits 1.python3 -m py_compileclean;admin/scripts/lint_changed.pyreports 0 warnings on the new file.admin/test/scripts/all pass (2 + 2 + 13 tests).🤖 Generated with Claude Code