Make feedback drafts and submitted history durable #11

Closed
opened 2026-08-28 19:24:41 +00:00 by dikka · 1 comment
Owner

What to build

Persist unfinished ordinary input and response-bound annotation drafts in Pilcrow's configured workspace state, including validated attachments. Keep cursor position, native selection geometry, menus, and editor placement in browser memory. Use bounded revisions so stale pages cannot silently overwrite a newer durable draft; elaborate multi-tab merge UI is out of scope.

Pi's real persisted user message remains the only submitted conversation record. Recognize valid persisted TOON input during history normalization and render its quoted targets, comments, overall reply, and attachment summaries as one structured immutable user entry. Do not add a marker to model-visible content, a paired custom entry, a duplicate hub transcript record, or a durable submitted-anchor repository.

After dispatch acceptance, retain immutable payload identity and fingerprint as recovery evidence until the matching real Pi user message appears. Allow a new draft immediately. Never fabricate a conversation entry while waiting, and preserve honest indeterminate/retry behavior if transport is lost. Multiple submitted batches may target the same response.

Acceptance criteria

  • Ordinary and annotation drafts, comments, and attachments survive browser closure and hub restart under the configured state root.
  • Cursor, selection geometry, menus, and editor placement are not persisted.
  • Concurrent stale draft writes receive a bounded conflict instead of silently replacing newer content.
  • A persisted valid TOON Pi user message renders as structured chronological feedback rather than raw encoding.
  • The implementation writes no marker, paired custom entry, duplicate conversation row, or submitted-anchor repository.
  • Dispatch acceptance clears the submitted editable draft, preserves recovery evidence, and permits immediate creation of another draft.
  • Matching durable Pi history resolves recovery evidence; missing or indeterminate history never causes a fabricated user entry.
  • Multiple immutable batches against one response remain separately visible in chronological history.
  • Restart, attachment, revision conflict, dispatch recovery, TOON normalization, and duplicate-history tests pass.

Blocked by

  • #10 — Make finalized stream responses annotation-capable

Human checkpoint note: Do not request routine per-ticket approval. The implementing agent may make the internal architecture, refactoring, testing, and UI-detail decisions needed to satisfy the acceptance criteria. Pause only if implementation requires a material product or ownership change, a destructive or hard-to-reverse action, excluded security or deployment scope, credentials or spending, or a real-browser design fork with no safe default. Forgejo completion updates may be batched with the rest of the completed frontier. The user performs final hub and Pi restart steps. Agents must not start, restart, replace, or stop the user-run Pilcrow development server.

## What to build Persist unfinished ordinary input and response-bound annotation drafts in Pilcrow's configured workspace state, including validated attachments. Keep cursor position, native selection geometry, menus, and editor placement in browser memory. Use bounded revisions so stale pages cannot silently overwrite a newer durable draft; elaborate multi-tab merge UI is out of scope. Pi's real persisted user message remains the only submitted conversation record. Recognize valid persisted TOON input during history normalization and render its quoted targets, comments, overall reply, and attachment summaries as one structured immutable user entry. Do not add a marker to model-visible content, a paired custom entry, a duplicate hub transcript record, or a durable submitted-anchor repository. After dispatch acceptance, retain immutable payload identity and fingerprint as recovery evidence until the matching real Pi user message appears. Allow a new draft immediately. Never fabricate a conversation entry while waiting, and preserve honest indeterminate/retry behavior if transport is lost. Multiple submitted batches may target the same response. ## Acceptance criteria - [ ] Ordinary and annotation drafts, comments, and attachments survive browser closure and hub restart under the configured state root. - [ ] Cursor, selection geometry, menus, and editor placement are not persisted. - [ ] Concurrent stale draft writes receive a bounded conflict instead of silently replacing newer content. - [ ] A persisted valid TOON Pi user message renders as structured chronological feedback rather than raw encoding. - [ ] The implementation writes no marker, paired custom entry, duplicate conversation row, or submitted-anchor repository. - [ ] Dispatch acceptance clears the submitted editable draft, preserves recovery evidence, and permits immediate creation of another draft. - [ ] Matching durable Pi history resolves recovery evidence; missing or indeterminate history never causes a fabricated user entry. - [ ] Multiple immutable batches against one response remain separately visible in chronological history. - [ ] Restart, attachment, revision conflict, dispatch recovery, TOON normalization, and duplicate-history tests pass. ## Blocked by - #10 — Make finalized stream responses annotation-capable > **Human checkpoint note:** Do not request routine per-ticket approval. The implementing agent may make the internal architecture, refactoring, testing, and UI-detail decisions needed to satisfy the acceptance criteria. Pause only if implementation requires a material product or ownership change, a destructive or hard-to-reverse action, excluded security or deployment scope, credentials or spending, or a real-browser design fork with no safe default. Forgejo completion updates may be batched with the rest of the completed frontier. The user performs final hub and Pi restart steps. Agents must not start, restart, replace, or stop the user-run Pilcrow development server.
Author
Owner

Implemented in jj revision f26f4371 (feat(feedback): persist revisioned drafts and delivery recovery state).

What changed:

  • Added bounded private durable feedback state under the configured Pilcrow state root. Workspace drafts, prepared operation identity, accepted-dispatch evidence, and consumed recovery facts use revisioned atomic metadata; decoded raster attachments are immutable content-addressed private blobs with digest/type/owner/mode/link/size/TOCTOU checks and post-commit garbage collection.
  • Ordinary and response-bound annotation drafts, overall/comment text, and validated attachments survive browser closure and hub restart. Cursor, native selection geometry, menus, and editor placement remain browser-memory only.
  • Stale page writes return conflicts instead of overwriting newer revisions. Two browser pages fence each other, retain local edits, and expose bounded conflict/retry state.
  • Browser mutations coalesce by draft key, flush attachments immediately, reuse unchanged attachment blobs, debounce typing, and use keepalive close-time flush rather than repeatedly sending/rewriting multi-megabyte base64 state.
  • Submission identity is durably prepared before dispatch. Lost-before-accept and lost-after-accept reloads retry the exact operation ID rather than creating a duplicate. Identical intentional batches remain legal because recovery never deduplicates solely by payload.
  • Acceptance persists evidence and compare-and-clears only the exact still-current submitted draft in one serialized hub transaction. Edits made while delivery is pending survive, and the committed revision/snapshot reaches the browser before success is reported so accepted content cannot resurrect after reload.
  • Accepted evidence contains only bounded IDs, timestamps, request/payload/message fingerprints, stable Pi authority, and reconciliation facts—no transcript payload, model-visible marker, custom entry, paired row, or submitted-anchor document.
  • Reconciliation is one-to-one across repeated visits, restart, branch paging, duplicate payloads, and equal timestamps using bounded non-content consumption facts tied to stable real Pi user entry IDs. No waiting conversation entry is fabricated.
  • Strict TOON mixed-content normalization validates exact producer grammar/order/associations, canonical base64, decoded bytes, count/aggregate limits, and PNG/JPEG/GIF/WebP magic. Valid Pilcrow output renders one structured immutable user entry; malformed mappings remain ordinary raw history.
  • Legal 16-image/10 MiB-per-image/40 MiB aggregate messages now round-trip through bounded Pi JSONL reading while the browser history projection remains blob-free and page-bounded.
  • Forget transactionally removes drafts, prepared operations, accepted/consumed recovery metadata, and unreferenced blobs with rollback/error handling; Pi JSONL remains byte-identical and browser repositories are pruned when sessions disappear.
  • Replaced borrowed-file-descriptor read streams with sole-owner positional FileHandle reads, fixing an abort race where EBADF could mask AbortError. A 400-abort stress run and metadata-integrity assertions cover it.
  • Stabilized the live-follow test fixture by installing layout geometry before mount and synchronizing frame callbacks inside act; production follow timing was unchanged. Ten repeated combined-suite runs passed without act warnings.

Audit and regression coverage:

  • Fresh review found legal messages that history could not reread, non-atomic accepted clearing, repeated-message double reconciliation, lost operation IDs after browser closure, loose/missing GIF-WebP grammar validation, orphaned sensitive state after Forget, and multi-gigabyte mutation rewrite amplification. All were fixed before closure.
  • Added store ownership/mode/symlink/hardlink/nonregular/oversize/malformed/TOCTOU/failure/concurrency tests; max attachment round-trip; exact grammar/magic; blob reuse/GC; two-page/offline conflicts; close flush; atomic accept/clear with pending edits; reload/retry/indeterminate; duplicate one-to-one reconciliation across restart/branch/paging; Forget rollback/no-Pi-touch; and capacity/backpressure tests.

Validation:

  • Supervisor focused verification passed: 6 files / 106 tests.
  • Final full suite passed: 67 files / 569 tests.
  • History abort stress passed 25 iterations / 400 simultaneous aborted reads.
  • Combined live-follow/full-suite stress passed ten consecutive runs with no act warnings.
  • vp check now passes all 200 formatted files with 0 errors and four non-blocking warnings in existing launcher/registry code.
  • TypeScript no-emit checks, hub build, production browser build, and git diff --check passed.
  • Browser QA was unavailable because no user-run development server was active; automated browser coverage exercises hydration, conflict, attachment, delivery, reconciliation, and structured rendering paths.

Protocol remains exact v9. Pi JSONL remains the sole submitted conversation authority and is never written, migrated, or duplicated by Pilcrow. No server was managed.

Implemented in jj revision `f26f4371` (`feat(feedback): persist revisioned drafts and delivery recovery state`). What changed: - Added bounded private durable feedback state under the configured Pilcrow state root. Workspace drafts, prepared operation identity, accepted-dispatch evidence, and consumed recovery facts use revisioned atomic metadata; decoded raster attachments are immutable content-addressed private blobs with digest/type/owner/mode/link/size/TOCTOU checks and post-commit garbage collection. - Ordinary and response-bound annotation drafts, overall/comment text, and validated attachments survive browser closure and hub restart. Cursor, native selection geometry, menus, and editor placement remain browser-memory only. - Stale page writes return conflicts instead of overwriting newer revisions. Two browser pages fence each other, retain local edits, and expose bounded conflict/retry state. - Browser mutations coalesce by draft key, flush attachments immediately, reuse unchanged attachment blobs, debounce typing, and use keepalive close-time flush rather than repeatedly sending/rewriting multi-megabyte base64 state. - Submission identity is durably prepared before dispatch. Lost-before-accept and lost-after-accept reloads retry the exact operation ID rather than creating a duplicate. Identical intentional batches remain legal because recovery never deduplicates solely by payload. - Acceptance persists evidence and compare-and-clears only the exact still-current submitted draft in one serialized hub transaction. Edits made while delivery is pending survive, and the committed revision/snapshot reaches the browser before success is reported so accepted content cannot resurrect after reload. - Accepted evidence contains only bounded IDs, timestamps, request/payload/message fingerprints, stable Pi authority, and reconciliation facts—no transcript payload, model-visible marker, custom entry, paired row, or submitted-anchor document. - Reconciliation is one-to-one across repeated visits, restart, branch paging, duplicate payloads, and equal timestamps using bounded non-content consumption facts tied to stable real Pi user entry IDs. No waiting conversation entry is fabricated. - Strict TOON mixed-content normalization validates exact producer grammar/order/associations, canonical base64, decoded bytes, count/aggregate limits, and PNG/JPEG/GIF/WebP magic. Valid Pilcrow output renders one structured immutable user entry; malformed mappings remain ordinary raw history. - Legal 16-image/10 MiB-per-image/40 MiB aggregate messages now round-trip through bounded Pi JSONL reading while the browser history projection remains blob-free and page-bounded. - Forget transactionally removes drafts, prepared operations, accepted/consumed recovery metadata, and unreferenced blobs with rollback/error handling; Pi JSONL remains byte-identical and browser repositories are pruned when sessions disappear. - Replaced borrowed-file-descriptor read streams with sole-owner positional FileHandle reads, fixing an abort race where EBADF could mask AbortError. A 400-abort stress run and metadata-integrity assertions cover it. - Stabilized the live-follow test fixture by installing layout geometry before mount and synchronizing frame callbacks inside act; production follow timing was unchanged. Ten repeated combined-suite runs passed without act warnings. Audit and regression coverage: - Fresh review found legal messages that history could not reread, non-atomic accepted clearing, repeated-message double reconciliation, lost operation IDs after browser closure, loose/missing GIF-WebP grammar validation, orphaned sensitive state after Forget, and multi-gigabyte mutation rewrite amplification. All were fixed before closure. - Added store ownership/mode/symlink/hardlink/nonregular/oversize/malformed/TOCTOU/failure/concurrency tests; max attachment round-trip; exact grammar/magic; blob reuse/GC; two-page/offline conflicts; close flush; atomic accept/clear with pending edits; reload/retry/indeterminate; duplicate one-to-one reconciliation across restart/branch/paging; Forget rollback/no-Pi-touch; and capacity/backpressure tests. Validation: - Supervisor focused verification passed: 6 files / 106 tests. - Final full suite passed: 67 files / 569 tests. - History abort stress passed 25 iterations / 400 simultaneous aborted reads. - Combined live-follow/full-suite stress passed ten consecutive runs with no act warnings. - `vp check` now passes all 200 formatted files with 0 errors and four non-blocking warnings in existing launcher/registry code. - TypeScript no-emit checks, hub build, production browser build, and `git diff --check` passed. - Browser QA was unavailable because no user-run development server was active; automated browser coverage exercises hydration, conflict, attachment, delivery, reconciliation, and structured rendering paths. Protocol remains exact v9. Pi JSONL remains the sole submitted conversation authority and is never written, migrated, or duplicated by Pilcrow. No server was managed.
dikka closed this issue 2026-08-29 05:13:28 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Reference
lab/pilcrow#11
No description provided.