Skip to content

fix(corrections): detect source fixes for missing values and align acceptance status - #346

Merged
iabaako merged 5 commits into
mainfrom
fix/337-replay-missing-value
Oct 19, 2026
Merged

iabaako merged 5 commits into
mainfrom
fix/337-replay-missing-value

Conversation

@iabaako

@iabaako iabaako commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Pull Request Summary 🚀

What does this PR do? 📝

Fixes both bugs in #337:

  1. Replay no longer overwrites a value that was fixed at source when the correction was made on a missing value.
  2. An acceptance's Status in the Correction Log now agrees with the check pages.
  • _current_value_mismatch: no longer skips a correction whose recorded value was missing. Missing still matches missing, so the correction applies only while the cell is still missing.
  • Replay (refresh_corrected_data): accept rows are no longer judged mid-replay. After replay, their status is set against the final data, using the same rule as get_active_acceptances.
  • Every log save (_append_log_rows): when the log has accept rows, their statuses are refreshed the same way.

Closes #337

Why is this change needed? 🤔

  • Bug 1 (data corruption): age is blank, and a correction fills in 5. The field team later fixes it at source to 8. Replay silently overwrote the 8 with 5. When the original value was not missing, replay already kept the source value and reported a failure.
  • Bug 2: after an accept followed by a modify of the same cell, the log showed the accept as Successful while the check pages correctly treated it as inactive.

Release blocker for v1.2.0 (#339).

How was this implemented? 🛠️

  • Removed the early return. _values_match already treats missing as matching missing, so a correction of a missing value still applies while the cell is missing, and fails with "changed since this correction was recorded" once the source has a value.
  • _apply_entry applies the same check when a correction is first saved, so an entry can't apply now and then fail on the next replay.
  • New _with_acceptance_statuses judges accept rows against the final corrected data. It runs after replay and on log saves that include accept rows.

Points for review:

  • Existing logs are safe. 1.0.0 and 1.1.0 recorded current_value from the actual cell value, so a null in an existing log really means the cell was missing.
  • Only null/NaN counts as missing, not an empty string, consistent with the rest of the module.

Merge danger: two-way door. No log schema change. Blast radius: corrections. Replay results and Status values can change for existing logs, but only for the two cases above.

How to test or reproduce ? 🧪

Before / After: the reproductions from #337 are now tests in tests/processing/test_corrections.py:

  • Missing → 5, source still missing: applied (this passed before too).
  • Missing → 5, source fixed to 8: was age 5 with no failure; now age 8 with 1 failure.
  • Applying missing → 5 when the cell now has a value: rejected.
  • Accept 25, then modify 25 → 30, then replay: was Successful; now Inactive.
  • The same without replay: Inactive.
  • A new accept of the corrected value: Successful.

just test: 3912 passed, 6 skipped. On one earlier run, test_prep_regex.py::test_safe_regex_no_backtracking failed once and then passed, both alone and on the full rerun. It looks timing-dependent and unrelated.

Screenshots (if applicable) 📷

N/A

Checklist ✅

  • I have run and tested my changes locally
  • I have limit this PR to less than 1000 lines of code change (if not, explain why)
  • I have updated/added tests to cover my changes (if applicable)
  • I have updated/added requirements to cover my changes (if applicable) (N/A)
  • I have run linting and formatting on any code changes (if applicable)
  • I have updated the documentation (README, etc.) accordingly (CHANGELOG, USER_GUIDE "Verifying Corrections", ARCHITECTURE status)
  • I have reviewed and resolved any merge conflict

Reviewer Emoji Legend

:code: Meaning
😃👍💯 :smiley: :+1: :100: I like this...

...and I want the author to know it! This is a way to highlight positive parts of a code review.
⭐⭐⭐ :star: :star: :star: Important to fix before PR can be approved...

And I am providing reasons why it needs to be addressed as well as suggested improvements.
⭐⭐ :star: :star: Important to fix but non-blocking for PR approval...

And I am providing suggestions where it could be improved either in this PR or later.
⭐ :star: Give this some thought but non-blocking for PR approval...

...and consider this a suggestion, not a requirement.
❓ :question: I have a question.

This should be a fully formed question with sufficient information and context that requires a response.
📝 :memo: This is an explanatory note, fun fact, or relevant commentary that does not require any action.
⛏ :pick: This is a nitpick.

This does not require any changes and is often better left unsaid. This may include stylistic, formatting, or organization suggestions and should likely be prevented/enforced by linting if they really matter
♻️ :recycle: Suggestion for refactoring.

Should include enough context to be actionable and not be considered a nitpick.

🤖 Generated with Claude Code

iabaako and others added 2 commits October 15, 2026 21:55
Replay skipped the current-value check when the recorded value was
missing, so a correction of a blank cell silently overwrote a value later
filled in at source. A missing recorded value is now checked like any
other: the correction reapplies only while the cell is still missing, and
fails with a reason otherwise. Applying such an entry checks the same.

An accept row's Status was judged against the data at its position in
the log, so a later correction of the same cell left it `Successful`
while `get_active_acceptances` dropped it. Accept statuses are now judged
against the final corrected data on replay and whenever log rows are
appended.

Closes #337

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@iabaako
iabaako requested a review from a team as a code owner October 15, 2026 21:57
@iabaako iabaako added this to the v1.2.0 milestone Oct 15, 2026
@iabaako iabaako self-assigned this Oct 15, 2026
@iabaako iabaako mentioned this pull request Oct 15, 2026
19 of 56 tasks
@iabaako
iabaako requested a balanced review from Copilot October 15, 2026 22:14

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Acceptance-status refresh can inspect the wrong record and incorrectly mark an active acceptance inactive.

1 open finding
What changed in this PR

Addresses #337, a v1.2.0 release blocker, by protecting source-fixed values during correction replay and aligning acceptance statuses with final corrected data.

Changes:

  • Check missing recorded values before applying corrections.
  • Refresh acceptance statuses after replay and log appends.
  • Add regression tests and update documentation.
File Description
tests/​processing/​test_corrections.py Adds missing-value and acceptance-status regressions.
src/​datasure/​processing/​corrections.py Updates correction validation and acceptance-status refresh.
docs/​USER_GUIDE.md Explains preservation of source-fixed values.
docs/​ARCHITECTURE.md Documents acceptance-status evaluation timing.
CHANGELOG.md Records both fixes for #337.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/datasure/processing/corrections.py Outdated
Replay and acceptance-status refresh located a record by the first column
holding its KEY value, so a value repeated in another column could point
them at the wrong record and mark an active acceptance Inactive on save.

Saves now pass through the key column their callers already have. Replay
resolves it from the check config (survey_key, or the backcheck KEY for
backcheck data), falling back to the old lookup only when none is set.

Addresses Copilot review feedback on #346.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@iabaako
iabaako requested a review from dmartinezIPA October 15, 2026 22:57

@wkirui wkirui left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All tests pass.

@sonarqubecloud

Copy link
Copy Markdown

@iabaako
iabaako merged commit 7a3a65d into main Oct 19, 2026
5 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.

Corrections: replay silently overwrites a value fixed at source when the original was missing

3 participants