Freeze the Change Before the Model Sees It
For OpenCodeReview, the first engineering question is not which model to call. It is what exact change the model is allowed to see. This chapter follows the project’s workspace, commit, range, and scan modes from a user’s request to the post-change file content supplied to review. That distinction lets a reader choose the right mode and recognize when a result is not reproducible because the Git history or reference moved underneath it.
A code review is an argument about a change, not about an abstract repository. If the change is defined differently on two runs, even identical model behavior can produce different findings. OCR therefore treats Git input as an evidence boundary: the mode determines which changes exist for the review, and the selected ref determines which version of a file supplies surrounding context.
Four modes define four different review questions
Workspace mode asks, “What has changed here right now?” With no range or commit flags, OCR reviews tracked changes in the working repository and also discovers untracked files. An untracked file has no earlier Git version to compare, so OCR represents it as a full-file addition. This makes the default command useful before a commit: new code can be reviewed even though it does not yet belong to history.
Workspace mode is convenient, but it is also the least immutable input. The working tree can change while a review is running. A developer can edit a file, switch branches, or generate another artifact after the diff has been read. That does not make workspace review useless; it makes its scope different from a historical review. It is a snapshot of local work, not a durable statement about a named commit.
Commit mode asks, “What did this one commit introduce?” OCR compares the selected commit with its parent. This is appropriate when a change has a clear unit of authorship or when a team wants a narrow review of one operation rather than the accumulated state of a branch. The relevant post-change content is the content of that commit, not whatever happens to be in the current working directory.
Range mode asks, “What did this branch add after it diverged from its base?” Given a source and target ref, OCR computes their merge-base and reviews the target-side changes after that common ancestor. Suppose a feature branch was created from main, and main has since received unrelated commits. Comparing the feature tip directly with today’s main would mix the feature’s work with changes that arrived later on the base branch. The merge-base answers a more useful question: which changes belong to the feature relative to the point where it actually started?
This is why a range command such as ocr review --from main --to feature-branch is not just a longer spelling of a two-ended diff. It encodes a causal relationship between a branch and its base. If the repository cannot resolve a merge-base—commonly because a CI checkout is shallow—OCR cannot construct the intended range. A pipeline that wants branch review must therefore preserve enough Git history for the comparison it requested.
Scan mode asks a different question: “What risks exist in these whole files, even when no meaningful diff is available?” It reviews current file content without requiring a Git change. That makes it useful for auditing an unfamiliar repository or directory, but it should not be confused with diff review. A scan does not establish that a finding was introduced by a particular change, and its templates and context limits are separate from the diff-review path. The distinction protects interpretation: a change review attributes findings to a delta; a scan evaluates a state.
The four modes can be summarized by the evidence they promise. Workspace mode follows local, often moving work. Commit mode follows one historical transition. Range mode follows a branch-relative transition from a merge-base. Scan mode examines a whole state without a change attribution. Choosing among them is already a review judgment, because it determines what a later “clean” or “risky” result can mean.
From named refs to model-visible evidence
The mode is only the first boundary. OCR must also build a representation that the agent can use without silently crossing into a different version of the repository.
For a diff review, the Git provider parses changes into structured records. A record carries paths, hunks, insertion and deletion counts, binary status, and rename information. Hunk context is limited to the normal Git-style neighborhood around changed lines. This is enough to orient the model while keeping the change representation explicit. The agent can later request more file context through its tools, but the initial review evidence still starts from a known diff.
Untracked files are the important workspace exception. Because Git has no parent version for them, OCR constructs a synthetic addition whose content is the file as it exists in the workspace. That makes the file reviewable before commit, but it also means the review is coupled to the moment when OCR reads it. If the file changes after that point, a later rerun is a review of a different artifact. The correct response is not to pretend the two results are comparable; it is to treat the new run as a new workspace input.
Range and commit modes use a stronger snapshot boundary for surrounding context. When the agent asks to read a file, OCR retrieves that file from the selected target ref rather than reading an arbitrary current working-tree copy. This matters when a reviewer runs from a checkout that contains local edits, generated files, or a different branch. The model should reason about the same post-change state that produced the diff. Otherwise, an unchanged line could have changed after the diff was computed, and a comment might be based on code that the reviewed commit did not contain.
The boundary also has a security purpose. References and paths are passed to Git as structured arguments, with option termination used where needed so a ref that resembles a command-line option is not interpreted as one. The broader design principle is simple: user-provided names select Git objects; they do not rewrite the Git command's meaning. A review tool that accepts a branch name but allows that name to alter command structure has already lost control before the model begins.
Once the provider has resolved the input, OCR can preserve the concrete endpoints used for the run. Later session manifests record actual commit identities rather than relying only on the strings the user typed. That difference matters because a branch name is mutable. feature can point to one commit today and another tomorrow; a short commit spelling can also be ambiguous until resolved. A durable review record needs the object Git actually examined.
The same reasoning explains why resuming a review is stricter than rerunning a command with the same words. A compatible range or commit resume must refer to the same kind of review and verify the resolved input and file-level fingerprint. If the base moves, the diff changes, or the relevant rules and filters change, old work may no longer describe the new review. Reusing it would save tokens by spending correctness. OCR’s frozen endpoint and manifest model exists to avoid that bargain.
There is a practical consequence for CI authors. A workflow that checks out only the latest commit may be able to read files but still be unable to answer the range question it was asked. A workflow that posts comments against a moving pull-request head may generate findings for one revision and attempt to attach them to another. Full history and stable head information are not administrative details around the review; they are part of the review’s evidence contract.
That contract also gives the reader a way to diagnose surprising results. If a changed file is absent, first ask whether the selected mode included it and whether the source and target resolved as expected. If a comment seems to describe a different version of a file, ask whether the review used a historical ref or the current workspace. If a resume reused work unexpectedly, ask whether the input and file fingerprint truly remained the same. These questions locate the failure at the evidence boundary before blaming the model.
The lifecycle is easiest to understand as a sequence of distinct states. First, the caller supplies a mode and perhaps names a commit or two refs. Next, Git resolves those names to objects; in range mode, OCR also resolves their common ancestor. Then the provider parses the resulting change into file-level diffs. Only after that does the file reader supply post-change content for the agent’s questions. A ref that fails at the first state cannot be repaired by better prompting at the last state. Keeping these transitions separate gives each failure a meaningful owner.
The transition from a raw Git comparison to a structured diff is important in its own right. A review does not need only a blob of text; it needs to know whether a file was added, modified, deleted, or renamed, and how much content changed. Those facts shape later choices about selection, grouping, and comment location. A binary file, a deletion, and a renamed source file may all appear in one branch comparison, but they do not present the same review problem. Preserving their identity early prevents the agent from having to reconstruct it from prose.
The post-change reader supplies another form of discipline. The diff tells the agent where a change occurred; the target snapshot tells it what the surrounding file looks like after the change. Those are related but not interchangeable. A diff can show a new call to a helper while the full post-change file reveals how errors are handled around it. Conversely, the full file may contain an old defect that is irrelevant to the patch. OCR’s mode boundary does not solve that judgment for the model, but it ensures that both sources of context describe the same target state.
This also explains why a branch name is a poor unit of audit by itself. A reviewer may say that “feature” was checked, but that label does not identify which commit was the head or which base was used. If the branch is force-pushed, a later run with the same command text may be reviewing a different artifact. Recording the resolved endpoints makes the claim narrower and more useful: this run examined this Git object relative to this concrete base. Later coverage records can then decide whether earlier work is eligible for reuse instead of guessing from a familiar ref spelling.
The distinction between workspace and historical modes is not merely about trust. It changes the kind of question a team can ask. A developer working before commit may want immediate feedback on an untracked file, even though the file is still changing. A release gate may need a branch-relative range whose base and head can be reconstructed after the job ends. A maintainer investigating one regression may want the exact transition introduced by a commit. A codebase audit may need scan mode because there is no meaningful patch at all. Choosing the mode is choosing the claim the resulting comments are allowed to support.
For the same reason, a failed range resolution should not be silently “helped” by falling back to an unrelated comparison. If the requested base is unavailable, a review of the target’s current workspace could still produce plausible comments, but they would answer a different question. OCR’s design keeps that mismatch visible. The safe recovery is to repair the checkout or choose a mode deliberately, not to preserve a green-looking result by changing the evidence boundary behind the user’s back.
The main conclusion is therefore narrower than “Git makes the review reproducible.” Git supplies the objects, but OCR chooses which relationship among those objects matters and preserves the selected post-change state for the agent. Workspace review accepts movement in exchange for immediacy. Commit and range review trade some flexibility for historical identity. Scan review gives up change attribution to inspect a whole state. None is universally best; each is honest only when its evidence promise matches the decision the team is trying to make.
Once the change is fixed as evidence, another question remains: not every parsed file should enter the agent, and different files may require different review guidance. The next boundary is deterministic scope and policy—how OpenCodeReview decides which files are admissible and what instructions govern them.