Skip to content

feat(corrections): record who made each correction log entry - #322

Open
iabaako wants to merge 3 commits into
feat/318-backcheck-target-metricsfrom
feat/321-correction-log-user
Open

iabaako wants to merge 3 commits into
feat/318-backcheck-target-metricsfrom
feat/321-correction-log-user

Conversation

@iabaako

@iabaako iabaako commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

Pull Request Summary 🚀

What does this PR do? 📝

This PR records who made each correction log entry. The correction log
(corr_log_{alias}) gets a new user column. Every new entry fills it,
whether it comes from the Corrections page or a check page. Entries logged
before this change show an empty user.

Closes #321. This PR is stacked on #318, so its base is
feat/318-backcheck-target-metrics. Retarget it to main once #318 merges.

Why is this change needed? 🤔

The log already records when, why and from where a change was made, but not
who made it. Reviewers need that for the audit trail. The backcheck
attribution log in #301 will use the same identity.

How was this implemented? 🛠️

src/datasure/
├── utils/reviewer.py            # NEW: reviewer identity + sidebar "Reviewer name" setting
├── processing/correction_log.py # `user` column in the log schema and legacy backfill
├── processing/corrections.py    # every new log entry records the reviewer
├── views/correction_view.py     # Correction Log shows `user` after `date`
└── app.py                       # renders the setting in the sidebar footer
  • Reviewer identity: every logging path calls one helper,
    get_reviewer_name(). It returns the "Reviewer name" set in the sidebar,
    otherwise the computer (OS) login. The name is saved in
    cache/user_settings.json and remembered across sessions. It holds a
    display name only, never credentials. Clearing it falls back to the OS
    login. If the login can't be looked up, the user is left empty and a warning
    is logged.
  • One lookup per save: the reviewer is looked up once per save, not once
    per row. All entries in one batch therefore record the same user.
  • Backfill: the new column extends the existing legacy-column backfill.
    Older logs load with an empty user and nothing else changes. Removing,
    refreshing, or importing corrections from a project config keeps the column
    as it is.
  • Replication package: correction_log.csv includes the user column.
  • Docs: USER_GUIDE.md (audit trail), ARCHITECTURE.md (cache files) and
    CHANGELOG.md.

Merge danger: this is a two-way door, but a narrow one. The column is
added to saved logs, and older code simply ignores it. The blast radius is the
correction log: the Correction Log table and the CSV header each gain a
column.

📝 The Reviewer name is saved once per install, not per browser session. This
is intentional: DataSure runs as a single-user desktop install today. When
shared installs are supported, a login will be added and the reviewer will
come from it, behind the same get_reviewer_name() helper.

How to test or reproduce ? 🧪

Automated: just test gives 3552 passed and 6 skipped, and
just pre-commit-run passes all hooks. The new and updated tests cover:

  • the default: with no name set, entries record the OS login
  • the override: a saved Reviewer name takes precedence, is trimmed, persists
    in the settings file, and a blank value clears it
  • fallbacks: an unreadable settings file or a failed login lookup doesn't
    crash anything
  • the sidebar input saving the name
  • single corrections, acceptances and batch applies all recording the reviewer
  • a legacy log loading with an empty user and no data loss, then taking new
    entries
  • the Correction Log display and the replication CSV including user

Manual:

  1. Run the app and open a project with corrected data.
  2. In the sidebar, open Reviewer: (your login). Make a correction on
    Correct Data. The Correction Log shows your login under user.
  3. Set a Reviewer name, then make another correction or accept an outlier from
    the Outliers page. The new entry shows that name.
  4. Restart the app. The name is still set.
  5. Clear the name. New entries go back to the OS login.
  6. Build a replication package. 4_output/3_logs/correction_log.csv has a
    user column.

Screenshots (if applicable) 📷

N/A. The only UI changes are a sidebar popover and one extra column in the
Correction Log table. Manual step 2 covers both.

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) (12 files, +320 / −7)
  • I have updated/added tests to cover my changes (if applicable)
  • I have updated/added requirements to cover my changes (if applicable) (N/A: no new dependencies, and getpass is in the standard library)
  • I have run linting and formatting on any code changes (if applicable)
  • I have updated the documentation (README, etc.) accordingly
  • 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 6, 2026 09:54
Add a `user` column to `corr_log_{alias}`. Every entry, from the
Corrections page or a check page, records the reviewer: the "Reviewer
name" set in the sidebar, else the OS login. The name is saved in
cache/user_settings.json and remembered across sessions. Logs saved
before this change load with an empty user, and the Correction Log
table and the replication package's correction_log.csv include it.

Closes #321

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Resolve the reviewer once per apply instead of once per log row, catch
only the OS-login lookup errors getpass raises and log them, show an
error instead of crashing when the reviewer name can't be saved, and
add the changelog entry.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@iabaako
iabaako requested a review from a team as a code owner October 6, 2026 10:08
@iabaako
iabaako requested a balanced review from Copilot October 6, 2026 10:19

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.

Copilot review overview

🟡 Changes recommended

An unhandled login-lookup exception can interrupt app rendering on supported Windows configurations.

Review effort: Balanced
Findings: 1 High severity

Open (1)
What changed in this PR

Adds reviewer attribution to correction logs for #321 and provides shared identity handling for future backcheck attribution.

Changes:

  • Adds a persistent reviewer-name override with an OS-login fallback.
  • Records and displays user, preserving legacy logs and CSV exports.
  • Updates tests and documentation.
File Description
tests/​views/​test_correction_view.py Tests reviewer display and legacy entries.
tests/​utils/​test_reviewer.py Tests identity settings and fallbacks.
tests/​replication/​test_package_builder.py Verifies reviewer CSV exports.
tests/​processing/​test_corrections.py Tests attribution across correction paths.
src/​datasure/​views/​correction_view.py Displays the reviewer column.
src/​datasure/​utils/​reviewer.py Adds reviewer identity and settings.
src/​datasure/​processing/​corrections.py Records reviewers on new entries.
src/​datasure/​processing/​correction_log.py Extends schema and legacy backfill.
src/​datasure/​app.py Adds the sidebar reviewer setting.
docs/​USER_GUIDE.md Explains reviewer attribution.
docs/​ARCHITECTURE.md Documents settings storage.
CHANGELOG.md Records the attribution feature.

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

Comment thread src/datasure/utils/reviewer.py Outdated
def _os_login() -> str:
try:
return getpass.getuser()
except (OSError, KeyError): # KeyError when the uid has no passwd entry

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Confirmed and fixed in c84cfac. Reproduced on Windows with Python 3.11: with LOGNAME, USER, LNAME and USERNAME unset, getpass.getuser() raises ModuleNotFoundError. _os_login() now catches ImportError along with OSError and KeyError, logs a warning and returns an empty name. A regression test (test_missing_pwd_module_gives_an_empty_name) covers it.

On Windows with Python 3.11/3.12 and no login environment variable,
getpass.getuser() falls back to importing the Unix-only pwd module and
raises ImportError, which broke the sidebar on every page. Catch it
with the other lookup errors so the reviewer falls back to an empty
name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sonarqubecloud

sonarqubecloud Bot commented Oct 6, 2026

Copy link
Copy Markdown

@iabaako iabaako linked an issue Oct 6, 2026 that may be closed by this pull request
4 tasks
@iabaako
iabaako added this pull request to stack #313 October 6, 2026 12:27

This branch has not been deployed

No deployments
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: record who made each correction log entry

2 participants