diff --git a/DEBT-DESIGN.md b/DEBT-DESIGN.md index 0c4c065..6c4f1c9 100644 --- a/DEBT-DESIGN.md +++ b/DEBT-DESIGN.md @@ -408,3 +408,36 @@ which is the priority function slice one deliberately omitted. None of these required a schema commitment to discover. That was the point of making the first slice read-only. + +## The invariant slice B was written against + +**A projection must never manufacture provenance to make evidence easier to +classify.** `task=None` is better than a confident lie. + +Both defects the first live run of durable observations exposed were failures +of exactly this rule, and both looked perfectly reasonable in code: + +- **False attribution.** The worker's ring outlives the work it describes, so + binding its entries to whatever task the worker is running now produced a + clean, well-formed, wrong association between an old failure and an unrelated + task. The task is read from the observation itself, and only an observation + that names no task belongs to the current lease. +- **Manufactured recurrence.** Treating "still present in the ring" as "it + happened again" turned one failure into four incidents. Presence is not + occurrence: an incident opens only when the entry advances past what has + already been accounted for, and that high-water mark survives the close. + +Either one would have corrupted the ledger while every number in it stayed +plausible, which is the specific way this repo's bugs have always presented. + +## Signatures are frozen at write time + +The signature is computed when an incident is recorded and stored in the event. +Re-projecting an old log with a newer normalizer therefore changes nothing: +running one history through the build before and after the pane-name fix +produced identical output. + +That is the intended behavior. An event must not silently change meaning +because normalization code changed. Repairing historical signatures is an +explicit migration or reclassification event, never a different projection +result from the same log.