Development record
The orphan sweep silently deletes committed reading records. With an orphaned stage present and its record already in the ledger, an ingest whose payload fails at the type check deleted a committed record from the durable tier and printed only the type error: the rolled-back and cleared-stage fields are dropped on the error path, and the JSON render emits an error object without them, because the surface renders those fields only when a refusal record exists. The code's own comment says this must not happen. It is the worst shape a defect can take here, because the loss is durable, silent, and triggered by a payload that was itself refused: an operator sees a validation error and has no way to learn that a record was destroyed while it was being reported.
The orphan sweep silently deletes committed reading records. With an orphaned stage present and its record already in the ledger, an ingest whose payload fails at the type check deleted a committed record from the durable tier and printed only the type error: the rolled-back and cleared-stage fields are dropped on the error path, and the JSON render emits an error object without them, because the surface renders those fields only when a refusal record exists. The code's own comment says this must not happen. It is the worst shape a defect can take here, because the loss is durable, silent, and triggered by a payload that was itself refused: an operator sees a validation error and has no way to learn that a record was destroyed while it was being reported.
Grounds
- pursued: validate-then-mutate makes the invariant structural rather than rendered; if a refused ingest ever again removes a ledger record, TestARefusedRunLeavesTheOrphanInPlace and TestIngestDisclosesTheOrphanItLeftOnRefusal go red
Frontmatter
| id | iss-2608311517509690 |
|---|---|
| type | issue |
| lifecycle | resolved |
| severity | critical |
.abcd/work/issues/resolved/iss-2608311517509690-the-orphan-sweep-silently-deletes.md
open on GitHub ↗ · commit history ↗
mentions2
- iss-2609012043443066Deferring the orphan sweep to the commit path lengthens the window in which an orphan's reading records can be dispositioned before they are deleted. The sweep now runs only when a later ingest validates (iss-2608311517509690), so an orphaned run's reading records sit in the committed ledger for longer, and during that window capture's disposition verb can act on one of them. A later sweep then removes the item record by its id grammar and leaves the disposition record dangling, pointing at an item that no longer exists. The dangling case existed before the move — any orphan could be dispositioned between its crash and the next invocation — but the move widens it from the next invocation to the next one that validates. A future change could have the sweep refuse, or report, an orphan whose records already carry a disposition.
- spc-63The cold-reading output contract: a strict per-position schema, a supply-regime gate, and a staged ingest that leaves evidence or nothing