ADR 0005: FactStore extension for command timing and dependency graph¶
Context¶
archfit needs to compute metrics such as verification latency (wall-clock test
time) and blast radius (transitive dependency reach). These require facts from
the command collector (Step 8) and the dependency-graph collector (Step 9), both
of which already exist under internal/collector/.
The current FactStore interface exposes three methods: Repo(), Git(), and
Schemas(). Adding Commands() and DepGraph() widens the interface, which
touches every implementation (scheduler, CLI wrapper, test fakes).
The key design question is whether these new fact sources should be always available or opt-in.
Decision¶
Add two new methods to the FactStore interface using the same optional-return
pattern as Git():
Commands() (CommandFacts, bool) // opt-in, only populated with --depth=deep
DepGraph() (DepGraphFacts, bool) // available when source is parseable
Both return (T, bool) so that callers can distinguish "not collected" from
"collected but empty". This is the same pattern already established by
Git() (GitFacts, bool).
Command timing is expensive (it runs make test, go test, etc.) so it is
gated behind --depth=deep. At shallow or standard depth, Commands()
returns (zero, false).
Dependency graph collection is lightweight (parsing import statements) so it
runs unconditionally for Go projects. DepGraph() returns (zero, false) only
when the repo has no parseable source.
New model types (CommandFacts, CommandResult, DepGraphFacts) are thin
projections of the collector output — they carry only what resolvers and metric
functions need, not raw stdout/stderr.
Consequences¶
- Every
FactStoreimplementation (scheduler, CLI, test fakes) must add the two new methods. Fakes return(zero, false). - The
ScanInputstruct gains aDepthfield so the scheduler knows whether to run the command collector. - Metric functions in
internal/score/can consume the new facts to computeverification_latency_s,blast_radius_score, and related metrics. - Future collectors follow the same pattern: add a method to
FactStore, update all implementations, gate on depth if the collector is expensive.