G findings: artifact-store-tools and mesh-config read what their held writer holds, so a restart neither drops nor rewrites their findings

Their in-memory open sets go.

Builds: design 47 G A-32, A-29, A-38
This commit is contained in:
2026-11-11 22:17:21 +01:00
parent 652493e2ac
commit 839147b146
8 changed files with 79 additions and 88 deletions
@@ -93,12 +93,10 @@ type Holder struct {
Now func() time.Time
Logf func(string, ...any)
sweep sync.Mutex // one sweep at a time
mu sync.Mutex
fmu sync.Mutex // the findings said and the sweep's refusal
said map[string]meshconditions.Finding // S25's findings as last written, by key
refused *meshconditions.Finding // the sweep's finding while a seat's refusal stands
ended map[string]time.Time // a done key's end, read once from its history
sweep sync.Mutex // one sweep at a time
mu sync.Mutex
fmu sync.Mutex // one pass of Observe at a time
ended map[string]time.Time // a done key's end, read once from its history
}
// Build is one done build of a module, as its key holds it, with when it ended.
@@ -856,7 +854,8 @@ func inStoreAt(image, address string) string {
}
// Observe says S25's findings (image-missing): each want whose build names an image the store does not hold, on the
// want's machine, written once and cleared once it no longer holds. Nothing is said without a listing.
// want's machine, written once and cleared once it no longer holds. Nothing is said without a listing. What stands is what
// the held writer holds (design 47 G A-32, A-38), so a restart neither drops nor rewrites it.
func (h *Holder) Observe(ctx context.Context) error {
now, err := h.observed(ctx)
if err != nil {
@@ -867,52 +866,36 @@ func (h *Holder) Observe(ctx context.Context) error {
}
h.fmu.Lock()
defer h.fmu.Unlock()
if h.said == nil {
h.said = map[string]meshconditions.Finding{}
said := map[string]meshconditions.Finding{}
for _, f := range h.Findings.Held() {
if f.Kind == ImageMissing {
said[views.FindingKey(f.Scope, f.ID, f.Kind)] = f
}
}
for k, was := range h.said {
for k, was := range said {
if _, still := now[k]; !still {
if err := h.Findings.Clear(ctx, was.Scope, was.ID, was.Kind, "the store holds the image again"); err != nil {
return err
}
delete(h.said, k)
}
}
for k, f := range now {
if was, ok := h.said[k]; ok && was.Summary == f.Summary {
if was, ok := said[k]; ok && was.Summary == f.Summary {
continue // written only when what it says changes
}
if err := h.Findings.Write(ctx, f); err != nil {
return err
}
h.said[k] = f
}
return nil
}
// Findings is the module's finding writer (views.Writer): the holder writes and clears through it (design 47 G §689).
// Findings is the module's held finding writer (views.HeldWriter): the holder writes and clears through it and reads what it
// holds (design 47 G §689, A-29, A-38).
type Findings interface {
Write(ctx context.Context, finding meshconditions.Finding) error
Clear(ctx context.Context, scope, id, kind, why string) error
}
// FindingsObserved answers the findings this module observes now, for its writer's statement (views.WriterConfig.Observe):
// S25's findings and the sweep's, when a seat refused it and no clean sweep cleared it.
func (h *Holder) FindingsObserved(ctx context.Context) (views.Observed[meshconditions.Finding], error) {
now, err := h.observed(ctx)
if err != nil {
return views.Observed[meshconditions.Finding]{}, err
}
var out views.Observed[meshconditions.Finding]
for _, f := range now {
out.Findings = append(out.Findings, f)
}
h.fmu.Lock()
defer h.fmu.Unlock()
if h.refused != nil {
out.Findings = append(out.Findings, *h.refused)
}
return out, nil
Held() []meshconditions.Finding
}
// observed is S25's findings now by key, nil without a listing.
@@ -418,6 +418,8 @@ func TestAWantedImageTheStoreLacksIsAFindingAndImagesNamesWantsAndHaves(t *testi
t.Fatalf("the finding is %+v (%v, %v)", f, found, err)
}
view.L.Repos[repo].Revisions[digest] = true
// A restart: a holder made afresh holds no finding of its own, and clears what the writer holds (design 47 G A-32, A-38).
h = &Holder{Bus: h.Bus, Findings: h.Findings, Door: h.Door, Listed: h.Listed, Seats: h.Seats, Now: h.Now, Acts: h.Acts, Logf: h.Logf}
if err := h.Observe(context.Background()); err != nil {
t.Fatal(err)
}
@@ -459,6 +461,24 @@ func (f findingsThrough) Write(_ context.Context, finding meshconditions.Finding
return f.bus.Put(FindingsState, views.FindingKey(finding.Scope, finding.ID, finding.Kind), finding)
}
// Held is what the writer holds: the findings in the module's state.
func (f findingsThrough) Held() []meshconditions.Finding {
var out []meshconditions.Finding
keys, _ := f.bus.(interface {
Keys(string) ([]string, error)
}).Keys(FindingsState)
for _, k := range keys {
raw, ok, _ := f.bus.(interface {
Get(string, string) ([]byte, bool, error)
}).Get(FindingsState, k)
var m meshconditions.Finding
if ok && json.Unmarshal(raw, &m) == nil {
out = append(out, m)
}
}
return out
}
func (f findingsThrough) Clear(_ context.Context, scope, id, kind, _ string) error {
return f.bus.Delete(FindingsState, views.FindingKey(scope, id, kind))
}
@@ -30,9 +30,9 @@ func main() {
h := &Holder{Bus: runtimeBus{views: v}, Door: DoorAt(os.Getenv("MESH_ARTIFACT_STORE_ADDRESS_FILE"), s), Listed: s.View,
Seats: stdio.Ask, Now: time.Now, Logf: logf}
h.Acts = meshhandactsclient.Recorder{Ask: stdio.Ask}
// The module's one writer (design 47 G §689, A-16): the holder's findings and the reader's go through it.
w, err := views.NewStdioWriter(views.WriterConfig[meshconditions.Finding, meshconditions.FindingCleared, meshconditions.FindingsStated, meshconditions.FindingsAskedEvent]{
Asked: meshconditions.SubjectFindingsAsked, Module: Module, State: stdio.State("findings"), Kinds: []string{ImageMissing, SweepRefused}, Observe: h.FindingsObserved})
// The module's one held writer (design 47 G §689, A-16, A-29, A-32): the holder's findings and the reader's go through it.
w, err := views.NewStdioHeldWriter(views.WriterConfig[meshconditions.Finding, meshconditions.FindingCleared, meshconditions.FindingsStated, meshconditions.FindingsAskedEvent]{
Asked: meshconditions.SubjectFindingsAsked, Module: Module, State: stdio.State("findings"), Kinds: []string{ImageMissing, SweepRefused}})
if err != nil {
logf("%v", err)
os.Exit(1)
@@ -123,25 +123,20 @@ func (h *Holder) sweepFinding(what string, err error) {
Needs: "read the seat holder's journal for the refusal; the next sweep asks again.",
Evidence: []meshconditions.Evidence{{At: at.UTC(), Said: fmt.Sprintf("%s: %v", what, err)}},
Source: "CAT-AS1", Observer: Module, At: at}
h.fmu.Lock()
h.refused = &f
h.fmu.Unlock()
if werr := h.Findings.Write(context.Background(), f); werr != nil {
h.logf("the sweep's finding (%s: %v) could not be written: %v", what, err, werr)
}
}
// sweepClean clears the sweep's finding after a sweep no seat refused.
// sweepClean clears the sweep's finding, when the held writer holds it, after a sweep no seat refused.
func (h *Holder) sweepClean() {
h.fmu.Lock()
was := h.refused
h.refused = nil
h.fmu.Unlock()
if was == nil {
return
}
if err := h.Findings.Clear(context.Background(), was.Scope, was.ID, was.Kind, "a sweep ran through without a refusal"); err != nil {
h.logf("the sweep's finding could not be cleared: %v", err)
for _, was := range h.Findings.Held() {
if was.Kind != SweepRefused {
continue
}
if err := h.Findings.Clear(context.Background(), was.Scope, was.ID, was.Kind, "a sweep ran through without a refusal"); err != nil {
h.logf("the sweep's finding could not be cleared: %v", err)
}
}
}