Move the docs stacklet to Paperless-ngx 3.0.4 - #51
Merged
Conversation
Paperless 3.0 stopped rejecting a re-uploaded identical file unless PAPERLESS_CONSUMER_DELETE_DUPLICATES is set, and when it does reject one the task now *succeeds* carrying result_data.duplicate_of instead of failing with a message naming the twin. Left alone, re-sending the same letter would quietly file a second copy. Set the flag, and read the twin's id out of the structured result so the archivist still answers "already filed" and links the original. The 2.x failure-text path stays for older images.
Paperless migrates its database on the first 3.x start and 2.x will not boot afterwards, so anyone already rolled to 3.x by Watchtower cannot pin back without a backup taken before that boot. Say so, and say what to back up first.
`exec` looks for a program, and stack_cli is a shell function, so passing an explicit target failed with "exec: stack_cli: not found" and tore nothing down. The no-argument form worked, which is why it went unnoticed.
The first pass was written from the upstream source, which suggested a rejected duplicate ends as a successful task with no related documents. A real 3.0.4 disagrees: the task is marked failure, and related_document_ids holds the *twin's* id. Capture the payload from a running container instead and parse that. Adds an e2e that drives the bot's own Paperless client against the live container, so notes, duplicates, and owner scoping are answered by the server rather than by a fixture we wrote.
Loading documents straight into Paperless skips the archivist, so the corpus has no tags, correspondent, type, summary, or vault entry, and anything measured against it describes a system we do not ship. Point agents at tools/family-docs/ingest.py and say why.
Two e2e checks counted documents via search, which reads an index that updates asynchronously. Both passed alone and failed inside the full suite, where indexing sits behind a busier queue, so a lag looked like a filing bug and a permissions bug. Ask the document list instead: the question is what the archive holds, not what the index has caught up on.
Paperless 3.0 swapped Whoosh for tantivy, whose parser joins bare terms with OR. Since we also wildcard every word, "homer car insurance" matched 18 of 24 documents in the demo archive: any one word was enough. Join the words with AND so all of them have to appear. The same archive now answers "marge recipe" with 1 document instead of 11. Queries where the user wrote their own operator or a quoted phrase keep their structure, because injecting AND into either breaks it outright.
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.
Closes #50.
Moves
docsfrom Paperless-ngx 2.20.15 to 3.0.4. A watchtower pull of:latestonce made this jump by accident and broke document filing; this is the deliberate version, with the two things that actually break fixed.Duplicate detection was broken twice over
3.0 changed duplicate handling in two independent ways, and unmodified we would have hit both.
It stops rejecting duplicates at all. Rejection is now conditional on
PAPERLESS_CONSUMER_DELETE_DUPLICATES, which defaults off. With it unset, re-sending the same letter files a second copy and reports success. Now set in the compose.The rejection no longer carries a message.
_DUPLICATE_REscraped the twin's name out of the failure text. On 3.x there is no text, sowait_taskreturnedNoneand the archivist reported a generic upload failure instead of "already filed". It now readsresult_data.duplicate_ofand looks up the title, with the 2.x text path kept for older images.Worth knowing for reviewers: on a rejected upload 3.x sets
related_document_idsto the twin. Nothing butresult_dataseparates that payload from a successful filing.A second search word narrows again
3.0 also replaced Whoosh with tantivy, whose parser joins bare terms with OR. Since we wildcard every token too,
homer car insurancematched 18 of 24 documents in the demo archive: one word was enough to hit. Joining with AND fixes it, measured on the same archive:Queries where the caller wrote their own operator or a quoted phrase keep their structure, because injecting AND into either breaks it:
"birth certificate"would become"birth AND certificate"and match nothing, andinsurance OR recipewould become a parse error.This trades one failure mode for another.
homer car insurancenow returns 0, because that document is titled "Auto Insurance Policy 2026" and the word "car" is nowhere in it. Ranking and a confidence cutoff are tracked separately in FAM-18, along with the fact that the German compound rationale for the wildcard is now unverified (the demo set is English only).On method
The first version of the duplicate parser was written from the upstream source at v3.0.4, and the real server disagreed with it. Source reading said a duplicate task ends
successwith no related documents; a live 3.0.4 returnsfailurewith the twin's id present. The offline tests passed against the wrong fixture. What is pinned now was captured by uploading the same file twice and dumping/api/tasks/verbatim, andTestTaskApiShapein the new e2e keeps it honest by handing the real payload to the real parser.Two of my own e2e assertions counted documents through search, which reads an asynchronously updated index. They passed alone and failed inside the full suite. They now ask the document list instead.
Also here
stacktests down <stacklet>never worked.execcannot run a shell function, so an explicit target died withexec: stack_cli: not foundand tore nothing down. The no-argument form masked it.