E-5 marked waits: a wait on a marked event runs only on the operator's warrant for that one wait

mesh_wait goes through the runner's approval gate (node-tools/internal/approval, Gate.Waited): a wait whose
subjects overlap a marked subject of any module the catalog half lists (the newest entry of every followed
branch, with the served entry of each module this runner serves) is an act of the runner's own module and
build (MESH_FINGERPRINT at its start), asked once on operator-channel as "Wait on <names> on <node>?", and
held, subscribing nothing but its ask's decided, until its timeout, its caller's going or the choice. On a
warrant it subscribes, its timeout running from then, and answers {answer, approval}. Before the marks are
read nothing is asked; a wait from a seat is never marked. The state fixture moves to meshtest so the
console's table can hold a gate.

Builds: design 34 every-event §34, §35, §36, §37; design 47 G lead answer A-168

Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
This commit is contained in:
2026-11-12 05:41:53 +01:00
parent 4116809162
commit 809288da69
12 changed files with 783 additions and 148 deletions
+21 -12
View File
@@ -70,7 +70,7 @@ func (g *Gate) askFor(c Call, digest, id string) seat.Ask {
if c.Seat != "" {
name = c.Seat + "." + c.Name
}
headline := headlineOf(name, g.d.Node, whole)
headline := headlineOf("Run", name, g.d.Node, whole)
first, _, _ := strings.Cut(strings.TrimSpace(c.Description), "\n")
if first == "" {
first = name
@@ -92,22 +92,23 @@ func (g *Gate) askFor(c Call, digest, id string) seat.Ask {
Level: operatorchannelclient.Approve, Binds: digest}}}
}
// headlineOf is "Run <tool> on <node>?", "Run <tool>?" when that is longer than the router allows, and the names cut with
// "…" when that too is longer; ending "Part shown" whenever an argument is not shown whole (§10, Q-HL).
func headlineOf(name, node string, whole bool) string {
// headlineOf is "<verb> <names> on <node>?", "<verb> <names>?" when that is longer than the router allows, and the names cut
// with "…" when that too is longer; ending "Part shown" whenever an argument is not shown whole (§10, Q-HL). verb is "Run"
// for a call and "Wait on" for a wait (design 34 every-event §35).
func headlineOf(verb, name, node string, whole bool) string {
suffix := ""
if !whole {
suffix = " Part shown"
}
max := operatorchannelclient.HeadlineLength
fits := func(s string) bool { return len([]rune(s)) <= max }
if h := "Run " + name + " on " + node + "?" + suffix; fits(h) {
if h := verb + " " + name + " on " + node + "?" + suffix; fits(h) {
return h
}
if h := "Run " + name + "?" + suffix; fits(h) {
if h := verb + " " + name + "?" + suffix; fits(h) {
return h
}
room := max - len([]rune("Run …?"+suffix))
room := max - len([]rune(verb+" …?"+suffix))
r := []rune(name)
if room < 1 {
room = 1
@@ -115,7 +116,7 @@ func headlineOf(name, node string, whole bool) string {
if len(r) > room {
r = r[:room]
}
return "Run " + string(r) + "…?" + suffix
return verb + " " + string(r) + "…?" + suffix
}
// firstCall is a marked call whose act has no ask open: refused at once when its arguments may not be asked (§9), else
@@ -140,7 +141,15 @@ func (g *Gate) firstCall(c Call) (any, error) {
// the first answer (§12), always an error, never a result.
func (g *Gate) raise(c Call, act operatorchannelclient.Act, digest, markedSince string) error {
id := newID()
a := g.askFor(c, digest, id)
if err := g.keepAsk(c, act, digest, g.askFor(c, digest, id)); err != nil {
return err
}
return g.firstAnswer(c, id, digest, markedSince)
}
// keepAsk raises an ask and keeps it in the runner's state with the act and the whole arguments, its act's key naming it
// (§10, §13); refused, as an error, when it cannot be.
func (g *Gate) keepAsk(c Call, act operatorchannelclient.Act, digest string, a seat.Ask) error {
cl := g.client(c.Module)
if size := keptSize(a, act, c.Args); size > MostKeptValue {
return g.refused(c, digest, fmt.Sprintf("its ask would keep %d bytes, more than the %d a value of the state %s holds", size, MostKeptValue, StateName))
@@ -148,15 +157,15 @@ func (g *Gate) raise(c Call, act operatorchannelclient.Act, digest, markedSince
if err := cl.Ask(a); err != nil {
return g.refused(c, digest, "the ask could not be raised: "+err.Error())
}
if err := g.keepCall(id, act, c.Args); err != nil {
if err := g.keepCall(a.ID, act, c.Args); err != nil {
g.stateFailed(err)
return g.refused(c, digest, "the ask was raised and its call could not be kept: "+err.Error())
}
if _, err := g.d.State.Put(g.actKey(digest), id); err != nil {
if _, err := g.d.State.Put(g.actKey(digest), a.ID); err != nil {
g.stateFailed(err)
return g.refused(c, digest, "the ask was raised and its act could not be kept: "+err.Error())
}
return g.firstAnswer(c, id, digest, markedSince)
return nil
}
// keptSize is the bytes the kept ask would take.