B5g3-1: a run's input is any size, RunInputBound goes

Builds: design 47 G §712, §354, A-237

Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
This commit is contained in:
2026-11-12 06:27:42 +01:00
parent c76d8ef381
commit b7e251a463
4 changed files with 18 additions and 25 deletions
@@ -153,8 +153,8 @@ func TestTheCheckingProgramAnswersTheVerdictOfItsFacts(t *testing.T) {
}
// Review finding 3 of milestone 47/G: the heads of a real group carry every seat definition the reader holds, unchanged
// (this repository's own contracts, laid as its head): the answer leaves them all to the checker's list and stays
// within the bound a run's answer is written under (buildstep.RunInputBound), where the whole list would not.
t.Run("heads carrying every definition the reader holds unchanged answer none of them, within the bound", func(t *testing.T) {
// far below the whole list.
t.Run("heads carrying every definition the reader holds unchanged answer none of them", func(t *testing.T) {
real := under{prefix: "novox/mesh-delivery", fs: os.DirFS("../../../..")}
group := rules.Facts{V: rules.FactsVersion, Members: []rules.Member{{Repository: "novox/mesh-delivery", Head: "h"}}}
// An empty list of digests answers every definition whole (a checker that hands its list's digests, holding none).
@@ -166,9 +166,9 @@ func TestTheCheckingProgramAnswersTheVerdictOfItsFacts(t *testing.T) {
group.SeatDigests = wholeDigests(t, real, "novox/mesh-delivery")
same, err := rules.SeatsOf(real, group)
answer, _ := json.Marshal(same)
if err != nil || len(same.Seats) != 0 || same.Same != len(whole.Seats) || len(answer) > buildstep.RunInputBound {
t.Errorf("unchanged heads answer %d definitions (%d the same), %d bytes; want none, all %d the same, within %d: %v",
len(same.Seats), same.Same, len(answer), len(whole.Seats), buildstep.RunInputBound, err)
if err != nil || len(same.Seats) != 0 || same.Same != len(whole.Seats) {
t.Errorf("unchanged heads answer %d definitions (%d the same), %d bytes; want none, all %d the same: %v",
len(same.Seats), same.Same, len(answer), len(whole.Seats), err)
}
// Review round 2 of G: a checker from before G (B0's, which makes G's own check) hands no digests, and the answer
// then keeps each seat's own description only, so a group's whole list stays within the bound; each still parses.
@@ -206,8 +206,8 @@ func TestTheCheckingProgramAnswersTheVerdictOfItsFacts(t *testing.T) {
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)
}
}
if answer, _ := json.Marshal(b0); len(answer) > buildstep.RunInputBound || len(answer) >= len(mustJSON(t, whole))*3/4 {
t.Errorf("B0-shaped facts answer %d bytes (whole %d), want within %d and far below the whole", len(answer), len(mustJSON(t, whole)), buildstep.RunInputBound)
if answer, _ := json.Marshal(b0); len(answer) >= len(mustJSON(t, whole))*3/4 {
t.Errorf("B0-shaped facts answer %d bytes (whole %d), want far below the whole", len(answer), len(mustJSON(t, whole)))
}
// One definition the heads change is answered alone.
for seat := range group.SeatDigests {
+2 -2
View File
@@ -21,8 +21,8 @@ import (
// milestones 47/B0 and 47/G): the checking program built from the heads reads the definitions the heads' contracts
// modules carry, by the domain SDK's one reading (sdk/seatdefs), the indexer's too, and answers them; the running checker
// lays them by seat over the list its reader holds from the seat mesh-catalog (verb seat-definitions) and reads no file
// of the heads. The reader's list is not in the program's input: the mesh's definitions are larger than a run input's
// bound (buildstep.RunInputBound).
// of the heads. The reader's list is not in the program's input: it is large, and the answer carries only what the heads
// change.
// SeatsVersion is the version of SeatsAnswer this program writes.
const SeatsVersion = 1
@@ -113,7 +113,7 @@ func TestAskCheckAndRoundTrip(t *testing.T) {
{"input on a state", func(a *StepAsk) { a.Run.Input.Verb = "mesh-delivery-checker.inputs" }, "no seat:<seat>.<verb>"},
{"input on one machine", func(a *StepAsk) { a.Run.Input.Verb = "seat:mesh-delivery-checker.input@ace" }, "no seat:<seat>.<verb>"},
{"input by no digest", func(a *StepAsk) { a.Run.Input.Digest = "d1" }, "no sha256 digest"},
{"input over its bound", func(a *StepAsk) { a.Run.Input.Size = RunInputBound + 1 }, "outside 1 to"},
{"input of no bytes", func(a *StepAsk) { a.Run.Input.Size = 0 }, "under 1"},
{"argument of the shell", func(a *StepAsk) { a.Run.Args = []string{"-x; rm"} }, "no word or flag"},
} {
a := runAsk()
@@ -148,8 +148,9 @@ func TestAskCheckAndRoundTrip(t *testing.T) {
if a := stepAsk(); !a.Step.Skips("./modules/nats/a", "sha256:bbbb") || a.Step.Skips("./modules/nats/a", "sha256:cccc") {
t.Error("a kept result skips its package at its digest and level only")
}
if _, err := RunInputOf("seat:mesh-delivery-checker.input", make([]byte, RunInputBound+1)); err == nil || !strings.Contains(err.Error(), "262145 bytes") {
t.Errorf("an input over its bound: %v", err)
// A-237: a run's input is any size.
if in, err := RunInputOf("seat:mesh-delivery-checker.input", make([]byte, 3<<20)); err != nil || in.Size != 3<<20 {
t.Errorf("an input of 3 MiB: %+v, %v", in, err)
}
in := runAsk().Run.Input
if err := in.Verify([]byte(`{"v":1}`)); err != nil {
+5 -13
View File
@@ -20,8 +20,8 @@ import (
// Input names, checks its digest and writes it to the file RunInputEnv names; then runs the program with Args, no
// network and no bus account (ADR 0448 §2, §4), and answers RunAnswer on its step key.
//
// The input is carried by reference, as a compose carries its manifests: the asker keeps it by its digest, measured
// against RunInputBound before it asks, and serves it on a verb of its seat (RunInput.Verb); the build module asks that
// The input is carried by reference, as a compose carries its manifests: the asker keeps it by its digest, of any
// size (A-237), and serves it on a verb of its seat (RunInput.Verb); the build module asks that
// verb as its manifest's `invokes` grants it, never reading the asker's state (ADR 0596 §2), so the ask on the stream
// never carries it (issue 1930). The layouts are the part build-step's `RunJob`, `RunProgram`, `RunHead`, `RunInput`
// and `RunAnswer`.
@@ -77,22 +77,14 @@ type RunAnswer struct {
Said string `json:"said,omitempty"`
}
// RunInputBound is the most bytes a run's input may hold: the bus's value limit the design already uses (256 KiB), so
// the asker keeps it as one value (the lead's ruling on milestone 47/B0, 2026-11-06).
const RunInputBound = 256 << 10
// RunHeadsEnv names, for the program, the directory its heads are laid in; RunInputEnv the file its input is written to.
const (
RunHeadsEnv = "MESH_RUN_HEADS"
RunInputEnv = "MESH_RUN_INPUT"
)
// RunInputOf is the reference to body served on verb (`seat:<seat>.<verb>`), refusing a body over RunInputBound, naming
// its size, so an asker refuses it before asking.
// RunInputOf is the reference to body served on verb (`seat:<seat>.<verb>`); a body is of any size.
func RunInputOf(verb string, body []byte) (RunInput, error) {
if len(body) > RunInputBound {
return RunInput{}, fmt.Errorf("buildstep: a run's input of %d bytes is over its bound of %d bytes", len(body), RunInputBound)
}
sum := sha256.Sum256(body)
in := RunInput{Verb: verb, Digest: hex.EncodeToString(sum[:]), Size: len(body)}
return in, in.check("")
@@ -118,8 +110,8 @@ func (i RunInput) check(id string) error {
return fmt.Errorf("buildstep: the run ask %s serves its input on %q, which is no seat:<seat>.<verb> of no one machine", id, i.Verb)
case !runDigestOK.MatchString(i.Digest):
return fmt.Errorf("buildstep: the run ask %s names its input by %q, which is no sha256 digest", id, i.Digest)
case i.Size <= 0 || i.Size > RunInputBound:
return fmt.Errorf("buildstep: the run ask %s names an input of %d bytes, outside 1 to %d", id, i.Size, RunInputBound)
case i.Size <= 0:
return fmt.Errorf("buildstep: the run ask %s names an input of %d bytes, under 1", id, i.Size)
}
return nil
}