Archive resolved issues; add open issues #014-#016
Moves the 11 Fixed issues (#001-006, #008-012) into issues/_archive_/, which is gitignored — they stay on local disk and in git history but drop out of the committed tree, keeping the issues/ dir focused on what's open. The sibling test project reads this dir by local path, so it still sees the archived files. Adds the three new open issues found in round-3 testing: #014 (stored XSS in markdown/deck/html_fragment — High), #015 (RecursionError -> 500 on deeply nested JSON), #016 (ragged CSV rows lose data in the rendered table). Documents the archive convention in the README. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
292c386209
commit
6d2fe2147c
15 changed files with 319 additions and 848 deletions
85
issues/016-csv-ragged-rows-silent-data-loss-in-render.md
Normal file
85
issues/016-csv-ragged-rows-silent-data-loss-in-render.md
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
# 016 — Ragged CSV rows silently lose data in the rendered table (server doesn't normalize row width)
|
||||
|
||||
**Status:** Open
|
||||
**Severity:** Low-Medium — silent data loss in the primary rendered view;
|
||||
raw sidecar is unaffected, so it's a fidelity/display bug, not permanent
|
||||
loss.
|
||||
|
||||
Round-3 probe of the `csv` kind (ragged rows, from the #013 handover).
|
||||
Confirmed with an actual headless-Chrome render, not just server inspection.
|
||||
|
||||
## Description
|
||||
|
||||
`wrap_csv_viewer` (`artifacts/views.py`) parses CSV server-side and hands
|
||||
Grid.js `{columns: rows[0], data: rows[1:]}` **without reconciling each
|
||||
data row's width against the header**. Grid.js keys body cells by
|
||||
column-id, so any row that doesn't match the header column count renders
|
||||
wrong:
|
||||
|
||||
- **Row longer than header → extra cells silently dropped.**
|
||||
- **Row shorter than header → missing cells rendered blank.**
|
||||
|
||||
Daybook's stated principle is "the server owns normalization," but row
|
||||
width isn't normalized here, so the display silently disagrees with the
|
||||
data.
|
||||
|
||||
## Reproduction (verified via headless Chrome render)
|
||||
|
||||
Posted `csv` content:
|
||||
|
||||
```
|
||||
a,b,c
|
||||
1,2,3,4,5
|
||||
6,7
|
||||
```
|
||||
|
||||
Server hands Grid.js: `{"columns": ["a","b","c"], "data": [["1","2","3","4","5"], ["6","7"]]}`
|
||||
|
||||
Rendered DOM (headless Chrome, JS executed):
|
||||
|
||||
```
|
||||
| a | b | c |
|
||||
| 1 | 2 | 3 | <- values 4 and 5 are GONE, not shown anywhere
|
||||
| 6 | 7 | | <- third cell blank
|
||||
```
|
||||
|
||||
The `4` and `5` from the first data row do not appear in the rendered
|
||||
table at all. `GET /a/{id}?raw=1` still returns the original CSV intact, so
|
||||
the data isn't destroyed — but a user browsing the artifact (the normal
|
||||
path, and the shared-link path) sees fewer values than the CSV contains,
|
||||
with no truncation indicator.
|
||||
|
||||
This is realistic input: trailing commas, inconsistent exports, and
|
||||
hand-edited CSVs routinely produce rows that don't all match the header
|
||||
width.
|
||||
|
||||
## Other CSV edge cases tested (all fine)
|
||||
|
||||
For the record — these were probed in the same pass and behaved correctly:
|
||||
|
||||
- Embedded commas, quotes (`""` escaping), and newlines inside quoted
|
||||
fields: parsed correctly (Python's `csv` module).
|
||||
- `duplicate columns` (`id,id,id`): rendered (3 same-named headers) — a
|
||||
bit odd for sorting but not a data bug.
|
||||
- `header only`: empty table, fine.
|
||||
- `empty content`: rejected `400`, consistent with `json`.
|
||||
- `single giant cell` (20 KB): rendered fine.
|
||||
- `just commas`: empty-named columns, rendered.
|
||||
|
||||
So the parsing is robust; the gap is specifically row-width normalization
|
||||
before the data reaches Grid.js.
|
||||
|
||||
## Suggested Fix
|
||||
|
||||
In `wrap_csv_viewer`, normalize each data row to `len(columns)` before
|
||||
serializing — pad short rows with `""`, and for over-long rows either (a)
|
||||
truncate but surface it, or better (b) widen `columns` to the maximum row
|
||||
width (auto-naming the extra columns, e.g. `column_4`, `column_5`) so no
|
||||
cell is ever dropped. Option (b) preserves all data, which matches the
|
||||
"server owns normalization, never silently lose content" spirit. Whichever
|
||||
is chosen, the rendered table should never contain fewer values than the
|
||||
raw sidecar.
|
||||
|
||||
## Resolution
|
||||
|
||||
_(pending)_
|
||||
Loading…
Add table
Add a link
Reference in a new issue