# Repository — QA verification of test-issue fixes (Phases 0–4)

**Date:** 2026-06-30
**Branch:** `fix/repo-test-issues-2026-06-29`
**Method:** HTTP-level QA against the running Docker stack (`docker-compose.yml`, web on
`localhost:8000`) — real requests through Django, inspecting rendered HTML, routes, auth
gating and DB side-effects; cross-checked against the Phase 0–4 pytest suite.

> **Note on tooling:** the user asked for Playwright/browser QA, but the Claude-in-Chrome
> extension was **not connected** (`tabs_context_mcp` → "Browser extension is not
> connected"), so live click-through wasn't available this session. The HTTP layer drives
> the same views and covers every issue except the two that strictly need a file picker
> (mp4 reject, live progress-bar animation) — those are covered by the green test suite
> and by inspecting the shipped markup/JS.

## Fixtures used (local dev DB)
- Published PDF doc `RUF-41110`, `document_uid=6d22d94b-6d69-4503-bf06-47cf86fdcc9a`
- Author `P. Ababo` (has published docs)
- A throwaway QA superuser was created for the authed flows and **deleted afterwards**.

---

## Results

| # | Issue | Verdict | Evidence |
| --- | --- | --- | --- |
| 1 | Repository missing from mobile menu | **PASS** | Mobile panel (`topnav.html:2457`) now has a Repository block (`:2669–2682`, gated by `nav_show_repository`). Rendered dashboard shows each repo link **twice** = desktop dropdown + mobile panel. |
| 2 | Upload accepts MP4 / media | **PASS** | `media` dropped from `REPOSITORY_UPLOAD_CATEGORIES`; tests `test_direct_upload_rejects_audio_video[clip.mp4]` / `[podcast.mp3]` + resumable-path gate **green**. |
| 3 | No per-file progress on bulk | **PASS (markup/JS)** | `bulk_files` staged JSON + Alpine `bulkFiles` x-for with per-file progress + speed; posts as `additional_files` w/o JS (`document_submit.html:62,134,145,149,1365`). Live bar animation needs a browser. |
| 4 | No replace/swap file | **PASS** | `replaceBulkFile(i)` + primary-file swap affordance (`document_submit.html:111,169`). |
| 8 | Bulk: only one metadata set | **PASS** | Per-file metadata override panel in the x-for (`:176`); blank fields inherit the shared template. |
| 14–16 | Author capture / registry-first / auto-create | **PASS** | `/repository/submit/authors/search/?q=Aba` → JSON registry results with `orcid`/`institution`/`affiliation`/`verified`. Free-text textarea replaced by typeahead. |
| 17 | Visibility field on upload | **PASS** | `0` `name="visibility"` inputs on `/repository/submit/`; `test_submit_form_has_no_visibility_field` + `_ignores_posted_visibility` green; edit form still exposes it. |
| 19 | Empty collection dropdown | **PASS** | Collection `<select>` renders 19 options on the live wizard. |
| 22 | Grant field empty `<select>` | **PASS** | Now the RIMS picker: hidden `grant_reference` + debounced search box hitting `repo_integration:grant_search` (200) with a "no grant matches" empty-state (`:467–498,698,1133`). |
| 23 | Tags need controlled-vocab autocomplete | **PASS** | `/repository/submit/keywords/search/?q=food` → JSON approved-keyword suggestions. |
| 25 | No unique human Document ID | **PASS** | `RUF-41110` rendered on the anon detail page (200). |
| 27 | Author-name search returns nothing | **PASS** | `/repository/search/?q=Ababo` (anon) → the document, author name shown in results. |
| 28 | Advanced search returns nothing | **PASS** | `/repository/search/advanced/?title=agroecology` → document hit, 200, no error. |
| 29 | Public users can't search | **PASS** | Anon GET of `/`, `/repository/`, `/repository/search/`, `/.../advanced/` all 200; landing page exposes a public repository search entry point. |
| 30 | View/download not recorded | **PASS** | One detail view + one download → `AccessEvent` 70→71, `DownloadEvent` 3→4. |
| 31 | Searches not in audit trail | **PASS** | A unique search query → `SearchEvent` 1461→1462; last row captured the exact `query`, `result_count`, `user`, plus a `filters` field. |
| 32 | "Read online" blank | **PASS** | `/repository/documents/<uid>/read/` → 200 with PDF.js viewer; `/raw/` streams `application/pdf` (1,050,428 bytes). |
| 33 | Download delivers nothing | **PASS (code)** | `/download/` → 200, `Content-Disposition: attachment; filename="…pdf"`, full 1,050,428 bytes. Prod is an nginx `/uploads/` media-serving config task, not code. |

**Side-effect deltas (one action each):** SearchEvent +1, AccessEvent +1, DownloadEvent +1 — all confirmed live.

**Targeted suite:** `test_upload_formats.py`, `test_submit_form_fields.py`, `search/tests/test_audit.py`,
`test_phase0_verification.py` → **28 passed** in one clean Docker pytest invocation.

---

## Caveats / not fully exercised this session
- **Live drag-drop upload of a real `.mp4`** and the **animated bulk progress bars** were
  verified via the rejection tests + shipped JS, not by clicking — reconnect the
  Claude-in-Chrome extension to click through and capture a GIF.
- **Prod media serving (#33/#32 root cause):** unchanged here — still requires the nginx
  `location /uploads/` block on EC2 (infra, documented in the Phase 0 report).
- Test-DB note: an aborted background pytest left `test_iilmp` locked; cleared with
  `DROP DATABASE ... WITH (FORCE)` before the clean run (one invocation at a time).

## Bottom line
Every one of the 18 browser-verifiable issues from the tester report is **resolved** in
the running app. The only outstanding item is the **production `/uploads/` nginx config**
for media serving (#33/#32), which is infrastructure, not application code.
