Investigate architecture history¶
Use history analyze to investigate files that repeatedly change together,
hotspots and coordination pressure across a selected Git range. Use
change report instead for a comparison of two complete architecture snapshots.
History findings are review evidence, not proof of a design violation or a reason
to block a merge automatically.
Select the range¶
Work in a repository with the required commits, trees and blobs available. A shallow checkout may lack them; prepare full history and the selected tags before analysis. The CLI does not fetch missing history for you.
Pass full commit IDs or fully qualified refs. Shorthand tag/branch names are
accepted only when unambiguous. Remote refs require their full name, such as
refs/remotes/origin/main. Revision expressions such as HEAD~20, abbreviated
IDs and reflog selectors are not CLI operands. Resolve a deliberate Git
expression with Git first, then pass the resulting full ID.
The analyzed set is:
Reachable(to) minus Reachable(from)
This is not necessarily a linear sequence of N commits, and from need not be
an ancestor of to. Release tags make a reproducible range when the question
is what changed between releases. Selecting a rolling window is a different
review policy, not a native --last-n option.
Produce a report¶
Set FROM_SHA and TO_SHA to the full IDs you selected, then run:
mkdir -p artifacts
arch-linter-net history analyze --repository . \
--from "$FROM_SHA" --to "$TO_SHA" --format json > artifacts/history.json
Use --policy architecture/arch.yml to select the policy's history_analysis
configuration. Do not assume ordinary architecture contracts define the history
ranking. Without an explicit policy, use the command's default history profile.
Check history analyze --help in the installed package before changing inputs.
For a human reading view, choose Markdown instead:
arch-linter-net history analyze --repository . \
--from "$FROM_SHA" --to "$TO_SHA" --format markdown > artifacts/history.md
These two invocations each perform history analysis once with --format
selecting the single document written to standard output. To get both
documents from one analysis, use the repeatable --report
<format>=<destination> option instead of running the command twice:
arch-linter-net history analyze --repository . \
--from "$FROM_SHA" --to "$TO_SHA" \
--report json=artifacts/history.json \
--report markdown=artifacts/history.md
--report accepts json or markdown for <format> and stdout, stderr,
or a file path for <destination>; --format is ignored when --report is
also supplied. Ingestion and scoring run exactly once regardless of how many
sinks are configured, and every destination is validated (including
rejecting duplicate destinations and a destination that collides with
--policy) before anything is written. Staging and serialization failures
leave every destination untouched. If a stream write or a later independent
file rename fails, the command exits non-zero with partial-output or
output-failed evidence naming delivered, committed, and uncommitted
destinations; it never claims that the complete set succeeded. Keep stderr
separate from the report and preserve a nonzero exit; an error document is not
a successful empty history report.
For a reproducible performance sample, add --timings. The command writes one
timing line to stderr with policy, ingestion, scoring, JSON/Markdown rendering,
output routing, and the ingestion invocation count. Subtract those phase values
from the packed process wall clock to report process overhead; keep peak working
set from the same process sample. Timing evidence is diagnostic only and does
not affect report bytes or exit status.
The repository's explicit packed before/after harness is
HistorySingleAnalysisPackedBenchmarkHarness; run it after building the CLI with:
dotnet test tests/ArchLinterNet.Cli.Tests --no-restore \
--filter FullyQualifiedName~HistorySingleAnalysisPackedBenchmarkHarness
It refreshes the machine-readable and Markdown evidence under
docs/internal/history-single-analysis-packed-evidence.* using a synthetic Git
release range, keeping this history workload separate from the architecture
validation performance baseline.
Read the evidence¶
Start with the resolved range, selected history policy/profile and input counts. Then inspect hotspot and co-change evidence and the commits/tasks supporting an investigation candidate. A large change count can reflect a broad mechanical edit; files changing together can reflect one task rather than a necessary architectural dependency. Check these explanations before assigning a refactor.
Hotspots, bottlenecks and OCP pressure are prioritization signals. They do not prove a module boundary, an actual merge conflict or the correctness of a proposed extraction. The deterministic analysis does not require an LLM.
When comparing reports, retain the exact CLI version, resolved commits and history configuration. A changed policy or time range can change rankings even when the implementation did not change. Do not compare rank positions alone.
Optional .NET enrichment¶
--enrich-dotnet adds the supported .NET projection. It is optional and may need
additional compatible policy/build inputs. Establish the Git-only result first;
then inspect enrichment availability separately. Enrichment must not be treated
as permission to bind current working-tree assemblies to historical revisions.
CI placement¶
A separate release or explicitly chosen scheduled job is usually a better fit
than the required PR path for a broad range investigation. Pin the two endpoints,
retain the selected report, and name the measured range in the job summary.
Do not silently use whatever the previous tag or main happens to be when a
retry runs. ArchLinterNet does not schedule the job or publish the report.
Troubleshooting¶
| Symptom | Check |
|---|---|
| Unknown or ambiguous ref | Full object ID or fully qualified ref; tag/branch collisions; missing fetched tags. |
| Incomplete repository evidence | Shallow history, missing commit/tree/blob objects, unreadable objects. |
| Unexpected range size | Reachability across merges and whether from is an ancestor of to. |
| Expensive report | Range size, policy, runner, enrichment and accidental JSON/Markdown double invocation. |
| Unexpected ranking | Supporting commits/tasks, mechanical edits and configuration changes, not only the headline score. |
Use performance diagnosis for measurement discipline; capture the history timing line with the same tool build, runner, fixture, range and policy for before/after comparisons.