A checker that hands no seat digests gets the heads' definitions without their verbs' and messages' schemas (issue 1921, milestone 47/G, the group check of 616c42434ac2)

The build seat's step state keeps the checking program's answer and refuses a
value with a field named like a credential; schema property names such as
mesh-vault's verb input 'credentials' tripped it. Neither the manifest
validator nor the composer reads those schemas: the verdicts of the head's and
the trunk's validator are byte-identical over the group, and the answer is
99,784 bytes (was 171,088).

Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
This commit is contained in:
2026-11-07 04:36:37 +01:00
parent 4a07e7a0ce
commit ce70589c84
2 changed files with 104 additions and 4 deletions
@@ -60,7 +60,7 @@ func TestTheCheckingProgramAnswersTheVerdictOfItsFacts(t *testing.T) {
}
heads := lay("heads", map[string]string{
"novox/x/x-contracts/module.json": contracts("x-contracts"),
"novox/x/x-contracts/seats/node-build-x/seat.json": `{"format":1,"seat":"node-build-x","scope":"node","grain":"whole","domain":"Delivery","decision":"ADR 1","description":"kept","includes":["build"],"verbs":[{"name":"own","input":{"type":"object"},"answer":{"type":"object"}}]}`,
"novox/x/x-contracts/seats/node-build-x/seat.json": `{"format":1,"seat":"node-build-x","scope":"node","grain":"whole","domain":"Delivery","decision":"ADR 1","description":"kept","includes":["build"],"verbs":[{"name":"own","input":{"type":"object","properties":{"credentials":{"$ref":"#/defs/Sealed"}}},"answer":{"type":"object"}}],"defs":{"Sealed":{"type":"object"}}}`,
"novox/x/x-contracts/parts/build.json": `{"format":1,"part":"build","verbs":[{"name":"current","input":{"type":"object"},"answer":{"type":"object"}}],"events":[{"name":"ended","body":{"type":"object"}}]}`,
"novox/x/contracts/module.json": contracts("mesh-contracts"),
"novox/x/contracts/seats/mesh-catalog/seat.json": `{"format":1,"seat":"mesh-catalog","scope":"mesh","grain":"whole","domain":"Delivery","decision":"ADR 1"}`,
@@ -130,6 +130,12 @@ func TestTheCheckingProgramAnswersTheVerdictOfItsFacts(t *testing.T) {
if d.Seat != "node-build-x" || len(d.Verbs) != 2 || len(sa.Left) != 1 || !strings.Contains(sa.Left[0].Why, "whose seats mesh-delivery-contracts defines") {
t.Errorf("%s: seats %s, left %+v; want node-build-x with its part's verb, and mesh-catalog left out", name, sa.Seats, sa.Left)
}
// The group check of 616c42434ac2: a checker from before G (no digests in these facts) writes the answer into the
// build seat's step state, whose writer refuses a value with a field named like a credential, here a schema's
// property name; the answer carries no verb's or message's schema and no type only they referred to.
if len(sa.Seats) == 1 && (bytes.Contains(sa.Seats[0], []byte("credentials")) || bytes.Contains(sa.Seats[0], []byte("Sealed"))) {
t.Errorf("%s: %s carries a verb's schema to a checker that hands no digests", name, sa.Seats[0])
}
continue
}
var a rules.Answer
@@ -185,7 +191,18 @@ func TestTheCheckingProgramAnswersTheVerdictOfItsFacts(t *testing.T) {
for _, m := range append(d.Verbs, d.Events...) {
inner += strings.Count(string(m), `"description":"`)
}
if _, perr := seatdef.Parse(raw); inner > 0 || d.Description != own.Description || perr != nil {
parsed, perr := seatdef.Parse(raw)
for _, v := range parsed.Verbs {
if len(v.Input) != 0 || len(v.Answer) != 0 {
t.Errorf("B0-shaped facts answer %s's verb %s with its schemas; want none", parsed.Seat, v.Name)
}
}
for name := range parsed.Defs {
if !bytes.Contains(raw, []byte(`"#/defs/`+name+`"`)) {
t.Errorf("B0-shaped facts answer %s with the type %s, which nothing it keeps refers to", parsed.Seat, name)
}
}
if inner > 0 || d.Description != own.Description || perr != nil {
t.Errorf("B0-shaped facts answer %s with %d inner descriptions, its own %q: %v; want only its own", raw[:min(len(raw), 80)], inner, d.Description, perr)
}
}