Random failure issue with OPDS 2 feed
[repro_opds_failure.py](https://github.com/user-attachments/files/27283878/repro_opds_failure.py)
Hey, I mentioned an issue with the OPDS feed that I brought up in discord, that I probably mischaracterized. I gave Gemini a pass at this, and it seems to have diagnosed it, with the fix _seeming_ to work for me. Here's the report. Take it with a grain of salt, but the suggested fix should be at least innocuous.
---
## Diagnostic Report: OPDS 2.0 Feed Hierarchy Inconsistency
### Symptoms
The OPDS 2.0 feeds in Codex exhibit inconsistent behavior across server restarts:
1. **Publisher Feed Regression:** Instead of showing `Publisher -> Series -> Publication`, the feed occasionally skips the Series level and lists all Publications directly under the Publisher.
2. **Series Feed Regression:** Instead of showing `Series -> Publication`, the feed occasionally lists matching Publishers under the Series.
This issue is intermittent and can often be "fixed" by restarting the server or reinstalling the app (which triggers a restart), but it eventually returns.
### Root Cause Analysis
The issue is caused by **non-deterministic iteration order** of a `frozenset` in the navigation logic.
In `codex/codex/views/settings.py`, the browser navigation levels are defined as follows:
```python
# FILE: codex/codex/views/settings.py
SHOW_KEYS = frozenset({"p", "i", "s", "v"})
```
### The Technical Failure
Codex calculates the navigation hierarchy by iterating through `SHOW_KEYS`. Because `frozenset` is an unordered collection in Python, the iteration order is determined by Python's internal hash randomization at startup.
* **Correct Order (`p, i, s, v`):** The app correctly identifies the hierarchy: Publisher -> Imprint -> Series -> Volume.
* **Incorrect Order (e.g., `s, v, p, i`):** If the internal hash table orders "Series" or "Volume" before "Publisher," the navigation logic (specifically in `SharedAnnotationsMixin._get_order_groups`) fails to correctly identify which groups are "children" of the cur
rent view.
#### Probability Analysis (The "Odds")
Because the application uses a set of 4 items, there are **24 possible permutations** (4!) of the navigation order that Python can pick at startup.
1. **Failure Rate:** About **50% of restarts** will result in a "Bad" feed.
2. **The Math:** For the hierarchy to work correctly, Publisher (`p`) must be processed before Series (`s`). In any random shuffle of two items, there is a 50/100 chance that one will appear before the other.
3. **Why Restarting "Fixes" It:** Every restart is a "coin flip." In half the cases, `p` comes before `s` (GOOD), and in the other half, `s` comes before `p` (BAD).
This results in the app "losing its place" in the hierarchy, leading to the skipped levels or inverted parent/child relationships reported by users.
### Resolution
The collection must be changed from an unordered `frozenset` to an ordered `tuple`. This ensures that the navigation hierarchy is calculated identically across every server instance and restart.
### Permanent Fix
Modify `codex/codex/views/settings.py` (Line 31):
**Old Code:**
```python
SHOW_KEYS = frozenset({"p", "i", "s", "v"})
```
**New Code:**
```python
SHOW_KEYS = ("p", "i", "s", "v")
```
1 条评论