BG9, BN9, BI3: the build seats' steps with drop writes the hand-act log first
A drop of a kept detected-steps key records the act with the caller the bus proved, then deletes the key; a log that refuses deletes nothing and is answered error; a drop without why is refused; fetch is asked unless drop. Builds: design 47 G §463, §480 Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshhandactsclient"
|
||||
stdio "git.novox.be/novox/mesh-sdk/go"
|
||||
)
|
||||
|
||||
// handActRecorder writes an act by hand in the hand-act log of the seat mesh-hand-acts (design 47 G §480); a log that
|
||||
// does not take it is an error, never a quiet success.
|
||||
func handActRecorder(what, why string) error {
|
||||
_, err := meshhandactsclient.Recorder{Ask: stdio.Ask}.Record(meshhandactsclient.Request{What: what, Why: why, Cause: "build-steps-drop", Verb: "steps drop"})
|
||||
return err
|
||||
}
|
||||
@@ -50,6 +50,8 @@ func main() {
|
||||
ReadSteps: readOf(stdio.State(seat.StateSteps)),
|
||||
Detected: stdio.State(seat.StateDetectedSteps).Put,
|
||||
ReadDetected: readOf(stdio.State(seat.StateDetectedSteps)).Get,
|
||||
ForgetDetected: stdio.State(seat.StateDetectedSteps).Delete,
|
||||
RecordAct: handActRecorder,
|
||||
Pauses: stdio.State(sdkstep.PausesState).Put,
|
||||
ReadPauses: readOf(stdio.State(sdkstep.PausesState)),
|
||||
ForgetPause: stdio.State(sdkstep.PausesState).Delete,
|
||||
|
||||
@@ -51,6 +51,10 @@ type Module struct {
|
||||
// Detected and ReadDetected are the Put and the read of the state detected-steps (design 47 G §326, §414).
|
||||
Detected buildstep.Put
|
||||
ReadDetected func(key string) (json.RawMessage, error)
|
||||
// ForgetDetected deletes one key of detected-steps; RecordAct writes an act in the hand-act log of the seat
|
||||
// mesh-hand-acts (§463, §480): a drop writes it first.
|
||||
ForgetDetected func(key string) error
|
||||
RecordAct func(what, why string) error
|
||||
// Pauses is the Put of the pauses state, which keeps the node's pause key without an age; ReadPauses reads it back.
|
||||
Pauses buildstep.Put
|
||||
ReadPauses StateRead
|
||||
|
||||
@@ -38,6 +38,9 @@ type StepsAnswer struct {
|
||||
Fingerprint string `json:"fingerprint,omitempty"`
|
||||
Steps []DetectedStep `json:"steps"`
|
||||
Kept bool `json:"kept,omitempty"`
|
||||
// Dropped is the artifact whose key a drop deleted; Error why a drop deleted nothing, naming the hand-act log.
|
||||
Dropped string `json:"dropped,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// detectSteps finds the steps of the package directories under dir.
|
||||
@@ -77,26 +80,31 @@ func (m *Module) stepsTool() stdio.Tool {
|
||||
return stdio.Tool{Name: Seat + "." + seat.VerbSteps,
|
||||
Description: "Which pipeline steps a TypeScript artifact can run: the type-check as lint, always; unit tests where a package has a test script; " +
|
||||
"integration tests where one has a test:integration script. A level with no test is not answered.",
|
||||
Input: map[string]any{"type": "object", "required": []string{"module", "artifact", "fetch"}, "properties": map[string]any{
|
||||
Input: map[string]any{"type": "object", "required": []string{"module", "artifact"}, "properties": map[string]any{
|
||||
"module": map[string]any{"type": "string"},
|
||||
"artifact": map[string]any{"type": "string", "description": "the artifact reference, <module>:<artifact>"},
|
||||
"fingerprint": map[string]any{"type": "string"},
|
||||
"fetch": map[string]any{"type": "object", "description": "what the fetch tool is asked: the repository, the full commit and the module's directory"},
|
||||
"again": map[string]any{"type": "boolean", "description": "find them anew, not from the kept answer"},
|
||||
"drop": map[string]any{"type": "boolean", "description": "delete the artifact's kept key instead of detecting; needs why (written in the hand-act log first)"},
|
||||
"why": map[string]any{"type": "string", "description": "with drop, why: a non-empty text"},
|
||||
}},
|
||||
Run: m.Short(m.steps)}
|
||||
}
|
||||
|
||||
func (m *Module) steps(ctx context.Context, args map[string]any) (any, error) {
|
||||
str := func(k string) string { s, _ := args[k].(string); return s }
|
||||
if str("artifact") == "" || str("module") == "" {
|
||||
return nil, fmt.Errorf("steps: the module and the artifact are asked")
|
||||
}
|
||||
if drop, _ := args["drop"].(bool); drop {
|
||||
return m.dropDetected(args, stdio.CallerOf(args))
|
||||
}
|
||||
fetch, _ := args["fetch"].(map[string]any)
|
||||
req, err := sdkstep.ParseFetchRequest(fetch)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if str("artifact") == "" || str("module") == "" {
|
||||
return nil, fmt.Errorf("steps: the module and the artifact are asked")
|
||||
}
|
||||
artifact, fp := str("artifact"), str("fingerprint")
|
||||
name := artifact
|
||||
if _, n, ok := strings.Cut(artifact, ":"); ok {
|
||||
@@ -126,6 +134,27 @@ func (m *Module) steps(ctx context.Context, args map[string]any) (any, error) {
|
||||
return StepsAnswer{Artifact: artifact, Fingerprint: fp, Steps: steps}, nil
|
||||
}
|
||||
|
||||
// dropDetected is `steps` with drop (§463, §480): the act is written in the hand-act log with the caller the bus proved,
|
||||
// then the kept key is deleted; a log that refuses leaves the key.
|
||||
func (m *Module) dropDetected(args map[string]any, caller string) (any, error) {
|
||||
artifact, _ := args["artifact"].(string)
|
||||
why, _ := args["why"].(string)
|
||||
module, _ := args["module"].(string)
|
||||
name := artifact
|
||||
if _, n, ok := strings.Cut(artifact, ":"); ok {
|
||||
name = n
|
||||
}
|
||||
key := seat.DetectedStepsByModuleArtifactKey(module, name)
|
||||
failed, err := buildstep.DropDetected(artifact, why, caller, key, m.RecordAct, m.ForgetDetected)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if failed != "" {
|
||||
return StepsAnswer{Artifact: artifact, Error: failed}, nil
|
||||
}
|
||||
return StepsAnswer{Artifact: artifact, Dropped: artifact}, nil
|
||||
}
|
||||
|
||||
// stepsOfTree fetches the commit alone (nothing installed) into a workspace removed at the end.
|
||||
func (m *Module) stepsOfTree(ctx context.Context, req sdkstep.FetchRequest) ([]DetectedStep, error) {
|
||||
if err := os.MkdirAll(m.Work, 0o700); err != nil {
|
||||
|
||||
@@ -2,9 +2,11 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -51,3 +53,27 @@ func TestTheStepsVerbIsServedAndRefusesAnAskWithoutAnArtifact(t *testing.T) {
|
||||
t.Error("an ask with no artifact was answered")
|
||||
}
|
||||
}
|
||||
|
||||
// Design 47 G §463, §480 (BN9): steps with drop writes the hand-act log first, then deletes the key; a log that
|
||||
// refuses deletes nothing; a drop without why is refused.
|
||||
func TestTheStepsDropWritesTheHandActLogFirst(t *testing.T) {
|
||||
var order []string
|
||||
m := &Module{
|
||||
ForgetDetected: func(key string) error { order = append(order, "delete "+key); return nil },
|
||||
RecordAct: func(what, why string) error { order = append(order, "log "+why); return nil },
|
||||
}
|
||||
args := map[string]any{"module": "mod", "artifact": "mod:web", "drop": true, "why": "stale"}
|
||||
got, err := m.dropDetected(args, "shanks.person")
|
||||
if a, _ := got.(StepsAnswer); err != nil || a.Dropped != "mod:web" || !reflect.DeepEqual(order, []string{"log stale", "delete mod.web"}) {
|
||||
t.Fatalf("drop = %+v, %v, order %v", got, err, order)
|
||||
}
|
||||
if _, err := m.dropDetected(map[string]any{"module": "mod", "artifact": "mod:web", "drop": true}, "shanks.person"); err == nil {
|
||||
t.Error("a drop without why was taken")
|
||||
}
|
||||
order = nil
|
||||
m.RecordAct = func(string, string) error { return errors.New("log down") }
|
||||
got, err = m.dropDetected(args, "shanks.person")
|
||||
if a, _ := got.(StepsAnswer); err != nil || !strings.Contains(a.Error, "hand-act log") || len(order) != 0 {
|
||||
t.Fatalf("a refusing log: %+v, %v, order %v", got, err, order)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user