mesh-issues: an issue knows whether its fix is delivered, says it ready to verify, and a fix stuck after its merge is said (hq ADR 0281)
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

The operator approved measuring from the delivery's own events whether each fix an
issue names reached the machines; delivered is not resolved, and a merged fix that
does not arrive is said on the issue and the operator's channel instead of found.
This commit is contained in:
jochen
2026-10-10 18:12:52 +02:00
parent 0b4ae8097f
commit 01bde68f96
10 changed files with 792 additions and 167 deletions
+21 -10
View File
@@ -30,9 +30,11 @@ type Tracker struct {
Records Records
// Judge is the triage's way to a model (ADR 0278, ADR 0279); nil judges nothing.
Judge Judgement
// Deliveries answers a pull request's delivery state (ADR 0279 §3); nil asks nothing.
// Deliveries answers a pull request's delivery (ADR 0279 §3, ADR 0281); nil asks nothing.
Deliveries DeliveryState
groom grooming
// Notify tells the operator's channel of a stuck fix (ADR 0281); nil says nothing there.
Notify Notifier
groom grooming
}
// The events this module says, one per kind of change.
@@ -395,12 +397,14 @@ func (t *Tracker) move(by string, a MoveAsk) (*Moved, error) {
is, err := t.change(a.Number, func(is *Issue) error {
changed = nil
from = is.Status
if from == to {
return fmt.Errorf("issue %d is already %s", is.Number, to)
}
// A field counts as changed only when its value does, so a move that changes nothing is refused.
set := func(name string, cond bool, apply func()) {
if cond {
apply()
if !cond {
return
}
before, _ := json.Marshal(is)
apply()
if after, _ := json.Marshal(is); string(before) != string(after) {
changed = append(changed, name)
}
}
@@ -410,14 +414,19 @@ func (t *Tracker) move(by string, a MoveAsk) (*Moved, error) {
set("replay", replay != "", func() { is.Replay, is.ReplayNone = replay, "" })
set("replay-none", replayNone != "", func() { is.ReplayNone, is.Replay = replayNone, "" })
set("reason", reason != "", func() { is.Reason = reason })
// 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).
if from == to && len(changed) == 0 {
return fmt.Errorf("issue %d is already %s", is.Number, to)
}
if err := cycleRules(is, to); err != nil {
return err
}
is.Status = to
if to == StatusResolved || to == StatusWontfix {
if (to == StatusResolved || to == StatusWontfix) && from != to {
at := t.now()
is.Closed = &at
} else {
} else if to != StatusResolved && to != StatusWontfix {
is.Closed = nil
}
return nil
@@ -622,6 +631,8 @@ type Row struct {
Ready bool `json:"ready"`
// SuggestedOwner is the triage's or a person's suggestion, for an issue located nowhere yet.
SuggestedOwner string `json:"suggested-owner,omitempty"`
// Delivery is whether its fix is delivered, in words (ADR 0281); empty when fixed-by names no pull request.
Delivery string `json:"delivery,omitempty"`
}
// Listed is the answer to a list.
@@ -700,7 +711,7 @@ func (t *Tracker) List(a ListAsk) (*Listed, error) {
out.Matched++
if len(out.Rows) < limit {
out.Rows = append(out.Rows, Row{Number: n, Status: is.Status, Owner: strings.Join(is.LocatedIn, "; "), Title: is.Title,
Severity: is.Severity, Needs: is.Needs, Ready: ready, SuggestedOwner: is.SuggestedOwner})
Severity: is.Severity, Needs: is.Needs, Ready: ready, SuggestedOwner: is.SuggestedOwner, Delivery: DeliveryLine(is)})
}
}
switch {