Symptom
A scan of all sys_upload_session rows after driving both the chunked-complete flow and the abandon/reap flow returns exactly ['in_progress', 'completed']. completing is written transiently and immediately overwritten. The failed and expired statuses are never written by the service, yet the retention rule references them — so retention references two states the system can never enter.
Root cause
Located. In packages/services/service-storage/src/objects/system-upload-session.object.ts the status enum declares failed and expired (lines 104-105) and the retention onlyWhen is { status: { $in: ['completed', 'failed', 'expired'] } } (line 134). A grep across service-storage finds failed/expired only in that enum, the retention clause, the metadata-store.ts type union, and tests — no writer sets either status. An expired session's row is TTL-reaped, never re-statused. This is an ADR-0049 enforce-or-remove candidate.
Fix shape: either give failed/expired a writer (status the row on abort-failure / TTL expiry before it is reaped) or drop them from the enum and the retention onlyWhen.
Related contract note (also captured in the checklist-maintenance card): the chunked-init route takes totalSize, not size (packages/services/service-storage/src/storage-routes.ts:274), and forces chunkSize >= 5 MiB; the checklist step text says size.
Reproduction
Drive a chunked upload to completion and abandon a second session so it is reaped; then scan sys_upload_session.status across all rows → only ['in_progress', 'completed'] ever appear. Grep service-storage/src for 'failed'/'expired' → matches only in the enum, the retention clause, the type union, and tests — no producer.
Source
Extracted from the QA run #7635 (framework 92f26f7, console 6314e87f).
Symptom
A scan of all
sys_upload_sessionrows after driving both the chunked-complete flow and the abandon/reap flow returns exactly['in_progress', 'completed'].completingis written transiently and immediately overwritten. Thefailedandexpiredstatuses are never written by the service, yet the retention rule references them — so retention references two states the system can never enter.Root cause
Located. In
packages/services/service-storage/src/objects/system-upload-session.object.tsthestatusenum declaresfailedandexpired(lines 104-105) and the retentiononlyWhenis{ status: { $in: ['completed', 'failed', 'expired'] } }(line 134). A grep acrossservice-storagefindsfailed/expiredonly in that enum, the retention clause, themetadata-store.tstype union, and tests — no writer sets either status. An expired session's row is TTL-reaped, never re-statused. This is an ADR-0049 enforce-or-remove candidate.Fix shape: either give
failed/expireda writer (status the row on abort-failure / TTL expiry before it is reaped) or drop them from the enum and the retentiononlyWhen.Related contract note (also captured in the checklist-maintenance card): the chunked-init route takes
totalSize, notsize(packages/services/service-storage/src/storage-routes.ts:274), and forceschunkSize >= 5 MiB; the checklist step text sayssize.Reproduction
Drive a chunked upload to completion and abandon a second session so it is reaped; then scan
sys_upload_session.statusacross all rows → only['in_progress', 'completed']ever appear. Grepservice-storage/srcfor'failed'/'expired'→ matches only in the enum, the retention clause, the type union, and tests — no producer.Source
Extracted from the QA run #7635 (framework 92f26f7, console 6314e87f).