G-catalog-B 7: a transfer dropped by hand is recorded through mesh-hand-acts first
registry_incoming, npm_incoming and go_incoming dropped a transfer by hand with only a log line. Each drop now records its hand act through the seat mesh-hand-acts before anything goes, as nats_requests does; an act not recorded leaves the transfer open. distribution's manifest invokes the seat. Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
This commit is contained in:
@@ -6,7 +6,6 @@ package main
|
||||
// when its idle key ends (the bus's marker), never on a timer.
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
@@ -36,10 +35,7 @@ func incomingTool(typ, seat string, holder func() (*packageseats.Holder, error))
|
||||
return nil, err
|
||||
}
|
||||
if id := str(args, "drop"); id != "" {
|
||||
if str(args, "why") == "" {
|
||||
return nil, errors.New("a drop is a hand act: say why")
|
||||
}
|
||||
t, err := h.Drop(seat, id)
|
||||
t, err := h.DropByHand(seat, id, stdio.CallerOf(args), str(args, "why"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import (
|
||||
npmreg "git.novox.be/novox/mesh-contracts/go/seats/npmpackageregistry"
|
||||
stdio "git.novox.be/novox/mesh-sdk/go"
|
||||
"git.novox.be/novox/mesh-sdk/go/delivery"
|
||||
"git.novox.be/novox/mesh-sdk/go/handacts"
|
||||
"git.novox.be/novox/mesh-sdk/go/health"
|
||||
"git.novox.be/novox/mesh-sdk/go/parts"
|
||||
|
||||
@@ -263,6 +264,12 @@ func finding(kind, subject, words string, raised bool) {
|
||||
}
|
||||
}
|
||||
|
||||
// recordAct records a hand act through the seat mesh-hand-acts alone.
|
||||
func recordAct(q handacts.Request) error {
|
||||
_, err := handacts.Recorder{Ask: stdio.Ask}.Record(q)
|
||||
return err
|
||||
}
|
||||
|
||||
// boundCap is incoming's cap from its binding, read once per bundle.
|
||||
var boundCap = parts.BusCap(packageseats.IncomingObjects)
|
||||
|
||||
@@ -275,7 +282,7 @@ func busHolder(forge func() (*Forge, error)) (*packageseats.Holder, error) {
|
||||
return &packageseats.Holder{Callers: callers, Objects: parts.BusObjects(packageseats.IncomingObjects),
|
||||
Transfers: parts.BusTransfers[packageseats.Opening](packageseats.TransfersState),
|
||||
Builder: delivery.BuilderVersions{Ask: stdio.Ask}, Store: seatStore{forge}, Say: say, Finding: finding,
|
||||
Cap: boundCap, Idle: parts.BusArm(packageseats.IdleState)}, nil
|
||||
Cap: boundCap, Record: recordAct, Idle: parts.BusArm(packageseats.IdleState)}, nil
|
||||
}
|
||||
|
||||
// SeatTools are both seats' verbs as tools <seat>.<verb>.
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"time"
|
||||
|
||||
stdio "git.novox.be/novox/mesh-sdk/go"
|
||||
"git.novox.be/novox/mesh-sdk/go/handacts"
|
||||
"git.novox.be/novox/mesh-sdk/go/parts"
|
||||
)
|
||||
|
||||
@@ -156,6 +157,9 @@ type Holder struct {
|
||||
Now func() time.Time
|
||||
// Cap reads incoming's cap from its binding (parts.BusCap); IncomingCap when nil or when the binding names none.
|
||||
Cap func() (uint64, error)
|
||||
// Record records a hand act through the seat mesh-hand-acts (handacts.Recorder); a drop by hand is refused
|
||||
// without it.
|
||||
Record func(handacts.Request) error
|
||||
// Idle writes a transfer's idle key with its own time to live, once (parts.BusArm over IdleState); the receiver
|
||||
// arms it on each open that leaves a transfer open. Nil arms nothing.
|
||||
Idle func(key string, ttl time.Duration) error
|
||||
@@ -334,6 +338,29 @@ func (h *Holder) Drop(seat, transfer string) (Transfer, error) {
|
||||
return h.receiver().Drop(key(seat, transfer))
|
||||
}
|
||||
|
||||
// DropByHand is <type>_incoming's drop: by a person, with why, recorded as a hand act through mesh-hand-acts before
|
||||
// anything goes; an act not recorded leaves the transfer open.
|
||||
func (h *Holder) DropByHand(seat, transfer, by, why string) (Transfer, error) {
|
||||
if strings.TrimSpace(why) == "" {
|
||||
return Transfer{}, errors.New("a drop is a hand act: say why")
|
||||
}
|
||||
if h.Record == nil {
|
||||
return Transfer{}, errors.New("no hand act can be recorded here, so nothing is dropped")
|
||||
}
|
||||
t, found, err := h.Transfers.Get(key(seat, transfer))
|
||||
if err != nil {
|
||||
return Transfer{}, fmt.Errorf("transfer %s cannot be read, so nothing is dropped: %w", transfer, err)
|
||||
}
|
||||
if !found {
|
||||
return Transfer{}, fmt.Errorf("transfer %s of %s is not open", transfer, seat)
|
||||
}
|
||||
what := fmt.Sprintf("dropped the open transfer %s of %s's incoming (%s@%s, opened by %s), by %s", transfer, seat, t.Shape.Name, t.Shape.Version, t.Opener, by)
|
||||
if err := h.Record(handacts.Request{What: what, Why: why, Cause: Seats[seat] + "_incoming"}); err != nil {
|
||||
return Transfer{}, fmt.Errorf("the hand act cannot be recorded, so transfer %s stays open: %w", transfer, err)
|
||||
}
|
||||
return h.Drop(seat, transfer)
|
||||
}
|
||||
|
||||
// Incoming is what npm_incoming and go_incoming answer of a seat: its open transfers, incoming's fill (both seats
|
||||
// share the store) and the cap its binding carries.
|
||||
type Incoming struct {
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"time"
|
||||
|
||||
stdio "git.novox.be/novox/mesh-sdk/go"
|
||||
"git.novox.be/novox/mesh-sdk/go/handacts"
|
||||
"git.novox.be/novox/mesh-sdk/go/parts"
|
||||
)
|
||||
|
||||
@@ -190,6 +191,20 @@ func TestTheForgeHoldsBothPackageSeats(t *testing.T) {
|
||||
if _, err := b.h.Publish(NpmSeat, nodeBuild, pub("d", "0.1.0", file)); err == nil || !strings.Contains(err.Error(), "idle bound") {
|
||||
t.Errorf("a publish whose idle key is not written = %v; want it failed loudly", err)
|
||||
}
|
||||
// Seams note 2: go_incoming's drop is a hand act recorded through mesh-hand-acts before anything goes; an act
|
||||
// not recorded leaves the transfer open.
|
||||
var acts []handacts.Request
|
||||
b.h.Record = func(handacts.Request) error { return errors.New("mesh-hand-acts has no holder") }
|
||||
if _, err := b.h.DropByHand(GoSeat, "t-b", "person.jochen", "stuck"); err == nil || !strings.Contains(err.Error(), "stays open") {
|
||||
t.Errorf("a drop whose act is not recorded = %v; want refused, t-b open", err)
|
||||
}
|
||||
b.h.Record = func(q handacts.Request) error { acts = append(acts, q); return nil }
|
||||
if got, err := b.h.DropByHand(GoSeat, "t-b", "person.jochen", "stuck"); err != nil || got.Shape.Name != "b" || len(acts) != 1 || acts[0].Cause != "go_incoming" || !strings.Contains(acts[0].What, "t-b") || !strings.Contains(acts[0].What, "person.jochen") {
|
||||
t.Errorf("a drop by hand = %+v, %v, acts %+v; want t-b dropped and its act recorded", got, err, acts)
|
||||
}
|
||||
if in, _ := b.h.IncomingOf(GoSeat); len(in.Transfers) != 0 {
|
||||
t.Errorf("after the drop by hand: %+v; want no Go transfer", in)
|
||||
}
|
||||
})
|
||||
t.Run("refusals", func(t *testing.T) {
|
||||
for _, c := range []struct {
|
||||
|
||||
Reference in New Issue
Block a user