G M-6: carry a template events entry's events, and name objects-max-mib (issue 1966)

A part's finding stream asked by the template events lists its three finding
events in its field events, which the catalog graph entry carries; read
leniently it was set aside. A state's objects store cap is the option
objects-max-mib.

Builds: design 47 G §529, §513, §547, §607

Claude-Session: https://claude.ai/code/session_01JG73KEq4zoDfM9WtYpcQgZ
This commit is contained in:
2026-11-11 15:46:33 +01:00
parent 44063bf430
commit c6a6bec3ab
2 changed files with 20 additions and 1 deletions
+6
View File
@@ -50,6 +50,9 @@ const (
OptionAgeDays = "max-age-days"
// OptionCapMiB is the cap of a stream, a bucket or an object store, in MiB.
OptionCapMiB = "max-mib"
// OptionObjectsCapMiB is the cap of a state's objects store `<state>-objects`, in MiB, where the state needs
// another than the one the bus module plans (design 47 G §513, §547).
OptionObjectsCapMiB = "objects-max-mib"
// OptionGrant names the trusted config value granting another module a part of it (ADR 0363 §4, ADR 0592 §9).
OptionGrant = "grant"
// OptionDeliveries is how many times a work queue's message is delivered before it is a dead letter.
@@ -142,6 +145,9 @@ type BusStateEntry struct {
Configuration map[string]json.RawMessage `json:"configuration,omitempty"`
// Types are a ledger's types (ADR 0597 §1), for the storage type ledger only.
Types []LedgerType `json:"types,omitempty"`
// Events are the events an entry of the template events carries, named locally, as a part's finding stream
// lists its three finding events; the catalog graph entry carries them (design 47 G §529).
Events []string `json:"events,omitempty"`
// KeptLayout is the layout its holder says it writes: its form and its catch-up tool (design 47).
KeptLayout
}
+14 -1
View File
@@ -81,6 +81,16 @@ func TestARequirementsLongForm(t *testing.T) {
// Issue 1966: a key-value entry of `requires` is kept state beside the old section's, by its local name.
{"a key-value entry beside an old state", `[{"name":"holds","storage":"key-value","template":"state"}], "state": ["seen"]`,
"", []BusStateEntry{{Name: "holds", Storage: StorageKeyValue, Template: TemplateState}}, nil, ""},
// G §529: a template events entry's field `events` is carried, not set aside; G §513: `objects-max-mib` is a
// state's named option.
{"a finding stream and a state's objects cap", `[{"name":"finding-events","storage":"stream","template":"events",
"options":{"max-age-days":7,"max-mib":16},"events":["finding-written","finding-cleared","findings-stated"]},
{"name":"findings","storage":"key-value","template":"state","options":{"` + OptionObjectsCapMiB + `":512}}]`,
"", []BusStateEntry{{Name: "finding-events", Storage: StorageStream, Template: TemplateEvents,
Options: map[string]json.RawMessage{"max-age-days": json.RawMessage(`7`), "max-mib": json.RawMessage(`16`)},
Events: []string{"finding-written", "finding-cleared", "findings-stated"}},
{Name: "findings", Storage: StorageKeyValue, Template: TemplateState,
Options: map[string]json.RawMessage{"objects-max-mib": json.RawMessage(`512`)}}}, nil, ""},
// A field given twice at any depth is refused, named by its path: a decoder would keep the last without a word.
{"a field given twice", `[], "requires": ["postgres-database"]`, "", nil, nil, "the field requires is given twice"},
{"a field given twice deeper", `[{"name":"records","storage":"ledger","name":"other","template":"ledger"}]`,
@@ -105,8 +115,11 @@ func TestARequirementsLongForm(t *testing.T) {
}
// Issue 1966: a ledger is no kept state; KeptStates names the old section's and the key-value entries' alone.
var keeps []string
if c.name == "a key-value entry beside an old state" {
switch c.name {
case "a key-value entry beside an old state":
keeps = []string{"holds", "seen"}
case "a finding stream and a state's objects cap":
keeps = []string{"findings"}
}
if kept := KeptStates(got); !reflect.DeepEqual(kept, keeps) {
t.Errorf("%s: kept states %v, want %v", c.name, kept, keeps)