Join (lead's iii): a series key's value is mesh-sdk's delivery.SeriesPackage; its readers decode it by the contract

The indexer's SeriesPackage and SeriesVersion are aliases of delivery.SeriesPackage and SeriesVersion (J4), SeriesKey and
IsSeriesKey are delivery.SeriesPackageKey and IsSeriesPackageKey; the indexer's readers (the series read for a user's
fingerprint, indexer_package_users) and the builder's NamesIn decode with delivery.DecodeSeriesPackage (the builder no
longer reads the indexer's value by field names). Found by the contract: a published newest's Contents named no time,
which DecodeSeriesPackage refuses, so the accepted series was left out and its users kept the commit form; the
indexer now stamps the time the contents were read (TestImportsReportedMoveTheFingerprintOnlyWithAnImportedPackage,
"an accepted series' newest ... pins it", failed with the decode before the stamp).

Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
This commit is contained in:
2026-11-04 15:14:41 +01:00
parent 7ae4f2bb7f
commit c8eccf299a
3 changed files with 26 additions and 55 deletions
@@ -2,18 +2,10 @@ package versions
import (
"context"
"encoding/json"
"sort"
"strings"
)
// seriesName is what the builder reads of a series key of the indexer's packages state (delivery.PackagesState): the
// package's name in its ecosystem and the `<module>/<artifact>` it is built from. The value's type is the indexer's own
// (its SeriesPackage, fields `name` and `package`); the fields are read here by their names, not by its type.
type seriesName struct {
Name string `json:"name"`
Package string `json:"package"`
}
"git.novox.be/novox/mesh-sdk/go/delivery"
)
// PackagesState is the indexer's packages state as the builder reads it (its manifest's reads grant): its keys, and one
// key's value (found false when it holds none).
@@ -34,15 +26,18 @@ func NamesIn(s PackagesState) PackageNames {
sort.Strings(keys)
built := NameOf(module, artifact)
for _, key := range keys {
if !strings.Contains(key, ".") {
if !delivery.IsSeriesPackageKey(key) {
continue
}
value, found, err := s.Get(ctx, key)
if err != nil {
return "", false, err
}
var v seriesName
if !found || json.Unmarshal(value, &v) != nil || v.Package != built || v.Name == "" {
if !found {
continue
}
v, err := delivery.DecodeSeriesPackage(value) // the indexer's value of a series key (mesh-sdk's contract, J4)
if err != nil || v.Package != built {
continue
}
return v.Name, true, nil
@@ -1,7 +1,6 @@
package index
import (
"encoding/json"
"fmt"
"maps"
"slices"
@@ -63,8 +62,8 @@ func PackageUsersOf(modules, manifests, packages views.Source, only string) ([]P
if !ok {
continue
}
var s SeriesPackage
if err := json.Unmarshal(e.Value, &s); err != nil {
s, err := delivery.DecodeSeriesPackage(e.Value)
if err != nil {
return nil, fmt.Errorf("packages.%s holds what is not a series: %w", key, err)
}
p := get(s.Name)
@@ -9,7 +9,6 @@ import (
"path"
"slices"
"strings"
"time"
"git.novox.be/novox/mesh-sdk/go/catalogue"
"git.novox.be/novox/mesh-sdk/go/delivery"
@@ -24,44 +23,19 @@ import (
// A series key always holds a dot (`mesh-sdk/go.0.1`), which EscapeName never leaves in a per-module key: a reader tells the
// two forms apart by IsSeriesKey.
// SeriesPackage is the value of a series key.
type SeriesPackage struct {
V int `json:"v"`
// Name is the package's name in its own ecosystem (design 32, the lead's design limit of 2026-11-04): a Go package's
// module path in its go.mod at the commit, an npm package's package.json name. The series key is named by it, and a
// user's `packages` names it. Package is the module and artifact it is built from, `<module>/<artifact>`, by which
// the builder finds the name to number under; Series its `<major>.<minor>`.
Name string `json:"name"`
Package string `json:"package,omitempty"`
Series string `json:"series"`
// Seat is the registry seat it is published through; GoModule the Go module path a Go package is fetched under (from
// go-package-registry's published), empty for any other.
Seat string `json:"seat,omitempty"`
GoModule string `json:"go-module,omitempty"`
// Newest is the newest version of the series a seat published: what a user accepting the series builds against.
Newest *SeriesVersion `json:"newest,omitempty"`
// Numbered is the newest version of the series the builder numbered, published or not yet.
Numbered *SeriesVersion `json:"numbered,omitempty"`
At time.Time `json:"at"`
}
// SeriesPackage is the value of a series key, and SeriesVersion one version of a series: mesh-sdk's
// delivery.SeriesPackage and SeriesVersion (J4), the contract every reader of the state decodes with
// delivery.DecodeSeriesPackage.
type (
SeriesPackage = delivery.SeriesPackage
SeriesVersion = delivery.SeriesVersion
)
// SeriesVersion is one version of a series: its number, the source commit it was built from, the digest and fingerprint.
type SeriesVersion struct {
Version string `json:"version"`
Commit string `json:"commit,omitempty"`
Digest string `json:"digest,omitempty"`
Fingerprint string `json:"fingerprint,omitempty"`
// Contents are, for a series' newest of a Go package, its Go module's requirements' and packages' digests read from the
// forge's listing at Commit (DLV-I6): what a user accepting the series is fingerprinted against. Nil when the forge
// could not list it (said), and on a numbered version.
Contents *delivery.PublishedPackages `json:"contents,omitempty"`
}
// SeriesKey is the key of a package's series in the packages state (delivery.SeriesPackageKey).
func SeriesKey(pkg, series string) string { return delivery.SeriesPackageKey(pkg, series) }
// SeriesKey is the key of a package's series in the packages state.
func SeriesKey(pkg, series string) string { return delivery.EscapeName(pkg) + "." + series }
// IsSeriesKey says whether a key of the packages state is a series key, not a per-module one.
func IsSeriesKey(key string) bool { return strings.Contains(key, ".") }
// IsSeriesKey says whether a key of the packages state is a series key, not a per-module one (delivery.IsSeriesPackageKey).
func IsSeriesKey(key string) bool { return delivery.IsSeriesPackageKey(key) }
// SeriesOf is the series of a trunk version (`0.1.15` is of `0.1`); false for a version that is no `<major>.<minor>.<patch>`
// or that carries a tag (a pre-release).
@@ -102,6 +76,9 @@ func (ix *Indexer) HearVersion(ctx context.Context, h HeardVersion) (bool, error
case !ok:
ix.logf("%s %s: the forge's listing at %s holds no Go module %s, so its users keep the commit form", h.Package, h.Version, h.Commit, h.GoModule)
default:
// When the contents were read: delivery.SeriesVersion.Contents is a PublishedPackages, which names its time
// (DecodeSeriesPackage refuses one with none).
p.At = ix.now().UTC()
v.Contents = &p
}
}
@@ -162,8 +139,8 @@ func (ix *Indexer) SeriesAll(ctx context.Context) map[string]SeriesPackage {
if err != nil || !found {
continue
}
var s SeriesPackage
if err := json.Unmarshal(value, &s); err != nil {
s, err := delivery.DecodeSeriesPackage(value)
if err != nil {
ix.logf("packages.%s holds what is not a series, left out: %v", key, err)
continue
}