Carry each build's repository, directory and commit in the builder's log, so the indexer, the outside-built registrations and the assigner read where a build came from there (issue 1955)

This commit is contained in:
2026-10-29 23:09:47 +01:00
parent 7fdbadc655
commit f9a496d3e1
2 changed files with 28 additions and 19 deletions
+10 -6
View File
@@ -76,23 +76,27 @@ func TestTheControlRecordsReadTheirWritersValues(t *testing.T) {
}
// ADR 0571 clause 1: the builder's log, a start and an end, and the duration between them.
at := time.Date(2026, 10, 29, 22, 0, 0, 0, time.UTC)
start := BuildLogEntry{Event: BuildStartedEvent, Module: "letta", FP: "src2:a", Source: "abc", Node: "ace", At: at}
start := BuildLogEntry{Event: BuildStartedEvent, Module: "letta", FP: "src2:a", Source: "abc", Repository: "novox/mesh-catalog",
Directory: "modules/letta", Commit: "abc123", Node: "ace", At: at}
end := start
end.Event, end.At, end.Outcome, end.Artifacts = BuildEndedEvent, at.Add(3*time.Minute), "done", []BuiltDigest{{Name: "image", Digest: "sha256:1"}}
for _, e := range []BuildLogEntry{start, end} {
raw, err := EncodeBuildLogEntry(e)
back, derr := DecodeBuildLogEntry(raw)
if err != nil || derr != nil || back.Event != e.Event || back.Outcome != e.Outcome {
if err != nil || derr != nil || back.Event != e.Event || back.Outcome != e.Outcome || back.Directory != "modules/letta" ||
back.Repository != "novox/mesh-catalog" || back.Commit != "abc123" {
t.Errorf("%s read back as %+v, %v %v", e.Event, back, err, derr)
}
}
if d, ok := BuildDuration(start, end); !ok || d != 3*time.Minute {
t.Errorf("the build took %s, %v", d, ok)
}
bad := end
bad.Outcome = ""
if _, err := EncodeBuildLogEntry(bad); err == nil {
t.Error("an end with no outcome was encoded")
for _, edit := range []func(*BuildLogEntry){func(e *BuildLogEntry) { e.Outcome = "" }, func(e *BuildLogEntry) { e.Commit = "" }} {
bad := end
edit(&bad)
if _, err := EncodeBuildLogEntry(bad); err == nil {
t.Errorf("%+v was encoded", bad)
}
}
if k, err := HeldValueKey("novox/mesh-catalog#42", "novox", "mail", "quota"); k != "novox.mesh-catalog.42.novox.mail.quota" || err != nil {
t.Errorf("a held value's key is %q, %v", k, err)
+18 -13
View File
@@ -126,18 +126,23 @@ type BuiltDigest struct {
Digest string `json:"digest"`
}
// BuildLogEntry is one entry of the builder's log: the module, the fingerprint, the source revision, the build node and
// the time; at the end, the outcome and each artifact's digest.
// BuildLogEntry is one entry of the builder's log: the module, the fingerprint, the source revision, where the module is
// built from (its repository, its directory there and the commit), the build node and the time; at the end, the outcome
// and each artifact's digest. The repository, directory and commit are what the indexer's PathOf, the outside-built
// registrations and the assigner's running commits read (the lead, 2026-10-29).
type BuildLogEntry struct {
V int `json:"v"`
Event string `json:"event"`
Module string `json:"module"`
FP string `json:"fp"`
Source string `json:"source"`
Node string `json:"node"`
At time.Time `json:"at"`
Outcome string `json:"outcome,omitempty"`
Artifacts []BuiltDigest `json:"artifacts,omitempty"`
V int `json:"v"`
Event string `json:"event"`
Module string `json:"module"`
FP string `json:"fp"`
Source string `json:"source"`
Repository string `json:"repository"`
Directory string `json:"directory"`
Commit string `json:"commit"`
Node string `json:"node"`
At time.Time `json:"at"`
Outcome string `json:"outcome,omitempty"`
Artifacts []BuiltDigest `json:"artifacts,omitempty"`
}
// EncodeBuildLogEntry is e as JSON at Version; it refuses an entry a reader could not place.
@@ -146,8 +151,8 @@ func EncodeBuildLogEntry(e BuildLogEntry) ([]byte, error) {
switch {
case e.Event != BuildStartedEvent && e.Event != BuildEndedEvent:
return nil, fmt.Errorf("delivery: a build log entry is %s or %s, not %q", BuildStartedEvent, BuildEndedEvent, e.Event)
case e.Module == "" || e.FP == "" || e.Node == "" || e.At.IsZero():
return nil, fmt.Errorf("delivery: a build log entry names its module, fingerprint, node and time")
case e.Module == "" || e.FP == "" || e.Node == "" || e.At.IsZero() || e.Repository == "" || e.Commit == "":
return nil, fmt.Errorf("delivery: a build log entry names its module, fingerprint, repository, commit, node and time")
case e.Event == BuildEndedEvent && e.Outcome == "":
return nil, fmt.Errorf("delivery: a build's end names its outcome")
case e.Event == BuildStartedEvent && (e.Outcome != "" || len(e.Artifacts) > 0):