Skip to content

Report a password-protected PDF as unreadable with cause protected - #96

Merged
flavorjones merged 3 commits into
masterfrom
card-5285-protected-pdf-cause
Oct 7, 2026
Merged

flavorjones merged 3 commits into
masterfrom
card-5285-protected-pdf-cause

Conversation

@flavorjones

@flavorjones flavorjones commented Oct 6, 2026 •

Copy link
Copy Markdown
Member

Motivation

An application that shows a lock placeholder for a password-protected PDF has to recognize one. The cell answers unreadable with no cause, so HEY matches mutool's stderr phrase cannot authenticate password inside the exception message (encryption_aware_pdf_previewer.rb:27). Nothing in Hot Cell specifies that phrase, so a change to mutool's wording, or to how the message is rendered, silently breaks the placeholder.

Details

  • A subclass of HotCell::UnreadableInput can define self.cause, and the worker sends that cause with the unreadable failure. unreadable stays permanent whatever its cause.
  • HotCell::Codes::PROTECTED ("protected") is the first such cause.
  • ToolOperation#run! takes causes:, a map from stderr pattern to the exception class to raise. Both PDF previewers map their password error to a new ProtectedDocument: mutool on cannot authenticate password, and Poppler's pdftoppm on Incorrect password. A password-protected PDF answers unreadable with cause protected. Every other failure of either tool answers as before.
  • docs/codes.md, docs/operation-api.md, docs/active-storage.md and the changelog describe the cause. docs/codes.md no longer says that every unknown cause is transient: only an unknown cause of killed is.

The cause is in the exception message, after the code (unreadable: protected: …). #104 exposes the failure on the exception, so an application reads error.hot_cell_failure.cause instead of parsing the message.

Copilot AI balanced review requested due to automatic review settings October 6, 2026 17:18

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

The response-code documentation currently gives contradictory permanence rules for unknown unreadable causes.

Review effort: Balanced
Findings: 1 Low severity

Open (1)
What changed in this PR

Adds a structured protected cause for password-protected PDFs instead of requiring stderr parsing.

Changes:

  • Propagates causes from unreadable-input exception subclasses.
  • Maps MuPDF password failures to protected.
  • Adds integration coverage and documentation.

[!TIP]
If you aren't ready for review, convert to a draft PR.
Click "Convert to draft" or run gh pr ready --undo.
Click "Ready for review" or run gh pr ready to reengage.

File Description
hotcell-server/​lib/​hot_cell/​worker.rb Propagates unreadable causes.
hotcell-server/​lib/​hot_cell/​server/​errors.rb Adds the cause extension point.
hotcell-core/​lib/​hot_cell/​codes.rb Defines PROTECTED.
activestorage-hotcell-server/​lib/​active_storage/​hot_cell/​server/​tool_operation.rb Maps stderr patterns to specialized failures.
activestorage-hotcell-server/​lib/​active_storage/​hot_cell/​server/​previewers/​pdf/​mutool.rb Detects password authentication failures.
activestorage-hotcell-server/​test/​previewers_test.rb Tests protected and ordinary unreadable PDFs.
docs/​operation-api.md Documents operation-defined causes.
docs/​codes.md Documents the protected cause.
docs/​active-storage.md Documents MuPDF behavior.
CHANGELOG.md Records both gem changes.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread docs/codes.md Outdated
djmb and others added 3 commits October 7, 2026 17:13
Applications rendering a lock placeholder for protected PDFs matched
mutool's stderr phrase in the failure message, which nothing specified.
A ProtectedDocument refusal now carries cause: protected onto the wire:
an UnreadableInput subclass may declare the failure's cause, run! maps
stderr patterns onto the subclass to raise, and the worker reports the
declared cause.
`PROTECTED` sat among the `killed` causes in `codes.rb`, under their
shared comment, and no doc mentioned that `unreadable` can carry a cause.
Move the constant beside `KILLED` with its own comment, document the
cause in `docs/codes.md`, `docs/operation-api.md` and
`docs/active-storage.md`, and add a changelog entry.
The Poppler previewer answered a password-protected PDF as `unreadable`
with no cause, unlike the `mutool` previewer. Map `pdftoppm`'s
`Incorrect password` stderr to `ProtectedDocument`.
@flavorjones
flavorjones force-pushed the card-5285-protected-pdf-cause branch from 916db97 to 6931732 Compare October 7, 2026 21:13
@flavorjones
flavorjones merged commit aaf5d71 into master Oct 7, 2026
33 checks passed
@flavorjones
flavorjones deleted the card-5285-protected-pdf-cause branch October 7, 2026 21:26
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.

3 participants