Skip to main content

Review a large branch without reading every file equally

A large review is not a smaller review repeated for every file. First establish the complete change inventory, separate mechanical artifacts from behavioral streams, then spend attention where intent, enforcement, contracts, and tests meet. Token-budgeted context can support that work, but the files that happen to fit are not automatically the files with the greatest review risk.

This recipe was exercised retrospectively against ctx commit 7bb2167, which introduced release governance and guardrails. It changed 29 files with 3,712 additions and 941 deletions across policy, CI, release automation, Python enforcement, tests, lockfiles, and a generated CLI contract. Later follow-up fixes provide unusually strong evidence about which review questions mattered.

:::note Worked-example provenance The historical example is pinned to ctx commit 7bb2167 and was exercised with ctx 0.3.5 on 2026-07-14. Its file and line counts describe that commit, not the current repository. :::

Quickest version

BASE="$(git merge-base HEAD origin/main)"
git diff --name-status "$BASE"..HEAD
git diff --stat "$BASE"..HEAD
ctx score --against "$BASE" --json
ctx check --against "$BASE" --json

Partition the complete inventory by responsibility, then inspect behavioral, contract, security, generated, and test streams separately. Token-budgeted context routes attention; it does not define review coverage.

Choose the comparison that represents the branch

For a feature branch, compare with its merge base rather than an arbitrary local main:

BASE=$(git merge-base HEAD origin/main)
git diff --stat "$BASE"..HEAD
git diff --name-status "$BASE"..HEAD

The worked example checked out the historical commit in an isolated clone and used its first parent:

BASE=7bb2167^
git diff --stat "$BASE"..HEAD
git diff --name-status "$BASE"..HEAD
ctx index

Record the base and head SHAs in the review. A moving branch name makes later measurements difficult to reproduce, especially when the branch is rebased during review.

1. Get the complete inventory before packing context

Retain ctx's stderr summary while counting the selected files on stdout:

ctx diff "$BASE" --summary --changes-only --no-tree --count-only

The summary identified all 29 changed paths and the new Python symbols. Keep the independent git inventory beside it: ctx can add symbol information, while git remains the authority for the full changed-file set, including YAML, Markdown, lockfiles, and generated JSON.

:::note Summary and count output use separate streams --summary adds diagnostics on stderr but does not suppress context by itself. Add --count-only to replace streamed context with the selected files' count summary on stdout. Add --stats when you also want count timing on stderr. :::

2. Treat the token budget as capacity, not priority

The default 8,000 tokens are not a required or recommended review budget. Try a budget appropriate to the receiving model and task:

ctx diff "$BASE" --summary --changes-only --no-tree --max-tokens 20000
ctx diff "$BASE" --summary --changes-only --no-tree --max-tokens 50000

Whole-file packing produced these representative results:

BudgetFiles selectedFiles omitted
8,000varied between repeated runsvaried between repeated runs
20,00016 in one content run13
50,00027 in one content run2

Three identical 8,000-token diagnostic runs selected 13, 13, and 7 files. Changed files all had the same priority, and their equal-priority ordering was not stable before greedy packing. Therefore, in ctx 0.3.5:

  • do not infer review priority from which changed files fit;
  • do not assume two runs at the same budget produce the same bundle;
  • check the selected and omitted counts every time;
  • use an explicit review-stream inventory when completeness or reproducibility matters.

Raising the budget improved coverage but did not solve prioritization. Large generated files and lockfiles can consume capacity while small workflow changes carry greater operational risk.

3. Split the branch by review responsibility

The 29 files became four coherent streams:

StreamRepresentative filesReview question
Intent and ownershipgovernance/*.md, AGENTS.md, CLAUDE.md, CODEOWNERSIs the promised policy coherent, scoped, and owned?
Enforcementscripts/version.py, contract/governance checkers, versioning testsDoes executable policy match the prose, including failure paths?
Workflow wiringpolicy, CI, snapshot, docs, and release workflowsAre permissions, events, toolchains, dependency order, and secrets correct?
Mechanical and generatedboth lockfiles, CLI contract, changelog, ignore rulesIs the artifact expected, reproducible, and reviewed through its owner?

This is more reliable than reviewing by directory or largest line count. Each stream has a different definition of correctness and a different validator.

The lockfile diff was the largest textual change—1,644 lines—but neither Cargo manifest changed in the commit. That is a review prompt: establish which dependency update regenerated the locks and which checks justify it. It is not a reason to read every lockfile line before examining release permissions or enforcement behavior.

4. Use score to route attention, not to cover the branch

ctx score --against "$BASE" --json

For this commit, score reported only the five new Python implementation and test files:

files_changed: 5
complexity_delta: 1107
fan_out_delta: 520
symbols_added: 84
new_duplication: 1

The git inventory contained 29 files. Score did not evaluate the workflows, policy prose, lockfiles, shell scripts, generated contract, or ownership configuration as code metrics. Its per-file results still routed attention effectively: the 500-line scripts/version.py accounted for the largest new complexity and fan-out.

Because every measured Python file was new, the large deltas mostly described added capability, not regression. Review the responsibilities, tests, and integration of the new code instead of setting a goal to make additive metrics zero.

5. Investigate every concrete signal

ctx duplicates --against "$BASE" --json

The one new duplicate was a 73-token subprocess wrapper shared by two standalone policy scripts. Source inspection showed that the scripts deliberately owned separate command-line entry points. Extracting a common module would add packaging and invocation coupling for very little behavioral reuse. The pair was worth reviewing, but retaining it was reasonable.

Use the same disposition format for every signal:

Signal:
Responsible symbols/files:
Source evidence:
Behavioral or ownership interpretation:
Action: fix, test, document, accept, or defer
Owner and re-evaluation trigger:

6. Trace distinctive symbols inside each stream

Avoid expanding a graph from generic names such as main, check, parse, or current_version. Choose symbols distinctive enough to preserve meaning:

ctx query callers validate_changelog --file scripts/version.py
ctx query deps validate_changelog --file scripts/version.py

ctx query callers pr_policy --file scripts/check-contracts.py
ctx query deps pr_policy --file scripts/check-contracts.py

ctx query callers compare_contracts --file scripts/check-contracts.py

These direct queries connected:

  • changelog validation to the version check entry point;
  • pull-request policy to contract comparison, base versions, labels, and breaking notes;
  • contract comparison to both policy execution and its focused unit test.

Read the owner function and its tests together. Then inspect the workflow step that invokes it. This forms a review triangle: declared policy → executable enforcement → CI wiring.

7. Be skeptical of automatic graph expansion

The experiment also ran diff context without --changes-only:

ctx diff "$BASE" --summary --depth 1 --no-tree --max-tokens 200000 >/dev/null
ctx diff "$BASE" --summary --depth 3 --no-tree --max-tokens 200000 >/dev/null

Depth 1 expanded 29 changed files to 30 context files by adding perf/src/main.rs. Depth 3 expanded to 40 files, including unrelated Rust indexing, configuration, schema, harness, scoring, and error modules. Generic same-named symbols in the new Python scripts caused cross-language false-positive paths.

Automatic expansion was less useful than --changes-only for this branch. Use it as a hypothesis source, and retain an added file only after its source contains the relationship that led to it. Direct queries from distinctive symbols were much cleaner.

:::caution Historical ctx 0.3.5 pattern-scoping limitation In the pinned 0.3.5 experiment, global help displayed positional patterns after the revision, but a verified run with scripts/version.py still analyzed all 29 files. This was fixed after 0.3.5 in issue #57: current builds scope changed files and graph expansion, with explicit rename and deletion handling. Use git diff -- <paths> when reproducing the pinned run exactly. :::

8. Review claims against their enforcement

For every policy statement containing words such as “enforces,” “requires,” “never,” or “only,” find the executable mechanism and its negative test.

For this branch, focused local validation passed:

python3 scripts/check-governance.py check
python3 -m unittest discover -s tests/versioning -p 'test_*.py'
python3 scripts/version.py show
python3 scripts/version.py check --skip-binary

The governance boundary check passed, all 12 focused tests passed, and version invariants were consistent. Those results proved the tested script behavior; they did not prove GitHub permissions, branch protection, environments, action compatibility, or every workflow matrix path.

Review external claims separately. This commit correctly documented that repository files could not prove branch protection or release-environment configuration. A reviewer should preserve that uncertainty rather than treating policy prose as external state.

9. Use follow-up history to calibrate the review

Later commits fixed several issues in or around the original change:

  • normal CI jobs explicitly selected Rust 1.91 and used --locked;
  • Clippy expanded to all targets and all features;
  • checkout credentials were disabled and permissions narrowed;
  • the cargo-deny action was updated for CVSS v4 advisories;
  • the isolated performance harness gained license metadata and an explicit wildcard-path exception.

These follow-ups validate the review-stream model. They live at the intersections that deserve the most attention: stated reproducibility versus actual CI commands, root policy versus the isolated perf/ package, and pinned workflow syntax versus the installed action version.

Retrospective evidence is not available during an ordinary review, so turn each lesson into a question:

Does every job use the declared toolchain and lockfile?
Does lint cover the feature/target matrix claimed by policy?
Are checkout credentials and job permissions minimized?
Does dependency policy cover every manifest, including isolated harnesses?
Is the pinned action version compatible with the configured policy format?

Produce a risk-ranked briefing

Base and head SHAs:
Complete changed-file inventory:
Review streams and owners:
High-risk behavior or permission changes:
Generated/mechanical artifacts and generators:
Score coverage and uncovered file types:
Concrete metric or duplication signals, with disposition:
Verified symbol-to-test-to-workflow paths:
Rejected graph expansions:
Commands and configurations validated:
External settings not proven from the repository:
Blocking findings:
Follow-up questions and optional improvements:

Rank findings by consequence and evidence, not file size. A four-line permission change can outrank a thousand-line lockfile update, while an unexplained lockfile regeneration can still block until its provenance is established.

What worked, and what did not

TechniqueVerified useLimitation observed
Git inventory plus ctx summaryCovered all 29 paths and added symbol detail--summary still streamed content
Adjustable budgetsIncreased whole-file coverage up to 27 of 29 filesEqual-priority packing was nondeterministic
Review streamsMatched intent, enforcement, wiring, and generated ownershipRequires human classification
ctx scoreRanked five new Python code/test filesDid not cover 24 workflow, policy, shell, lock, or generated files
New-duplication inspectionFound and dispositioned one exact helper pairA duplicate finding did not imply extraction was beneficial
Distinctive direct queriesConnected policy functions, callers, dependencies, and testsGeneric names remained ambiguous
Automatic depth expansionExposed possible related contextAdded unrelated files at depth 1 and worsened at depth 3
Focused repository checksVerified 12 tests and local policy/version invariantsCould not prove external GitHub settings or hosted matrix behavior
Follow-up commit analysisConfirmed which review intersections were fragileAvailable only retrospectively

The reliable loop is inventory everything, classify review streams, route with metrics, trace distinctive symbols, verify claims against enforcement, reject false expansion, and report external uncertainty.

Give the workflow to an agent

Review this large branch without reading every changed file equally. Record immutable base and head
SHAs, then build a complete git inventory before generating context. Split the branch into coherent
review streams such as intent/ownership, executable enforcement, workflow wiring, product behavior,
tests, and generated or mechanical artifacts. Use ctx score only for the file types it reports and
investigate every concrete signal from source. Trace distinctive symbols into callers, dependencies,
tests, and invoking workflows; reject automatic graph expansions whose source does not verify the
relationship. Choose token budgets for capacity, report selected and omitted files, and do not infer
priority from the packed subset. Verify policy claims with negative tests and workflow wiring, and
separate repository evidence from external settings that cannot be proven locally. Produce a
risk-ranked briefing with blocking findings, accepted signals, validation, and uncertainty.

Next in Cookbook v2

The next recipe will compare keyword, natural-language, semantic, and structural retrieval against the same engineering questions so users can choose the right search mode deliberately.