Merge pull request 'A drill is recorded through its own verb, and S15 never counts it (hq issue 292)' (#109) from fix/a-drill-is-no-repair into main
This commit was merged in pull request #109.
This commit is contained in:
@@ -41,6 +41,11 @@ type handActVerb struct {
|
||||
// causeLeakedInLogs is the cause a rotation after a value was printed into a log gives.
|
||||
const causeLeakedInLogs = "leaked-in-logs"
|
||||
|
||||
// causeDrill is the cause of every act `hand-act drill` records, and the one cause `hand-act record`
|
||||
// refuses: a drill has its own verb, so whether an act was a drill is said by the verb a person chose,
|
||||
// never by a word typed into a repair's cause (novox/hq issue 292).
|
||||
const causeDrill = "drill"
|
||||
|
||||
// handActVerbs is every verb that writes the hand-act log (novox/hq to-be 45 §7). **S15 reads it**:
|
||||
// an act recorded by a verb whose entry names a decision is the mesh working as decided, never a
|
||||
// repair, and does not count toward `healer-wanted` — whatever cause it gives. A verb not listed, or
|
||||
@@ -57,8 +62,14 @@ var handActVerbs = []handActVerb{
|
||||
{Verb: "broker consumer-reset"},
|
||||
// Silencing the same condition twice says the condition, or what it watches, wants mending.
|
||||
{Verb: "conditions silence"},
|
||||
// An act done outside the mesh: the mesh cannot tell a repair from a decision there, so it counts.
|
||||
{Verb: "hand-act record"},
|
||||
// An act done outside the mesh: the mesh cannot tell a repair from a decision there, so it counts —
|
||||
// except a drill recorded through it before `hand-act drill` existed (2026-10-07). It refuses the
|
||||
// cause since, so no act recorded through it now carries it.
|
||||
{Verb: "hand-act record", Decision: "a drill recorded before `hand-act drill` existed: a person's " +
|
||||
"deliberate test, never a repair", DecidedFor: []string{causeDrill}},
|
||||
// A drill: something broken on purpose to see the mesh raise and clear it. A person's test, never a
|
||||
// repair, however often it is run.
|
||||
{Verb: "hand-act drill", Decision: "a drill is a person's deliberate test of the mesh, never a repair"},
|
||||
// A person's decisions by design.
|
||||
{Verb: "retire approve", Decision: "nothing is retired past its bound without a person (ADR 0230)"},
|
||||
{Verb: "retire reject", Decision: "keeping a consumer active is a person's word (ADR 0230)"},
|
||||
@@ -174,6 +185,10 @@ func handActCommand(ctx context.Context, args []string) error {
|
||||
return errors.New("hand-act record says the cause too: --cause <word>, the word a second " +
|
||||
"act for the same reason will use — it is how a repair done twice is found")
|
||||
}
|
||||
if strings.EqualFold(strings.TrimSpace(*f.cause), causeDrill) {
|
||||
return errors.New("a drill is not recorded as a repair: hand-act drill <what was done> --why <text> " +
|
||||
"records it as the person's deliberate test it is, which no healer is wanted for. Nothing was recorded")
|
||||
}
|
||||
act := link.HandAct{Verb: "hand-act record", Args: []string{what}, Why: strings.TrimSpace(*f.why),
|
||||
Cause: strings.TrimSpace(*f.cause), Condition: strings.TrimSpace(*f.condition)}
|
||||
return onTheBus(func(conn *nats.Conn) error {
|
||||
@@ -186,8 +201,12 @@ func handActCommand(ctx context.Context, args []string) error {
|
||||
return nil
|
||||
})
|
||||
}
|
||||
if len(args) > 0 && args[0] == "drill" {
|
||||
return handActDrill(ctx, args[1:])
|
||||
}
|
||||
if len(args) > 0 && args[0] != "list" && !strings.HasPrefix(args[0], "-") {
|
||||
return errors.New("hand-act record <what> --why <text> --cause <word> | hand-acts [--days N] [--json]")
|
||||
return errors.New("hand-act record <what> --why <text> --cause <word> | hand-act drill <what> --why <text> " +
|
||||
"| hand-acts [--days N] [--json]")
|
||||
}
|
||||
if len(args) > 0 && args[0] == "list" {
|
||||
args = args[1:]
|
||||
@@ -239,6 +258,38 @@ func handActCommand(ctx context.Context, args []string) error {
|
||||
})
|
||||
}
|
||||
|
||||
// handActDrill is `hand-act drill`: an act done on purpose to test the mesh — a module stopped, a
|
||||
// process killed — recorded so the conditions it raises are read as the drill they are. Its cause is
|
||||
// always causeDrill and S15 never counts it (handActVerbs).
|
||||
func handActDrill(ctx context.Context, args []string) error {
|
||||
set := flag.NewFlagSet("hand-act drill", flag.ContinueOnError)
|
||||
why := set.String("why", "", "what the drill tests — recorded in the hand-act log (novox/hq to-be 45 §7)")
|
||||
condition := set.String("condition", "", "the key of the condition the drill is meant to raise, if any")
|
||||
positionals, err := parseAround(set, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
what := strings.TrimSpace(strings.Join(positionals, " "))
|
||||
if what == "" {
|
||||
return errors.New("hand-act drill <what was done on purpose> --why <what it tests> [--condition <key>]")
|
||||
}
|
||||
if strings.TrimSpace(*why) == "" {
|
||||
return errors.New("a drill says what it tests: --why <text> (recorded in the hand-act log, novox/hq " +
|
||||
"to-be 45 §7). Nothing was recorded")
|
||||
}
|
||||
act := link.HandAct{Verb: "hand-act drill", Args: []string{what}, Why: strings.TrimSpace(*why),
|
||||
Cause: causeDrill, Condition: strings.TrimSpace(*condition)}
|
||||
return onTheBus(func(conn *nats.Conn) error {
|
||||
written, err := link.RecordHandAct(ctx, conn, act)
|
||||
if err != nil {
|
||||
return fmt.Errorf("the drill could not be recorded: %w", err)
|
||||
}
|
||||
fmt.Printf("recorded as %s: %s drilled %q, because %q — a drill, which no healer is wanted for\n",
|
||||
written.ID, written.By, what, written.Why)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// repairs are the acts that are not a person's decision by design: what S15 counts.
|
||||
func repairs(acts []link.HandAct) []link.HandAct {
|
||||
out := make([]link.HandAct, 0, len(acts))
|
||||
|
||||
@@ -92,3 +92,32 @@ func TestDurationsAreSummarisedPerSubject(t *testing.T) {
|
||||
t.Fatalf("a minute between words suggests %q", got[1].Suggests)
|
||||
}
|
||||
}
|
||||
|
||||
// **A drill has its own verb** — `hand-act drill`, the seat's `drill` — and `hand-act record` refuses
|
||||
// the cause, so a repair cannot pass for a drill by the word it gives.
|
||||
func TestADrillIsRecordedThroughItsOwnVerb(t *testing.T) {
|
||||
err := handActCommand(context.Background(), []string{"record", "stopped searxng", "--why", "a test", "--cause", "drill"})
|
||||
if err == nil || !strings.Contains(err.Error(), "hand-act drill") {
|
||||
t.Errorf("hand-act record --cause drill was not sent to the drill verb: %v", err)
|
||||
}
|
||||
if err := handActCommand(context.Background(), []string{"drill", "stopped searxng"}); err == nil ||
|
||||
!strings.Contains(err.Error(), "--why") {
|
||||
t.Errorf("a drill without what it tests: %v", err)
|
||||
}
|
||||
if err := handActCommand(context.Background(), []string{"drill", "--why", "a test"}); err == nil ||
|
||||
!strings.Contains(err.Error(), "hand-act drill <what") {
|
||||
t.Errorf("a drill without what was done: %v", err)
|
||||
}
|
||||
argv, err := argvFor("drill", map[string]any{"what": "stopped searxng", "why": "ADR 0240 phase A",
|
||||
"condition": "machine.ace.module.searxng.unhealthy"})
|
||||
if want := "hand-act drill stopped searxng --why ADR 0240 phase A --condition machine.ace.module.searxng.unhealthy"; err != nil ||
|
||||
strings.Join(argv, " ") != want {
|
||||
t.Errorf("the seat's drill: %v %v, want %q", argv, err, want)
|
||||
}
|
||||
if _, err := argvFor("drill", map[string]any{"what": "stopped searxng"}); err == nil {
|
||||
t.Error("the seat's drill without why was not refused")
|
||||
}
|
||||
if repairingCommand([]string{"hand-act", "drill", "x"}) != "hand-act drill" {
|
||||
t.Error("a drill through `command` is not held to why")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -456,6 +456,15 @@ func (a *verbArguments) commandLine() ([]string, error) {
|
||||
argv = append(argv, "--condition", c)
|
||||
}
|
||||
return argv, nil
|
||||
case "drill":
|
||||
if err := need("what", "why"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
argv := []string{"hand-act", "drill", str("what"), "--why", str("why")}
|
||||
if c := str("condition"); c != "" {
|
||||
argv = append(argv, "--condition", c)
|
||||
}
|
||||
return argv, nil
|
||||
case "hand-acts":
|
||||
argv := []string{"hand-acts", "--json"}
|
||||
if d := str("days"); d != "" {
|
||||
@@ -723,6 +732,8 @@ func repairingCommand(argv []string) string {
|
||||
return "plans " + argv[1]
|
||||
case argv[0] == "broker" && len(argv) > 1 && argv[1] == "consumer-reset":
|
||||
return "broker consumer-reset"
|
||||
case argv[0] == "hand-act" && len(argv) > 1 && argv[1] == "drill":
|
||||
return "hand-act drill"
|
||||
case argv[0] == "hand-act":
|
||||
return "hand-act record"
|
||||
case argv[0] == "conditions" && len(argv) > 1 && argv[1] == "silence":
|
||||
|
||||
@@ -550,3 +550,47 @@ func TestAWalkWaitingFourHoursIsUrgentAndNamesTheWayOn(t *testing.T) {
|
||||
t.Fatalf("it does not say how on: %q", got[0].Summary)
|
||||
}
|
||||
}
|
||||
|
||||
// **A drill is a person's deliberate test, never a repair** — the log of 2026-10-07: two drills of ADR
|
||||
// 0240 recorded through `hand-act record --cause drill` before `hand-act drill` existed raised
|
||||
// `mesh.hand-acts.drill.healer-wanted`. A drill through its own verb never counts, the two recorded
|
||||
// before it clear on the next tick, and the cause word alone on any other verb still counts — whether
|
||||
// an act is a drill is said by the verb chosen, not by a word typed into a repair's cause.
|
||||
func TestADrillIsNoRepairAndItsHealerWantedClears(t *testing.T) {
|
||||
now := time.Date(2026, 10, 7, 12, 0, 0, 0, time.UTC)
|
||||
f := calm(now)
|
||||
f.handActs = []link.HandAct{actOf(now.Add(-26*time.Hour), "hand-act drill", causeDrill),
|
||||
actOf(now.Add(-time.Hour), "hand-act drill", causeDrill), actOf(now.Add(-time.Minute), "hand-act drill", causeDrill)}
|
||||
if got := watchHandActs(f); len(got) != 0 {
|
||||
t.Errorf("drills repeated asked for a healer: %+v", got)
|
||||
}
|
||||
for _, verb := range []string{"push", "conditions silence", "plans close", "a verb nobody listed"} {
|
||||
f := calm(now)
|
||||
f.handActs = []link.HandAct{actOf(now.Add(-26*time.Hour), verb, causeDrill), actOf(now.Add(-time.Hour), verb, causeDrill)}
|
||||
if got := watchHandActs(f); len(got) != 1 {
|
||||
t.Errorf("%s with the cause %q passed for a drill: %+v", verb, causeDrill, got)
|
||||
}
|
||||
}
|
||||
|
||||
store := conditions.NewInMemory()
|
||||
k := conditions.NewKeeper(t.Context(), conditions.Options{Store: store, History: store,
|
||||
Teller: &conditions.Told{}, Now: func() time.Time { return now }})
|
||||
defer k.Close(context.Background())
|
||||
before := []conditions.Observation{{Scope: conditions.ScopeMesh, ID: "hand-acts." + causeDrill,
|
||||
Token: "healer-wanted", Kind: "healer-wanted", Severity: conditions.Warning,
|
||||
Summary: "\"drill\" was repaired by hand 2 times in 14 days"}}
|
||||
if err := k.Reconcile(t.Context(), "S15", before); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if open, _ := k.Open(t.Context()); len(open) != 1 {
|
||||
t.Fatalf("the condition of the build before was not open: %+v", open)
|
||||
}
|
||||
f = calm(now)
|
||||
f.handActs = []link.HandAct{actOf(now.Add(-11*time.Hour), "hand-act record", causeDrill),
|
||||
actOf(now.Add(-30*time.Minute), "hand-act record", causeDrill)}
|
||||
w := &watchdogs{keeper: k, started: now.Add(-time.Hour)}
|
||||
w.see(t.Context(), f)
|
||||
if open, _ := k.Open(t.Context()); len(open) != 0 {
|
||||
t.Fatalf("a healer-wanted for two drills stayed open: %+v", open)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,6 +262,14 @@ var ControllerVerbs = []Verb{
|
||||
"cause": "the cause in a word, or a condition's kind — the word a second act for the same reason uses",
|
||||
"condition": "the key of the condition it addressed, if any (optional)",
|
||||
}, []string{"what", "why", "cause"})},
|
||||
{Name: "drill", Description: "Record a drill — something broken on purpose to see the mesh raise and clear it: " +
|
||||
"a module stopped, a process killed — with what it tests, in the hand-act log. A drill is a person's " +
|
||||
"deliberate test, never a repair: no healer is wanted for it however often it is run (S15).",
|
||||
Input: schema(map[string]string{
|
||||
"what": "what was done on purpose, in a line",
|
||||
"why": "what the drill tests",
|
||||
"condition": "the key of the condition the drill is meant to raise, if any (optional)",
|
||||
}, []string{"what", "why"})},
|
||||
{Name: "hand-acts", Description: "What was done by hand lately — pushes, plans ended, consumers re-made, acts " +
|
||||
"recorded — who, why and the cause of each, and which causes repeat: each repeat is a healer the mesh lacks.",
|
||||
Input: schema(map[string]string{"days": "how many days back (default 14)"}, nil)},
|
||||
|
||||
@@ -60,6 +60,7 @@
|
||||
"pause",
|
||||
"resume",
|
||||
"hand-act",
|
||||
"drill",
|
||||
"hand-acts",
|
||||
"durations",
|
||||
"conditions",
|
||||
|
||||
Reference in New Issue
Block a user