From 7714f164c33fcbcfd4a2a3f916a91de9f705b382 Mon Sep 17 00:00:00 2001 From: jochen Date: Sun, 11 Oct 2026 19:22:18 +0200 Subject: [PATCH 1/2] mesh-issues: take every condition key the controller raises, a delivery's with its slash among them (hq issue 475) The tracker's own pattern refused the slash a delivery's id carries, so no issue could track a delivery's condition and the operator's alert kept saying no issue tracks it. Mirror the controller's key rule instead of a pattern of our own; a router test proves a slashed key is matched and named end to end. --- modules/mesh-issues/cmd/mesh-issues/check.go | 43 +++++++++++++-- .../cmd/mesh-issues/conditionkey_test.go | 55 +++++++++++++++++++ .../cmd/mesh-issues/tracker_test.go | 4 +- .../cmd/messenger/tracking_delivery_test.go | 42 ++++++++++++++ 4 files changed, 136 insertions(+), 8 deletions(-) create mode 100644 modules/mesh-issues/cmd/mesh-issues/conditionkey_test.go create mode 100644 modules/messenger/cmd/messenger/tracking_delivery_test.go diff --git a/modules/mesh-issues/cmd/mesh-issues/check.go b/modules/mesh-issues/cmd/mesh-issues/check.go index 88f3bc7b..db590940 100644 --- a/modules/mesh-issues/cmd/mesh-issues/check.go +++ b/modules/mesh-issues/cmd/mesh-issues/check.go @@ -3,6 +3,7 @@ package main import ( "fmt" "regexp" + "slices" "strings" "unicode" "unicode/utf8" @@ -219,13 +220,42 @@ const ( var LinkKinds = []string{LinkDuplicates, LinkRelatesTo, LinkDependsOn, LinkPullRequest, LinkDecision, LinkDesign, LinkCondition, LinkDelivery} var ( - pullRequest = regexp.MustCompile(`^[a-z0-9][a-z0-9._-]{0,99}#[1-9][0-9]{0,6}$`) - decision = regexp.MustCompile(`^[0-9]{4}$`) - conditionKey = regexp.MustCompile(`^[a-z0-9][a-z0-9._:=@-]{0,199}$`) - deliveryID = regexp.MustCompile(`^[A-Za-z0-9][A-Za-z0-9._:-]{0,99}$`) - issueNumber = regexp.MustCompile(`^[1-9][0-9]{0,8}$`) + pullRequest = regexp.MustCompile(`^[a-z0-9][a-z0-9._-]{0,99}#[1-9][0-9]{0,6}$`) + decision = regexp.MustCompile(`^[0-9]{4}$`) + deliveryID = regexp.MustCompile(`^[A-Za-z0-9][A-Za-z0-9._:-]{0,99}$`) + issueNumber = regexp.MustCompile(`^[1-9][0-9]{0,8}$`) ) +// The controller's rule for a condition's key, mirrored (novox/hq issue 475): mesh-controller's +// internal/conditions/condition.go composes every key in `Key` as `..`, the id split on its dots, +// each token made of the bus's safe characters `A-Za-z0-9_=/-` (anything else becomes `_`, an empty token `_`), +// and `Observation.check` refuses a scope not in its `Scopes`. A delivery's id carries its repository as +// owner/name, so its keys hold a slash: the narrower shape this replaced refused every one of them, and no issue +// could track a delivery's condition. Mirroring the rule, rather than widening a pattern, keeps the tracker taking +// exactly what the controller can raise. +var ( + conditionScopes = []string{"machine", "plan", "call", "build", "merge", "provider", "seat", "bus", "core", + "probe", "mesh", "delivery", "module"} + conditionKeyToken = regexp.MustCompile(`^[A-Za-z0-9_=/-]+$`) +) + +// MostConditionKey is the longest key a link takes: the controller sets no bound, the tracker keeps a link one line. +const MostConditionKey = 255 + +// isConditionKey says whether k is a key the controller could raise. +func isConditionKey(k string) bool { + parts := strings.Split(k, ".") + if len(k) > MostConditionKey || len(parts) < 3 || !slices.Contains(conditionScopes, parts[0]) { + return false + } + for _, p := range parts { + if !conditionKeyToken.MatchString(p) { + return false + } + } + return true +} + // checkTarget is a link's target, as its kind takes it, said the one way it is kept. func checkTarget(kind, target string) (string, error) { t := strings.TrimSpace(target) @@ -241,7 +271,8 @@ func checkTarget(kind, target string) (string, error) { case LinkDesign: ok, shape = designPath.MatchString(t), "a design document, such as 03-DESIGN/01-to-be/53-the-issue-tracker.md" case LinkCondition: - ok, shape = conditionKey.MatchString(t), "a condition's key as the controller names it" + ok, shape = isConditionKey(t), "a condition's key as the controller names it: .., "+ + "the scope one of "+strings.Join(conditionScopes, ", ")+", each part of letters, digits and _=/-" case LinkDelivery: ok, shape = deliveryID.MatchString(t), "a delivery's id as the controller names it" default: diff --git a/modules/mesh-issues/cmd/mesh-issues/conditionkey_test.go b/modules/mesh-issues/cmd/mesh-issues/conditionkey_test.go new file mode 100644 index 00000000..72bb7fd3 --- /dev/null +++ b/modules/mesh-issues/cmd/mesh-issues/conditionkey_test.go @@ -0,0 +1,55 @@ +package main + +import ( + "strings" + "testing" +) + +// A condition link takes every key the controller raises (novox/hq issue 475). The keys are real: the delivery's +// as `mesh-controller.status` named it when the link was refused, the others as `mesh-controller.conditions` +// answered on 2026-10-11. +var realConditionKeys = []string{ + "delivery.novox/mesh-controller_d2e9dc61590f.stalled", // a delivery's id carries its repository, owner/name + "machine.novox.telegram.telegram-token.secret-given", + "module.openrazer.shanks.relogin-needed", + "mesh.hand-acts.plans_go.healer-wanted", // a space in the id, made `_` by the controller + "delivery.leaf.over-budget", +} + +func TestAConditionLinkTakesEveryKeyTheControllerRaises(t *testing.T) { + h := newHarness(t) + n := h.open(t, "a delivery stalls", "mesh-catalog") + for _, k := range realConditionKeys { + if _, err := h.Link(LinkAsk{Number: n, Kind: LinkCondition, Target: k}); err != nil { + t.Errorf("%s: %v", k, err) + } + } + got, err := h.Tracking([]string{realConditionKeys[0]}) + if err != nil { + t.Fatal(err) + } + if is := got.Conditions[realConditionKeys[0]]; len(is) != 1 || is[0].Number != n || got.Said != "Issues track 1 condition." { + t.Fatalf("the delivery's condition is not said tracked: %+v", got) + } +} + +// What the controller never raises is refused, so a link never names a condition that cannot exist. +func TestAConditionLinkRefusesWhatTheControllerNeverRaises(t *testing.T) { + for _, k := range []string{ + "", + "delivery.stalled", // no id: a key is scope, id and kind + "weather.novox.rain", // no scope the controller knows + "machine..secret-given", // an empty token + "machine.novox.secret given", // a space the controller makes `_` + "machine.novox:1.secret-given", // a colon the controller makes `_` + "delivery.novox/mesh-controller@d2e9dc61590f.stalled", // `@` too + "machine.*.silent", // a wildcard on the bus + "machine.>", // a wildcard on the bus + "machine.ace.silent\nmore", // a second line + "machine." + strings.Repeat("a", 300) + ".silent", + } { + if _, err := checkTarget(LinkCondition, k); err == nil { + t.Errorf("%q was taken as a condition's key", k) + } + } +} diff --git a/modules/mesh-issues/cmd/mesh-issues/tracker_test.go b/modules/mesh-issues/cmd/mesh-issues/tracker_test.go index 557951d5..0528ffa7 100644 --- a/modules/mesh-issues/cmd/mesh-issues/tracker_test.go +++ b/modules/mesh-issues/cmd/mesh-issues/tracker_test.go @@ -473,7 +473,7 @@ func TestLinksAreTypedAddedOnceAndRemoved(t *testing.T) { {Kind: LinkPullRequest, Target: "mesh-controller#246"}, {Kind: LinkDecision, Target: "0275"}, {Kind: LinkDesign, Target: "03-DESIGN/01-to-be/53-the-issue-tracker.md"}, - {Kind: LinkCondition, Target: "healer-wanted.ace.backup"}, + {Kind: LinkCondition, Target: "mesh.hand-acts.backup.healer-wanted"}, {Kind: LinkDelivery, Target: "d-2026-10-10.3"}, } for _, l := range good { @@ -494,7 +494,7 @@ func TestLinksAreTypedAddedOnceAndRemoved(t *testing.T) { {LinkAsk{Kind: LinkDecision, Target: "275"}, "four-digit"}, {LinkAsk{Kind: LinkDesign, Target: "03-DESIGN/../../etc/passwd"}, "design document"}, {LinkAsk{Kind: LinkCondition, Target: "a key\nwith a line"}, "condition"}, - {LinkAsk{Kind: LinkCondition, Target: "token=abcdefgh123"}, "secret"}, + {LinkAsk{Kind: LinkCondition, Target: "machine.ace.token=abcdefgh123.leaked"}, "secret"}, {LinkAsk{Kind: LinkRelatesTo, Target: keyOf(b), Remove: true}, ""}, {LinkAsk{Kind: LinkRelatesTo, Target: keyOf(b), Remove: true}, "no relates-to link"}, } diff --git a/modules/messenger/cmd/messenger/tracking_delivery_test.go b/modules/messenger/cmd/messenger/tracking_delivery_test.go new file mode 100644 index 00000000..eca5ad38 --- /dev/null +++ b/modules/messenger/cmd/messenger/tracking_delivery_test.go @@ -0,0 +1,42 @@ +package main + +import ( + "encoding/json" + "strings" + "testing" +) + +// A delivery's condition, whose key holds its repository as owner/name, is matched to the issue that tracks it and +// its message names that issue (novox/hq issue 475). The key is the real one `mesh-controller.status` named; the +// event is decoded as the controller says it, so the key travels as it does on the bus. +func TestADeliverysConditionWithASlashInItsKeyNamesTheIssueThatTracksIt(t *testing.T) { + const key = "delivery.novox/mesh-controller_d2e9dc61590f.stalled" + h, tg, _, c, _ := newHolder(t) + h.Ask = func(address string, body any) (json.RawMessage, error) { + if address != TrackingVerb { + return json.RawMessage(`{"ok":true}`), nil + } + return json.RawMessage(`{"conditions":{"` + key + `":[{"number":475,"status":"open"}]}}`), nil + } + k, err := DecodeCondition(EventRaised, []byte(`{"key":"`+key+`","kind":"stalled","severity":"urgent",`+ + `"subject":{"scope":"delivery","id":"novox/mesh-controller_d2e9dc61590f"},`+ + `"headline":"Delivery of mesh-controller stalled",`+ + `"explanation":"Needs you: let the walk go or drop it. The delivery of mesh-controller waits for a walk that never starts.",`+ + `"needs":"let the walk go or drop it.","summary":"the delivery of mesh-controller waits for its walk"}`)) + if err != nil { + t.Fatal(err) + } + if k.Key != key { + t.Fatalf("the key was read as %q", k.Key) + } + k.Raised = c.now() + h.Condition(EventRaised, k) + settle(h, c) + if len(tg.sends) != 1 { + t.Fatalf("telegram %d", len(tg.sends)) + } + body := tg.sends[0].Body + if !strings.Contains(body, "Tracked as issue 475") || strings.Contains(body, "No issue tracks this yet.") { + t.Fatalf("body: %q", body) + } +} From 98d494619f5a55f5049252a45396119f12b354a2 Mon Sep 17 00:00:00 2001 From: jochen Date: Sun, 11 Oct 2026 19:24:23 +0200 Subject: [PATCH 2/2] mesh-issues: take a delivery's id as mesh-delivery forms it, owner/repo@commit (hq issue 475) The delivery link's own pattern refused the slash and the @ every delivery id carries, so no delivery could be linked either. Mirror mesh-delivery's IDOf. --- modules/mesh-issues/cmd/mesh-issues/check.go | 8 +++-- .../cmd/mesh-issues/conditionkey_test.go | 36 +++++++++++++++++++ modules/mesh-issues/cmd/mesh-issues/main.go | 2 +- .../cmd/mesh-issues/tracker_test.go | 2 +- 4 files changed, 44 insertions(+), 4 deletions(-) diff --git a/modules/mesh-issues/cmd/mesh-issues/check.go b/modules/mesh-issues/cmd/mesh-issues/check.go index db590940..0b362672 100644 --- a/modules/mesh-issues/cmd/mesh-issues/check.go +++ b/modules/mesh-issues/cmd/mesh-issues/check.go @@ -222,7 +222,10 @@ var LinkKinds = []string{LinkDuplicates, LinkRelatesTo, LinkDependsOn, LinkPullR var ( pullRequest = regexp.MustCompile(`^[a-z0-9][a-z0-9._-]{0,99}#[1-9][0-9]{0,6}$`) decision = regexp.MustCompile(`^[0-9]{4}$`) - deliveryID = regexp.MustCompile(`^[A-Za-z0-9][A-Za-z0-9._:-]{0,99}$`) + // deliveryID mirrors mesh-delivery's `IDOf` (modules/mesh-delivery/cmd/mesh-delivery/model.go): the forge's + // repository as owner/name, lower-cased, `@` and at most twelve characters of its commit. The pattern this + // replaced took neither the slash nor the `@`, so no delivery could be linked (novox/hq issue 475). + deliveryID = regexp.MustCompile(`^[a-z0-9][a-z0-9._-]{0,99}/[a-z0-9][a-z0-9._-]{0,99}@[0-9a-f]{1,12}$`) issueNumber = regexp.MustCompile(`^[1-9][0-9]{0,8}$`) ) @@ -274,7 +277,8 @@ func checkTarget(kind, target string) (string, error) { ok, shape = isConditionKey(t), "a condition's key as the controller names it: .., "+ "the scope one of "+strings.Join(conditionScopes, ", ")+", each part of letters, digits and _=/-" case LinkDelivery: - ok, shape = deliveryID.MatchString(t), "a delivery's id as the controller names it" + ok, shape = deliveryID.MatchString(t), "a delivery's id as mesh-delivery names it: the repository as owner/name, @ and twelve "+ + "characters of its commit, such as novox/mesh-controller@d2e9dc61590f" default: return "", fmt.Errorf("kind %q is not a kind of link: one of %s", kind, strings.Join(LinkKinds, ", ")) } diff --git a/modules/mesh-issues/cmd/mesh-issues/conditionkey_test.go b/modules/mesh-issues/cmd/mesh-issues/conditionkey_test.go index 72bb7fd3..649abb4d 100644 --- a/modules/mesh-issues/cmd/mesh-issues/conditionkey_test.go +++ b/modules/mesh-issues/cmd/mesh-issues/conditionkey_test.go @@ -53,3 +53,39 @@ func TestAConditionLinkRefusesWhatTheControllerNeverRaises(t *testing.T) { } } } + +// A delivery link takes every id mesh-delivery gives (novox/hq issue 475): the ids are real, as +// `mesh-delivery.deliveries` answered on 2026-10-11. +var realDeliveryIDs = []string{ + "novox/mesh-controller@0f853e93fa11", + "novox/mesh-catalog@7714f164c33f", + "novox/hq@34bdb1a34f5a", + "novox/mesh-media-catalog@dd3f0abb3f78", + "novox/mesh-tools@82aefe1988c2", +} + +func TestADeliveryLinkTakesEveryIdMeshDeliveryGives(t *testing.T) { + h := newHarness(t) + n := h.open(t, "a delivery stalls", "mesh-catalog") + for _, id := range realDeliveryIDs { + if _, err := h.Link(LinkAsk{Number: n, Kind: LinkDelivery, Target: id}); err != nil { + t.Errorf("%s: %v", id, err) + } + } + for _, id := range []string{ + "", + "mesh-controller@0f853e93fa11", // no owner + "novox/mesh-controller", // no commit + "novox/mesh-controller@0f853e93fa11aa", // more than twelve characters of the commit + "Novox/Mesh-Controller@0f853e93fa11", // mesh-delivery lower-cases the repository + "novox/mesh-controller@0F853E93FA11", // a commit is lower-case hex + "novox/mesh-controller@main", // a branch, not a commit + "novox/mesh/controller@0f853e93fa11", // a repository is owner/name, no deeper + "novox/mesh-controller_d2e9dc61590f", // a condition key's form of it, not the id + "novox/mesh-controller@0f853e93fa11\nmore", // a second line + } { + if _, err := checkTarget(LinkDelivery, id); err == nil { + t.Errorf("%q was taken as a delivery's id", id) + } + } +} diff --git a/modules/mesh-issues/cmd/mesh-issues/main.go b/modules/mesh-issues/cmd/mesh-issues/main.go index 30e1353e..a98bef56 100644 --- a/modules/mesh-issues/cmd/mesh-issues/main.go +++ b/modules/mesh-issues/cmd/mesh-issues/main.go @@ -506,7 +506,7 @@ func Tools(t *Tracker) []stdio.Tool { Description: "Link an issue to something, or with remove, take a link away. Kinds: duplicates or relates-to " + "another issue (its number), pull-request (such as mesh-controller#246), decision (a decision record's " + "number, such as 0275), design (a design document's path), condition (a condition's key) and delivery " + - "(a delivery's id). Refused: a target not of its kind's shape, an issue that does not exist, a link it " + + "(a delivery's id, such as novox/mesh-controller@d2e9dc61590f). Refused: a target not of its kind's shape, an issue that does not exist, a link it " + "already has.", Input: schema([]string{"number", "kind", "target"}, map[string]any{ "number": number("the issue's number"), diff --git a/modules/mesh-issues/cmd/mesh-issues/tracker_test.go b/modules/mesh-issues/cmd/mesh-issues/tracker_test.go index 0528ffa7..1b0c8d15 100644 --- a/modules/mesh-issues/cmd/mesh-issues/tracker_test.go +++ b/modules/mesh-issues/cmd/mesh-issues/tracker_test.go @@ -474,7 +474,7 @@ func TestLinksAreTypedAddedOnceAndRemoved(t *testing.T) { {Kind: LinkDecision, Target: "0275"}, {Kind: LinkDesign, Target: "03-DESIGN/01-to-be/53-the-issue-tracker.md"}, {Kind: LinkCondition, Target: "mesh.hand-acts.backup.healer-wanted"}, - {Kind: LinkDelivery, Target: "d-2026-10-10.3"}, + {Kind: LinkDelivery, Target: "novox/mesh-controller@0f853e93fa11"}, } for _, l := range good { l.Number = a