Running checklist for the clean-room build. Legend: ✅ done · 🔄 in-flight · ⛔ blocked · ⬜ not started.
Build order (per
docs/spec/16-implementation-plan.md): P0 scaffold → P1 read-only walking skeleton (rpc-contract → core → web-server → ui), host-git-first. Then P2–P5 + VSCode extension. Verify → commit → status → continue at each boundary; never advance on red.
main— P0–P3 all landed here; oldfeat/*branches merged/abandoned.
- ✅ Feature branch created.
- ✅
LICENSE(MIT),PROVENANCE.md,PROGRESS.md. - ✅ Spec digestion (8 parallel readers →
docs/_impl-notes/03/02/14/15/04/05/10/12). - ✅
docs/_impl-notes/DECISIONS.md— locked all implementer-gap resolutions (D1–D10): method tags, repoId hash, NDJSON via lib, side-channel routes, stale-AC reconciliations, authored P1 success Schemas.
- ✅ pnpm monorepo:
packages/{core,rpc-contract,ui}+apps/{web-server,vscode-ext},workspace:*, one root lockfile. - ✅ Shared
tsconfig.base.json(strict,module: Preserve+moduleResolution: Bundler, project refs); oxlint + oxfmt; Vite 8 / Rolldown (output.codeSplitting.groups[]); Tailwind v4 via@tailwindcss/vite; Base UI1.0.0-rc.0(all 12 needed primitives present; HoverCard→PreviewCard, DropdownMenu→Menu); base-lyra placeholder Button (full registry vendoring deferred to P1). - ✅ Pinned EXACTLY:
effect@4.0.0-beta.84,oxfmt@0.55.0,oxlint@1.70.0. tsgolint not wired (advisory). - ✅ CI (
.github/workflows/ci.yml) +pnpm gate= license-audit → lint → format:check → typecheck → build → test → depcheck. License audit: prod strict-permissive, dev allows build-time MPL-2.0 (lightningcss, documented), strong copyleft denied. Dep-direction check enforces D10 + socket rule. - ✅ Gate green on empty skeleton (5 pkgs build; 5 tests pass).
- Flags: Base UI rc.0 is npm-deprecated prerelease (pinned exact, re-evaluate); TS pinned
^5.9(5.9.3) over 6.0.3.
- ✅ All
⚠symbols verified accurate at the pin via a RUNNING in-memory round-trip. Playbook locked:Rpc.make(tag, {payload, success, error, stream})(payload = bare fields ok; success/error MUST be Schemas;stream:true⇒ top-level errorNever);RpcGroup.make(...)variadic; servergroup.toLayer({Tag: handler}); client object keyed by tag;Stream.runCollect→Array. - ✅ In-memory contract-test transport found:
RpcTest.makeClient(group)(NF-TEST-6). Adapter now re-exportsRpcTest. Smoke test kept atpackages/rpc-contract/src/_contract-smoke.test.ts. - Flag carried to contract author: test files are excluded from
tsc -b; contract type-assertions need a dedicated test typecheck config.
- ✅
rpc-contract:CbranchRpcs(10 P1 methods), GitError (23 codes), Domain/InvalidationEvent, LogQuery/DiffSpec, authored success Schemas; in-memory contract tests (NF-TEST-5/6); test typecheck wired. (commit 4e08d00) - 🔄
core: GitEngine + host-git backend (exact05commands);cat-file --batchpool;--no-optional-locks; repoId = SHA-256 of common git dir (D2); non-interactive git env; per-repoIdEffect.Semaphore(1)scaffold.- ✅ core-A: host-git infra (runGit/env/error-classify, cat-file pool, SHA-256 repoId, version gate ≥2.37, semaphore scaffold) + config store (NF-CFG-7) +
repo.open/state/recentList/recentRemove+ fixture harness (NF-TEST-3/4) + 77 unit tests. Root gate now includes coretypecheck:test. (commit 9074957) - 🔄 core-B:
log.stream,commit.detail,commit.diff,diff.workingFile,file.contentAtRev,repo.subscribe(chokidar→InvalidationEvent per 15) + parsers + tests.
- ✅ core-A: host-git infra (runGit/env/error-classify, cat-file pool, SHA-256 repoId, version gate ≥2.37, semaphore scaffold) + config store (NF-CFG-7) +
- ✅ NF-TEST-11 coverage gate:
@vitest/coverage-v8installed;vitest.coverage.config.tsat root enforces ≥80% lines+branches for core+rpc-contract (96.27% lines / 82.13% branches). Per-package thresholds documented inpackages/{core,rpc-contract}/vitest.config.ts.pnpm coverage+pnpm gatewired.
Backbone built sequentially in main tree (core → web-server → ui) to keep one clean lockfile/gate per step; parallel fan-out reserved for install-free intra-package work (e.g. UI view panels).
- ✅
web-server: Effect platform HTTP/WS (one multiplexed NDJSON socket at/rpcviaRpcServer.layerHttpprotocolwebsocket+RpcSerialization.layerNdjson) + static SPA serve (HttpStaticServer, spa fallback)- HTTP side-channel (
GET /sidechannel/blob, blob via the enginecat-filepool, NF-SEC-5/6 containment) + global Origin/Host allowlist on BOTH HTTP routes and the WS upgrade (NF-SEC-3) + default loopback bind 7420 with non-loopback warning (NF-PKG-2/9) + startup git-version gate (NF-PKG-5, viagitEngineLayer). Bound on Node via@effect/platform-node@4.0.0-beta.84(DECISIONS D11 —effectcore ships no Node listener; spec-literal wiring otherwise). 10 RPC handlers →GitEngineApi; migrated off the P0 placeholder bridge. 37 unit + 1 real end-to-end round-trip test (NF-TEST-8). Gate green (168 tests). Chokidar→bus wiring is the client step (below).
- HTTP side-channel (
- ⬜
ui: shell (Resizable, cmdk), status summary, virtualized streaming history + graph (10), details panel, read-only diff (react-diff-view + Shiki) + file-at-rev (CodeMirror 6); React Query sole synced feeder + Zustand ephemeral.
- ✅
05AC-1…AC-15 pass (unit+integration+component tests; see coverage below).- AC-1/5 (open/state) — e2e + repo.test.ts; AC-2 (invalid open) — repo.test.ts + git-engine.test.ts; AC-3 (recent list) — git-engine.test.ts; AC-4 (status porcelain) — repo.test.ts; AC-6/7 (history scale/columns) — history.test.tsx + graph layout tests; AC-8 (filters) — FilterBar.test.tsx + filters.test.ts; AC-9 (quick-find) — quick-find.test.ts; AC-10 (details) — e2e + components.test.tsx; AC-11 (merge diff) — diff.test.tsx; AC-12 (diff modes) — diff.test.tsx; AC-13 (file at rev) — e2e + file-at-revision.test.tsx; AC-14 (binary/submodule/large) — diff.test.tsx; AC-15 (read-only) — no mutation API exposed.
- ✅ Tests: 253 total (core unit, rpc-contract contract, ui component, one e2e happy-path NF-TEST-8, watcher→refetch NF-TEST-10).
- ✅ Gate: license-audit → oxlint → oxfmt → typecheck → build → test → coverage (≥80%) → depcheck. Green.
- ⬜ Perf: NF-PERF-1/2/3 measured on reference repo within budget (
scripts/measure-perf.mjsready; run against a 50k-commit repo on reference hardware per docs/spec/12).
Routing is a cross-cutting concern that needs to land before the app grows more navigation surfaces. It is not a separate milestone but a prerequisite for all future work. See DECISIONS D13.
- ✅ Add
react-router@^8topackages/ui(8.0.1). - ✅ Define
router.tsxwith the route tree:/(landing → redirect to last repo or empty state),/repos/:repoId(history),/repos/:repoId/commits/:oid(selected commit), plus placeholder routes for/repos/:repoId/branches/:name,…/tags/:name,…/worktrees/:id,…/stash/:index,…/blame/:rev/*. - ✅ Wrap the app in
<RouterProvider>inmain.tsx(route element renders<App>). - ✅ Migrate
activeRepoIdandselectedOidfrom Zustand-only to URL-driven: write side usesuseNavigation()(navigation.ts);<SyncRouteToStore>mirrors route params → store (useLayoutEffect, no first-paint flash) so legacy store subscribers keep working. - ✅ Update component tests to wrap navigation-using components in
<MemoryRouter>(components.test.tsx). - ⬜ VS Code extension WebView caveat (D13):
MemoryRouterentry point deferred to VSCode ext milestone.
- ⬜ P2 (
06) · P3 (07) · P4 (08/11) · P5 (09) · VSCode extension (13).
- (none yet)
Per-feature vertical slices, easiest-first (D18). Each = a core commit then a ui commit.
- ✅ S1 — gc. core: bootstrapped P5 scaffolding (
schemas/phase5.tsGcPrune/GcResult,index.tsbarrel,group.test.tsP5 catalog/round-trip),RepoGcmethod + handler, puregit/maintenance.ts(gcArgs+gc, whole-run lock),api.tsfacade +useGc(invalidatesrefs+commits). ui:GcDialog(aggressiveCheckbox+ pruneSelect, non-dismissable while running, captured-output<pre>+ toast, mid-oprole="alert"warn-only) +gcDialogOpenstore slice + wiredrepository.maintenance.compress. REQ-P5-GC-001..004. - ✅ S2 — clean. core:
CleanEntry/CleanPreview/CleanResult;CleanPreview(read) +Clean(✎) RPCs;git/clean.ts(pure argv builders, C-unquote for git's quoted-path form, empty-pathspec no-op guard at engine + UI); engine/live (preview lockless, clean repo-locked); api facade + options-keyedcleanPreviewkey +useCleanPreview(enabled-gated)/useClean. ui:CleanDialog(two option checkboxes, Preview, would-remove list, destructiveDestructiveConfirmDialoggated on previewed-options==current ∧ entries>0 ∧ !fetching, empty-state) +cleanDialogOpenslice + wiredcommands.clean+ StatusPanel "Clean…". REQ-P5-CL-001..005. - ✅ S3 — archive. core:
ArchiveFormat/ArchiveDescriptor(no size);ArchivePrepare(read) RPC; newstreamGitBytesraw-byte runner (byte-fidelity vs the lossystreamGit);git/archive.ts(format table, prefix/sub-path sanitizers, argv); internal route-onlyarchiveStreamengine method (not in the group) +GET /sidechannel/archivestreamed route (re-validates tree-ish before 200, no partial download; inherits the Origin/Host guard) with end-to-end integration probes; api facade +useArchivePrepare. ui:ArchiveDialog(treeish/format/prefix/subpath, fetch→blob→<a download>, inline "Exported …(N bytes)", invalid→inline error no download) +archiveDialogstore slice + wiredcommands.archive(retag P5) + commit-context "Archive revision…". REQ-P5-AR-001..005. - ✅ S4 — reflog. core:
ReflogEntry/ReflogPage;ReflogList(read) RPC;git/reflog.ts(git log -g -zmachine parser, action = %gs before first colon, malformed records skipped; skip-cursor reuses history codec; no-reflog/unborn → empty page); engine/live lockless; api facade + refs-domain reflog key +useRefloginfinite query. ui:ReflogPanel(refSelect, rows with selector/oid/action/ message, per-row menu: Create-branch→BranchCreate(startPoint=oid), Reset soft·mixed direct / hard behind consequence-confirmResetTo(target=oid), View-commit→selectOid, Load more) as a routed"reflog"view (ActiveView+VIEWS+switch); wiredcommands.reflog+view.showReflog. REQ-P5-RL-001..006. - ✅ S5 — bisect. core:
BisectMark/BisectState/BisectStatus;BisectStart/Mark/Reset(✎) +BisectStatus(read) RPCs;git/bisect.tscomputeBisectStatus(machine-derived fromrefs/bisect/*rev-list --bisect-vars, concluded ⟺ bisect_rev===bad; "could be any of" → unbisectable); lock-held mutations + lockless status; inProgress-domainbisectkey +useBisectStatus/Start/Mark/Reset. ui: top-of-shellBisectBanner(detached-HEAD warning, current+counts, good/bad/skip, conclude firstBad- View commit, unbisectable candidates, Reset behind confirm;
selectOid(current)after start/mark) +BisectStartDialog+bisectStartDialogstore slice; wiredcommands.bisect+ commit-context "Bisect from here". REQ-P5-BS-001..007. Deferred hardening: per-surface branch-mutating disable (BranchesPanel/ reflog/commit-context) — the always-visible banner states the detached-HEAD/unavailable indication (the REQ-BS-007 MUST); explicit per-action disabling is a follow-up.
- ✅ S6 — submodules. core:
SubmoduleStatusliteral +SubmoduleInfo;SubmoduleList(read)Update/Sync/Add/Remove(✎ Void) RPCs;git/submodules.tsindex-cross-read (gitlink fromls-files --stage -z= authoritative paths +recordedOid; line-basedsubmodule status= status/checkedOutOid/describe;.gitmodules= name/url/branch; joined by path, status lines unmatched to a gitlink dropped; conflicted = stages 1/2/3 with no stage-0 gitlink →recordedOidabsent) + pure argv builders + guarded remove (deinit→rm→modules/<path>cleanup) + leading-dash guards on add. engine/live (list lockless, mutationswithRepoLock, remove usescommonDir);status-domainsubmoduleskey +useSubmodules+ 4 mutation hooks (Update→status; Sync/Add/Remove →status+config). ui:SubmodulesPanel(Table,SubmoduleStatusBadge, row menu Update/Force-update/ Sync/Open/Remove with Sync+Open disabled when uninitialized, bulk Update-all/Sync-all,AddDialog, force-updateAlertDialog, reusedDestructiveConfirmDialog, Open→RepoOpen(absPath)→navigate) as a routed"submodules"view; wiredrepository.submodulesManage(→view)/UpdateAll/SyncAll(bulk ops). REQ-P5-SM-001..006.
- ⬜ S7 settings/config · ⬜ S8 interactive rebase.
▶ RESUME HERE — P5 COMPLETE ✅ (S1–S8 all landed: gc, clean, archive, reflog, bisect, submodules, settings/config, interactive rebase)
P5 (power features) is done. All eight vertical slices landed on main core+UI, gate
green. The last slice, S8 interactive rebase, shipped: a scripted git rebase -i
driven by a GIT_SEQUENCE_EDITOR shim (copied into the web-server bundle) with an
exec-amend todo rewrite for reword/squash, a backend-aware machine-state status reader,
the InteractiveRebaseDialog (base picker → live plan → reorderable todo rows + per-row
action + message editor), an extended in-progress banner (step X/Y, stop-reason copy,
execFailed→Abort), and the commit-context "Rebase commits since here…" entry. Continue/
Skip/Abort and the conflicts view are the reused P4 sequencer surface. Next: P5 review
pass or P6 — await user direction.
P0–P4 all landed on main. P4 (cherry-pick / revert / conflicts / blame / single-file
history) shipped core + UI: conflict.list/sides, take-side / save-merged / mark-resolved,
cherry-pick / revert / continuation, per-line blame + file history with rename-following
(commits 61d0f9c→1e795b1), plus the 06-24 correctness pass (am/bisect continue-abort
refusal, machine-classified branch-switch dirty refusal, re-verify-unmerged) and a 06-28 UI
polish round (colored ref chips, favicon, resizable history/details divider). Gate green:
783 tests, 80.53% branches.
Next major phase: P5 (power features) — docs/spec/09-phase5-power.md: interactive
rebase, reflog recovery, bisect, archive export, safe clean preview, gc, submodules, and a
config/identity editor. The plan is already authored and validated:
docs/_impl-notes/P5-PLAN.md (823 lines — grounding facts, 8 vertical slices, 23-method
contract table, engine shapes, → D18). Its line anchors were re-checked against the tree on
2026-06-28 and still hold (phase5.ts absent, barrel insert point, detectInProgress literals,
live.ts:147 lock registry, rpc-handlers.ts:16 exhaustive toLayer, D17 latest).
Strategy (D18): unlike P4's batched S1, P5's eight groups are independent, so the plan ships
per-feature vertical slices, easiest-first — each a core commit (schemas + Rpc.make +
engine impl + handler + tests) then a ui commit. Order: S1 gc → S2 clean → S3 archive →
S4 reflog → S5 bisect → S6 submodules → S7 settings/config → S8 interactive rebase. Hard
serialize-first edge: S1 bootstraps the shared scaffolding (creates schemas/phase5.ts, inserts
the index.ts barrel line, opens the group.test.ts P5 catalog block) — must land before any
other slice. Two genuinely-new core mechanisms: streamGitBytes (raw-byte runner for archive,
S3) and the rebase-seq-editor.mjs shim copied into the web-server bundle (S8). Start at S1.
- Fixed a diff-assembly alignment bug (
packages/core/src/git/diff.ts). Under-w/-b,git diff --name-statuskeeps whitespace-only files but--numstat/-pboth drop them, so the by-index zip inbuildDiffFilesemitted a phantom row and — when the suppressed file sorted first — grafted a real file's hunks onto the wrong path. Now driven offnumstat(co-aligned with the patch) with the status letter joined fromname-statusby path. This was the one red test (git-engine-core-b.test.ts:417) on git 2.43.0; added a regression test. - Wired right-click on commit rows (
HistoryList.tsx). Vendored the base-lyracontext-menuprimitive (Base UIContextMenu) and wrapped each row's trigger; right-click now opens Cherry-pick / Revert instead of the browser's default menu. The hover…dropdown and the context menu share one pair of action handlers.
Earlier — P3 fully complete (self-review groups A/B/D/E landed; group C robustness and the
14-rpc-contract §7 reconciliation deferred).
S1 contract+stubs (5d31d47) · S2 branch listing (79c81a4) · S3 branch lifecycle (5b38e4a) · S4 merge (7fdd625) · S5 sync streaming (693c513) · S6 remotes (c0d36e9) · S7 worktrees (9273602) · S8 stash (63902b7) · S9 tags (0aabe44) · fix unused import (0e7d5fd).
33 new RPC methods across refs, config, worktrees, stash, tags domains. All engine stubs replaced with real git invocations.
- UI-A (4c28f5c): P3 query/mutation hooks ·
activeViewstore state · AppShell view nav tabs · BranchesPanel (local/remote list, create/rename/delete/dirty-tree dialogs, context menus) - UI-B (1b5ba77): Fetch/Pull/Push streaming toolbar buttons · RemotesManagerDialog · WorktreesPanel · StashPanel · TagsPanel
STOP here — await user review before starting P4.
Per docs/spec/08-phase4-cherrypick-conflicts.md + 11-conflict-merge-kdiff3.md. Four capability
groups: cherry-pick (single/range/mainline/no-commit), revert, conflict resolution (detect/take-side/
take-base/edit/mark-resolved/continue/abort across merge·rebase·cherry-pick·revert), blame + single-file
history. No P4 plan doc yet — author one first (cf. P2-PLAN.md / P3-PLAN.md slice pattern).
The app runs end-to-end with stage+commit. Open the "Changes" tab to see staged/unstaged file list, click a file to diff it, stage/unstage hunks, write a commit message, and commit.
To run: pnpm -r build then CBRANCH_CLIENT_DIR=$PWD/packages/ui/build/client pnpm --filter @cbranch/web-server start → http://127.0.0.1:7420.
To run current build: pnpm -r build then CBRANCH_CLIENT_DIR=$PWD/packages/ui/build/client pnpm --filter @cbranch/web-server start → http://127.0.0.1:7420.
Key context files (gitignored working notes): docs/_impl-notes/DECISIONS.md (D1–D12 locked decisions) + the 8 spec digests. Verify command: pnpm gate. Clean-room: never read .local/SPEC-AGENT-BRIEF.md; build only from docs/spec/+LICENSES.md+BRANDING.md+git/lib public docs. Undercover: no AI/model mentions in commits.
- 2026-06-28 — S8 (interactive rebase) landed — core + ui, gate green. P5 COMPLETE.
core (
feat(p5): interactive rebase engine):RebaseAction/RebaseStopReasonliteralsRebaseTodoCommit/RebasePlan/RebaseStep/RebaseStatus(reusingOperationProgress)- 3 RPCs (
RebasePlan/RebaseStatusread,RebaseStart✎). Newgit/rebase.ts: plan lists<upstream>..HEADoldest-first; start writes a fullgit-rebase-todoand drivesgit rebase -ithrough aGIT_SEQUENCE_EDITORshim (git/shims/rebase-seq-editor.mjs, resolved viadefaultShimPath()+import.meta.url, copied into the web-server bundle bybuild.mjs/dev.mjs), baking reword/squash messages asexec git commit --amend -Flines (GIT_EDITOR=true); empty reword/squash messages rejected in-engine, dirty tree refused; status backend-aware overrebase-merge/+rebase-apply/, stop reason totalized from machine state (conflict/edit/execFailed/none). Continue/Skip/Abort reuse the P4 sequencer. 29 engine tests + a packaged-shim check + contract round-trips. ui (feat(ui): interactive rebase dialog):RebaseDialog(base picker → liverebasePlan→ reorderable native-select todo rows +RebaseMessageDialog), extendedInProgressBannerfor rebase (step X/Y, stop-reason copy,execFailed→Abort, no message box),rebaseDialogstore slice,commands.rebasehandler + palette unhide, commit-context "Rebase commits since here…" (seeds upstream to the commit's parent).pnpm gategreen. Adversarial review follow-ups landed (fix(p5)): consumed-message validation (reword folded into a squash / non-last squashes no longer validate-then-discard),break/apply-backend stops classifiednonenotexecFailed,--ontochange + dirty-guard no longer clobber edits, Continue disabled until the rebase stop reason loads, sidecar reaped after a reused Continue/Skip/Abort, shim marker guards a foreign-rebase race, packaged-shim test keyed on a build-only marker.
- 2026-06-28 — S7 (settings & git config) landed — core + ui, gate green. core
(
feat(p5): settings & git config):ConfigScope/WritableScope/ThemePref+GitConfigEntry/GitConfigValue/KeyBinding/AppSettingsschemas + 6 RPCs (ConfigList/ConfigGetread;ConfigSet/ConfigUnset✎ repo-lock;ConfigAppGet/ConfigAppSetnon-repo, host config.json). Newgit/git-config.ts(--list --show-origin --show-scope -zgrouped-by-3 parse; scoped/effective--get, exit 1 =present:false;--global/--localwrites, system refused; idempotent--unsetexit 5; reads passread:falseso injected-coverrides never surface ascommand-scope rows).config-store.tsgetAppSettings/setAppSettings(theme/locale/keybindings, NEVER git). 17 git-config + 3 config-store tests + contract round-trips. ui (feat(ui): settings dialog): vendoredtabs+radio-group,SettingsDialog(Tabs: guided Identity/Editor/Credentials/Diff-Merge sections incl.difftool/mergetool.<tool>.cmd, scopeSelectwith system disabled, advanced add/unset table; App tab themeRadioGroup+ remappable keybindings with conflict detection + reset),lib/keybindings.ts+useKeybindingsdispatcher replacing the three ad-hoc keydown listeners (palette/commit/find, the latter lifted to afindOpenstore slice), cmdk palette wiring for the eight named commands, menutools.settings/repository.settings/maintenance.editConfig. Theme reconciled from host config.json on load. S8 (interactive rebase) next. - 2026-06-28 — S6 (submodules) landed — core + ui, gate green. core (
feat(p5): submodules):SubmoduleStatus/SubmoduleInfoschemas + 5 RPCs (SubmoduleListread;Update/Sync/Add/Remove✎ Void) +git/submodules.tsindex-cross-read (gitlinkls-files --stage -zjoined with line-basedsubmodule status+.gitmodules; conflicted = no stage-0 →recordedOidabsent) + guarded remove + leading-dash add guards; engine/live + 5 handlers; 17 module tests + contract round-trip. ui:useSubmodules+ 4 mutation hooks (status / +config),SubmodulesPanelrouted"submodules"view (Table + status badge + per-row Update/Force/Sync/Open/Remove + bulk + Add + Open→RepoOpen), menusubmodulesManage/UpdateAll/SyncAllwired; 8 component tests. Also a tinystyle(ui)commit reformatting a pre-existing oxfmt drift inToolbar.tsx. S7 (settings/config) next. - 2026-06-28 — P5 started — S1 (gc) core landed + P5 scaffolding bootstrapped (D18). Created
schemas/phase5.ts(GcPrune/GcResult), theindex.tsbarrel line, and the P5group.test.tscatalog/round-trip block — the one-time bootstrap that must precede S2–S8. Added theRepoGcRPC method + web-server handler,git/maintenance.ts(puregcArgsbuilder +gc, captured stdout/stderr, whole-run repo lock per REQ-P5-GC-003,read:false), the enginegcmethod,api.tsfacade, and theuseGchook (explicitrefs+commitsinvalidation — a pure repack emits no watcher events, REQ-P5-GC-004). D18 opened (slice strategy + no-new-error/domain + gc sub-section). Next: S1 ui (GcDialog). - 2026-06-28 — Reconciled progress to reality + two fixes. P4 (cherry-pick/conflicts/blame/
file-history) had fully landed but the doc still pointed at it as "next"; updated to mark
P0–P4 done and P5 next. Fixed the lone red test: a
-w/-bdiff-assembly misalignment inbuildDiffFiles(--name-statuskeeps whitespace-only files that--numstat/-pdrop, so the by-index zip emitted phantom rows / grafted hunks) — now numstat-driven with a path join, plus a regression test. Wired right-click commit-row context menu (vendored base-lyracontext-menu, Base UIContextMenu) so Cherry-pick/Revert replace the browser default. Gate green: 783 tests, 80.53% branches. - 2026-06-20 — P3 self-review fixes COMPLETE + Group E test sweep merged. All
P3-REVIEW.mdgroups A/B/D/E landed onmain: merge/sync/branch correctness (3cd61e7/a1c44d5/9fba60b), worktree switch + branches panel + dense toolbar (dbe9b0d/598cfb6/479f629), commit-dialog surface (bfb5657/d0d77b6/4be131b+ UX follow-ups), non-ff push retry (8166cf0), stash preview + confirmations (502eef3), graph seed-hashed lane colors + default-all-refs + post-commit reactivity (2a957b9/508ec49/d864534), optimistic history prepend (8f1ec33), and the Group E test sweep merge (a8f2813: core branch-ops/run-git/stash/sync + UI WorktreesPanel tests). Gate green: 590 UI + 354 core/rpc tests, 80.49% branches. Group C (robustness) descoped;§7spec reconciliation deferred. Next: P4 (cherry-pick/conflicts/blame) — author a plan first. - 2026-06-20 — P2 S2–S10 complete. Gate green: 385 tests. Core slices (b3183af / 9df6f0f / 2f1f213 / 4a5c13e): porcelain-v2 status parser+statusGet (NUL-sep,
#/1/2/u/?/!types), stage/unstage/discard/deleteUntracked/resetTo (per-repo mutex lock, stdin support in run-git), partial-stage patch builder (buildPatchpure fn +stageHunks/unstageHunks/discardHunks+--recount), commitCreate (stdin F-, amend/signoff/sign, pre-flight guard) + commitLastMessage. All 11 engine stubs replaced in live.ts. UI slices (dc175a9 / 6fa20be / 7bd43c9 / 3d6a0ad / eb3bf5f): S6 status helpers + store slices (commitDraft, selections, selectedDiffFile) + 9 mutation hooks (optimistic stage/unstage); S7 StatusPanel (ChangeListToolbar + StatusChangeList + Checkbox/Separator primitives); S8 WorkingDiffPanel (hunk block + Stage/Unstage/Discard Hunk buttons); S9 CommitPanel (ConventionalCommitBar + CommitMessageEditor + Switch/Select/Tooltip primitives + 7 tests); S10 DestructiveConfirmDialog + AlertDialog primitive + stageAll/unstageAll menu commands. Watcher coalesce widened to 300 ms (Windows NTFS reliability, f59d9d4). Coverage: 80.48% branches / 91.85% statements. Next: AppShell integration — wire StatusPanel/WorkingDiffPanel/CommitPanel into a "Changes" tab. - 2026-06-20 — P2 started — slice S1 landed (D15). RPC write-path contract + full method plumbing as
typed stubs (
360845b):schemas/working-tree.ts(8 Schema.Class types) + 11 group methods (StatusGet, Stage/Unstage/Discard/DeleteUntracked/ResetTo, Stage/Unstage/DiscardHunks, CommitCreate, CommitLastMessage)- GitEngineApi/live.ts stubs + web-server handlers + UI api/query-keys. Gate green: 276 tests. Plan at
docs/_impl-notes/P2-PLAN.md; D15 records selection-over-patch + DeleteUntracked-split decisions. Next: S2 (porcelain-v2 status parser).
- GitEngineApi/live.ts stubs + web-server handlers + UI api/query-keys. Gate green: 276 tests. Plan at
- 2026-06-20 — Base UI migration + desktop menu chrome (D14). Migrated the deprecated
@base-ui-components/react@1.0.0-rc.0→ stable@base-ui/react@^1.6.0(renamed package;check:primitivesgreen on 12/12). Wired the shadcn@/* → srcalias across tsconfig/vite/root-vitest/components.json soshadcn addresolves and emits working imports (verified with a throwawaytooltipadd). Vendored the base-lyradropdown-menu+menubar(copied source, REQ-STACK-014; only icon-placeholder swapped for lucide). RebuiltMenuBarto render the full nine-menu chrome frommenu/menu-model.ts(transcribed from docs/design/menu-hierarchy.md) with unwired items greyed via theuse-menu-actionscapability layer; wired Open/Recent/Refresh/Exit/Close/relative-date/About. Gate green: 256 tests. First real Base UI usage in the repo. - 2026-06-20 — Client-side routing (D13) landed. Added
react-router@8.0.1topackages/ui. Newrouter.tsx(createBrowserRouter):/→<Landing>(redirect to most-recent repo viarecentList, else the shell's "Open a repository" empty state),/repos/:repoId,/repos/:repoId/commits/:oid, + five<PlaceholderPage>routes staking the branches/tags/worktrees/stash/blame namespace. URL is now the source of truth foractiveRepoId/selectedOid: write side callsuseNavigation()(navigation.ts,openRepo/selectOid);<SyncRouteToStore>mirrors params → store viauseLayoutEffect(no first-paint flash) so legacy store subscribers are untouched.CommandPaletteopen + commit selection now navigate instead of mutating the store. Tests wrap nav-using components in<MemoryRouter>. Gate green: 253 tests, typecheck/build/coverage/depcheck clean. WebViewMemoryRouterentry deferred to the VSCode milestone. - 2026-06-20 — P1 verification gate complete. NF-TEST-11:
@vitest/coverage-v8wired; rootpnpm coverage(viavitest.coverage.config.ts) enforces ≥80% lines+branches on core+rpc-contract; current: 96.27% lines / 82.13% branches. Per-package configs inpackages/{core,rpc-contract}/vitest.config.tsfor independent threshold control.pnpm gateupdated: addscoveragestep betweentestanddepcheck. NF-PERF-1/2/3:scripts/measure-perf.mjsready (Node 22+ WebSocket, real WS RPC, 5 probe runs, p95 TTFR + incremental check- throughput). AC-1…AC-15 mapped to existing tests. P1 COMPLETE. Gate green: 253 tests. STOP for review.
- 2026-06-19 — ui-C + ui-D complete (8 gate-green commits, 185→253 tests). ui-C: commit graph (incremental
append-only lanes/edges, SVG cell), ref chips, server filters, date pref, keyboard nav, quick-find. ui-D:
changed-file list (flat/tree), diff controls (inline/split, ws, context, merge-parent/combined), next/prev nav,
binary/submodule/large-diff cards, react-diff-view + on-demand Shiki, sonner toasts, CodeMirror 6 file-at-rev.
ui-D2b (react-diff-view+Shiki+sonner) and ui-D3 (CodeMirror) were built by context-inheriting forks, each
verified independently green.
@shikijs/codemirroris NOT in the registry (404) → Shiki tokens bridged into CodeMirror as decorations directly. - 2026-06-18 — Recon: Node 24.17, pnpm 10.32, git 2.54, registry reachable (effect beta, oxfmt, oxlint). Branch + bootstrap docs created. Spec digestion launched.
- 2026-06-19 —
apps/web-serverbuilt: verified (running round-trip) thateffect@4.0.0-beta.84ships no Node HTTP/WS listener; adopted@effect/platform-node@4.0.0-beta.84(DECISIONS D11) for the spec-literal wiring. Assembled the WS RPC bus + static + side-channel + global Origin/Host guard; 37 web-server tests incl. one real e2e round-trip. Full gate green (168 tests).