## Plan ### Problem `get_recent_comments_by_target_uids` in `database/comments.py` selects the `LIMIT` most recent comments **by individual comment time**, then builds a tree using `in_group` set. A child whose parent is outside the limit (e.g., parent is #4 most recent) gets orphaned to root level, breaking hierarchy. ### Fix: approach A – retroactively fetch missing parent comments Modify `get_recent_comments_by_target_uids` at `database/comments.py:76–115`: 1. After executing the SQL and grouping rows by `target_uid` (existing `for target_uid, group in groupby(sorted_rows, key=lambda x: x["target_uid"]):` loop), add a new step **before** the tree-building code. 2. For each group (list of `CommentItemOut` records), collect the set `current_uids = {c.comment.uid for c in group}` and `seen_uids = set()`. For each record `c` in the group, if `c.comment.parent_uid is not None` and `c.comment.parent_uid not in current_uids` and `c.comment.parent_uid not in seen_uids`, then fetch that parent comment (and recursively its ancestors) using a helper from the same file (e.g., `fetch_comment_tree_upwards(uid)` that queries comments by uid and follows `parent_uid` until reaching a comment in `current_uids` or a root). Append any fetched ancestors to the current group list, and add their uids to `seen_uids` and `current_uids`. Implementation detail: use a simple loop per missing uid – query the DB for a single comment by uid, add its uid to the set, check its `parent_uid`, repeat until `parent_uid` is `None` or already in set. This is a small number of extra queries per target (at most `limit` extra rows). 3. Then let the existing tree-building loop (which uses `in_group = set(...)`) proceed – it will now find the parent in `in_group` and nest the child correctly. 4. **No changes** to template, CSS, schema, or call sites. ### Test additions For each listing page, add a new e2e test that seeds 4 comments where the parent is the **4th most recent** (outside the top‑3 window) and a child reply is the most recent. Assert that the child appears nested under the parent (i.e., `.comment-replies` element exists and contains the child text). Use the same test pattern as existing hierarchy tests but adjust timestamps: | Comment | Time offset | parent_uid | Expected row_number | |---|---|---|---| | `-excluded` | `base - 3s` | None | 4 | | `-older` | `base - 2s` | None | 3 | | `-parent` | `base - 1s` | None | 2 | | `-reply` | `base` | parent’s uid | 1 | The critical assertion: the child (most recent) should appear inside a `.comment-replies` block under the parent comment block. Files to modify: - `tests/e2e/feed.py` – add `test_feed_preserves_comment_hierarchy_with_orphaned_parent`. - `tests/e2e/gists.py` – add `test_gists_list_preserves_comment_hierarchy_with_orphaned_parent`. - `tests/e2e/news.py` – add `test_news_list_preserves_comment_hierarchy_with_orphaned_parent`. - `tests/e2e/projects/index.py` – add `test_projects_list_preserves_comment_hierarchy_with_orphaned_parent`. The existing happy‑path tests must still pass (they will, because the fix ensures hierarchy for all cases). ### Verification - Run `pip install -e '.[dev]' -q && make test-unit` – all tests pass (both new and existing). - Run `pip install -q ruff && ruff check .` – no lint errors. - Manually inspect that the new tests actually assert hierarchy (child text inside `.comment-replies .comment-text`). ## Definition of done - [ ] `get_recent_comments_by_target_uids` in `database/comments.py` is modified to include missing parent comments when building the tree. - [ ] Four new e2e tests exist (one per listing page: feed, gists, news, projects) that seed a threaded comment where the parent is the 4th most recent, and verify the child is nested under the parent via `.comment-replies`. - [ ] The existing happy‑path hierarchy tests continue to pass. - [ ] `pip install -e '.[dev]' -q && make test-unit` exits with code 0. - [ ] `pip install -q ruff && ruff check .` exits with code 0. - [ ] No other files changed (no template, CSS, schema, or router modifications).