# Extracted from paperless-ngx src/documents/tests/search/test_translate.py
# and test_query.py (query strings passed to translate_query/parse_user_query
# before Tantivy translation, i.e. the whoosh-syntax "raw" side of each case).
# Extracted in full: every string literal reachable as a
# translate_query()/parse_user_query() argument, including f-string/
# parametrize-fed values, not just directly-quoted literals.
#
# Section markers below record which lines are expected to structurally
# compare against the real whoosh oracle vs. which are expected to skip via
# an allowlist.py entry (see that file's docstring for the prefix
# convention). Skip accounting is enforced by test_differential.py, which
# reports the *specific* matched allowlist reference for every skip (run
# `pytest tests/differential -rs` to see the per-query breakdown): these
# markers are just a human-readable map of what to expect where.

# --- compared: basic terms, booleans, dashes, field/numeric coercion -----
tag:foo,bar
tag:foo,bar,baz
tag:foo,type:bar
correspondent:foo,bar
created:2020 OR foo
(created:2020 OR invoice)
# Entry 15's correctly-fielded OR-context shape: a known TEXT field's
# multi-token value inside a user-written OR (bare and wrapped in a
# degenerate paren group, which analyze()'s entry normalization collapses
# before context resolution, so both spellings resolve OR).
content:foo OR title:multi-word
(0) OR (title:00-000)
# Same divergence through a quoted comma KEYWORD value: the keyword
# analyzer splits on the comma with no minimum token length, so both
# 1-char halves survive and resolve against the enclosing OR. tag_id pins
# the once-forgotten non-lowercase KEYWORD sibling cell (the allowlist
# derives its field alternation from the registry precisely so no KEYWORD
# field can be silently missing again).
NOT ((0) OR (tag:'0,00'))
(0) OR (tag_id:'0,00')
# The İ pathway: U+0130 is the only character whose str.lower() expands
# to two codepoints, so a single-character value survives minsize after
# lowercasing and the demoted text splits into two tokens (found by a
# deep fuzz soak, through both the unknown-field and bare-JSON
# demotion spellings).
zzz:İ
attrs:İ
# DIVERGENCES.md entry 43: whoosh case-folds bracket-range bounds into
# the AST; whoosh-compat's TermRange keeps the typed case (AST-level
# only: a text TermRange is unsupported at emit, entry 5).
title:[A* TO B]
bank statement
bank   statement
bank statement today
type:invoice
title:invoice
path:/foo/bar
path:foo
type_id:5
path_id:7
type:[2020 TO 2021]
H52.1 - Kurzsichtigkeit
bar - baz
foo -
foo - bar - baz
foo + bar
term -other
-term
+term
foo -bar +baz
invoice
h52.1 - kurzsichtigkeit
H52.1 - asd
h52.1 -
. -
h52. -
.12 -
h52.1 - ku
type:invoice

# --- compared: unknown-field colon (foobar isn't a registered field; both
# taggers demote it to text identically: unlike the dotted-name case
# below, there's no dot for whoosh-compat's tagger to treat specially).
foobar:today

# DIVERGENCES.md entry 42: is_shared exists in the v2 whoosh schema (a
# BOOLEAN permission-bookkeeping column) but is deliberately not a
# registered field here, so the oracle parses a typed boolean Term while
# whoosh-compat demotes the unknown field to a multifield text search.
is_shared:true

# --- compared: NUMERIC (U64) fields must NOT be caught by date-field
# rewriting (only created/modified/added are date fields): both scalar
# values and bracket ranges.
asn:20240101
id:20240101
page_count:12345678
num_notes:20231201
asn:[2000 TO 2024]
id:[2000 TO 2024]
page_count:[2000 TO 2024]

# --- compared: single-word natural-date keywords (whoosh's stock English
# grammar understands these natively, no app-level rewrite needed), plus
# compact numeric date scalars (exact instants go through the *single-value*
# date path, which, unlike ranges below, whoosh's LocalDateParser tz
# override does correctly reach).
created:2020
created:202003
created:today
created:yesterday
created:20240115120000
created:20231201
added:today
added:yesterday
added:20231201
modified:20231201

# --- KNOWN DIVERGENCE (DIVERGENCES.md entry 3, allowlist.py): a boost on
# a natural-date keyword. paperless-ngx v2's rewrite_natural_date_keywords
# substitutes "added:yesterday" for a literal bracket range before whoosh
# parses anything, and whoosh's syntax.RangeNode has has_boost = False, so
# BoostPlugin.clean_boost demotes the "^2" to a stray search term.
# whoosh-compat never rewrites the keyword, so the boost binds to the
# DateRange. NOT a general date-boost divergence: real whoosh preserves a
# boost on "created:2020^2" and friends (measured EQUAL), and a boost
# after a bracketed range is dropped identically on both sides.
added:yesterday^2

# DIVERGENCES.md entries 36 and 46: a boost on a value the parser or
# analyzer splits. tag_id pins entry 36's once-forgotten comma sibling;
# title pins entry 46's analyzer-split sibling.
tag_id:alpha,beta^2
title:foo-bar^2

# --- compared: quoted multi-word natural-date keywords (whoosh's own
# multi-word-value quoting mechanism; contrast with the unquoted forms
# further below, which are a documented divergence).
created:"previous quarter"
added:"previous quarter"

# --- KNOWN DIVERGENCE (design, allowlist.py): bare (non-bracketed)
# dashed/dotted/space-separated single-value ISO dates on a date field.
# whoosh's DateParserPlugin.text_to_dt fails to fully parse these (its
# grammar has the same "datetime" Bag before "simple" Choice ordering
# whoosh-compat fixed, see dateparse.py's English.setup()), but
# ErrorNode.query() falls back to running the *original* wrapped node's
# query() method regardless (query.error_query just annotates an .error
# attribute onto whatever query that produces), which for a DATE/DATETIME
# field is DATETIME.parse_query's own separator-stripping self-parse
# (fields.py): the value comes out numerically correct, but as a
# query.NumericRange, a completely different mechanism/AST shape than
# whoosh-compat's uniform DateParserPlugin-grammar-only architecture (see
# module docstring, parser/dateparse.py) ever produces. whoosh-compat has
# no field-level self-parse fallback concept to replicate: fixing the same
# bundle-ordering bug makes its *single* grammar path parse these directly.
created:2020-01-01
created:2020-01
created:'2020.01.01'
# DIVERGENCES.md entry 48: quoted T-separated datetime values. whoosh's
# grammar has no T separator and bottoms out in _NullQuery (matches
# nothing); whoosh-compat parses the correct DateRange, honoring a
# trailing Z as the UTC designator.
added:'2026-08-04T10:30:00'
added:'2026-08-04T10:30:00Z'
# DIVERGENCES.md entry 54 (superseding entry 49): the bare unquoted
# sibling. Colon tokenization cuts the value mid-token; whoosh swallows
# the dangling separator and searches the truncated period ANDed with
# the leftover time tokens, whoosh-compat diagnoses BAD_DATE (so these
# three lines take the entry-6 diagnostic skip).
added:2026-08-04T10:30:00
added:2026-08-04T10:30:00Z
added:2026-08T10:30
# DIVERGENCES.md entry 50: no-separator T-fused values. whoosh's grammar
# cannot read them at all (_NullQuery, matches nothing); whoosh-compat
# reads year-T-month, joining a colon-split trailing token into a day.
# The double-quoted spelling is entry 45's search-time crash cell.
created:2026T10
added:2026T10:30
added:'2026T10'
added:"2026T10"
# DIVERGENCES.md entry 45: the double-quoted sibling. whoosh's ErrorNode
# fallback wraps a PhraseNode here, yielding a Phrase that crashes at
# search time; whoosh-compat parses the correct day-period DateRange.
created:"2020-01-01"

# --- KNOWN DIVERGENCE (DIVERGENCES.md entry 6, structural not pattern-based): bad
# date: test_differential.py skips on any non-empty diagnostics list.
# (month=13 in the 8-digit compact form.)
added:20231340

# --- KNOWN DIVERGENCE (whoosh-bug, allowlist.py): bracketed date ranges --
# real whoosh's LocalDateParser tz-reversal override never reaches range
# bounds (a confirmed defect in DateParserPlugin.range_to_dt's wiring, not
# an intended whoosh design choice); whoosh-compat applies tz conversion
# uniformly instead of reproducing the bug. See allowlist.py's "whoosh-bug:"
# entry for the bracket-range pattern.
created:[2020 TO 2021],added:[2022 TO 2023]
created:[20200101 TO 20201231]
created:[2020-01-01 TO 2020-12-31]
# This bound pair also exercises a second, distinct symptom of the same
# range_to_dt root cause (no ToEnd around the bare grammar's date_from):
# real whoosh silently collapses both bounds to the whole of 2020 instead of
# June 15-20 (confirmed directly against the oracle: verify with
# oracle_parse("created:[2020-06-15 TO 2020-06-20]", ...) -> NumericRange
# spans all of 2020). whoosh-compat's range_to_node now requires full
# consumption of each bound (matching text_to_node's existing ToEnd usage)
# and does not reproduce the collapse.
created:[2020-06-15 TO 2020-06-20]
# Joint disambiguation of a bracketed range's two bounds
# (timespan.disambiguated's range heuristics): a backward-reading month
# range borrows the previous year, day-precision bounds crossing a year
# boundary copy the end's year, an overnight time range pushes the end
# past midnight, and backward years swap. Each bound must stay ambiguous
# until the combine step; disambiguating them independently against the
# basedate produces inverted lo > hi ranges that match nothing.
added:[dec to feb]
added:[dec 25 to jan 5]
added:[noon to 3am]
added:[3pm to 10am]
added:[feb to may]
added:[2021 to 2020]
created:[dec to feb]
created:[2020 to]
created:[to 2020]
title:x,created:[2020 TO 2021]
added:[-7 days to now]
added:[-1 week to now]
created:[-1 month to now]
modified:[-1 year to now]
added:[-3 hours to now]
added:[-1 WEEK TO NOW]
added:[now-7d TO now]
added:[now+1h TO now-1h]
created:[-999yrs to now]
added:[-1y to now]
added:[-1yr to now]
created:[-3mos to now]
added:[-3mos to now]
added:[-3mo to now]
added:[-2wks to now]
added:[-2wk to now]
added:[-5dys to now]
added:[-5dy to now]
added:[-1hrs to now]
added:[-1hr to now]
added:[-10mins to now]
added:[-10min to now]
added:[-30secs to now]
added:[-30sec to now]
created:[2020 TO 2021]
created:[2020-01-01T00:00:00Z TO 2021-01-01T00:00:00Z]
created:[2026-01-01T00:00:00Z TO 2026-06-01T00:00:00Z]
created:[2026-01-01T00:00:00Z TO 2026-06-01T00:00:00Z],added:[2026-05-01T00:00:00Z TO 2026-06-01T00:00:00Z]
created:[20200101 TO 20201231]
created:[2020 TO 2020]
created:[2018 TO 2021]
added:[2022 TO 2023]
modified:[2021 TO 2021]
created:[2020 to 2020]
created:[2025 TO 2020]
# DIVERGENCES.md entry 44: an exclusive bracket on an exact-bound date
# range. whoosh's DateRangeNode drops the typed {} flags (always
# inclusive-both); whoosh-compat honors them on exact bounds like now.
added:{now TO now}

# --- Unquoted multi-word natural-date keywords, extracted faithfully from
# TestMultiWordDateKeywords/TestKeywordDateResolution. Real paperless v2
# rewrites these via an *app-level* regex (rewrite_natural_date_keywords,
# index.py) before whoosh ever parses the string, because whoosh's own
# grammar has no native "previous week" support at all; the oracle harness
# replicates that rewrite. whoosh-compat's own date grammar joins the six
# phrases itself (DateParserPlugin.do_date_phrases), so these compare
# equal on both sides and are ordinary corpus lines, not a divergence
# section. The remaining difference is against *stock* whoosh, which this
# harness (rewrite and all) cannot express: DIVERGENCES.md entry 19.
created:previous week
created:this month
created:previous month
created:this year
created:previous year
created:previous quarter
added:previous week
added:this month
added:previous month
added:this year
added:previous year
added:previous quarter
schäfersee,created:previous year
created:previous week

# --- KNOWN DIVERGENCE (DIVERGENCES.md entry 6, structural not pattern-based): bad
# number: test_differential.py skips on any non-empty diagnostics list.
created:202023
