Skip to content

terni: Measurement::accumulate keeps both losses through a Failure - #2

Merged
systemic-engineer merged 2 commits into
mainfrom
reed/accumulate-loss
Nov 1, 2026
Merged

systemic-engineer merged 2 commits into
mainfrom
reed/accumulate-loss

Conversation

@systemic-engineer

Copy link
Copy Markdown
Contributor

Measurement::accumulate dropped the other side's loss on Failure, breaking "composition never drops loss" and the absorbing total. Red first; the first error still wins; the loss is l1.combine(l2). Property test over six loss types.

Merged by prism-Reed at Alex's request ("Regarding the merges. You can do that.").

🤖 Generated with Claude Code

https://claude.ai/code/session_01G8bTSUPSTntzPWqYHKMepf

systemic-engineer and others added 2 commits November 1, 2026 14:37
…ate drops the other side's loss on Failure

The arm `(Failure(e, l), _) | (_, Failure(e, l)) => Failure(e, l)` keeps
only the failing side's loss. The spec (prism/docs/spec/imperfect.md, "What
must never happen") forbids composition dropping loss and a failure's
earlier cost being thrown away; accumulate's own docstring says "Loss
combines."

Tests, in self-then-other order (same as the Partial+Partial arm):
- Partial(l1) + Failure(e, l2) → Failure(e, l1 ⊕ l2), and the mirror order
- Failure(a, l1) + Failure(b, l2) → Failure(a, l1 ⊕ l2): first error wins,
  as the existing arm already does
- total stays absorbing: Partial(total) + Failure(e, 3) currently gives 3
- law over u64, usize, Vec<String>, String, ConvergenceLoss, (u64, Vec)

Red against the unchanged implementation: 5 failing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G8bTSUPSTntzPWqYHKMepf
…ate carries both losses through a Failure

Only the Failure arm changes. The error is unchanged (self's error if self
failed, so the first wins when both fail); the loss is now
self_loss.combine(other_loss), the same order as Partial+Partial. A Success
side contributes zero, so Failure+Settled keeps its loss by the identity law.
total stays absorbing: Partial(total) + Failure(e, 3) is now Failure(e, total).

Mutants checked: restoring the drop fails 5 tests; swapping the combine order
in the self-failed arm fails 3.

fmt, clippy --all-targets -D warnings, cargo test --workspace (226 + 22 + 4
doc) clean. Line coverage 97.34 % (main 97.28 %, gate 99 % is older debt).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G8bTSUPSTntzPWqYHKMepf
@systemic-engineer
systemic-engineer merged commit 0caa62f into main Nov 1, 2026
1 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant