RR2-5: the reader reads a seat-named view in consumes and a seat's views
G's builder and checker follow the assigner's views by the seat, seat:mesh-module-assigner.views.assignments; SeatViewConsume splits that form, and a seat compiled from its definition names the states it offers as views, which the validator checks the form against. Builds: design 47 G §621, §616, §699 Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
This commit is contained in:
@@ -5,6 +5,8 @@ import (
|
|||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"git.novox.be/novox/mesh-sdk/go/seatdef"
|
||||||
)
|
)
|
||||||
|
|
||||||
// A manifest carrying the words design 47 G writes is read whole by the reader release (design 47 G §340, §409):
|
// A manifest carrying the words design 47 G writes is read whole by the reader release (design 47 G §340, §409):
|
||||||
@@ -69,3 +71,31 @@ func TestTheSecondReaderReleaseReadsGsManifestWords(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A consumed view of a seat, `seat:<seat>.views.<state>`, is read apart from a consumed event, and a seat's compiled form
|
||||||
|
// names the states its definition offers as views (design 47 G §616, §699, §621).
|
||||||
|
func TestTheSecondReaderReleaseReadsASeatNamedView(t *testing.T) {
|
||||||
|
for _, row := range []struct {
|
||||||
|
consume, seat, state string
|
||||||
|
ok, bad bool
|
||||||
|
}{
|
||||||
|
{"seat:mesh-module-assigner.views.assignments", "mesh-module-assigner", "assignments", true, false},
|
||||||
|
{"mesh-delivery-assigner.views.assignments", "", "", false, false},
|
||||||
|
{"seat:mesh-module-assigner.assignments", "", "", true, true},
|
||||||
|
{"seat:.views.assignments", "", "", true, true},
|
||||||
|
} {
|
||||||
|
seat, state, ok, err := SeatViewConsume(row.consume)
|
||||||
|
if seat != row.seat || state != row.state || ok != row.ok || (err != nil) != row.bad {
|
||||||
|
t.Errorf("SeatViewConsume(%q) = %q, %q, %v, %v", row.consume, seat, state, ok, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m, err := decodeForTest([]byte(`{"module":"m","version":"1.0","consumes":["seat:mesh-module-assigner.views.assignments"]}`))
|
||||||
|
if err != nil || len(m.UnknownField()) != 0 || m.Consumes[0] != "seat:mesh-module-assigner.views.assignments" {
|
||||||
|
t.Errorf("a seat-named view in consumes read as %v, %v", m.Consumes, err)
|
||||||
|
}
|
||||||
|
s := SeatFromDefinition(seatdef.Definition{Seat: "mesh-module-assigner", Scope: "mesh",
|
||||||
|
States: []seatdef.State{{Name: "assignments", View: true}, {Name: "placement"}}})
|
||||||
|
if !slices.Equal(s.Views, []string{"assignments"}) {
|
||||||
|
t.Errorf("the seat's views = %v", s.Views)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -25,6 +25,11 @@ func SeatFromDefinition(d seatdef.Definition) Seat {
|
|||||||
Input: seatdef.ResolveRefs(v.Input, d.Defs), Output: seatdef.ResolveRefs(v.Answer, d.Defs),
|
Input: seatdef.ResolveRefs(v.Input, d.Defs), Output: seatdef.ResolveRefs(v.Answer, d.Defs),
|
||||||
Optional: v.Optional, Replaces: v.Replaces})
|
Optional: v.Optional, Replaces: v.Replaces})
|
||||||
}
|
}
|
||||||
|
for _, st := range d.States {
|
||||||
|
if st.View {
|
||||||
|
s.Views = append(s.Views, st.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
for _, r := range d.Receives {
|
for _, r := range d.Receives {
|
||||||
rv := Receivable{Kind: r.Kind, Comment: r.Comment, Dirs: r.Dirs, Offered: r.Offered}
|
rv := Receivable{Kind: r.Kind, Comment: r.Comment, Dirs: r.Dirs, Offered: r.Offered}
|
||||||
if r.Shape != nil {
|
if r.Shape != nil {
|
||||||
|
|||||||
@@ -45,6 +45,9 @@ type Seat struct {
|
|||||||
// Serves carries each verb in full — name, description, schema — because a role's tools are the
|
// Serves carries each verb in full — name, description, schema — because a role's tools are the
|
||||||
// mesh's to define and an agent's to call (novox/hq ADR 0132, design 33 §2).
|
// mesh's to define and an agent's to call (novox/hq ADR 0132, design 33 §2).
|
||||||
Serves []Verb
|
Serves []Verb
|
||||||
|
// Views are the names of the states the seat offers as views, which a module follows by `consumes`
|
||||||
|
// `seat:<seat>.views.<state>` (design 47 G §616, §699). Compiled from the definition's states marked `view`.
|
||||||
|
Views []string
|
||||||
// Receives is what other modules may contribute to the seat's holder, by kind (novox/hq ADR
|
// Receives is what other modules may contribute to the seat's holder, by kind (novox/hq ADR
|
||||||
// 0212): each kind is text in the tool's own grammar, placed by the holder with
|
// 0212): each kind is text in the tool's own grammar, placed by the holder with
|
||||||
// ${contribution:<seat>:<kind>}. Compiled, never stored: like the protocol, it is the mesh's
|
// ${contribution:<seat>:<kind>}. Compiled, never stored: like the protocol, it is the mesh's
|
||||||
|
|||||||
@@ -78,6 +78,25 @@ func (s StateDeclaration) MarshalJSON() ([]byte, error) {
|
|||||||
return json.Marshal(plain(s))
|
return json.Marshal(plain(s))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SeatViewPrefix opens a consumed view of a seat, `seat:<seat>.views.<state>` (design 47 G §616).
|
||||||
|
const SeatViewPrefix = "seat:"
|
||||||
|
|
||||||
|
// SeatViewConsume splits a consumed view of a seat, `seat:<seat>.views.<state>`, into the seat and the state; ok is false for a
|
||||||
|
// consumed entry that is not of this kind (an event, `<emitter>.<event>`), and err says why a `seat:` entry is malformed. The
|
||||||
|
// holder is not in it: it is resolved where the view is followed, so a new holder is followed with no change of the
|
||||||
|
// manifest (design 47 G §616, §621).
|
||||||
|
func SeatViewConsume(consume string) (seat, state string, ok bool, err error) {
|
||||||
|
rest, isSeat := strings.CutPrefix(consume, SeatViewPrefix)
|
||||||
|
if !isSeat {
|
||||||
|
return "", "", false, nil
|
||||||
|
}
|
||||||
|
seat, view, named := strings.Cut(rest, ".views.")
|
||||||
|
if !named || !stateName.MatchString(seat) || !stateName.MatchString(view) {
|
||||||
|
return "", "", true, fmt.Errorf("%q does not name a seat and its view: a consumed view of a seat is seat:<seat>.views.<state>", consume)
|
||||||
|
}
|
||||||
|
return seat, view, true, nil
|
||||||
|
}
|
||||||
|
|
||||||
// ReadState splits a read into the owning module and the local name, or says why it is not one.
|
// ReadState splits a read into the owning module and the local name, or says why it is not one.
|
||||||
func ReadState(read string) (module, local string, err error) {
|
func ReadState(read string) (module, local string, err error) {
|
||||||
at := strings.LastIndex(read, ".")
|
at := strings.LastIndex(read, ".")
|
||||||
|
|||||||
Reference in New Issue
Block a user