# 013 — Handover to AGENT_DAYBOOK__LLM_TEST (round 2) **Status:** For information — a handback covering everything shipped since the round-1 handoff (#007). Round 1 (#007) closed out issues #002–#006. Since then, your round-2 testing filed #008–#012 (all now fixed), and several new capabilities landed. This doc summarizes all of it and points at where the fresh surface area is worth probing. All of this is committed on `main` (pushed to Forgejo) and live on the local dev instance you test against (`http://127.0.0.1:8001`) — Django's autoreloader has already picked it up, no restart needed on your end. ## New Capabilities To Exercise These are new since #007 and largely untested by you yet: 1. **`json` and `csv` artifact kinds** (commit `e5d2f19`). Text kinds like markdown. `json` renders as a collapsible tree (renderjson), `csv` as a sortable/searchable table (Grid.js). Both validate server-side (`json` must parse; `csv` only needs non-blank content) and preserve original text as a `?raw=1` sidecar. Both vendored libs are served from `/static/vendor/…`. 2. **`.xlsx` upload → `csv`** (commit `4b5ec09`). Uploading an `.xlsx` file (multipart, like any file) is converted server-side via openpyxl into a `csv` artifact rather than stored as `binary`. Active sheet only; cached formula results only; `.xls` unsupported; corrupt file → `400`. 3. **Per-artifact public sharing** (commit `91ea19d`). Owner toggles a share link from the feed UI; `GET /s/{share_token}` then serves that one artifact with **no authentication at all**. `is_shared`/`share_url` now appear in every artifact API response. Embedded images in a shared artifact are also served unauthenticated while it's shared. **This is the highest-value target for adversarial testing** — see below. 4. **Syntax-highlighted code + styled tables** (commits `af9ecf2`, `696cfe7`). Markdown fenced code blocks get Pygments highlighting; tables in markdown and `html_fragment` render styled. Cosmetic, low-risk. 5. **Posting script supports `json`/`csv`/`.xlsx`** (commit `e137725`). `daybook_post.py --kind json/csv`, positional auto-detect of `.json`/`.csv`/`.xlsx`. 6. **Light/dark UI toggle** (commit `9a3b381`). UI-chrome only, no API surface — not relevant to API testing. ## Fixes Since #007 (issues you filed) - **#008** — `source_name`/`source_id`/`source_prompt` now reject non-string values with `400` instead of silently mangling them. - **#009** — the `html_fragment` content-shape check is substring-based; documented as a known limitation rather than switched to real HTML parsing (deliberate — matches the client helper's own approach). - **#010** — concurrent posts could race past quota; fixed with a write-lock-before-read + atomic transaction. Verified live but **not** covered by an automated test (SQLite shared-cache test DB behaves differently — see the issue). Worth re-probing. - **#011** — CDN snippets documented for `html_full`; `--theme` help typo fixed. - **#012** — posting script gained `json`/`csv` support. ## Suggested Round-3 Probes Prioritized by where the new surface area is riskiest. ### Sharing (#91ea19d) — security boundary, probe hardest - Can an **unshared** artifact ever be reached via `/s/`? Brute/ guessed/empty/malformed tokens should all `404`. - Does **unsharing immediately** kill the old link? (Confirmed manually, but re-verify — and try racing an unshare against an in-flight request.) - Is `share_token` ever leaked in a response for an artifact you *don't* own, or in the list endpoint, or anywhere a non-owner could see it? - Can a shared artifact's **embedded assets** be reached unauthenticated — and, importantly, can an *un*shared artifact's assets be reached that way (they must not)? Also: does an orphaned/unattached asset stay private even when some unrelated artifact is shared? - Does `?raw=1` on `/s/` correctly serve raw source for the kinds that support it, and not leak anything for kinds that don't? - Cross-user: user A shares an artifact; can user B toggle/​unshare it, or only view it? ### json / csv (#e5d2f19) - `json`: valid-but-not-an-object payloads (bare array, string, number, `null`); deeply nested / very large; unicode; the `` injection vector (confirmed handled for json — verify **csv** escapes its embedded data block the same way, it's a separate code path). - `csv`: ragged rows (fewer/more columns than the header), embedded commas/ quotes/newlines, duplicate column names, header-only, empty, a single giant cell, BOM/encoding oddities. - Quota accounting: json/csv now write a sidecar file — confirm size accounting and eviction include/delete the sidecar (this generalized the markdown-only logic; worth verifying it didn't regress markdown either). ### .xlsx conversion (#4b5ec09) - Multi-sheet workbook — verify only the active sheet survives and the others are silently dropped (documented behavior, confirm it's true). - Formula cells never calculated by a real spreadsheet app (openpyxl doesn't evaluate) → should be blank, not error. - A non-`.xlsx` file renamed to `.xlsx`; a real `.xlsx` sent with a wrong/ generic content type; a huge sheet; empty workbook; `.xls` (must not convert). - Field mangling regression: this path rebuilds the payload dict manually because multipart `QueryDict` + `{**data}` was silently list-wrapping values (the bug that made this a multi-fix). Re-probe that title/tags/ source_* all come through correctly on `.xlsx` posts specifically. ### #010 quota race (no automated coverage) - Fire N truly-concurrent posts at a tight quota; confirm final usage never exceeds quota and no artifact is left half-created (row without files or files without row). As always: use the `test` / `testpwd` account, clean up what you create, check `artifacts/views.py` before calling a surprise a bug (some, like #009, are documented-by-design), and file anything real as a new numbered issue (next is #014), linking back if it's a variant of a closed one.