Skip to content
Ritesh FirodiyaGet in touch

Work / Chitragupt / Wiki / Entities

inbox-document-status

Entitycanonicalverified 2026-08-10

INBOX.DOCUMENT-STATUS

Document status

Summary

The closed set of statuses every document row can carry. The persisted enum lives in packages/shared/src/schemas/document.ts (DOCUMENT_STATUSES). Any status outside this set is a bug — either the parser emitted an unknown state or the UI invented copy that doesn't exist.

Canonical values

The 14 persisted values below are the source of truth. UI copy strings live in apps/website/src/components/inbox/StatusBanner.tsx and must render every value.

Key Meaning Terminal? Route
unreviewed Parser succeeded; user has not confirmed yet. Default post-parse state. no review-document
confirmed User pressed "Looks good" on Review. Ledger fan-out has run. no (may become superseded) review-document
needs_classification Parser could not pick a form_type (below classifier confidence floor). User picks one via classifyDocument. no review-document-failed
needs_ocr Scanned PDF with too few extractable characters — LLM fallback did not rescue. no review-document-failed
parse_pending Transient parser failure (LLM API down, timeout, download error). Hourly hourlySweepParsePending auto-retries up to MAX_AUTO_PARSE_RETRIES; user can retry immediately via the Sync button (rescanDocument), which resets retry_count. no review-document-failed
pending_password Encrypted PDF; the parser needs the user's password. no review-document-locked
pending_identity_confirmation Parser ran but the extracted identity does not match an existing one. Sub-flow (own / transfer / entity-link) is disambiguated by transfer_to_member_uid + identity_id fields on the row. no review-document-owner-mismatch · review-document-transfer-pending
view_only Uploaded on the Free tier; no parse attempted. Backfilled on plan upgrade. no review-document-view-only
superseded A newer document with the same (form_type, ay, instance_key) was ingested; ledger entries have been reconciled to the new doc. yes (hidden from Inbox by default)
rejected_format Terminal — file is not a parseable PDF/XLSX (wrong magic bytes, unsupported encoding, non-decryptable). User must re-upload. yes review-document-failed
rejected_quota Upload exceeded workspace storage cap. Bytes were deleted from GCS. yes (banner on upload; row visible in Inbox)
rejected_oversized Upload exceeded per-file cap (MAX_INGEST_BYTES = 100 MB). yes (banner on upload; row visible in Inbox)
rejected_duplicate Byte-identical content hash matches an existing non-rejected doc. Stamped with duplicate_of. yes (hidden from Inbox by default)
rejected_owner_denied User confirmed the doc isn't theirs; a scheduled job sweeps these after a 7-day grace. Uploader can undo via restoreOwnership until the sweep runs. yes (banner in Inbox)
rejected_transfer_denied Family-transfer recipient declined; doc bounces back to the uploader. The uploader can re-route or delete via denyOwnership → rejected_owner_denied. yes review-document-owner-mismatch
rejected_parser_error Hourly hourlySweepParsePending gave up after MAX_AUTO_PARSE_RETRIES transient failures. Distinct from rejected_format — the file may be parseable but our runner couldn't complete. User re-uploads or contacts support; support can inspect the retry_count on the row. yes review-document-failed

Confirmation allowlist

The user can only flip a doc to confirmed from one of:

  • unreviewed
  • pending_identity_confirmation

Enforced by CONFIRMABLE_STATUSES in apps/functions/src/_lib/document-status.ts. Both confirmDocument and confirmAisCode route through the same assertConfirmable helper — no other status may short-circuit to confirmed.

Ownership allowlists

  • Confirm ownership (confirmOwnership): pending_identity_confirmation → unreviewed only.
  • Deny ownership (denyOwnership): {pending_identity_confirmation, rejected_transfer_denied} → rejected_owner_denied.
  • Restore (restoreOwnership): rejected_owner_denied → pending_identity_confirmation.

Related

Sources

  • packages/shared/src/schemas/document.ts — DOCUMENT_STATUSES (authoritative)
  • apps/functions/src/_lib/document-status.ts — confirmation + denial allowlists
  • apps/website/src/components/inbox/StatusBanner.tsx — copy per status
  • .context/designs/web/inbox/inbox.html
  • .context/designs/web/inbox/inbox-locked.html

Every project of mine is written down like this.

Read the résumé