refactor: move compile-check's records into a resultstore package
Merged
HA
1d ago+696+696+012345678901234567890123456789-321-321-012345678901234567890123456789
Summary
- compile-check's records now live in their own package,
resultstore. Everything else in compile-check reaches them only through one store type, and the compiler enforces that. - No behaviour changes: the output JSON, the fallback reasons and their order, and the names and bytes of every record are the same.
User Impact
- None directly. The next change, reusing the changed-files check's result, adds a fourth record. With this package it is one more file in the store plus a load and a record method, and
Forgetstays the single place that removes every record.
Changes
- The store's API:
The record formats, file names, version checks, atomic writes and hashing are unexported. The package comment states the contract: records are written through a temporary file, a baseline is handed out only while its compile result is still on disk,func Open[D any](projectRoot, outputDir string) Store[D] func (s Store[D]) Reusable(assembly, key string) (CompileResult[D], bool) func (s Store[D]) RecordCompile(assembly, key string, result CompileResult[D], outputs []string) error func (s Store[D]) LoadBaseline(assembly string) (Baseline[D], string) func (s Store[D]) GeneratorOutputUnchanged(baseline Baseline[D]) bool func (s Store[D]) RecordBaseline(assembly string, inputs BaselineInputs) error func (s Store[D]) GeneratedDirectory(assembly string) string func (s Store[D]) Forget(assembly string) errorForgetremoves every kind of record, and the reasonsLoadBaselinegives. - Why the diagnostic type is a type parameter
D:- The store never reads a diagnostic, and the type parameter lets the compiler guarantee that.
- Diagnostics are not copied field by field at the boundary.
- No extra package is needed for a single type.
- compile-check uses one instantiation,
resultstore.Open[Diagnostic].
- The non-source key crosses the boundary as
resultstore.KeyDigest. It has the same fields as compile-check's ownnonSourceIdentity, so the two convert into each other with a plain type conversion and nothing is copied. compile-check keeps owning how the key is computed. - The store keeps private copies of
hashFile(12 lines) and the project-relative path helper rather than sharing them through another package.resultstoreimports only the standard library. - The store's own tests use a stand-in diagnostic type with the same field order, so the golden record bytes are unchanged. A golden test in compile-check pins the JSON form of the real diagnostic type, because the store records diagnostics exactly as it is given them. Swapping two of its fields, or adding a JSON tag, fails that test.
- New tests at the store's boundary (separate commit). Coverage is measured per package, so the baseline paths that compile-check's tests used to exercise would otherwise count for nothing:
- a recorded baseline comes back as recorded;
- a changed, removed or added generated file stops the generator output matching;
- a compile result that is gone, unreadable, of another key, failed, or whose output changed stops the baseline being handed out;
- each reason a baseline is missing;
- a failed baseline write.
Verification
go list -deps ./internal/compilecheck/resultstore | grep -c 'internal/compilecheck$':0. Its direct imports are all standard library.git grep -Povercli/dispatcher/internal/compilecheck/*.go(not descending into subpackages) for record internals (struct names, constants, paths, internal functions, record file names): no matches.- No expected reason, byte or count changed in the moved tests. The tests outside the store only switched to the public names.
- Mutation checks, each restored afterwards:
- swapping two fields of either record struct fails its golden test;
- swapping the fields of
KeyDigeststops the type conversion compiling and fails the baseline golden test; - checking the manifest before the baseline's version fails the order test;
- moving the generator output check before the non-source checks fails the order test;
- dropping the failed-compile check from
LoadBaselinefails a parent test and a new store test; - dropping the file-count check from the generator output match fails the new store test.
cli/dispatcher:golangci-lint fmt --diffis empty;go vet ./...passes;golangci-lint runand the complexity config both report 0 issues.go test ./...andgo test -race ./internal/compilecheck/...(includingresultstore) pass.- Coverage with the CI exclusions: 94.25% (baseline 94.2). It was 93.74% before the boundary tests.
cli/release-automation:go test ./...passes. The file-length check passes.- Out of scope: keeping the previous baseline after a failed compile is still awaiting a decision. If it is done later, it only touches
ForgetandRecordCompile.