Files
mesh-delivery/modules/mesh-delivery-indexer/internal/index/order.go
T
jschoubben edf7b3c0bf
mesh/delivery-group group feat/judge-once checking: 6 of 6 member(s) ready
mesh/delivery closed: a newer head of the same pull request
mesh/check checking edf7b3c0bf3a on b1f262d7d06e | novox/mesh-delivery#129 in group feat/judge-once
Answer review round 1: fresh is only what a take-in newly wrote, a merge keeps the verdict, the check compares with the trunk (ADR 0578, 0579)
Issue 1585, R1: fresh holds the digests a take-in newly wrote (a new module, a changed manifest); a registered or
taken-in module is judged too; a start pass that fails is judged again at the next message heard, no timer.
R2: a module's verdict, problems and warnings are carried while its digest stands and are no part of the compare.
R3: the checker judges the trunk beside the change and fails on every problem the change case adds, an untouched
manifest's included. R4: the judge reads the indexer's kept predefined keys, or the catalogue member's when it
changes them. A log line names a package no held module publishes. Every module pins mesh-sdk 62cddf4.

Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
2026-11-01 03:12:09 +01:00

129 lines
5.7 KiB
Go

package index
import (
"context"
"errors"
"fmt"
"slices"
"strings"
"git.novox.be/novox/mesh-sdk/go/delivery"
"git.novox.be/novox/mesh-sdk/go/process"
)
// A merge never moves a module backwards (issue 1126, note 76). The indexer wrote mesh-catalog's merge 9cdac09a back over
// the later 69056948 for kernel and mesh-build-image: applyManifests and writeOverlay wrote whatever commit a merged
// message carried, so a late or repeated message rolled the modules, and the nodes that want them, back.
//
// The question is whether the incoming commit is OLDER: the forge says the incoming commit is in the later one and the
// two differ (Contains(incoming, in: later)). Only then is it kept back. A diverged or rewritten history answers no, and
// is written forward; a commit the forge no longer has (a 404) is not known to be older, is written, and said. A forge
// that cannot say for another reason (a timeout) writes nothing and is an error: the server delivers the message again.
//
// - A merged message asks once, before it writes anything: is its merge older than the repository's taken merge (the
// last merge applied whole, taken.go)? Then the whole message is late: no module is written or deleted, the taken key
// stays, and the log says so.
// - A take-in of a held module asks once for that module: is the source's head older than the module's record
// (takeInHeld)?
// mergeWrite is one merge's write of the modules: its repository and commit, whether it is late (older than the taken
// merge), the taken merge it was compared with and the answer, and the module keys written, for the line the indexer says
// per applied merged message.
type mergeWrite struct {
repository, merge string
late string // the taken merge this one is older than, or ""
asked string // the taken merge the order was asked against, or "" when none was asked
written []string
// fresh are the manifest digests this take-in newly wrote: a new module's, or a changed one's (ADR 0579 §1).
fresh map[string]bool
}
// taken marks a digest this take-in newly wrote.
func (w *mergeWrite) taken(digest string) {
if w.fresh == nil {
w.fresh = map[string]bool{}
}
w.fresh[digest] = true
}
func newMergeWrite(f delivery.Forge) *mergeWrite {
return &mergeWrite{repository: f.Repository, merge: f.Merge}
}
// notFound says the forge answered that a commit it was asked about does not exist: gitea's status ": 404 ", matched as
// readVia matches it (cmd/mesh-delivery-indexer named.go). A bare "404" is not enough: the error's words carry both shas,
// and a 502 naming a sha with 404 in it would read as not older and write a late message backwards. The thorough form,
// a typed not-found answered by gitea_contains, is noted on issue 1126.
func notFound(err error) bool { return err != nil && strings.Contains(err.Error(), ": 404 ") }
// older says commit is older than later: the forge says commit is in later and the two differ. A commit the forge does not
// have is not known to be older (false, said); a forge that cannot say otherwise is an error. Without a forge to ask
// (Contains nil) nothing is older.
func (ix *Indexer) older(ctx context.Context, repository, commit, later string) (bool, error) {
if ix.Contains == nil || commit == "" || later == "" || commit == later {
return false, nil
}
in, err := ix.Contains(ctx, repository, commit, later)
if notFound(err) {
ix.logf("%s: the forge does not have %.12s or %.12s (a rewritten history?), so %.12s is not known to be older and is written: %v", repository, commit, later, commit, err)
return false, nil
}
if err != nil {
return false, fmt.Errorf("%s: whether %.12s is older than %.12s cannot be read, so nothing of it is written (a merge never moves a module backwards, issue 1126): %w", repository, commit, later, err)
}
return in, nil
}
// lateMerge asks, before a merged message writes anything, whether its merge is older than the repository's taken merge
// (one forge call). A taken state not on the bus yet, or no taken key, asks nothing.
func (ix *Indexer) lateMerge(ctx context.Context, w *mergeWrite) error {
if ix.Taken == nil || w.merge == "" {
return nil
}
key, err := delivery.RepositoryKey(w.repository)
if err != nil {
return nil // writeTaken says it
}
value, _, found, err := ix.Taken.Get(ctx, key)
if errors.Is(err, process.ErrNotYet) || !found {
return nil
}
if err != nil {
return fmt.Errorf("taken.%s: %w", key, err)
}
cur, err := delivery.DecodeTaken(value)
if err != nil || cur.Merge == "" || cur.Merge == w.merge {
return nil
}
old, err := ix.older(ctx, w.repository, w.merge, cur.Merge)
if err != nil {
return err
}
w.asked = cur.Merge
if old {
w.late = cur.Merge
ix.logf("%s at %.12s: the merged message is older than taken.%s at %.12s, so no module is written or deleted (a late or repeated message; a merge never moves a module backwards, issue 1126)",
w.repository, w.merge, key, cur.Merge)
}
return nil
}
// wrote records a module key the merge wrote.
func (w *mergeWrite) wrote(key string) {
if w != nil && !slices.Contains(w.written, key) {
w.written = append(w.written, key)
}
}
// said is the line of an applied merged message: its repository, commit and pull request, and the modules written.
func (w *mergeWrite) said(number int) string {
if w.late != "" {
return fmt.Sprintf("%s at %.12s (#%d): merged message applied as late: older than the taken %.12s, nothing written", w.repository, w.merge, number, w.late)
}
written := "none"
if len(w.written) > 0 {
written = strings.Join(slices.Sorted(slices.Values(w.written)), ", ")
}
return fmt.Sprintf("%s at %.12s (#%d): merged message applied; modules written: %s", w.repository, w.merge, number, written)
}