mesh-issues: a take-over note records who acted, not the worker named; tests for the remaining rules (hq issue 399)
mesh/merge-gate pass: builds mesh-issues → novox; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)
mesh/delivery delivered
mesh/delivery-group group feat/399-fixing-status delivered: every member is delivered

The note's by is who acted as the runtime proves it (ADR 0275 §5); the
note's text names both workers. Tests for a resolved issue corrected, link
and set keeping the worker current, and a take-over reason with a secret's
shape. The ready-to-verify note says an issue resolves from fixing.
This commit is contained in:
jochen
2026-10-10 21:10:36 +02:00
parent 11afde55d6
commit a73b04843d
4 changed files with 57 additions and 3 deletions
@@ -187,7 +187,7 @@ func (t *Tracker) afterFix(n uint64) error {
prefix := fmt.Sprintf("Ready to verify: every fix of this issue is delivered (%s).", strings.Join(prs, ", "))
if !noted(is, prefix) {
if _, err := t.note(GroomBy, n, prefix+" Delivered is not resolved: prove the acceptance live, then "+
"resolve it. (novox/hq ADR 0281)"); err != nil {
"resolve it, from fixing: move it to fixing with by first if it is not there. (novox/hq ADR 0281, ADR 0283)"); err != nil {
return err
}
}
@@ -463,7 +463,7 @@ func (t *Tracker) move(by string, a MoveAsk) (*Moved, error) {
changed = append(changed, "by")
}
if work.from != "" {
is.Notes = append(is.Notes, Note{By: worker, At: at, Text: takeOverNote(work, worker, takeOver, prev)})
is.Notes = append(is.Notes, Note{By: by, At: at, Text: takeOverNote(work, worker, takeOver, prev)})
}
// The same status again only to change what it holds: a fix named while the issue stays located, to be
// resolved once it is delivered and proven (ADR 0281 §3).
@@ -303,6 +303,7 @@ func TestTheCyclesRulesHoldAtTheWrite(t *testing.T) {
{"take-over on another status", []string{"hq"}, "", MoveAsk{Status: StatusLocated, TakeOver: "x"}, "take-over is for"},
{"take-over with nobody to take from", nil, "", MoveAsk{Status: StatusFixing, By: "a@g14", TakeOver: "x"}, "nobody works on"},
{"an amended design that is not one", nil, "", MoveAsk{Status: StatusDiagnosing, By: "a@g14", AmendedDesign: []string{"../etc/passwd"}}, "not a design document"},
{"a take-over reason that carries a secret", nil, StatusDiagnosing, MoveAsk{Status: StatusFixing, By: "b@ace", TakeOver: "the key is sk-ant-api03-abcdefghijklmnopqrstuvwxyz"}, "carries no secret"},
{"a fixed-by of two lines", []string{"hq"}, fx, MoveAsk{Status: StatusResolved, FixedBy: []string{"a\nb"}}, "one line"},
}
for _, c := range cases {
@@ -91,7 +91,7 @@ func TestATakeOverNeedsAReasonAndIsNoted(t *testing.T) {
is, _ := h.Get(n)
if is.Worker.By != "jochen@shanks" || m.TookOverFrom != "fix-a@g14" || len(is.Notes) != 1 ||
!strings.Contains(is.Notes[0].Text, "from fix-a@g14") || !strings.Contains(is.Notes[0].Text, "the operator finishes it by hand") ||
is.Notes[0].By != "jochen@shanks" {
is.Notes[0].By != Unproven {
t.Fatalf("worker %+v, notes %+v, answer %+v", is.Worker, is.Notes, m)
}
ev := h.said()
@@ -244,3 +244,56 @@ func TestTheMoveVerbTakesByAndTakeOver(t *testing.T) {
}
}
}
// A resolved issue may still have what it holds corrected: resolved to resolved is not refused as "not from fixing".
func TestAResolvedIssueMayBeCorrected(t *testing.T) {
h := newHarness(t)
n := h.open(t, "x", "hq")
h.fixing(t, n)
if _, err := h.Move(MoveAsk{Number: n, Status: StatusResolved, FixedBy: []string{"hq#1"}}); err != nil {
t.Fatal(err)
}
if _, err := h.Move(MoveAsk{Number: n, Status: StatusResolved, FixedBy: []string{"hq#1", "hq#2"}}); err != nil {
t.Fatalf("a correction of a resolved issue: %v", err)
}
if is, _ := h.Get(n); len(is.FixedBy) != 2 {
t.Fatalf("%+v", is.FixedBy)
}
}
// A caller's link and set keep the worker current, as a note does (ADR 0283 §4).
func TestALinkAndASetKeepTheWorkerCurrent(t *testing.T) {
for _, act := range []string{"link", "unlink", "set"} {
t.Run(act, func(t *testing.T) {
h := newHarness(t)
now := clocked(h)
n := h.open(t, "x", "hq")
other := h.open(t, "y")
if act == "unlink" {
if _, err := h.Link(LinkAsk{Number: n, Kind: LinkRelatesTo, Target: keyOf(other)}); err != nil {
t.Fatal(err)
}
}
if _, err := h.Move(MoveAsk{Number: n, Status: StatusFixing, By: "fix-a@g14"}); err != nil {
t.Fatal(err)
}
*now = now.Add(20 * time.Hour)
var err error
switch act {
case "link":
_, err = h.Link(LinkAsk{Number: n, Kind: LinkRelatesTo, Target: keyOf(other)})
case "unlink":
_, err = h.Link(LinkAsk{Number: n, Kind: LinkRelatesTo, Target: keyOf(other), Remove: true})
case "set":
_, err = h.Set(SetAsk{Number: n, Severity: "minor"})
}
if err != nil {
t.Fatal(err)
}
*now = now.Add(10 * time.Hour) // 30 h after the start, 10 h after the act
if _, err := h.Move(MoveAsk{Number: n, Status: StatusFixing, By: "fix-b@ace"}); err == nil {
t.Fatalf("the %s did not keep the worker current", act)
}
})
}
}