Files
pad/testdata
xarmian 3f567965bc fix(web): a refused title keeps the typed text, and a too-long one is refused before sending (BUG-3115) (#1437)
* fix(web): a refused title keeps the typed text, and a too-long one is refused before sending (BUG-3115)

The sidebar quick-add dialog closed and cleared itself before the create
request, and the item title editor closed before its PATCH and re-seeds from
the stored title on reopen, so a title the server refused was simply gone.
Both now keep the text on screen, editable, with the reason beside it.

Every web door that sends a typed title (11 doors, 12 call sites) now checks
it against the server's limit first, on the exact string it sends. The limit
lives in web/src/lib/items/titleLimit.ts and counts code points after Go's
TrimSpace set, which is not JS's trim set (U+FEFF, U+0085). A shared corpus,
testdata/item_title_limit.json, is asserted by a Go test and a vitest suite,
and the Go half proves the corpus's whitespace list is exactly
unicode.IsSpace over the whole rune range.

The roles page's create refusal was console-only; it and the playbook and
convention forms now show the server's message instead of a generic one.

* fix(web): an in-flight quick-add belongs to one opening of the dialog (BUG-3115, codex r1)

The old response recognised "its" dialog by collection, so dismissing and
reopening the SAME collection mid-request let it close the new dialog and
clear the new text (the store's $state list hands out one stable proxy per
collection, so the comparison matched). A per-opening session counter
replaces it; Sidebar.quickAdd.svelte.test.ts pins both outcomes against a
$state-backed double and fails on the old comparison.

Also: the playbook duplicate refusal names the server's reason, and the
comments claiming every web door is checked now say UI doors where a user
types a title — WebMCP's agent-supplied titles and generated titles such as a
playbook "(copy)" are not pre-checked.

* fix(web): quick-add is read-only while its create is in flight, and a new opening does not inherit the busy state (BUG-3115, codex r2)

* fix(web): the playbook editor no longer refuses to save an unchanged legacy over-limit title (BUG-3115, lead NO-GO)

The server re-validates a title only when it changes (the handler's early
refusal and the store's echo comparison), so a playbook whose title predates
the 255-rune bound stays saveable as long as its title is sent back as-is.
save() always sends the title, and a5ea9e0b checked it unconditionally, so
such a playbook could no longer be saved at all, not even to change its body.

Both UPDATE doors now go through titleEditError(sent, stored), which mirrors
the server's echo rule (raw or TrimSpace'd equal to the stored title) before
applying the limit. ItemDetail already skipped an unchanged title; it now
shares the helper. Every other door the change touches is a create.

Pinned by titleEditError unit cases, and by an e2e leg in which the editor is
shown a legacy title and must send the save. It fails, with its premise holding,
when the editor goes back to the unconditional check. The server half is
TestPatchItemVerbatimEchoOfALegacyTitleIsANoOp.

* test(e2e): a control leg so the playbook editor's legacy-title leg cannot pass without a length check (BUG-3115, codex r4)
2026-09-22 15:30:37 -04:00
..