# Code Review workflow

Version **0.3.0** requires **PI WEB >=1.202610.6**. Automated tests, builds, artifact smoke checks and production-bundle Chromium checks passed against `1.202610.6`; live-host testing remains outstanding. See [compatibility results](compatibility.md) for the validation limits.

## Install the standalone package

Install `npm:@compn3rd/pi-web-code-review` through **Settings → Pi packages** on the target machine. If migrating from the unscoped package, disable/remove that plugin first; do not enable both copies. The plugin ID and storage keys are unchanged. Enable the scoped plugin and restart safely as described below. To build and install locally:

Build from this repository's root:

```sh
npm ci --ignore-scripts
npm run build
```

`--ignore-scripts` avoids native installation scripts from the development-only PI WEB dependency. This plugin's build does not use those native modules. The browser's Lit and Markdown dependencies are bundled; the server entry uses only the host-provided Git runner. Installed users need the built package, not its development dependencies.

Link this directory into the target machine's plugin directory. On Linux/macOS, while still at the repository root:

```sh
mkdir -p "${PI_WEB_DATA_DIR:-$HOME/.pi-web}/plugins"
ln -s "$PWD" "${PI_WEB_DATA_DIR:-$HOME/.pi-web}/plugins/code-review"
```

On Windows, run PowerShell from the built plugin directory:

```powershell
$data = if ($env:PI_WEB_DATA_DIR) { $env:PI_WEB_DATA_DIR } else { Join-Path $env:USERPROFILE '.pi-web' }
New-Item -ItemType Directory -Force (Join-Path $data 'plugins')
New-Item -ItemType Junction -Path (Join-Path $data 'plugins/code-review') -Target (Get-Location).Path
```

Alternatively, copy the package's `package.json`, `dist`, `LICENSE`, `README.md`, and `docs` into that directory. For distribution, `npm pack` creates a self-contained tarball; extract it as the plugin directory, retaining `package.json` at its root. Do not copy `node_modules`.

Enable **Code Review** in **Settings → PI WEB plugins**. Because the package includes a server entry, **manually restart the target session daemon when safe**, then reload the browser. Restarting interrupts active sessions and terminals; do it from outside the sessions that daemon hosts. The plugin does not restart anything itself. Browser reload or Pi's `/reload` alone is insufficient after installing or updating this paired package.

For remote workspaces, install and enable the package on each target machine. Git runs on the panel's machine, never on the gateway as a fallback. Files and package-peer requests use the host's scoped helpers, including nested deployments.

## Review files and changes

1. Select a workspace and open the **Review** tab (or **Open Code Review** in the action palette).
2. Choose **Files**, **Unstaged**, **Staged**, or **Compare**. Files includes untracked files. Browse directories or expand **Open a file by path** to enter a workspace-relative file path. For committed work across multiple commits, use the comparison controls below.
3. Click a line number to open and focus the comment editor directly below it inside the viewer. Shift-click extends its range on the same side; on touch screens, expand **Line range** and edit **Start line** and **End line** instead. Deleted diff lines use old-side coordinates; context and additions use new-side coordinates. Ranges cannot span omitted diff context.
4. Enter Markdown and choose **Save comment**. Ctrl/Cmd+Enter also saves; ordinary Enter inserts a newline.
5. Review the saved list. **Edit comment** reloads its source before allowing a save; **Remove comment** deletes that comment.

Comments render safe Markdown: raw HTML is displayed as text, images do not load, and links are limited to HTTP/HTTPS. Binary, truncated, very large sources (over 200,000 characters or 5,000 lines), and directories/change lists with over 2,000 entries are rejected rather than displaying incomplete selectable coordinates. Git must be installed. Git views show tracked changes; inspect untracked files in Files. Submodules are shown as Git's gitlink diff, not recursively expanded into another repository's file changes.

Saved comments are local to this browser origin, keyed by machine, project, and workspace. They survive reloads and session changes; they are not synchronized across browsers or machines. IndexedDB transactions serialize concurrent saves and acknowledgements across tabs, so independent comments are not lost through competing read/modify/write operations. IndexedDB does not require HTTPS or Web Locks; LAN HTTP remains supported where the browser permits origin storage. Storage errors are shown and an unsuccessful save leaves the editor text available. Corrupt or unrecognized storage is not overwritten automatically. Feedback warnings remain separate from source-loading errors, survive panel/workspace remounts within the activation, and stay visible until explicitly dismissed.

### Returning to Review and expanding context

Switching from Review to chat and back in the same workspace retains the selected file, frozen comparison, draft, context setting, and code/document scroll position. Returning does not re-resolve comparison refs; use **Refresh** to read current content. This navigation state is in memory, not persisted across browser reloads, plugin reloads, or workspace switches.

Git views offer **Diff context**: **3 lines**, **20 lines**, **100 lines**, or **Whole file**. Whole file includes unchanged surrounding lines with additions/deletions still highlighted, using the correct staged, unstaged, or frozen comparison endpoints—not the working file as a substitute. Existing size limits still apply; binary files cannot be expanded. Unchanged files have no Git diff to expand. Save or cancel the current draft before changing context. Display context alone does not mark saved comments stale. If a saved comment lies outside the current context, expand again before editing it.

For the automated and visual review workflow, see [UI testing](ui-testing.md).

### Layout and phone controls

Choose **Review settings** in the panel header. **Workbench** shows files, code and saved notes in columns on wide panels (notes move below at intermediate widths). **Focus** hides the persistent file list, keeps feedback inline and collapses the saved-review summary. Switching layouts preserves the current file, range, draft and code-view DOM; normal responsive reflow can adjust scroll geometry.

On panels at most 640px wide, use **Files** (Workbench) or the current filename (Focus) to open a file sheet. **Notes** opens all saved feedback. Choose a file to close the sheet; opening a directory keeps it open for browsing. Close sheets with the close button or Escape. Desktop previous/next controls navigate the current file list.

**Wrap code** is enabled by default. Turning it off scrolls long source lines inside the code viewer; comments and the draft remain constrained to the viewer width. Wrapping does not change original line coordinates. Layout and wrapping choices are stored per browser origin, shared across workspaces on subsequent panel creation; existing tabs do not live-sync these preferences. A failed settings write is reported without affecting saved comments.

Settings are in the Review panel, not the host-wide settings screen. Unsaved drafts still need to be saved before reloading or switching workspaces. Neither applying settings nor attaching a review sends a message.

### Review accumulated branch or commit changes

Select **Compare**, enter **Base revision** and **Target revision**, then choose a comparison mode and click **Compare**:

| Goal | Base | Target | Mode |
| --- | --- | --- | --- |
| Current branch's work since diverging from main | `main` (or `origin/main`) | `HEAD` | Branch changes since merge base (`A...B`) |
| Another branch's accumulated work | `main` | `feature/my-branch` | Branch changes since merge base (`A...B`) |
| Last three commits together | `HEAD~3` | `HEAD` | Between revisions (`A..B`) |
| Changes since a particular commit or tag | Commit ID or tag | `HEAD` | Between revisions (`A..B`) |

Merge-base mode compares the common ancestor of base and target with the target, excluding changes made only on main after divergence. Between-revisions mode compares the two commit trees directly. A `main` branch is not assumed to exist: enter `master`, a remote-tracking branch, or another available revision as needed. Refs must exist locally; this feature does not fetch, checkout, stage, or modify Git data. Revisions are single branch/tag/commit expressions (including `HEAD~3` or `HEAD^`), not combined `A..B` strings, paths, or Git options.

Only **committed** changes appear. Dirty index/worktree and untracked changes remain available in the other source modes. Click a changed file to review its complete accumulated diff, then comment as usual.

The list and all opened files use the same resolved commit IDs, even if a branch moves meanwhile. **Compare** or **Refresh** resolves the inputs again and resets the file selection; choose a file in the new list. Saved comments retain the original endpoints, comparison mode, and snapshot hash. **Edit comment** reopens those frozen endpoints, not today's branch tips. A different comparison never silently re-anchors an existing comment, even if its text diff is identical. Feedback Markdown includes the revision labels and abbreviated commit IDs.

### Storage upgrade and recovery

Reload **all old plugin tabs before using the upgraded plugin**. Comparison comments introduce a new source type; older plugin versions cannot read a workspace record containing them and report unrecognized storage without overwriting it. Upgrade all tabs before saving comparison comments; copy/export feedback before downgrading. On first access to each workspace, the plugin imports its previous `pi-web-code-review:v1:` localStorage record into IndexedDB in one transaction. The record itself marks migration complete, including when its comment list is empty after removal or acknowledgement. Existing IndexedDB data always wins. Legacy localStorage is retained unchanged as a backup, not an active store after migration. Old plugin tabs still write only localStorage; their later edits cannot safely be merged automatically and will not appear in the upgraded plugin. Copy any such feedback before reloading those tabs.

If migration is corrupt, blocked, or fails, the panel reports it and retains the original data for recovery; it does not substitute an empty successful save. Close older tabs if an upgrade is blocked, then reopen Review to retry. Browser storage clearing deletes active comments and may also delete the backup; clearing only IndexedDB can reimport the retained legacy snapshot. Export/copy needed feedback before clearing storage.

Cross-tab chip withdrawal and live badges use BroadcastChannel notifications after durable commits. A notification failure cannot undo a saved comment. If the browser blocks BroadcastChannel, transaction safety remains, but other tabs may display stale feedback/chips until refreshed; reattach a fresh snapshot before sending.

Switching away from the tab preserves the current editor within this activation. Switching workspace, reloading the browser, or disabling the plugin discards **unsaved** edits. Save before doing so.

Refreshing or host file invalidation reloads the current snapshot (in comparison mode, it re-resolves the revision inputs and resets the file selection). A changed file does not silently delete feedback: saved comments remain in the list, are flagged as stale when that source is viewed, and are not attached to its new lines. Copy any unfinished text before cancelling a stale edit. Create a new comment against the current snapshot instead of automatically moving an old anchor. Sources you have not reopened have not been checked for staleness; verify coordinates before handing off.

## Attach feedback to the composer

Choose a ready, unarchived conversation in this workspace, then select **Attach review to composer** in the panel header. The header shows saved-comment and unsaved-draft counts; save your draft first if you want it included. One removable **Review (N)** chip contains a snapshot of all saved comments. Repeating the action replaces that conversation's review chip, not the text at its cursor. You can inspect the payload under **Feedback Markdown**.

Send the chip with a message or by itself. Failed sends keep it and the saved comments for retry. Server acceptance clears only unchanged comments from the submitted snapshot; later edits and new comments survive. Acceptance does not mean the assistant has finished answering. Removing the composer chip only detaches it—saved comments remain available.

Saving edits or removing comments withdraws this workspace's staged feedback; attach again when ready. Changes from another browser tab also withdraw this activation's copies. If withdrawal fails, remove the stale chip manually before sending. If clearing submitted comments fails, inspect the accepted conversation before reattaching to avoid duplicate feedback. This acceptance warning remains visible alongside later action or storage errors until you explicitly dismiss it, including after switching workspaces or reopening Review within the same activation.

Chips survive closing the panel or navigating away, but not reloading the page. Saved comments survive reloads; open the intended conversation and attach again. Different conversations can hold independent snapshots, so attach to multiple conversations only if you intend to send the feedback more than once.

## Differences from the former core UI

This is an independent Review tab, not an extension of the bundled Files/Git tabs: main does not expose inline decoration hooks for those panels. Composer integration uses main's public chip API, including removal and server-accepted callbacks. There are no private DOM hooks, private HTTP routes, host-owned review services, or patches to PromptEditor.

Feedback is workspace-scoped rather than session-scoped, so it can be authored before choosing a session and requires no temporary-session migration hooks. The old branch's `pi-web:review-comments:` session stores are not automatically imported or deleted; copy any remaining feedback from the old UI before switching installations.

Comment ownership stays in the plugin; the host owns only the staged composer snapshot and its send lifecycle.
