Validator (A-337): the trunk case counts and declares by every manifest that decodes
A change of migrated manifests was refused against an unmigrated trunk: the old sections were counted and the seats declared only by the trunk manifests the new rules accept, so every count was 0 and every declarer gone. The trunk case now counts and declares by each manifest that decodes, and one that does not decode is named in the trunk case's verdict. Builds: design 47 G §712, A-337 Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
This commit is contained in:
@@ -95,6 +95,12 @@ func ShelfCounting(raws map[string][]byte, predefined catalogue.PredefinedList,
|
||||
// (novox/hq ADR 0578 §1, amended). The indexer judges so; the checker, which runs the judge built at the head of the change,
|
||||
// judges with Shelf.
|
||||
func ShelfWaiting(raws map[string][]byte, predefined catalogue.PredefinedList, longestMachine int, counts OldSectionCounts, known KnownPackages) (refused, waits map[string][]string, unnamed []string) {
|
||||
return shelfWaiting(raws, predefined, longestMachine, counts, known, nil)
|
||||
}
|
||||
|
||||
// shelfWaiting is ShelfWaiting where the seats the trunk case declares (A-337) are declared too, each where no module of the
|
||||
// shelf is its declarer's: a module the shelf holds declares by its own manifest.
|
||||
func shelfWaiting(raws map[string][]byte, predefined catalogue.PredefinedList, longestMachine int, counts OldSectionCounts, known KnownPackages, trunk trunkSeats) (refused, waits map[string][]string, unnamed []string) {
|
||||
refused, waits = map[string][]string{}, map[string][]string{}
|
||||
shelf := catalogue.Shelf{}
|
||||
for name, raw := range raws {
|
||||
@@ -117,20 +123,26 @@ func ShelfWaiting(raws map[string][]byte, predefined catalogue.PredefinedList, l
|
||||
}
|
||||
shelf[name] = m
|
||||
}
|
||||
between := Between(shelf, longestMachine, known)
|
||||
also := trunkSeats{}
|
||||
for seat, d := range trunk {
|
||||
if _, held := shelf[d.module]; !held {
|
||||
also[seat] = d
|
||||
}
|
||||
}
|
||||
problems := between(shelf, longestMachine, known, also)
|
||||
without := map[string]map[string]bool{} // by module: the problems between the rest, once asked
|
||||
ends := func(module, problem string) bool {
|
||||
if without[module] == nil {
|
||||
rest := maps.Clone(shelf)
|
||||
delete(rest, module)
|
||||
without[module] = map[string]bool{}
|
||||
for _, p := range Between(rest, longestMachine, known) {
|
||||
for _, p := range between(rest, longestMachine, known, also) {
|
||||
without[module][p] = true
|
||||
}
|
||||
}
|
||||
return !without[module][problem]
|
||||
}
|
||||
for _, p := range between {
|
||||
for _, p := range problems {
|
||||
// The modules it names are asked first; only when none of them ends it is every module asked.
|
||||
var of []string
|
||||
for _, name := range Named(p, shelf) {
|
||||
@@ -163,10 +175,15 @@ func ShelfWaiting(raws map[string][]byte, predefined catalogue.PredefinedList, l
|
||||
// the longest machine name (catalogue.DefaultLongestMachine when not above 0), DataProblems, and
|
||||
// PackagesCatalogueProblems against the known packages (nil judges no name).
|
||||
func Between(shelf catalogue.Shelf, longestMachine int, known KnownPackages) []string {
|
||||
return between(shelf, longestMachine, known, nil)
|
||||
}
|
||||
|
||||
// between is Between with the seats the trunk case declares outside the shelf declared too (A-337).
|
||||
func between(shelf catalogue.Shelf, longestMachine int, known KnownPackages, trunk trunkSeats) []string {
|
||||
if longestMachine <= 0 {
|
||||
longestMachine = catalogue.DefaultLongestMachine
|
||||
}
|
||||
between := CatalogueProblems(shelf)
|
||||
between := catalogueProblems(shelf, trunk)
|
||||
between = append(between, PackagesCatalogueProblems(shelf, known)...)
|
||||
between = append(between, IdentityProblems(shelf, longestMachine)...)
|
||||
between = append(between, DataProblems(shelf)...)
|
||||
@@ -228,7 +245,7 @@ func Request(r composer.Request) (composer.Verdict, error) {
|
||||
}
|
||||
v := composer.Verdict{V: composer.Version, SDK: Identity()}
|
||||
seen := map[string]bool{}
|
||||
counts := trunkOldSections(r)
|
||||
trunkCase := readTrunk(r)
|
||||
known := knownOf(r.Packages)
|
||||
for _, c := range r.Cases {
|
||||
if seen[c.Name] {
|
||||
@@ -242,7 +259,15 @@ func Request(r composer.Request) (composer.Verdict, error) {
|
||||
}
|
||||
raws[name] = m.Raw
|
||||
}
|
||||
refused, unnamed := ShelfCounting(raws, r.Predefined, 0, counts, known)
|
||||
refused, waits, unnamed := shelfWaiting(raws, r.Predefined, 0, trunkCase.counts, known, trunkCase.declared)
|
||||
for name := range waits {
|
||||
_, refused[name] = Manifest(raws[name], r.Predefined)
|
||||
}
|
||||
if c.Name == TrunkCase {
|
||||
for name, why := range trunkCase.undecoded {
|
||||
refused[name] = append(refused[name], undecodedWords(name, why))
|
||||
}
|
||||
}
|
||||
cv := composer.CaseVerdict{Name: c.Name, Manifests: map[string]composer.ManifestRead{}}
|
||||
for name := range raws {
|
||||
if problems := refused[name]; len(problems) > 0 {
|
||||
@@ -270,34 +295,63 @@ func UseSeatList(defs []seatdef.Definition) {
|
||||
// TrunkCase is the case of a request holding the catalogue as the trunk holds it (the checker's JudgeTrunk).
|
||||
const TrunkCase = "trunk"
|
||||
|
||||
// trunkOldSections counts the old sections the modules accepted at the trunk use, as the indexer counts them from its
|
||||
// verdicts (issue 1966 D4, ADR 0595 §11): a change is refused at the merge check exactly as at take-in (judged once, ADR
|
||||
// 0578). Nil where the request holds no trunk case, which refuses no use of a section.
|
||||
func trunkOldSections(r composer.Request) OldSectionCounts {
|
||||
// trunkRead is what the trunk case as it stands gives every case of a request (design 47 G A-337, §712, ADR 0579 §2): every
|
||||
// trunk-case manifest that decodes counts its old sections and declares its seats, accepted by this judge's rules or not, so
|
||||
// a change is refused only for what it causes and not for a trunk the new rules refuse; each that does not decode is named,
|
||||
// with why, for the trunk case's verdict.
|
||||
type trunkRead struct {
|
||||
counts OldSectionCounts
|
||||
declared trunkSeats
|
||||
undecoded map[string]string
|
||||
}
|
||||
|
||||
// trunkSeats are the seats the trunk case's manifests declare, by seat: the first declaring module in name order and its
|
||||
// declaration.
|
||||
type trunkSeats map[string]trunkSeat
|
||||
|
||||
type trunkSeat struct {
|
||||
module string
|
||||
declaration catalogue.SeatDeclaration
|
||||
}
|
||||
|
||||
// readTrunk reads the request's trunk case (TrunkCase): the old sections its manifests use, as the indexer counts them from
|
||||
// its verdicts (issue 1966 D4, ADR 0595 §11), so a change is refused at the merge check exactly as at take-in (judged once,
|
||||
// ADR 0578), and the seats they declare. No count where the request holds no trunk case, which refuses no use of a section.
|
||||
func readTrunk(r composer.Request) trunkRead {
|
||||
for _, c := range r.Cases {
|
||||
if c.Name != TrunkCase {
|
||||
continue
|
||||
}
|
||||
raws := map[string][]byte{}
|
||||
for name, m := range c.Manifests {
|
||||
if len(m.Raw) > 0 {
|
||||
raws[name] = m.Raw
|
||||
}
|
||||
}
|
||||
refused, _ := Shelf(raws, r.Predefined, 0)
|
||||
var accepted []catalogue.Manifest
|
||||
for name, raw := range raws {
|
||||
if len(refused[name]) > 0 {
|
||||
read := trunkRead{declared: trunkSeats{}, undecoded: map[string]string{}}
|
||||
var decoded []catalogue.Manifest
|
||||
for _, name := range slices.Sorted(maps.Keys(c.Manifests)) {
|
||||
raw := c.Manifests[name].Raw
|
||||
if len(raw) == 0 {
|
||||
continue
|
||||
}
|
||||
if m, err := catalogue.Decode(raw); err == nil {
|
||||
m.Module = name
|
||||
accepted = append(accepted, m)
|
||||
m, err := catalogue.Decode(raw)
|
||||
if err != nil {
|
||||
read.undecoded[name] = err.Error()
|
||||
continue
|
||||
}
|
||||
m.Module = name
|
||||
decoded = append(decoded, m)
|
||||
for _, s := range m.DefinesSeats {
|
||||
if _, taken := read.declared[s.Name]; s.Name != "" && !taken {
|
||||
read.declared[s.Name] = trunkSeat{module: name, declaration: s}
|
||||
}
|
||||
}
|
||||
}
|
||||
return CountOldSections(accepted)
|
||||
read.counts = CountOldSections(decoded)
|
||||
return read
|
||||
}
|
||||
return nil
|
||||
return trunkRead{}
|
||||
}
|
||||
|
||||
// undecodedWords names a trunk-case manifest that does not decode, which counts no old section and declares no seat.
|
||||
func undecodedWords(module, why string) string {
|
||||
return fmt.Sprintf("%s does not decode, so it counts no old section and declares no seat for the change (design 47 G "+
|
||||
"A-337): %s", module, why)
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
@@ -132,6 +132,29 @@ func TestTheJudge(t *testing.T) {
|
||||
!got["newer"].Accepted || !got["user"].Accepted || !got["mesh-grants"].Accepted {
|
||||
t.Errorf("the change's old sections: %+v", got)
|
||||
}
|
||||
// A-337 (§712, ADR 0579 §2): the trunk case as it stands counts and declares, every manifest of it that decodes, accepted
|
||||
// by the new rules or not: a change of migrated manifests against an unmigrated trunk (version "1") refuses nothing for
|
||||
// a count or a declarer, and a trunk manifest that does not decode is named in the trunk case's verdict.
|
||||
unmigrated := composer.Request{V: composer.Version, Cases: []composer.Case{
|
||||
{Name: "change", Manifests: map[string]composer.Manifest{
|
||||
"user": {Raw: json.RawMessage(`{"module":"user","version":"1.0","state":["x"],"seats":[{"name":"channel","scope":"mesh"}]}`)},
|
||||
"caller": {Raw: json.RawMessage(`{"module":"caller","version":"1.0","uses":["channel","kept"]}`)},
|
||||
"declarer": {Raw: json.RawMessage(`{"module":"declarer","version":"1","seats":[{"name":"kept","scope":"mesh"}]}`)}}},
|
||||
{Name: "trunk", Manifests: map[string]composer.Manifest{
|
||||
"user": {Raw: json.RawMessage(`{"module":"user","version":"1","state":["x"],"seats":[{"name":"channel","scope":"mesh"}]}`)},
|
||||
"caller": {Raw: json.RawMessage(`{"module":"caller","version":"1"}`)},
|
||||
"declarer": {Raw: json.RawMessage(`{"module":"declarer","version":"1","seats":[{"name":"kept","scope":"mesh"}]}`)},
|
||||
"broken": {Raw: json.RawMessage(`{"module":"broken","version":[`)}}}}}
|
||||
uv, err := Request(unmigrated)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got := uv.Cases[0].Manifests; !got["user"].Accepted || !got["caller"].Accepted || got["declarer"].Accepted {
|
||||
t.Errorf("a change of migrated manifests against an unmigrated trunk: %+v", got)
|
||||
}
|
||||
if got := uv.Cases[1].Manifests["broken"]; got.Accepted || !strings.Contains(got.Refused, "broken does not decode") {
|
||||
t.Errorf("an undecodable trunk manifest is not named: %+v", got)
|
||||
}
|
||||
r.Cases[0].Manifests["c"] = composer.Manifest{Digest: strings.Repeat("a", 64)}
|
||||
if _, err := Request(r); err == nil {
|
||||
t.Fatal("a manifest left as a digest was judged")
|
||||
|
||||
@@ -4806,6 +4806,12 @@ const meshSeatPrefix = "mesh-"
|
||||
const retiredLoginShell = "login-shell"
|
||||
|
||||
func CatalogueProblems(shelf catalogue.Shelf) []string {
|
||||
return catalogueProblems(shelf, nil)
|
||||
}
|
||||
|
||||
// catalogueProblems is CatalogueProblems with the seats the trunk case declares (A-337) declared too, each a seat no module
|
||||
// of the shelf declares: a module the trunk holds and the new rules refuse still declares.
|
||||
func catalogueProblems(shelf catalogue.Shelf, trunk trunkSeats) []string {
|
||||
var problems []string
|
||||
// A stream name has one owner (novox/hq ADR 0363).
|
||||
problems = append(problems, StreamNameProblems(shelf)...)
|
||||
@@ -4847,6 +4853,12 @@ func CatalogueProblems(shelf catalogue.Shelf) []string {
|
||||
declared[s.Name] = s
|
||||
}
|
||||
}
|
||||
for seat, d := range trunk {
|
||||
if _, taken := declaredBy[seat]; !taken {
|
||||
declaredBy[seat] = d.module
|
||||
declared[seat] = d.declaration
|
||||
}
|
||||
}
|
||||
|
||||
exists := func(seat string) bool {
|
||||
if _, isMesh := catalogue.SeatNamed(seat); isMesh {
|
||||
|
||||
Reference in New Issue
Block a user