Superseded evidence is distinguished by opacity alone #138

Closed
opened 2026-08-04 05:09:24 +00:00 by claude-bot · 1 comment

Severity: LOW — accessibility gap, same family as #102

Found while building #102 and deliberately not fixed there, because #102 did not name it and fixing it needs new copy rather than a CSS change.

The problem

EvidenceSection renders a retired row at 40% opacity and nothing else:

<button className="evidence-row" style={{ opacity: ev.is_active ? 1 : 0.4 }}>

That is a state conveyed by visual weight alone, which is the defect #102 spent its length on in three other places. Specifically:

  • A screen reader announces a superseded row identically to a live one. The evidence a reviewer is looking at and the evidence the archive has retired sound the same.
  • Opacity is not colour, so it is not caught by a contrast check — but it is the same class of failure, and it makes the row's text worse against its background rather than better.
  • The row is a button since #96 and remains adoptable, so a reviewer can adopt a date from evidence that has been superseded without anything saying so. That is the part with consequences: supersede exists (#70, #80) precisely because a piece of evidence has been judged no longer to hold, and adopting from it puts a retired date into a live decision.

Why it was left

#102's scope was the three cases it enumerated. Adding a fourth mid-pass would have meant inventing user-facing copy — what a retired row should say — inside an accessibility-and-layout commit, without anyone having agreed the wording. Better as its own small piece of work.

Scope

  • Give a superseded row a visible, readable marker — a "Superseded" label or similar — rather than only dimming it.
  • Convey the same state to assistive technology, so it is announced and not merely seen.
  • Decide whether a superseded row should still be adoptable at all. Two defensible answers: keep it adoptable but make the state unmistakable, or make it inert the way an unparsed row already is. This is a product question, not a technical one — a reviewer might legitimately want to re-adopt a date that was retired in error.
  • If it stays adoptable, consider whether the resulting decision should record that its adopted_evidence_id (#96) pointed at inactive evidence.

Done when

  • A superseded row is identifiable without relying on opacity
  • Assistive technology announces the state
  • Whether such a row can be adopted from is a decision that has been made on purpose, and is tested

References

  • frontend/src/pages/ReviewWorkspacePage.tsxEvidenceSection
  • #102 (accessibility baseline, where this was found), #96 (adoption), #70 / #80 (supersede)
## Severity: LOW — accessibility gap, same family as #102 Found while building #102 and deliberately not fixed there, because #102 did not name it and fixing it needs new copy rather than a CSS change. ## The problem `EvidenceSection` renders a retired row at 40% opacity and nothing else: ```tsx <button className="evidence-row" style={{ opacity: ev.is_active ? 1 : 0.4 }}> ``` That is a state conveyed by **visual weight alone**, which is the defect #102 spent its length on in three other places. Specifically: - A screen reader announces a superseded row identically to a live one. The evidence a reviewer is looking at and the evidence the archive has retired sound the same. - Opacity is not colour, so it is not caught by a contrast check — but it *is* the same class of failure, and it makes the row's text worse against its background rather than better. - The row is a `button` since #96 and remains adoptable, so a reviewer can adopt a date from evidence that has been superseded without anything saying so. That is the part with consequences: `supersede` exists (#70, #80) precisely because a piece of evidence has been judged no longer to hold, and adopting from it puts a retired date into a live decision. ## Why it was left #102's scope was the three cases it enumerated. Adding a fourth mid-pass would have meant inventing user-facing copy — what a retired row should *say* — inside an accessibility-and-layout commit, without anyone having agreed the wording. Better as its own small piece of work. ## Scope - Give a superseded row a visible, readable marker — a "Superseded" label or similar — rather than only dimming it. - Convey the same state to assistive technology, so it is announced and not merely seen. - Decide whether a superseded row should still be adoptable at all. Two defensible answers: keep it adoptable but make the state unmistakable, or make it inert the way an unparsed row already is. **This is a product question, not a technical one** — a reviewer might legitimately want to re-adopt a date that was retired in error. - If it stays adoptable, consider whether the resulting decision should record that its `adopted_evidence_id` (#96) pointed at inactive evidence. ## Done when - [ ] A superseded row is identifiable without relying on opacity - [ ] Assistive technology announces the state - [ ] Whether such a row can be adopted from is a decision that has been made on purpose, and is tested ## References - `frontend/src/pages/ReviewWorkspacePage.tsx` — `EvidenceSection` - #102 (accessibility baseline, where this was found), #96 (adoption), #70 / #80 (supersede)
Author

Done in 1dfd22c, CI green (run 64).

The product question is decided: a superseded row is now inert. Recording the reasoning, since the issue rightly refused to default it.

supersede exists precisely because a piece of evidence has been judged no longer to hold. Adopting from one would carry a retired date into a live decision — and since #96 records provenance as a foreign key, the resulting decision would point at inactive evidence and look entirely legitimate in the history afterwards. That is the silent-wrong-data shape this project is most careful about. #96 had already set the precedent that a row which cannot answer is not activatable (the unparsed June 83?), so this is consistent rather than novel.

The counter-argument in the issue — a reviewer might want to re-adopt a date retired in error — turns out to be the weaker path even for that reviewer. They are not stuck: they record manual evidence saying so (#101, which landed alongside this), and that leaves a reason in the chain rather than a live decision quietly sourced from a retired row. Better provenance, not worse.

The three other halves:

  • The row carries "Superseded — no longer part of the answer" as ordinary text, so it is read and seen by the same means. An aria-label would have fixed the announcement and left the screen saying nothing.
  • It recedes by colour, using the --text-muted token measured under #102, rather than by opacity: 0.4. The old dimming pushed the text towards its background — the one direction a contrast rule never permits — and rendered pixel-identical to .btn:disabled, so "withdrawn" and "unavailable" looked alike.
  • It keeps its full weight in the layout. Superseded evidence is part of how the date was arrived at, and a panel that hid it would be hiding the reasoning.

The follow-up the issue anticipated — "consider whether the resulting decision should record that its adopted_evidence_id pointed at inactive evidence" — is now moot: that decision cannot be made.

Mutation-tested: dropping the is_active check from adoptable() fails two tests, removing the label fails one, reinstating the inline opacity fails one. Frontend tests 185 → 190.

Done in `1dfd22c`, CI green (run 64). **The product question is decided: a superseded row is now inert.** Recording the reasoning, since the issue rightly refused to default it. `supersede` exists precisely because a piece of evidence has been judged no longer to hold. Adopting from one would carry a retired date into a live decision — and since #96 records provenance as a foreign key, the resulting decision would point at inactive evidence and look entirely legitimate in the history afterwards. That is the silent-wrong-data shape this project is most careful about. #96 had already set the precedent that a row which cannot answer is not activatable (the unparsed `June 83?`), so this is consistent rather than novel. The counter-argument in the issue — a reviewer might want to re-adopt a date retired in error — turns out to be the weaker path even for that reviewer. They are not stuck: they record manual evidence saying so (#101, which landed alongside this), and that leaves a *reason* in the chain rather than a live decision quietly sourced from a retired row. Better provenance, not worse. The three other halves: - The row carries **"Superseded — no longer part of the answer"** as ordinary text, so it is read and seen by the same means. An `aria-label` would have fixed the announcement and left the screen saying nothing. - It recedes by **colour**, using the `--text-muted` token measured under #102, rather than by `opacity: 0.4`. The old dimming pushed the text *towards* its background — the one direction a contrast rule never permits — and rendered pixel-identical to `.btn:disabled`, so "withdrawn" and "unavailable" looked alike. - It keeps its full weight in the layout. Superseded evidence is part of how the date was arrived at, and a panel that hid it would be hiding the reasoning. The follow-up the issue anticipated — "consider whether the resulting decision should record that its `adopted_evidence_id` pointed at inactive evidence" — is now moot: that decision cannot be made. Mutation-tested: dropping the `is_active` check from `adoptable()` fails two tests, removing the label fails one, reinstating the inline opacity fails one. Frontend tests 185 → 190.
Sign in to join this conversation.
No description provided.