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:
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user