G findings4 watchman: the watchman's findings go through views.NewHeldWriter and its own copy of the held writer goes

Builds: design 47 G A-29, §689, §461
Claude-Session: https://claude.ai/code/session_01JG73KEq4zoDfM9WtYpcQgZ
This commit is contained in:
2026-11-11 22:03:27 +01:00
parent 08fcdac0f8
commit f531d5524d
@@ -14,21 +14,20 @@ import (
"mesh-delivery-watchman/internal/watch"
)
type findingWriterOf = views.Writer[condseat.Finding, condseat.FindingCleared, condseat.FindingsStated, condseat.FindingsAskedEvent]
type heldWriterOf = views.HeldWriter[condseat.Finding, condseat.FindingCleared, condseat.FindingsStated, condseat.FindingsAskedEvent]
// heldFindings is the watchman's findings through mesh-sdk's finding writer (design 47 G §461, §689): every finding the
// watchman holds, by its own key, which the writer states at its start and when the keeper asks, and writes and clears as the
// watchman puts and deletes them. It has a lock of its own, never the watchman's: the writer calls observe under its own
// lock while the watchman writes under its.
// heldFindings is the watchman's findings through mesh-sdk's held finding writer (design 47 G §461, §689, A-29): the writer
// holds what the watchman has put, states it at its start and when the keeper asks, writes and clears as the watchman puts and
// deletes. Here is only the watchman's own key of each finding, which the watchman deletes by.
type heldFindings struct {
mu sync.Mutex
held map[string]condseat.Finding
w *findingWriterOf
mu sync.Mutex
by map[string]condseat.Finding
w *heldWriterOf
}
// seedFindings reads the findings that stand in the state `findings` at the start, by the watchman's key of each.
func seedFindings(state process.State) (*heldFindings, map[string][]byte, error) {
h := &heldFindings{held: map[string]condseat.Finding{}}
h := &heldFindings{by: map[string]condseat.Finding{}}
seeds := map[string][]byte{}
keys, err := state.Keys()
if err != nil {
@@ -46,25 +45,16 @@ func seedFindings(state process.State) (*heldFindings, map[string][]byte, error)
if err != nil {
continue
}
h.held[f.Key()] = f.Contract()
h.by[f.Key()] = f.Contract()
seeds[f.Key()] = e.Value
}
return h, seeds, nil
}
// start makes and starts the writer: it states what is held at once, so the seeds are made before it.
// start makes and starts the held writer, which reads the state's findings itself before it states anything.
func (h *heldFindings) start(ctx context.Context, cred process.Account, conn *nats.Conn, js jetstream.JetStream, state process.State, logf func(string, ...any)) error {
w, err := views.NewWriter(views.WriterConfig[condseat.Finding, condseat.FindingCleared, condseat.FindingsStated, condseat.FindingsAskedEvent]{
w, err := views.NewHeldWriter(views.WriterConfig[condseat.Finding, condseat.FindingCleared, condseat.FindingsStated, condseat.FindingsAskedEvent]{
Module: cred.Module, State: state, Node: cred.Node, Asked: condseat.SubjectFindingsAsked, JS: js, Conn: conn, Logf: logf,
Observe: func(context.Context) (views.Observed[condseat.Finding], error) {
h.mu.Lock()
defer h.mu.Unlock()
var o views.Observed[condseat.Finding]
for _, f := range h.held {
o.Findings = append(o.Findings, f)
}
return o, nil
},
})
if err != nil {
return err
@@ -86,7 +76,7 @@ func (h *heldFindings) Put(ctx context.Context, key string, value []byte) error
}
c := f.Contract()
h.mu.Lock()
h.held[key] = c
h.by[key] = c
h.mu.Unlock()
return h.w.Write(ctx, c)
}
@@ -94,8 +84,8 @@ func (h *heldFindings) Put(ctx context.Context, key string, value []byte) error
// Delete clears the finding the watchman held under key.
func (h *heldFindings) Delete(ctx context.Context, key string) error {
h.mu.Lock()
c, ok := h.held[key]
delete(h.held, key)
c, ok := h.by[key]
delete(h.by, key)
h.mu.Unlock()
if !ok {
return nil