backnotprop/plannotator
tldr.page
Intent Since Base Github View 20260701 224500

Intent: "Since main" default view with three-stack panel

Build a new default code-review experience that answers "what would I see in GitHub" with zero configuration, by adding a since-base git diff type — merge-base(base, HEAD) compared against the working tree, plus untracked files — and making it the default for everyone, rendered as a three-section file panel (Committed / Changes / Untracked) in place of the flat tree.

The why: the two most common user complaints are "I just want to see what GitHub would show me" and "I just want to see what git status shows me," and the current DiffTypePicker default answers neither — it forces users to translate intent into git mechanics before anything renders. The composite diff dissolves that choice: the diff content is exactly the future PR (every diff on screen means "since main," no exceptions), while the section grouping is the git-status answer. Viewed — the app's most-used feature — stays as each row's primary action.

The how, server side: add a since-base case to runGitDiff (git merge-base <base> HEAD then git diff <mb> with no right-hand ref, plus the existing untracked appender, with the fresh-repo hasHead guard), and matching cases in getGitDiffFingerprint (HEAD sha + hashed mb-diff + untracked hash + base tip), getFileContentsForDiff (old = show <mb>:path, new = working tree), getGitContext diffOptions (emitted first, label "Since "), GIT_DIFF_TYPES, canStageFiles, WORKTREE_SUB_TYPES, compareTarget.diffTypes, and getLocalDiffInstruction. Compute a sections sidecar (git status --porcelain + git diff --name-only <mb>..HEAD, partitioned committed/changes/untracked with staged bits) and return it from /api/diff and /api/diff/switch when the type is since-base. Extend the startup ls-remote path to keep the remote tip SHA it currently discards, expose a baseBehindRemote flag, and add POST /api/fetch-base (runs git fetch origin <branch>). Flip resolveDefaultDiffType's fallback to since-base (explicit configs honored, legacy branchmerge-base mapping kept). Pi picks up all shared changes via vendor.sh; hand-mirror only the sections field and fetch-base endpoint in serverReview.ts.

The how, client side: a new Sections panel component sharing the FileTree's slot, with three sections sized viewport-adaptively (Changes and Untracked always fully rendered, Committed filling remaining room with a minimum-rows floor and an "N more files" expand), rows carrying viewed checkbox / staged dot / quiet stage button / status letter per the mockup; a persisted Sections|Tree toggle in the panel header (Commits slot reserved); zero pickers on the default screen with "vs origin/main" opening the existing BaseBranchPicker and a quiet footer "Advanced" row exposing today's DiffTypePicker (advanced modes render Tree-only); a "Baseline is behind GitHub · Fetch" banner wired to fetch-base; since-base added to STAGEABLE_DIFF_TYPES, OPTION_HINTS, the App.tsx worktree-subtype parse, and DiffTypeSetupDialog as the recommended option. Git only — jj, Perforce, workspace, and PR modes unchanged; nothing existing is removed.

References:

  • adr/research/code_review_panel_three_stack_mockup.svg
  • adr/research/SPIKE-github-view-composite-diff-20260701-222935.md
  • adr/research/synthesis-github-view-20260701-222935.md
  • adr/research/SPIKE-git-graph-view-20260618-220909.md (backlogged; reserved Commits toggle)
  • adr/specs/github-view-three-stack-20260701-222935.md
  • adr/decisions/005-since-base-github-view-default-20260701-223706.md