G-delivery 3, 4: family-not-heard says it clears at the part's next start; views.Bound is two minutes

Bind runs once at a part's start, so the finding's words no longer promise it clears when the grants part makes
the consumer. The assigner's comment on firstViewBound named five seconds for views.Bound, which is two minutes.

Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
This commit is contained in:
2026-11-04 18:10:51 +01:00
parent 121c6d9c48
commit 441b6d2922
3 changed files with 8 additions and 6 deletions
@@ -136,7 +136,8 @@ type indexerViews struct {
var indexerFirstViews = map[string]string{"manifests": delivery.ManifestsBucket, "modules": delivery.ModulesBucket, graph.State: graph.Bucket}
// firstViewBound and firstViewWait are each first view's bound before its condition is raised, and its first wait
// between two failed asks; zero is the views package's (views.Bound, five seconds). A test shortens them.
// between two failed asks; zero is the views package's (views.Bound, two minutes, ADR 0615 §6; and a first wait of five
// seconds). A test shortens them.
var firstViewBound, firstViewWait time.Duration
// start asks the three first views, each answer taken into w under the indexer's bucket names and settled once (a pass waits
@@ -187,7 +187,8 @@ func TestTheWatchmansFindings(t *testing.T) {
t.Errorf("%s: the finding stands once bound", row.name)
case row.want != "":
f, err := health.DecodeFinding(raw)
if err != nil || f.Kind != heard.Kind || f.Summary != row.want || f.Observer != "mesh-delivery-indexer" {
// Review round 2: it says it clears at the part's next start, since Bind runs at the start.
if err != nil || f.Kind != heard.Kind || f.Summary != row.want || f.Observer != "mesh-delivery-indexer" || !strings.Contains(f.Explanation, "next start") {
t.Errorf("%s: the finding %+v (%v), want summary %q", row.name, f, err, row.want)
}
}
+4 -4
View File
@@ -2,8 +2,8 @@
// family it follows (novox/hq ADR 0615 §5; review round 1 of the registry milestone): the consumer not there yet, a
// hearing that could not start, a watch that cannot be opened. Without it the part's health stays healthy and its
// status says answered while the events it waits on are lost to it. The finding names the observer and the family,
// says what is not heard and why, and is deleted when the consumer binds (at the part's next start, or when it opens
// later); the condition keeper raises and clears the condition from it (ADR 0564 §2).
// says what is not heard and why, and is deleted when the consumer binds: at the part's next start, or where the part
// binds again at a change of its membership, then; the condition keeper raises and clears the condition from it (ADR 0564 §2).
package heard
import (
@@ -36,8 +36,8 @@ func Words(observer, family, consequence string, why error) (summary, headline,
summary = fmt.Sprintf("%s does not hear %s: %s (%s)", observer, family, consequence, reason)
headline = fmt.Sprintf("%s does not hear %s", observer, family)
explanation = fmt.Sprintf("%s follows %s on a consumer of its own, and that consumer is not there or could not be heard, so %s. "+
"It is heard again once the consumer binds, at %s's next start or when the grants part has made it; this clears then. "+
"Look at whether the grants part made %s's consumers.", observer, family, consequence, observer, observer)
"This clears when the consumer binds: at %s's next start, or sooner where %s binds again at a change of its membership. "+
"Look at whether the grants part made %s's consumers, then start %s again if it does not bind by itself.", observer, family, consequence, observer, observer, observer, observer)
return summary, headline, explanation
}