A-241: the validation's seats are the revision's definitions with the merges' laid over
A revision that touches no seat definition was judged against no seats at all; it is now judged against the whole seat list, the trunk's definitions standing in for the revision's until A-234 keeps them. Builds: design 47 G §712, A-241, A-234 Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
This commit is contained in:
@@ -122,23 +122,62 @@ func placeKey(repository, path string) string {
|
||||
return strings.ToLower(trunk.RepositoryName(repository)) + " " + path
|
||||
}
|
||||
|
||||
// revisionDefinitions are the seat definitions the merges' trees carry, raw (§712 `seats`).
|
||||
// revisionDefinitions are the validation's seat definitions, raw (§712 `seats`, A-241): the branch's revision's seat
|
||||
// definitions with the definitions the merges' trees carry laid over them, so a revision that touches no definition is still
|
||||
// judged against the whole seat list. A revision's own definitions are not kept yet (A-234), so the revision's are the
|
||||
// trunk's, read from the state seat-definitions as the verb seat-definitions answers them.
|
||||
func (ix *Indexer) revisionDefinitions(ctx context.Context, ready []PendingEntry) ([]json.RawMessage, error) {
|
||||
defs, err := ix.revisionSeatDefinitions(ctx, ready)
|
||||
defs, err := ix.trunkDefinitions(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var out []json.RawMessage
|
||||
for _, seat := range slices.Sorted(maps.Keys(defs)) {
|
||||
raw, err := json.Marshal(defs[seat])
|
||||
merged, err := ix.revisionSeatDefinitions(ctx, ready)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for seat, d := range merged {
|
||||
raw, err := json.Marshal(d)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("the definition of %s: %w", seat, err)
|
||||
}
|
||||
out = append(out, raw)
|
||||
defs[seat] = raw
|
||||
}
|
||||
var out []json.RawMessage
|
||||
for _, seat := range slices.Sorted(maps.Keys(defs)) {
|
||||
out = append(out, defs[seat])
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// trunkDefinitions are the trunk's seat definitions of the state seat-definitions, raw, by seat: every `<seat>.trunk` entry
|
||||
// that holds a definition; none where the indexer keeps no such state.
|
||||
func (ix *Indexer) trunkDefinitions(ctx context.Context) (map[string]json.RawMessage, error) {
|
||||
defs := map[string]json.RawMessage{}
|
||||
if ix.SeatDefinitions == nil {
|
||||
return defs, nil
|
||||
}
|
||||
keys, err := ix.SeatDefinitions.Keys(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("the %s state cannot be listed: %w", SeatDefinitionsState, err)
|
||||
}
|
||||
for _, key := range keys {
|
||||
seat, ok := strings.CutSuffix(key, "."+SourceTrunk)
|
||||
if !ok || strings.HasPrefix(key, outOfStepPrefix) {
|
||||
continue
|
||||
}
|
||||
v, _, found, err := ix.SeatDefinitions.Get(ctx, key)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s.%s cannot be read: %w", SeatDefinitionsState, key, err)
|
||||
}
|
||||
var e SeatDefinitionEntry
|
||||
if !found || json.Unmarshal(v, &e) != nil || e.Digest == "" || len(e.Definition) == 0 {
|
||||
continue // an entry that holds no definition is no seat of the list
|
||||
}
|
||||
defs[seat] = e.Definition
|
||||
}
|
||||
return defs, nil
|
||||
}
|
||||
|
||||
// validationJob is the run of the manifest validator for the request (§712): the program cmd/mesh-judge under the Go module
|
||||
// the indexer entry's Go artifact names, at the entry's path, built at head, the revision's head of the entry's repository; no
|
||||
// heads and no arguments; the input the request's bytes, served by the seat mesh-catalog's verb input.
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
package index
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-contracts/go/seats/meshcatalog"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-forge-bridge/forgemsg"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-sdk/buildstep"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-sdk/composer"
|
||||
|
||||
@@ -72,3 +75,56 @@ func TestValidationRefusesWhatTheRevisionCauses(t *testing.T) {
|
||||
t.Errorf("no indexer entry: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// The validation's seats are the branch's revision's seat definitions with the merges' changed ones laid over them (A-241): a
|
||||
// revision that touches no definition is judged against the whole seat list, and a merge's definition replaces its seat's.
|
||||
func TestValidationSeatsAreTheRevisionsWithTheMergesOver(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
defs := newMem()
|
||||
for seat, raw := range map[string]string{"node-engine": `{"seat":"node-engine","verbs":[{"name":"old"}]}`, "git": `{"seat":"git"}`} {
|
||||
v, _ := json.Marshal(SeatDefinitionEntry{Seat: seat, Source: SourceTrunk, Digest: "d-" + seat, Definition: json.RawMessage(raw)})
|
||||
defs.put(SeatDefinitionKey(seat, SourceTrunk, "", 0), v)
|
||||
}
|
||||
v, _ := json.Marshal(SeatDefinitionEntry{Seat: "pulled", Source: SourcePull, Pull: 3, Digest: "d", Definition: json.RawMessage(`{"seat":"pulled"}`)})
|
||||
defs.put(SeatDefinitionKey("pulled", SourcePull, "r", 3), v)
|
||||
ix := &Indexer{SeatDefinitions: defs}
|
||||
seatsOf := func(raws []json.RawMessage) map[string]string {
|
||||
out := map[string]string{}
|
||||
for _, raw := range raws {
|
||||
var d struct {
|
||||
Seat string `json:"seat"`
|
||||
Verbs []struct {
|
||||
Name string `json:"name"`
|
||||
} `json:"verbs"`
|
||||
}
|
||||
if err := json.Unmarshal(raw, &d); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
out[d.Seat] = ""
|
||||
if len(d.Verbs) > 0 {
|
||||
out[d.Seat] = d.Verbs[0].Name
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
got, err := ix.revisionDefinitions(ctx, nil)
|
||||
if err != nil || !reflect.DeepEqual(seatsOf(got), map[string]string{"node-engine": "old", "git": ""}) {
|
||||
t.Errorf("a revision touching no definition: %v (%v), want the trunk's whole list and no pull request's", seatsOf(got), err)
|
||||
}
|
||||
const contracts = "modules/seat-contracts"
|
||||
f := forgemsg.Forge{Repository: "r", Merge: strings.Repeat("c", 40), Manifests: map[string]string{
|
||||
contracts: `{"module":"seat-contracts","version":"1.0","build":{"artifacts":[{"name":"go-seats","kind":"package","language":"go","paths":["go"],"series":"0.1","generated-from":"."}]}}`}}
|
||||
ix.Files = func(_ context.Context, _, _ string, dirs []string) (map[string]map[string]string, error) {
|
||||
return map[string]map[string]string{dirs[0]: {"node-engine/seat.json": "1"}}, nil
|
||||
}
|
||||
ix.ReadFile = func(_ context.Context, _, _, p string) ([]byte, error) {
|
||||
if p == contracts+"/seats/node-engine/seat.json" {
|
||||
return []byte(`{"format":1,"seat":"node-engine","scope":"node","grain":"seat-list","decision":"d","domain":"Core","verbs":[{"name":"new"}]}`), nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
got, err = ix.revisionDefinitions(ctx, []PendingEntry{{Forge: f}})
|
||||
if err != nil || !reflect.DeepEqual(seatsOf(got), map[string]string{"node-engine": "new", "git": ""}) {
|
||||
t.Errorf("a merge changing a definition: %v (%v), want its definition over the trunk's and the rest kept", seatsOf(got), err)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user