refactor: gather compile-check's records behind a record store

Merged
HA
1d ago
+795-431

Summary

  • uloop compile-check's records (the compile result manifest, the changed-files check baseline, and the saved generator output) are now read and written through one record store inside the package, instead of from four files.
  • 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. This prepares the next change (reusing the changed-files check's result), which adds a fourth record: with this change it only has to touch the store.

Changes

  • Tests first (separate commit, passing against the previous code):
    • Fallback reason order where two reasons apply at once: a changed non-source input before missing generator output; a baseline compile changed by hand before a changed non-source input; missing generator output before too many changed files, and before zero changed files; a missing baseline before an unreadable non-source key; a baseline of another format before a missing manifest.
    • Golden bytes of the result manifest and of the baseline record.
  • recordStore, opened per plan through Compiler.records, now owns:
    • from the result cache: the manifest format, path, atomic write, the reuse check, the output match, and the output hashing (now given output names, which unitOutputNames lists);
    • from the baseline code: the baseline format, path, write, generator output hashing and match, and the generator output location;
    • from the changed-files check: the baseline load and the missing-baseline reasons. Loading a baseline returns one value that also carries what the full compile reported, so the check no longer reads the manifest itself;
    • from removeUnitOutputs: removing the manifest, the baseline and the generator output (forget).
  • removeUnitOutputs becomes a Compiler method. It removes the two outputs and then asks the store to forget the records, in the same order (.dll, .ref.dll, manifest, baseline, generator output) and with the same error messages.
  • What stays outside the store: the input keys, the worker calls, the fallback decisions, changedSources, mergeDiagnostics, the first half of recording a baseline (re-reading the non-source key, fingerprinting, matching content hashes), removing the outputs, and creating the generator output directory.

Verification

  • Each pinning test was checked by a mutation, then restored, and each mutation fails it:
    • generator output check before the non-source checks;
    • the baseline reason returned after the non-source checks;
    • generator output check after the changed-file count;
    • zero-changed check before the generator output check;
    • empty-key check before the baseline reason;
    • manifest check before the version check;
    • two fields of each record struct swapped.
  • Existing tests only changed how they call the moved code; no expected string, byte or count changed. Two exceptions:
    • The test that split in two: the old reference-assembly test now checks unitOutputNames and the store's hashing separately, and both still expect one output. A new run-level test compiles a unit without a reference assembly twice and expects the second run to reuse it, so the compile result keeps being recorded with the outputs the unit names; passing both output names regardless fails it.
    • The store's reuse test no longer checks Reused and Assembly, because the caller now fills them in. Setting either wrongly in the caller fails five reuse tests.
  • cli/dispatcher: golangci-lint fmt --diff (empty), go vet ./..., golangci-lint run (0 issues), the complexity config (0 issues), go test ./..., and go test -race ./internal/compilecheck/... pass. Coverage with the CI exclusions: 94.30% (baseline 94.2).
  • cli/release-automation: go test ./... passes. The file-length check passes.