You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
ART M4: review — full paging, include/exclude, versioned cell edits (BR-25, BR-26, BR-27) #108
Review is recorded now and applied in M6. M4 records include and exclude decisions and cell edits against the stored upload (M3's source_rows), and everyone in the tenant can see them. The table imported at upload time doesn't change. M6's approval and staged import will import the reviewed version.
Who reviews:reviewer and tenant_admin may decide rows and edit cells. Everyone with read_rows can view.
A reason is required for every decision and edit. The API refuses an empty one.
Parts
M4a (API and database):
Insert-only row_decisions and cell_edits, where the latest entry wins and the history is kept.
The column types each upload used are stored, so every row can be validated, not only the first 200 failures.
GET /api/csv/uploads/{id}/rows pages through every row, giving original and current values, validation errors and the row's decision.
Endpoints to record a decision and a cell edit, plus a row's history. Each change is also written to the audit log, with before and after values.
M4b (frontend): a review screen that pages through every row, with include and exclude, cell edits and the history.
✅ PUT …/rows/{n}/decision and PUT …/rows/{n}/cells/{column} record decisions and edits; GET …/rows/{n}/history lists them; each change writes an audit row with before/after values
✅ Review screen at /review/{uploadId} pages 100 rows at a time with column types
✅ Reviewers and tenant admins can include/exclude rows and edit cells; dialog requires a reason, Save disabled until entered
✅ History button per row shows decisions and edits with who/when/why
✅ scripts/e2e/m4-review.js exercises the full flow against real API + frontend + PostgreSQL 16
Owner constraints from 28 Oct 2026:
✅ Review is recorded against stored source_rows; the imported table is unchanged; M6 will apply the reviewed version at import
✅ Role gating: reviewer and tenant_admin can write; API refuses other roles; test_roles.py covers all 26 role/endpoint scenarios
✅ Reason required at API (422 on empty), at DB (CHECK constraint), and at UI (Save disabled); mutation test confirms removing the API check fails the test
V&V evidence worth noting
335 integration tests passed on local PostgreSQL 16 replica; 88 unit tests passed; 147 frontend tests passed
26 of 26 role-matrix tests passed
17 positive and 16 negative test cases documented in docs/test-cases/M4-review.md with manual + automated coverage
Mutation testing done explicitly in both PRs: code was deliberately broken (latest-wins swap, original-value validation, uploader allowed to review, reason-required removal) and each broken case failed the expected test
VCRM: BR-25, BR-26, BR-27 all moved to ✅
Known limitation (not a defect)
T&E-mode uploads have no stored column types, so their values are reviewed as text with no type validation (PR #142, "Not in this PR"). Deferred by design; not blocking M4 acceptance.
Activity
amar-python commentedon Oct 28, 2026
Decisions by the product owner, 28 Oct 2026
source_rows), and everyone in the tenant can see them. The table imported at upload time doesn't change. M6's approval and staged import will import the reviewed version.reviewerandtenant_adminmay decide rows and edit cells. Everyone withread_rowscan view.Parts
row_decisionsandcell_edits, where the latest entry wins and the history is kept.GET /api/csv/uploads/{id}/rowspages through every row, giving original and current values, validation errors and the row's decision.Generated by Claude Code
fix(api): allow PUT in CORS so the browser can send review changes (#108
test(review): positive and negative test cases for the review API (#108)
Merge pull request #142 from amar-python/feat/108-m4a-review-api
Merge pull request #143 from amar-python/feat/108-m4b-review-screen
amar-python commentedon Nov 2, 2026
Closed — accepted (2026-11-02)
Delivered by PR #142 (M4a, API/DB) and PR #143 (M4b, frontend), both merged to main. CI green on both.
Acceptance criteria vs delivered
M4a (#142):
row_decisionsandcell_editstables (migration 0008); triggers reject UPDATE/DELETE/TRUNCATE; CHECK rejects blank reasonuploads.columns,uploads.column_types); every row validates against stored types, not capped at 200 failuresGET /api/csv/uploads/{id}/rows?offset=&limit=returns columns, types, totals, excluded/edited counts, per-row original/current/decision/errorsPUT …/rows/{n}/decisionandPUT …/rows/{n}/cells/{column}record decisions and edits;GET …/rows/{n}/historylists them; each change writes an audit row with before/after valuesM4b (#143):
/review/{uploadId}pages 100 rows at a time with column typesscripts/e2e/m4-review.jsexercises the full flow against real API + frontend + PostgreSQL 16Owner constraints from 28 Oct 2026:
source_rows; the imported table is unchanged; M6 will apply the reviewed version at importreviewerandtenant_admincan write; API refuses other roles;test_roles.pycovers all 26 role/endpoint scenariosV&V evidence worth noting
docs/test-cases/M4-review.mdwith manual + automated coverageKnown limitation (not a defect)
T&E-mode uploads have no stored column types, so their values are reviewed as text with no type validation (PR #142, "Not in this PR"). Deferred by design; not blocking M4 acceptance.
Related