G-10 §479: a per-branch state's first view is named <owner>.<state>.<branch>
FollowBranch on the Reader and the ProcessReader, BranchState names the view with the branch escaped as a key's name is; one row per branch in the first views. Builds: design 47 G §479 Claude-Session: https://claude.ai/code/session_01JG73KEq4zoDfM9WtYpcQgZ
This commit is contained in:
@@ -104,6 +104,13 @@ func (r *ProcessReader) Follow(owner, state, tool string) (*Picture, error) {
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// FollowBranch is Follow for a state kept per branch: the view of one branch is named `<owner>.<state>.<branch>` (the
|
||||
// branch escaped as a key's name is, BranchState) and its picture `<owner>_<state>.<branch>`, so a process follows
|
||||
// several branches of one state, each its own view (design 47 G §479). Call it before Start.
|
||||
func (r *ProcessReader) FollowBranch(owner, state, branch, tool string) (*Picture, error) {
|
||||
return r.Follow(owner, BranchState(state, branch), tool)
|
||||
}
|
||||
|
||||
// Adopt takes a follower a seat's client made (its Ask a seat's verb, such as the catalog half's view) as one of the
|
||||
// process's first views, so the client's callers write no glue: the reader sets its conditions (the unanswered first
|
||||
// view and view-waits, in the reader's findings), its log and clock, and its picture (`<owner>_<state>`) hands each
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"time"
|
||||
|
||||
stdio "git.novox.be/novox/mesh-sdk/go"
|
||||
"git.novox.be/novox/mesh-sdk/go/keys"
|
||||
)
|
||||
|
||||
// Reader is a module's pictures of the owners' states it used to read (novox/hq ADR 0615 §1): it
|
||||
@@ -86,6 +87,17 @@ func (r *Reader) Follow(owner, state, tool string) *Follower {
|
||||
return f
|
||||
}
|
||||
|
||||
// BranchState is the name of a per-branch state's view: `<state>.<branch>`, the branch escaped as a key's name is (design
|
||||
// 47 G §479), so a reader names the view `<owner>.<state>.<branch>`. A state that is not per branch keeps its name.
|
||||
func BranchState(state, branch string) string { return state + "." + keys.EscapeName(branch) }
|
||||
|
||||
// FollowBranch is Follow for a state kept per branch: the view of one branch is named `<owner>.<state>.<branch>`
|
||||
// (BranchState), so a reader follows several branches of one state, each its own view and its own row of
|
||||
// `<module>_first_views` (design 47 G §479). Call it before Start.
|
||||
func (r *Reader) FollowBranch(owner, state, branch, tool string) *Follower {
|
||||
return r.Follow(owner, BranchState(state, branch), tool)
|
||||
}
|
||||
|
||||
// Adopt takes a follower a seat's client made (its Ask a seat's verb, such as the catalog half's view) as one of the
|
||||
// reader's first views, so the client's callers write no glue: the reader sets its conditions (the unanswered first view
|
||||
// and view-waits, in the reader's findings), its log and clock, and hands each change to Watch, Changed and the
|
||||
|
||||
@@ -595,6 +595,36 @@ func TestViews(t *testing.T) {
|
||||
// A seat's client makes the follower (its Ask a seat's verb) and both readers adopt it, so its callers write no glue:
|
||||
// the reader's findings (unanswered, view-waits), Keys, Get, Watch, statuses and tools, and the seat's event handed to
|
||||
// the client's handler.
|
||||
// Design 47 G §479: a per-branch state's view is named <owner>.<state>.<branch>, several branches in one reader.
|
||||
t.Run("a per-branch state is followed once per branch, each view its own row named with its escaped branch", func(t *testing.T) {
|
||||
if got := BranchState("catalog-revisions", "feat/x y"); got != "catalog-revisions.feat/x=20y" {
|
||||
t.Errorf("BranchState = %q", got)
|
||||
}
|
||||
r := &Reader{Module: "reader", Now: now}
|
||||
a, b := r.FollowBranch("s", "catalog-revisions", "main", "s.read"), r.FollowBranch("s", "catalog-revisions", "feat/x", "s.read")
|
||||
r.Follow("s", "plain", "s.read")
|
||||
if a.State != "catalog-revisions.main" || b.State != "catalog-revisions.feat/x" {
|
||||
t.Errorf("states %q %q", a.State, b.State)
|
||||
}
|
||||
for _, n := range []string{"s.catalog-revisions.main", "s.catalog-revisions.feat/x", "s.plain"} {
|
||||
if !r.Follows(n) {
|
||||
t.Errorf("%s is not followed", n)
|
||||
}
|
||||
}
|
||||
if r.Follows("s.catalog-revisions") {
|
||||
t.Errorf("the unnamed per-branch state is followed")
|
||||
}
|
||||
if st := r.Statuses(); len(st) != 3 || st[0].State != "catalog-revisions.main" || st[1].State != "catalog-revisions.feat/x" || st[2].State != "plain" {
|
||||
t.Errorf("rows = %+v", st)
|
||||
}
|
||||
pr := &ProcessReader{Module: "reader"}
|
||||
p1, err1 := pr.FollowBranch("s", "catalog-revisions", "main", "s.read")
|
||||
p2, err2 := pr.FollowBranch("s", "catalog-revisions", "feat/x", "s.read")
|
||||
if err1 != nil || err2 != nil || p1 == p2 || p1.Bucket() != "s_catalog-revisions.main" || pr.Picture("s_catalog-revisions.feat/x") != p2 {
|
||||
t.Errorf("pictures %v %v %v", p1, p2, err1)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("a follower a seat's client made is adopted: the reader's findings, reads and tools hold it, and its seat event goes to the client", func(t *testing.T) {
|
||||
ended := make(chan bool, 1)
|
||||
kept := waitBound
|
||||
|
||||
Reference in New Issue
Block a user