A kept data's form below 0 is refused where it is read, once for every kept kind
Claude-Session: https://claude.ai/code/session_01JG73KEq4zoDfM9WtYpcQgZ
This commit is contained in:
@@ -179,6 +179,9 @@ func readBusStateEntry(raw json.RawMessage) (BusStateEntry, []string, error) {
|
||||
var e BusStateEntry
|
||||
err := strict(&e)
|
||||
if err == nil {
|
||||
if err := e.KeptLayout.refuse(fmt.Sprintf("requires entry %q", e.Name)); err != nil {
|
||||
return BusStateEntry{}, nil, err
|
||||
}
|
||||
return e, aside, nil
|
||||
}
|
||||
unknown := asUnknownField(err)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package catalogue
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
)
|
||||
|
||||
@@ -21,6 +22,16 @@ type KeptLayout struct {
|
||||
CatchUp string `json:"catch-up,omitempty"`
|
||||
}
|
||||
|
||||
// refuse is the one reading of a layout's form every kept kind's decoder calls: a form is a whole number from 0, and one
|
||||
// below it is refused here, naming the declaration (`what` is its kind and name, such as `state "seen"`).
|
||||
func (k KeptLayout) refuse(what string) error {
|
||||
if k.Form < 0 {
|
||||
return fmt.Errorf("%s: its form is %d; a form is a whole number from 0, which its holder raises when it changes how "+
|
||||
"it writes it", what, k.Form)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// The kinds of kept data, by the template each is on (ADR 0595 §2): the five a restore point is taken of.
|
||||
const (
|
||||
KeptKindState = "state"
|
||||
|
||||
@@ -2,6 +2,7 @@ package catalogue
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -70,3 +71,19 @@ func TestAKeptDataSaysItsFormAndItsCatchUp(t *testing.T) {
|
||||
t.Errorf("a manifest applied over itself changes %+v", got)
|
||||
}
|
||||
}
|
||||
|
||||
// A form below 0 is refused where it is read, in every kept kind's declaration, naming it.
|
||||
func TestAKeptDataFormBelowZeroIsRefused(t *testing.T) {
|
||||
for _, c := range []struct{ name, raw, says string }{
|
||||
{"state", `"state":[{"name":"seen","form":-3}]`, `state "seen": its form is -3`},
|
||||
{"log", `"logs":[{"name":"acts","form":-1}]`, `log "acts": its form is -1`},
|
||||
{"stream", `"streams":[{"name":"forge","events":["merged"],"form":-2}]`, `stream "forge": its form is -2`},
|
||||
{"objects", `"objects":[{"name":"revisions","max-mib":64,"form":-1}]`, `object bucket "revisions": its form is -1`},
|
||||
{"requires", `"requires":[{"name":"holds","storage":"key-value","template":"state","form":-1}]`, `requires entry "holds": its form is -1`},
|
||||
} {
|
||||
_, err := decodeForTest([]byte(`{"module":"x","version":"1",` + c.raw + `}`))
|
||||
if err == nil || !strings.Contains(err.Error(), c.says) {
|
||||
t.Errorf("%s: read as %v, want a refusal holding %q", c.name, err, c.says)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +55,9 @@ func (l *LogDeclaration) UnmarshalJSON(raw []byte) error {
|
||||
if err := dec.Decode(&full); err != nil {
|
||||
return fmt.Errorf("a log is either a name or {name, max-mib, max-age-days, form, catch-up}: %w", typedUnknown(err))
|
||||
}
|
||||
if err := full.KeptLayout.refuse(fmt.Sprintf("log %q", full.Name)); err != nil {
|
||||
return err
|
||||
}
|
||||
l.Name = full.Name
|
||||
l.KeptLayout = full.KeptLayout
|
||||
l.MaxMiB = 0
|
||||
|
||||
@@ -49,6 +49,9 @@ func (o *ObjectsDeclaration) UnmarshalJSON(raw []byte) error {
|
||||
if err := dec.Decode(&p); err != nil {
|
||||
return fmt.Errorf("an object bucket is {name, max-mib, grant, form, catch-up}: %w", typedUnknown(err))
|
||||
}
|
||||
if err := p.KeptLayout.refuse(fmt.Sprintf("object bucket %q", p.Name)); err != nil {
|
||||
return err
|
||||
}
|
||||
*o = ObjectsDeclaration(p)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -52,6 +52,9 @@ func (s *StateDeclaration) UnmarshalJSON(raw []byte) error {
|
||||
if err := dec.Decode(&full); err != nil {
|
||||
return fmt.Errorf("a state is either a name or {name, history, ttl-seconds, per-machine, key-ttl, read-only, form, catch-up}: %w", typedUnknown(err))
|
||||
}
|
||||
if err := full.KeptLayout.refuse(fmt.Sprintf("state %q", full.Name)); err != nil {
|
||||
return err
|
||||
}
|
||||
*s = StateDeclaration(full)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -88,6 +88,9 @@ func (s *StreamDeclaration) UnmarshalJSON(raw []byte) error {
|
||||
return fmt.Errorf("a stream is {name, events, max-age-days, max-mib, grant, retention, max-deliveries, "+
|
||||
"duplicates, form, catch-up}: %w", typedUnknown(err))
|
||||
}
|
||||
if err := p.KeptLayout.refuse(fmt.Sprintf("stream %q", p.Name)); err != nil {
|
||||
return err
|
||||
}
|
||||
*s = StreamDeclaration(p)
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user