Summary
The report lifecycle transition buttons ("Publish & disseminate →", etc.) are plain form POSTs that navigate immediately (src/iceberg/templates/report_edit.html:622-630). The autosave has a 1200 ms debounce (src/iceberg/static/js/tags.js:168). A pending debounce (or in-flight fetch, aborted by navigation) is dropped by the transition.
Failure scenario
A writer types a fix to a key judgement and clicks "Publish & disseminate →" within ~1.2 s. The debounced autosave never fires; the PublicationSnapshot freezes the pre-edit text, and report_save's status != PUBLISHED guard (web/reports.py:306) makes the loss unrecoverable — published output is immutable.
Notes
The race predates this PR, but PR #267 removed the manual "Save draft" flush users previously had before publishing, so there's no longer a natural way to force-persist first. The AI panel already shows the correct pattern — it awaits saveNow() before acting (tags.js:262).
Suggested fix
Give the transition forms the same flush: @submit.prevent → await saveNow() (bail if it returns a conflict, see #271) → submit.
Found in Fable review of PR #232 → HEAD.
Summary
The report lifecycle transition buttons ("Publish & disseminate →", etc.) are plain form POSTs that navigate immediately (
src/iceberg/templates/report_edit.html:622-630). The autosave has a 1200 ms debounce (src/iceberg/static/js/tags.js:168). A pending debounce (or in-flight fetch, aborted by navigation) is dropped by the transition.Failure scenario
A writer types a fix to a key judgement and clicks "Publish & disseminate →" within ~1.2 s. The debounced autosave never fires; the
PublicationSnapshotfreezes the pre-edit text, andreport_save'sstatus != PUBLISHEDguard (web/reports.py:306) makes the loss unrecoverable — published output is immutable.Notes
The race predates this PR, but PR #267 removed the manual "Save draft" flush users previously had before publishing, so there's no longer a natural way to force-persist first. The AI panel already shows the correct pattern — it
awaitssaveNow()before acting (tags.js:262).Suggested fix
Give the transition forms the same flush:
@submit.prevent→await saveNow()(bail if it returns a conflict, see #271) → submit.Found in Fable review of PR #232 → HEAD.