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
|
var e BusStateEntry
|
||||||
err := strict(&e)
|
err := strict(&e)
|
||||||
if err == nil {
|
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
|
return e, aside, nil
|
||||||
}
|
}
|
||||||
unknown := asUnknownField(err)
|
unknown := asUnknownField(err)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package catalogue
|
package catalogue
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -21,6 +22,16 @@ type KeptLayout struct {
|
|||||||
CatchUp string `json:"catch-up,omitempty"`
|
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.
|
// The kinds of kept data, by the template each is on (ADR 0595 §2): the five a restore point is taken of.
|
||||||
const (
|
const (
|
||||||
KeptKindState = "state"
|
KeptKindState = "state"
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package catalogue
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -70,3 +71,19 @@ func TestAKeptDataSaysItsFormAndItsCatchUp(t *testing.T) {
|
|||||||
t.Errorf("a manifest applied over itself changes %+v", got)
|
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 {
|
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))
|
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.Name = full.Name
|
||||||
l.KeptLayout = full.KeptLayout
|
l.KeptLayout = full.KeptLayout
|
||||||
l.MaxMiB = 0
|
l.MaxMiB = 0
|
||||||
|
|||||||
@@ -49,6 +49,9 @@ func (o *ObjectsDeclaration) UnmarshalJSON(raw []byte) error {
|
|||||||
if err := dec.Decode(&p); err != nil {
|
if err := dec.Decode(&p); err != nil {
|
||||||
return fmt.Errorf("an object bucket is {name, max-mib, grant, form, catch-up}: %w", typedUnknown(err))
|
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)
|
*o = ObjectsDeclaration(p)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,6 +52,9 @@ func (s *StateDeclaration) UnmarshalJSON(raw []byte) error {
|
|||||||
if err := dec.Decode(&full); err != nil {
|
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))
|
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)
|
*s = StateDeclaration(full)
|
||||||
return nil
|
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, "+
|
return fmt.Errorf("a stream is {name, events, max-age-days, max-mib, grant, retention, max-deliveries, "+
|
||||||
"duplicates, form, catch-up}: %w", typedUnknown(err))
|
"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)
|
*s = StreamDeclaration(p)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user