Operations: holds, failures, recall and deletion
Product-specific procedures (who on the desk does what, notice templates, clocks) live in each product's own
runbook. This page covers what the engine and the reference runner do and report.
Holds
A hold keeps one file (or one record, or one part of a file) out of the delivery and lists it in the job result
as [path hash, reason, size, item hash]. Holds never carry the value or the real path. The desk sees reasons and
counts; it can release only the releasable sensitive reasons (below) for a source. A held file leaks nothing, so
holds are the engine's answer to "can't prove this is clean".
tests/test_techdocs.py checks that every code in the tables below exists as a literal in the runner or package.
Intake and unpacking
| Code |
Meaning |
excluded_unreadable |
a file the owner's exclusions couldn't be checked against |
risky_name |
a file name that looks like a credential store or key file |
archive_too_deep |
archive nesting past the limit |
bad_archive |
an archive entry escapes its directory or nests too far |
unreadable_archive |
an archive that won't open |
av_unscanned |
the malware scanner couldn't scan it |
malware |
the malware scanner matched |
macro_enabled |
an Office file with macros |
binary_unscanned |
a binary format the scrub can't read |
binary_secret |
a credential pattern in a binary file |
json_too_big |
a JSON document too big to parse whole |
Detection and gates
| Code |
Meaning |
residual |
the residual gate found a rule hit in what the scrub wrote |
recheck_hit |
the independent re-check found something |
recheck_unreadable |
the re-check couldn't read a document back |
detector_failed |
a detector errored under a profile with no fallback |
blind_term |
an owner-identity term in a confidential-seller deal |
blind_media |
media in a confidential-seller deal |
sheet_name_pii |
a spreadsheet tab name carries personal data |
Documents
| Code |
Meaning |
doc_encrypted |
password-protected |
doc_embedded |
an embedded object the rewrite can't reach |
doc_too_big, doc_too_deep, doc_too_long |
past the size, nesting or (PDF) page limits |
doc_unconvertible |
a legacy format that wouldn't convert |
doc_unparsed |
couldn't parse |
doc_xml_unsafe |
XML with entity or DTD constructs |
doc_rewrite_failed |
the rewrite didn't complete |
doc_residual |
the rewritten document still had a hit |
doc_secret |
a credential in a document |
pdf_scan_too_long |
a scanned PDF past the OCR page limit |
Images, audio and video
| Code |
Meaning |
media_unreviewed |
media under the default media policy (hold until the desk chooses deliver or redact) |
media_too_big, media_too_long, media_too_many_frames |
past the limits |
media_unparsed |
couldn't decode |
media_no_ocr |
text reading isn't installed |
media_ocr_failed, media_ocr_timeout, media_ocr_langs_missing |
text reading failed or lacks the language |
media_face_model_missing, media_face_unverified |
face detection missing, or the boxes couldn't be verified |
media_code_reader_missing |
barcode and QR reading missing |
media_asr_model_missing, media_asr_failed |
the speech model is missing or failed |
media_subtitles_unparsed |
subtitle track couldn't be read |
media_redaction_too_dense |
too many ranges or boxes to redact credibly |
media_redaction_unverified |
the redaction couldn't be read back as clean |
media_reencode_failed, media_strip_failed |
the re-encode or metadata strip failed |
media_timeout |
the A/V pass ran out of time |
media_voice_held |
audio with speech under voices: hold (the transcript still ships) |
Sensitive content
| Code |
Meaning |
Releasable |
special_category: + category |
a special category under special_categories: hold |
yes |
minor |
a minor's data under minors: hold |
yes |
image_unclassified |
an image that would need a content classifier, with no fallback |
yes |
pending_detector |
a detector the profile needs isn't registered (faces, voices) |
yes |
sexual_minor |
sexual content about a minor, under every profile; raises an escalation |
never |
image_sexual |
an image the classifier scores as sexual (no classifier is registered yet, so this doesn't fire today) |
never |
Record-level holds inside a table, mail box or chat export drop the record and count it as
sensitive_held: + reason; the file still ships.
Healthcare, git, sandbox
| Code |
Meaning |
health_parser_failed, health_unknown_kind |
a healthcare file the parser failed on or didn't recognize (a parser's own refusal reason is used when it gives one) |
dicom_unreadable, dicom_burned_in, dicom_burned_in_possible, dicom_encapsulated_document |
DICOM that's unreadable, has (or may have) burned-in text, or wraps a document |
random_stand_ins_git |
git history under random stand-ins (not built into the history rewrite) |
limit_cpu, limit_fsize, limit_killed, limit_wall, limit_output |
a sandboxed parser hit a limit |
parser_crash |
a sandboxed parser crashed |
Failure modes
- Permanent (
jobs/errors.py): retrying won't help. Unknown or unavailable profile; random stand-ins without
the identity map; Expert Determination without a valid certificate reference; a baked model that doesn't match
its hash (any profile); a baked model missing, or an ensemble member failing to load or failing the self-test,
under a no-fallback profile; a canary surviving the scrub or a re-check blind to a canary. Nothing has been
written when these fire. The job fails with retry: false.
- Transient: anything else fails the job with
retry: true; the control plane decides whether to requeue.
- Per file: everything in the hold tables. The job goes on.
- Fallback: under a profile with
fallback_allowed, a missing ensemble falls back to the rules plus name model
A and the report says so; strict profiles don't fall back.
- Errors leave the machine only through
safe_error and safe_trace: exception type, a masked message and frame
locations, never the text a parser or model was reading.
- Live credentials: a scanner run over the source counts credentials and names the provider (so the owner knows
what to rotate); never the value or location. Inside the parser sandbox the scanner has no network, so the
count is unverified (
liveVerified: false).
Recall and deletion requests
What the engine and runner provide; who decides and the clocks are each product's.
- Deletion request for a person. The control plane holds the narrow lookup key, which unwraps to the deal
salt. Keyed stand-ins: it computes
HMAC(salt, "<kind>:<normalized value>") and gets the stand-ins directly.
Random stand-ins: it computes the index and opens the map's lookup section. Either way it gets the stand-ins
the person became, without the data key or any delivered data. It can then find which deliveries carry them
and tell those buyers. Later scrubs keep redacting the values (redaction only grows). Removing the person
from later deliveries is a source-side or control-plane step; the engine has no per-person exclusion list for
people (the owner exclusions cover the owner's own terms and addresses).
- Recall of a delivery. Each delivery has a manifest with a Merkle leaf per record and file, so the affected
records can be named exactly. A per-buyer watermark lets a leaked copy be
attributed (method in the auditor edition). Recall itself (notifying buyers, revoking pulls) is
the control plane's.
- Crypto-shredding. Destroying the deal data key ends new linkage and makes the sealed map unreadable; a claim
whose map won't open under its key fails rather than starting an empty one. Destroying the package key also
ends watermark attribution for that version (keys.md).