Diffline — product requirements
This product is a pull-request review tool for the halden/billing-service repository. Reviewers sign in, find a pull request in a filterable list, read its commits and unified or split diffs, discuss individual lines in threads, submit reviews and merge once every merge requirement is met.
Problem. Reviewers need to find the right change, read it line by line, track which conversations are still open and know exactly what blocks a merge, without merging something that has failing checks, missing approvals or unresolved discussion.
Users
- Reviewer — Read diffs, comment on lines, resolve threads and approve or request changes.
- Author — See what blocks the pull request and merge it once everything is satisfied.
- Phone or tablet user — Triage and review from a small screen without sideways scrolling.
Goals
- The merge gate states every unmet requirement and never allows a merge while one is unmet.
- Counts (tabs, files, additions, deletions, resolved conversations) always equal what is on screen.
- Diffs read correctly: each deleted line sits beside the line that replaces it in split view.
Out of scope
- Real source control
- Notifications and email
- Branch protection settings
Contents
Sign-in and sign-out
Session access to the pull request list.
- The sign-in page is headed "Sign in to" followed by the product name, with Username, Password and a "Sign in" button
- After sign-in the tab strip reads Open 8, Merged 3, Closed 2, All 13
- Empty username shows "Enter your username"
- Wrong password shows "Invalid credentials" and no list is shown
- Sign out is in the left rail, or in the bottom bar on a phone
Pull request list
Tabs, filters, search and sort over the repository’s pull requests.
- Order: #421, #420, #418, #417, #415, #414, #412, #409
- #421 is "WIP: audit log CSV export" with a Draft pill, label feature, "#421 opened Oct 18, 2026 by Ines Carvalho", "1 pending", 0 comments, "+5 -0"
- #412 "Add idempotency keys to POST /charges": labels feature and security, "4 passed", 4 comments, "+75 -1"
- #409 "Fix rounding in partial and prorated refunds": label bug, "1 failing", 3 comments, "+12 -4"
- #415 "Cache currency rates for 5 minutes": "3 passed", 1 comment, "+7 -0"
- Merged (3): #411, #405, #403
- Closed (2): #407 and #398
- All shows 13, first #421, last #398
- Label "security": 2 pull requests, #420 and #412
- Author "Bao Nguyen": 2 pull requests, #415 and #409
- "cache" returns only #415
- No match shows "No pull requests match these filters", "0 pull requests" and a "Clear filters" button that restores the 8 open pull requests
- "Awaiting my review": #414 and #412
- "Oldest": #409, #412, #414, #415, #417, #418, #420, #421
Pull request page
Conversation, Commits and Files changed tabs with a sidebar of reviewers, checks and conversations.
- #412: Open pill, "Tomasz Kowalski wants to merge tomasz/idempotency-keys into main", labels feature and security
- Tabs: Conversation 4, Commits 4, Files changed 4 with "+75 -1"
- Reviewers: Amira Hassan "approved"; Ines Carvalho and Bao Nguyen "review requested"
- Checks: build, unit-tests and lint "Passed · required"; e2e-smoke "Passed"
- Conversations: "1 of 2 resolved"
- #412: a13f7c2 "Add idempotency helpers", 5be09d1 "Wire idempotency into POST /charges", f20c6ae "Add idempotency_keys migration", 62d8b07 "Cover replay and conflict in tests", all by Tomasz Kowalski
- #411 shows "Merged commit 4be71c9 into main by ahassan using squash and merge on Oct 12, 2026."
Diff reading
Files changed tab with file tree, unified and split layouts and viewed marks.
- #412: "0 of 4 files viewed", Unified selected
- idempotency.ts +37 -0; charges.ts +15 -1; 0042_idempotency_keys.sql +9 -0; charges.test.ts +14 -0
- The first file section reads src/payments/idempotency.ts, "added", "+37 -0" with an unchecked Viewed box
- #412 shows "+75 -1" in the list and tab, and charges.ts "+15 -1"
- src/payments/refunds.ts on #409 reads "+3 -3"
- refunds.ts: left row 9 "const unused = (daysInPeriod - daysUsed) / daysInPeriod;" beside right row 9 "const unusedDays = daysInPeriod - daysUsed;"
- Left row 10 "return Math.round(total * unused);" beside right row 10 "return Math.floor((total * unusedDays) / daysInPeriod);"
- Unified view lists the deleted old lines 9 and 10, then the added new lines 9 and 10
- Folded file reads "Marked as viewed — the diff is hidden." with a "Show diff" button; Viewed stays ticked when the diff is shown again
- After viewing two files and reloading, "2 of 4 files viewed" is kept
Inline conversations
Comment on a line, then resolve and unresolve the thread.
- Composer reads "Comment on line 2" with Cancel and "Add comment"
- An empty comment shows "Comment cannot be empty" and the composer stays
- On success a toast "Comment added" appears; the Conversation tab reads 5 and the sidebar reads "1 of 3 resolved" listing idempotency.ts:2 as Unresolved
- Resolving charges.ts line 34 on #412 shows toast "Conversation resolved", summary "2 of 2 resolved" and gate line "All conversations resolved"
- Unresolving idempotency.ts line 4 shows toast "Conversation reopened"; the resolved count drops by one (from "1 of 2 resolved" to "0 of 2 resolved" with gate "2 unresolved conversations")
- idempotency.ts line 4 shows a Resolved pill and "Show resolved conversation (2 comments)"
- Expanded it shows Amira Hassan "Is 24 hours enough for clients that retry from a queue?" and Tomasz Kowalski "Matches the payment provider window. I can make it configurable in a follow-up."
Reviews
Approve or request changes from the Review changes popover.
- On #412 approving moves the Merge box from "1 of 2 required approvals" to "2 of 2 required approvals" and lists Ines Carvalho as "approved"
- "Add a comment explaining the requested changes" appears and the popover stays open
- Reviewer states are unchanged afterwards
- The popover shows "You can't approve your own pull request"
- The reviewer list and the approval count do not change
Merge gate and merge
A pull request merges only when every requirement is met.
- #412 initially: "1 of 2 required approvals" and "1 unresolved conversation" not met, others met, button disabled
- With unit-tests "Failed · required", the requirement reads "1 required check failing" as not met and the button is a disabled "Merge blocked"
- #421: "This pull request is still a draft", "1 required check pending", "0 of 2 required approvals" not met; "No changes requested" and "All conversations resolved" met
- #415: 3 checks passed (met); "0 of 2 required approvals", "Changes requested by smoreau" and "1 unresolved conversation" not met; Sophie Moreau is "requested changes"
- Methods include "Create a merge commit" (default) and "Squash and merge"; the squash title reads "Add idempotency keys to POST /charges (#412)" with counter "44/72"
- Dialog "Merge pull request #412?" with Confirm merge; toast "Pull request merged"
- Card reads "Merged commit <hash> into main by you using squash and merge on Oct 19, 2026."
- After merging #412 the tabs read Open 7, Merged 4, Closed 2, All 13
- #418: all five requirements met, "2 of 2 required approvals", method "Create a merge commit", Commit title "Docs: describe the webhook retry policy (#418)"
- After merging, the card reads "...using create a merge commit on Oct 19, 2026." and the merge button is gone
- Dialog "Close pull request #418?" with Cancel; toast "Pull request closed"; pill Closed; merge box "This pull request is closed. Reopen it to continue the review."; timeline "closed this pull request"
- Reopen shows toast "Pull request reopened", pill Open and an enabled "Merge pull request"
- "Ready for review" replaces the Draft pill with Open and adds timeline "marked this pull request as ready for review"
Keyboard shortcuts
Review the files without a mouse.
- j makes charges.ts current; v gives "1 of 4 files viewed" and folds it; s switches to Split; k returns to idempotency.ts
Non-functional requirements
- 16 px side margins
- On the pull request page the sidebar sections (Reviewers, Checks, Conversations, Labels) follow the conversation and the merge form is one full-width column
Glossary and rules
| Merge gate | The set of five requirements that must all be met before a pull request can merge. |
|---|---|
| Required check | A CI check marked "required"; it must pass for the gate to open. |
| Viewed | A per-file mark that folds the diff and counts toward "N of M files viewed". |