RR-2: the reader reads an accepted kind's stream
mesh/delivery merged: source.main moved to novox/mesh-sdk@83772f2908a1
mesh/check checking 0036455e6380 on 45e143fba672

check or delivery; the same kind name may ride both.

Builds: design 47 G §409, §415

Claude-Session: https://claude.ai/code/session_01JG73KEq4zoDfM9WtYpcQgZ
This commit is contained in:
2026-11-11 10:50:51 +01:00
parent e29c452aa3
commit 0036455e63
2 changed files with 24 additions and 2 deletions
+17 -2
View File
@@ -223,6 +223,12 @@ type Verb struct {
NeedsApproval bool `json:"needs-approval,omitempty"`
}
// The streams an accepted kind may ride (design 47 G §415).
const (
StreamCheck = "check"
StreamDelivery = "delivery"
)
// Message is one accepted message or one event of the seat, its body a JSON Schema.
type Message struct {
// Name is the message's name; an event's may be lower-case words joined by dots (pull.updated), as a module's
@@ -245,6 +251,9 @@ type Message struct {
Keep *Keep `json:"keep,omitempty"`
// Callers says who may send an accepted kind, as a verb's (design 47 G §338).
Callers *Callers `json:"callers,omitempty"`
// Stream is the stream an accepted kind rides, StreamCheck or StreamDelivery; its subject is `<stream>.<kind>`, and
// the same kind name may ride more than one stream (design 47 G §415).
Stream string `json:"stream,omitempty"`
// MaxAgeDays and MaxMiB bound an event kept KeepStream: how long a message is kept and how much the stream holds
// (design 47 *What the gate owes the forge*: the stream `owed`, 7 days and at most 64 MiB). Given with KeepStream
// alone.
@@ -814,10 +823,16 @@ func checkMessages(field string, ms []Message, whole bool) Problems {
}
if !named.MatchString(m.Name) {
ps = append(ps, Problem{where + ".name", "missing, or not a lower-case name"})
} else if seen[m.Name] {
} else if key := m.Stream + "/" + m.Name; seen[key] {
ps = append(ps, Problem{where + ".name", fmt.Sprintf("%q twice", m.Name)})
}
seen[m.Name] = true
seen[m.Stream+"/"+m.Name] = true
switch {
case m.Stream != "" && field != "accepts":
ps = append(ps, Problem{where + ".stream", "only an accepted kind rides a stream"})
case m.Stream != "" && m.Stream != StreamCheck && m.Stream != StreamDelivery:
ps = append(ps, Problem{where + ".stream", fmt.Sprintf("%q is not %s or %s", m.Stream, StreamCheck, StreamDelivery)})
}
mode := m.legacyMode()
switch {
case m.Keep != nil && field != "events":
+7
View File
@@ -143,6 +143,13 @@ func TestADefinitionIsReadStrictlyNamingWhatIsWrong(t *testing.T) {
{"a verb marked for approval", strings.Replace(whole, `"name":"list",`, `"name":"list","needs-approval":true,`, 1), ""},
{"a verb marked with a word that is no boolean", strings.Replace(whole, `"name":"list",`, `"name":"list","needs-approval":"yes",`, 1), "not a seat definition's JSON"},
{"a bodies section", strings.Replace(whole, `"family":`, `"bodies":{"Finding":{"type":"object"}},"family":`, 1), ""},
{"one kind on two streams", strings.Replace(whole, `"events":`,
`"accepts":[{"name":"step","body":{},"stream":"check"},{"name":"step","body":{},"stream":"delivery"}],"events":`, 1), ""},
{"one kind twice on a stream", strings.Replace(whole, `"events":`,
`"accepts":[{"name":"step","body":{},"stream":"check"},{"name":"step","body":{},"stream":"check"}],"events":`, 1), `"step" twice`},
{"a stream that is none", strings.Replace(whole, `"events":`, `"accepts":[{"name":"step","body":{},"stream":"mail"}],"events":`, 1),
`accepts[0].stream: "mail" is not check or delivery`},
{"an event on a stream", strings.Replace(whole, `"name":"created"`, `"name":"created","stream":"check"`, 1), "only an accepted kind rides a stream"},
{"over 256 KiB", listGrain[:len(listGrain)-1] + `,"description":"` + strings.Repeat("x", MaxSize) + `"}`,
ErrTooLarge.Error()},
}