daybook/planning/daybook-issues-log.md

163 lines
7.9 KiB
Markdown

# Daybook — Issues Found During LLM-Posting Testing
**Date:** 2026-06-10
**Context:** Found while smoke-testing the deployed instance (`192.168.1.36:8000`)
and hardening the `daybook-posting` skill's `daybook_post.py` helper. Auth/
reachability items are tracked separately in
`planning/next_steps/llm-posting-skill-plan.md` and not duplicated here.
Severity key: **High** = blocks a stated feature · **Med** = degrades UX or
correctness · **Low** = cosmetic. Status: **Open** / **Fixed** / **By design**.
---
## Open — Server-Side
### S1 · Multipart `metadata` field is not parsed as a JSON object — **High / Open**
- **Symptom:** Any file upload (multipart) that includes a `metadata` field returns
`HTTP 400 {"detail":"metadata must be an object"}`.
- **Repro:** `python daybook_post.py test.svg --meta run_id=1` (or any `--file` +
`--meta`). Text artifacts (JSON path) are unaffected — they send a real object.
- **Root cause:** The multipart handler reads `metadata` as a raw form string and
type-checks it against `dict` without `json.loads`. A stringified `{}` or
`{"k":"v"}` therefore fails the check.
- **Impact:** Machine-readable metadata (run_id, model, etc.) cannot be attached to
image/pdf/binary artifacts — only to text artifacts.
- **Fix:** In the multipart code path, `json.loads` the `metadata` form field before
validating, mirroring the JSON path. Confirm `tags` is handled consistently
(currently sent as a comma string and split server-side).
- **Client workaround in place:** the helper now omits `metadata` from multipart
when empty, so metadata-less uploads work. Non-empty metadata on uploads still
needs this server fix.
### S2 · Users cannot delete or archive artifacts (artifacts are immutable) — **High / Open**
- **Requirement:** Users need to be able to **archive** and **delete** artifacts —
both as API endpoints and as controls in the web UI.
- **Symptom:** There is no delete endpoint, and `content`/`kind`/`persona`/`day`
are not editable. The malformed test deck `5df27410` and the session's test
artifacts can only be superseded, never removed or hidden.
- **Impact:** Test and mistake artifacts accumulate permanently in the feed with no
way for a user to clean it up.
- **Fix — two distinct actions:**
- **Archive:** user-initiated, hides the artifact from the default feed but
retains it and allows restore. Needs an archive/unarchive endpoint, a default
feed filter that excludes archived items, and a UI control (plus an
"archived" view).
- **Delete:** user-initiated permanent removal (or a soft-delete tombstone).
Needs a `DELETE` endpoint, a UI control with a confirm step, and removal of the
stored content/raw file.
- **Related:** consider allowing content replacement for an existing id (revision),
which would also address re-posting a corrected artifact.
### S3 · No renderer for CSV / JSON / code — **Med / Open**
- **Symptom:** These upload as download-only `binary` (e.g. `test.csv` →
`c562128b`, kind `binary`).
- **Impact:** Tabular/code artifacts aren't viewable inline.
- **Fix:** Add a renderer, or formally bless the client's `--as-markdown` fenced-
block convention as the interim path and document it.
### S4 · Favorites and project/group labels — **Med / Open**
- **Requirement:** Users want to (a) mark artifacts as **favorites**, and (b) label
artifacts as belonging to a **group / project**. The group/project label must be
**settable at upload time** (and editable afterward). Favorite is primarily a UI
toggle but should also be settable at upload.
- **Design notes:**
- **Keep this distinct from `tags`.** Tags are many free-form filter labels; a
project/group is a first-class, usually single container used for navigation and
grouping. Recommend a dedicated `project` (or `group`) field rather than
overloading tags. `favorite` is a boolean, not a tag.
- **Data model:** add `favorite: bool = false` and `project: str | null` to the
artifact record.
- **Scope — server / client / UI:**
- **Server:** accept `favorite` and `project` on POST; add endpoints to toggle
favorite and set/clear project after upload; support `?project=` and
`?favorite=true` feed filters.
- **Client (`daybook_post.py`):** add `--project NAME` and `--favorite` flags,
sent as first-class JSON/form fields — NOT inside `metadata` (see S1, which
breaks for multipart string fields).
- **UI:** a favorite (star) toggle and a favorites view; group/filter the feed by
project.
---
## Open — Web UI
### U1 · Feed does not refresh when new artifacts arrive — **Med / Open**
- **Symptom:** The web UI renders a static snapshot of the feed. Artifacts posted
after the page loads do not appear until the user manually reloads.
- **Impact:** Agents publish continuously, but a human watching the feed silently
misses new arrivals — which undercuts Daybook's purpose as a live journal of
agent output. Observed throughout this session: each test post required a manual
browser refresh to show up.
- **Fix options (simplest first):**
- Client-side polling of the list endpoint on an interval (e.g. every few
seconds), diffing against the loaded set.
- Server-sent events (SSE) for push updates — a natural fit for this
publish-only, append-mostly model and lighter than WebSockets.
- To avoid disrupting scroll position, surface a "N new artifacts — click to
load" indicator rather than auto-injecting items at the top.
---
## By Design — Worth a Decision
### D1 · Strict rendering, no normalization — **By design**
- **Behavior:** "Daybook does not fix malformed content." Wrong-shaped content is
stored and rendered as-is.
- **Observed consequence:** Markdown sent to `deck` (`5df27410`) was stored and
rendered malformed — no error, just broken output.
- **Implication:** A validating client is load-bearing. The server's per-kind
structure rules and the client's pre-flight checks must stay in sync; if the
server adds a kind, the client's validation/sniffing must follow.
- **Optional improvement:** Consider rejecting obviously-malformed content with a
`422` (e.g. `deck` with no `<section>`) so it fails loud at post time rather than
rendering broken later. This complements, not replaces, the client guard.
---
## Fixed — Client (recorded for traceability)
### C1 · Empty `metadata` broke all multipart uploads — **Fixed**
- The helper serialized empty `metadata` as the string `"{}"` into the multipart
body, triggering S1's 400 even when no metadata was supplied.
- **Fix:** omit empty optional fields (`metadata`, `tags`, `source_id`,
`source_prompt`) from the multipart body, restoring the minimal known-good shape.
### C2 · `html_full` client validation was over-strict — **Fixed**
- Originally required BOTH `<!doctype` AND `<html>`; an auto-sniffed full page
lacking an explicit doctype was rejected.
- **Fix:** require `<html>` only (doctype recommended, not mandatory).
---
## Minor / Cosmetic
### M1 · `deck` title inference picks the first slide heading — **Low / Open**
- Auto mode derived the title "Slide One" from a deck's first `<h1>` (`ac6da43f`).
Correct but awkward as a title.
- **Fix:** for `deck`, prefer the filename over the first `<h1>`.
### M2 · CSV content-type guessed as `application/vnd.ms-excel` on Windows — **Low / Open**
- Python's `mimetypes` maps `.csv` to `application/vnd.ms-excel` on this host rather
than `text/csv`. Harmless — the server still stores it as `binary` — but
inconsistent with the earlier manual `text/csv` upload.
- **Fix (optional):** force `text/csv` for `.csv` in the client's `content_type_for`.
---
## Test Artifacts Created (for cleanup once S2 lands)
Auto-mode validation posts under persona `claude`, tag `auto-test`:
`e7a769c5` (markdown), `2d162697` (html_full), `49291e85` (html_fragment),
`ac6da43f` (deck), `3ad914cc` (image), `794d29e8` (pdf), `c562128b` (binary).
Plus earlier manual smoke-test artifacts and the malformed deck `5df27410`.