AS6: assigner_release with step delivery releases a dependent's delivery wait; assigner_waits lists them
The hand act is recorded first, then the release is written on the wait in delivery-waits, which the process ends released at its next pass, writing the dependent's want. Builds: design 47 G §376, A-246 (G-5's row "delivery of a dependency") Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
This commit is contained in:
@@ -259,7 +259,7 @@ func TestTheToolsReadAndReleaseAnOutsideWait(t *testing.T) {
|
||||
r.cond("machine.hub.unreachable", "ace")
|
||||
r.review(false, nil)
|
||||
var acts []string
|
||||
s := newPutTools(memStore{waitsState: &memKV{values: map[string][]byte{}}}, func(key string, body any) (json.RawMessage, error) {
|
||||
s := newPutTools(memStore{waitsState: &memKV{values: map[string][]byte{}}, buckets.DeliveryWaitsState: &memKV{values: map[string][]byte{}}}, func(key string, body any) (json.RawMessage, error) {
|
||||
acts = append(acts, key)
|
||||
return json.RawMessage(`{"ok":true,"log":"logged"}`), nil
|
||||
})
|
||||
@@ -296,4 +296,26 @@ func TestTheToolsReadAndReleaseAnOutsideWait(t *testing.T) {
|
||||
if r.bodies[len(r.bodies)-1].How != "go-on" || n.Haves["ace"]["nats"].Health != nodeengineclient.HealthOK {
|
||||
t.Errorf("last %+v health %s", r.bodies[len(r.bodies)-1], n.Haves["ace"]["nats"].Health)
|
||||
}
|
||||
// A-246: a dependent's delivery wait is listed beside them, and released by its module and step delivery, its hand act first.
|
||||
dw, _ := json.Marshal(deliveryWaiting{Wait: meshwants.Wait{Step: meshwants.WaitStepDelivery, Module: "app", Part: "db", On: "db@1.1.0", Machines: []string{"g14"}}})
|
||||
s.st.put(buckets.DeliveryWaitsState, "app", dw)
|
||||
got, err = s.doWaits(map[string]any{"node": "g14"})
|
||||
if d := got.(map[string]any)["delivery"].([]deliveryWaiting); err != nil || len(d) != 1 || d[0].Module != "app" {
|
||||
t.Errorf("the delivery waits listed = %+v %v", got, err)
|
||||
}
|
||||
if _, err := s.doRelease(map[string]any{"module": "app", "step": "build", "why": "x"}, "shanks.node-tools"); err == nil {
|
||||
t.Error("a release of another step is taken")
|
||||
}
|
||||
if _, err := s.doRelease(map[string]any{"module": "web", "step": "delivery", "why": "x"}, "shanks.node-tools"); err == nil {
|
||||
t.Error("a release of a module waiting for no delivery is taken")
|
||||
}
|
||||
before := len(acts)
|
||||
if _, err := s.doRelease(map[string]any{"module": "app", "step": "delivery", "why": "db is fine as it runs"}, "shanks.node-tools"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
raw, _, _, _ = s.st.get(buckets.DeliveryWaitsState, "app")
|
||||
var released deliveryWaiting
|
||||
if json.Unmarshal(raw, &released) != nil || !released.Released || !strings.Contains(released.By, "db is fine") || len(acts) != before+1 {
|
||||
t.Errorf("the delivery wait after its release = %+v, hand acts %v", released, acts[before:])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"slices"
|
||||
@@ -9,7 +10,9 @@ import (
|
||||
"time"
|
||||
|
||||
"git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshhandactsclient"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-contracts/go/seats/meshwants"
|
||||
stdio "git.novox.be/novox/mesh-sdk/go"
|
||||
"git.novox.be/novox/mesh-sdk/go/keys"
|
||||
|
||||
"mesh-delivery-assigner/internal/buckets"
|
||||
"mesh-delivery-assigner/internal/outside"
|
||||
@@ -58,7 +61,59 @@ func (s *putTools) doWaits(args map[string]any) (any, error) {
|
||||
}
|
||||
out = append(out, said)
|
||||
}
|
||||
return map[string]any{"waits": out}, nil
|
||||
// And each dependent's wait for its dependency's delivery (design 47 G §376, A-246), from the state delivery-waits.
|
||||
delivery := []deliveryWaiting{}
|
||||
dkeys, err := s.st.keys(buckets.DeliveryWaitsState)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("the delivery waits cannot be listed: %w", err)
|
||||
}
|
||||
sort.Strings(dkeys)
|
||||
for _, key := range dkeys {
|
||||
raw, _, found, err := s.st.get(buckets.DeliveryWaitsState, key)
|
||||
if err != nil || !found {
|
||||
continue
|
||||
}
|
||||
var w deliveryWaiting
|
||||
if json.Unmarshal(raw, &w) != nil || (arg(args, "module") != "" && w.Module != arg(args, "module")) ||
|
||||
(arg(args, "node") != "" && !slices.Contains(w.Machines, arg(args, "node"))) {
|
||||
continue
|
||||
}
|
||||
delivery = append(delivery, w)
|
||||
}
|
||||
return map[string]any{"waits": out, "delivery": delivery}, nil
|
||||
}
|
||||
|
||||
// doReleaseDelivery is assigner_release with step delivery: the hand act is recorded first, then the release is written on the
|
||||
// module's delivery wait, which the assigner's process ends released at its next pass, writing the module's want.
|
||||
func (s *putTools) doReleaseDelivery(args map[string]any, by string) (any, error) {
|
||||
module, why := arg(args, "module"), arg(args, "why")
|
||||
if why == "" {
|
||||
return nil, errors.New("release says why: it is kept in the hand-act log")
|
||||
}
|
||||
key := keys.EscapeName(module)
|
||||
raw, _, found, err := s.st.get(buckets.DeliveryWaitsState, key)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("the delivery wait of %s is not read: %w", module, err)
|
||||
}
|
||||
var w deliveryWaiting
|
||||
if !found || json.Unmarshal(raw, &w) != nil || w.Released {
|
||||
return nil, fmt.Errorf("%s waits for no delivery: assigner_waits lists the delivery waits", module)
|
||||
}
|
||||
rec := meshhandactsclient.Recorder{Ask: s.ask}
|
||||
taken, err := rec.Record(meshhandactsclient.Request{What: fmt.Sprintf("assigner_release %s step delivery (waits on %s)", module, w.On), Why: why,
|
||||
Cause: "delivery-wait", Verb: "mesh-wants.assigner_release"})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("the hand act could not be recorded, so nothing was released: %w", err)
|
||||
}
|
||||
w.Released, w.By = true, by+": "+why
|
||||
data, err := json.Marshal(w)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := s.st.put(buckets.DeliveryWaitsState, key, data); err != nil {
|
||||
return nil, fmt.Errorf("the release of %s's delivery wait is not written: %w", module, err)
|
||||
}
|
||||
return map[string]any{"released": module, "step": meshwants.WaitStepDelivery, "by": by, "hand-act": taken.Log}, nil
|
||||
}
|
||||
|
||||
// doReleaseWait is assigner_release with how: the hand act is recorded first, then the release is written on the wait of node and
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-sdk/catalogkey"
|
||||
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-contracts/go/seats/meshwants"
|
||||
stdio "git.novox.be/novox/mesh-sdk/go"
|
||||
"git.novox.be/novox/mesh-sdk/go/seatlist"
|
||||
|
||||
@@ -209,6 +210,12 @@ func (s *putTools) doRelease(args map[string]any, by string) (any, error) {
|
||||
if arg(args, "how") != "" {
|
||||
return s.doReleaseWait(args, by) // a wait on an outside cause (outside_tools.go, design 47 G §706)
|
||||
}
|
||||
if step := arg(args, "step"); step != "" {
|
||||
if step != meshwants.WaitStepDelivery {
|
||||
return nil, fmt.Errorf("step is %s, the one wait released by its step, not %q", meshwants.WaitStepDelivery, step)
|
||||
}
|
||||
return s.doReleaseDelivery(args, by) // a dependent's delivery wait (delivered.go, design 47 G §376, A-246)
|
||||
}
|
||||
node, module, why := arg(args, "node"), arg(args, "module"), arg(args, "why")
|
||||
key, err := puts.Key(node, module)
|
||||
if err != nil {
|
||||
@@ -341,8 +348,9 @@ func (s *putTools) tools() []stdio.Tool {
|
||||
"rules write the machine's want again from their next pass. Nothing changes on the machine until they move it.",
|
||||
Input: schema(map[string]string{"node": "the machine", "module": "the module", "why": "why, kept with the put",
|
||||
"how": "with how, the wait of the delivery on an outside cause (assigner_waits) is released, not a put: go-on (the module counts healthy there), " +
|
||||
"failed (the failing check is the delivery's) or rejudge (judge it again now); written in the hand-act log first"},
|
||||
[]string{"node", "module", "why"}),
|
||||
"failed (the failing check is the delivery's) or rejudge (judge it again now); written in the hand-act log first",
|
||||
"step": "delivery: the module's wait for its dependency's delivery (assigner_waits) is released, its want written now; no machine is named; written in the hand-act log first"},
|
||||
[]string{"module", "why"}),
|
||||
Run: func(a map[string]any) (any, error) { return s.doRelease(a, stdio.CallerOf(a)) }},
|
||||
s.waitsTool(),
|
||||
{Name: toolPuts, Description: "Every put and where it stands (novox/hq ADR 0546): its version, hold, why, each step with " +
|
||||
|
||||
Reference in New Issue
Block a user