Record a drill through its own verb, so S15 never counts a deliberate test as a repair
mesh/merge-gate pass: builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus step; every machine composes with the change as it…
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery delivered

Two ADR 0240 drills recorded with hand-act record --cause drill raised
mesh.hand-acts.drill.healer-wanted. hand-act drill (seat verb drill) records
them as a person's decision; hand-act record now refuses the cause, so the
two recorded before it clear on the next tick and a repair cannot pass for a
drill by the word it gives.
This commit is contained in:
jochen
2026-10-07 13:55:31 +02:00
parent 582f4a082a
commit 2799e95035
6 changed files with 147 additions and 3 deletions
+54 -3
View File
@@ -41,6 +41,11 @@ type handActVerb struct {
// causeLeakedInLogs is the cause a rotation after a value was printed into a log gives. // causeLeakedInLogs is the cause a rotation after a value was printed into a log gives.
const causeLeakedInLogs = "leaked-in-logs" 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**: // 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 // 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 // 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"}, {Verb: "broker consumer-reset"},
// Silencing the same condition twice says the condition, or what it watches, wants mending. // Silencing the same condition twice says the condition, or what it watches, wants mending.
{Verb: "conditions silence"}, {Verb: "conditions silence"},
// An act done outside the mesh: the mesh cannot tell a repair from a decision there, so it counts. // An act done outside the mesh: the mesh cannot tell a repair from a decision there, so it counts —
{Verb: "hand-act record"}, // 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. // A person's decisions by design.
{Verb: "retire approve", Decision: "nothing is retired past its bound without a person (ADR 0230)"}, {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)"}, {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 " + 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") "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), 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)} Cause: strings.TrimSpace(*f.cause), Condition: strings.TrimSpace(*f.condition)}
return onTheBus(func(conn *nats.Conn) error { return onTheBus(func(conn *nats.Conn) error {
@@ -186,8 +201,12 @@ func handActCommand(ctx context.Context, args []string) error {
return nil 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], "-") { 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" { if len(args) > 0 && args[0] == "list" {
args = args[1:] 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. // repairs are the acts that are not a person's decision by design: what S15 counts.
func repairs(acts []link.HandAct) []link.HandAct { func repairs(acts []link.HandAct) []link.HandAct {
out := make([]link.HandAct, 0, len(acts)) out := make([]link.HandAct, 0, len(acts))
+29
View File
@@ -92,3 +92,32 @@ func TestDurationsAreSummarisedPerSubject(t *testing.T) {
t.Fatalf("a minute between words suggests %q", got[1].Suggests) 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")
}
}
+11
View File
@@ -456,6 +456,15 @@ func (a *verbArguments) commandLine() ([]string, error) {
argv = append(argv, "--condition", c) argv = append(argv, "--condition", c)
} }
return argv, nil 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": case "hand-acts":
argv := []string{"hand-acts", "--json"} argv := []string{"hand-acts", "--json"}
if d := str("days"); d != "" { if d := str("days"); d != "" {
@@ -723,6 +732,8 @@ func repairingCommand(argv []string) string {
return "plans " + argv[1] return "plans " + argv[1]
case argv[0] == "broker" && len(argv) > 1 && argv[1] == "consumer-reset": case argv[0] == "broker" && len(argv) > 1 && argv[1] == "consumer-reset":
return "broker 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": case argv[0] == "hand-act":
return "hand-act record" return "hand-act record"
case argv[0] == "conditions" && len(argv) > 1 && argv[1] == "silence": case argv[0] == "conditions" && len(argv) > 1 && argv[1] == "silence":
+44
View File
@@ -550,3 +550,47 @@ func TestAWalkWaitingFourHoursIsUrgentAndNamesTheWayOn(t *testing.T) {
t.Fatalf("it does not say how on: %q", got[0].Summary) 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)
}
}
+8
View File
@@ -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", "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)", "condition": "the key of the condition it addressed, if any (optional)",
}, []string{"what", "why", "cause"})}, }, []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 " + {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.", "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)}, Input: schema(map[string]string{"days": "how many days back (default 14)"}, nil)},
+1
View File
@@ -60,6 +60,7 @@
"pause", "pause",
"resume", "resume",
"hand-act", "hand-act",
"drill",
"hand-acts", "hand-acts",
"durations", "durations",
"conditions", "conditions",