Files
mesh-delivery/modules/mesh-delivery-indexer/internal/index/form.go
T
jschoubben 03164e853e The indexer writes no fingerprint from a packages state it did not read, keeps no import form beside a version line, and computes fingerprints again by hand (issue 1966)
An indexer that started while the bus's storage was down read no published package,
took every import for unpublished and wrote the version line over ~130 modules'
fingerprints, which a later pass kept through the build's shortcut. A failed or empty
read of the packages state, where held modules were computed from published ones,
now fails the pass and says why; a version line clears the import form it was
computed beside; indexer_fingerprints_again computes the import form again by hand,
acting first and recording the hand act after, with a bound.

Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
2026-11-09 15:15:26 +01:00

91 lines
4.8 KiB
Go

package index
import (
"slices"
"strings"
"git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient"
"git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog"
sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep"
"mesh-delivery-indexer/internal/fingerprint"
)
// form is a module's fingerprint, or why it has none, and the version of each mesh Go module of another repository
// its build is pinned to.
type form struct {
fp, none string
versions sdkstep.PackageVersions
}
// formOf is the module's fingerprint from its kept inputs (bases already its bases' fingerprints) and toolchains, in the
// form they call for (novox/hq ADR 0593 §2, §4):
//
// - **The import form**, for a module whose last trunk build reported its imports (kept.Imports) when every import is
// published (the packages state): the content digest of each imported package and the requirements' digest of each
// mesh Go module holding one. Its versions are each holding module's published commit (another repository's only).
// - **A change of form never rebuilds by itself** (§4): kept.ImportForm is the import-form fingerprint of the inputs
// the build that reported the imports was built from. While the import form computes to it, nothing the build was
// built from changed: the module keeps the fingerprint it holds (prev), in whatever form, and its versions.
// Otherwise the import form is written, and ImportForm moves with it.
// - **The version line** otherwise (no import set, or an import none publishes): the version of each mesh Go module of
// another repository its go.sum names, read as the indexer always read it (fingerprint.HeldVersionsOf), and the
// content of each mesh Go module of its own repository its go.mod replaces by a directory (fingerprint.VersionLine),
// so a change of that directory alone moves it (review finding 2). Its versions are the other repositories' alone.
// - **An accepted series** (DLV-I6): published and pins come from acceptedSeries, so a mesh Go module of another
// repository whose series the module accepts enters, in either form, by its series' newest published version and the
// digests of that version's commit.
//
// It sets kept.ImportForm when it writes the import form.
func formOf(module, repository string, kept *meshcatalog.ModulesByModuleValueInputs2, toolchains map[string]meshcatalogclient.Toolchain2, prev meshcatalog.ModulesByModuleValue, held map[string]meshcatalog.ModulesByModuleValue, published map[string]meshcatalog.PackagesByModuleValue, pins sdkstep.PackageVersions, logf func(string, ...any)) form {
in := inputsFrom(module, *kept, toolchains)
if len(kept.Imports) > 0 {
r := fingerprint.Resolve(repository, kept.Imports, published)
if len(r.Missing) == 0 {
in.Imports, in.Requires = r.Digests, r.Requires
fp, none := fingerprint.Of(in)
switch {
case fp == "":
return form{none: none}
case kept.ImportForm == fp && prev.Fp2 != "":
return form{fp: prev.Fp2, versions: prev.Packages} // the build that reported the imports stands
}
kept.ImportForm = fp
return form{fp: fp, versions: r.Versions}
}
if logf != nil {
logf("%s: no published package holds %s, so its fingerprint takes the version line", module, strings.Join(r.Missing, ", "))
}
}
// The fingerprint written here is the version line's, not the import form's: no import form is held for the inputs it was
// computed from, so a later pass whose import form computes the same does not take this one for the build's (issue 1966).
kept.ImportForm = ""
others := fingerprint.OtherPackages(kept.Packages, repository)
versions, unpublished := fingerprint.HeldVersionsOf(others, held)
for p, v := range pins { // an accepted series' newest published version (acceptedSeries, DLV-I6)
if slices.Contains(others, p) {
if versions == nil {
versions = sdkstep.PackageVersions{}
}
versions[p] = v
unpublished = slices.DeleteFunc(unpublished, func(u string) bool { return u == p })
}
}
if len(unpublished) > 0 && logf != nil {
logf("%s: no module the indexer holds publishes %s, so its fingerprint takes no version of it", module, strings.Join(unpublished, ", "))
}
in.Packages = fingerprint.VersionLine(repository, kept.Packages, versions, published)
fp, none := fingerprint.Of(in)
if fp == "" {
return form{none: none}
}
return form{fp: fp, versions: versions}
}
// inputsFrom is the fingerprint's inputs of module m from its kept inputs and the given toolchains, no package of
// either form yet.
func inputsFrom(module string, k meshcatalog.ModulesByModuleValueInputs2, toolchains map[string]meshcatalogclient.Toolchain2) fingerprint.Inputs {
return fingerprint.Inputs{Module: module, Tree: k.Tree, Bases: k.Bases, Builder: k.Builder, Contexts: k.Contexts,
Locks: k.Locks, Toolchains: toolchains}
}