Held writer: a part names the keys it cannot judge yet in its findings-stated's pending

views.HeldWriter gains Pend and Judged: a key pended is named, with its since and bound, in every
statement until the part judges it, a key pended again keeping its first since. The tool runner pends
an acted, unrecorded ask's call-unanswered at its start until its warranted is made again.

Builds: design 46 7-approval-mark §16; design 47 G §384

Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
This commit is contained in:
2026-11-12 05:45:15 +01:00
parent 6209734dc3
commit aabece5ce3
2 changed files with 37 additions and 1 deletions
+28 -1
View File
@@ -4,6 +4,7 @@ import (
"context"
"encoding/json"
"errors"
"sort"
"sync"
)
@@ -20,6 +21,9 @@ type HeldWriter[F, C, S, A any] struct {
started bool
pending map[string]F // written before Start, written through the writer at Start
cleared map[string][4]string // cleared before Start, cleared through the writer at Start
// pends are the keys the part cannot judge yet since its start (design 47 G §384): a kept call it has not yet made
// again, named in every statement until the part judges it.
pends map[string]PendingKey
}
// NewHeldWriter makes the writer for cfg, whose Observe is none (a given Observe is refused): the findings that stand in
@@ -32,7 +36,7 @@ func NewHeldWriter[F, C, S, A any](cfg WriterConfig[F, C, S, A]) (*HeldWriter[F,
if cfg.State == nil {
return nil, errors.New("a finding writer needs the state `findings`")
}
h := &HeldWriter[F, C, S, A]{held: map[string]F{}}
h := &HeldWriter[F, C, S, A]{held: map[string]F{}, pends: map[string]PendingKey{}}
h.state, h.pending, h.cleared = cfg.State, map[string]F{}, map[string][4]string{}
cfg.Observe = func(context.Context) (Observed[F], error) {
h.mu.Lock()
@@ -41,6 +45,10 @@ func NewHeldWriter[F, C, S, A any](cfg WriterConfig[F, C, S, A]) (*HeldWriter[F,
for _, f := range h.held {
o.Findings = append(o.Findings, f)
}
for _, p := range h.pends {
o.Pending = append(o.Pending, p)
}
sort.Slice(o.Pending, func(i, j int) bool { return o.Pending[i].Key < o.Pending[j].Key })
return o, nil
}
w, err := NewWriter(cfg)
@@ -100,6 +108,25 @@ func (h *HeldWriter[F, C, S, A]) WriteWire(ctx context.Context, finding map[stri
return h.Write(ctx, f)
}
// Pend names a key the part cannot judge yet since its start, with its since and its bound, in every statement until Judged
// (design 47 G §384; design 46 7-approval-mark §16: an acted ask whose hand-act is not yet asked again). A key pended again
// keeps its first since.
func (h *HeldWriter[F, C, S, A]) Pend(p PendingKey) {
h.mu.Lock()
defer h.mu.Unlock()
if was, ok := h.pends[p.Key]; ok {
p.Since = was.Since
}
h.pends[p.Key] = p
}
// Judged ends a key's pending: the part judged it, raising or clearing its finding as it found.
func (h *HeldWriter[F, C, S, A]) Judged(key string) {
h.mu.Lock()
defer h.mu.Unlock()
delete(h.pends, key)
}
// Held answers the findings the writer holds, a copy taken under its lock (design 47 G A-38), so a part reads its open findings
// from the writer.
func (h *HeldWriter[F, C, S, A]) Held() []F {
+9
View File
@@ -505,6 +505,12 @@ func subHeldWriterStatesWhatItHoldsFromItsOwnState(t *testing.T) {
if err := h.Clear(ctx, "module", "seeded", "k", "no longer"); err != nil {
t.Fatal(err)
}
// a key the part cannot judge yet is named in the statement's pending until judged (design 47 G §384), keeping its since
since := time.Date(2026, 11, 12, 9, 0, 0, 0, time.UTC)
h.Pend(views.PendingKey{Key: "machine.n1.a2.call-unanswered", Since: since, Bound: "5m"})
h.Pend(views.PendingKey{Key: "machine.n1.a2.call-unanswered", Since: since.Add(time.Hour), Bound: "5m"})
h.Pend(views.PendingKey{Key: "machine.n1.a3.call-unanswered", Since: since, Bound: "5m"})
h.Judged("machine.n1.a3.call-unanswered")
sent = nil
if err := h.State(ctx, "a1"); err != nil {
t.Fatal(err)
@@ -514,6 +520,9 @@ func subHeldWriterStatesWhatItHoldsFromItsOwnState(t *testing.T) {
len(stated.Findings) != 2 || stated.Asked != "a1" {
t.Fatalf("the statement says %+v after %d events", stated, len(sent))
}
if p := stated.Pending; len(p) != 1 || p[0].Key != "machine.n1.a2.call-unanswered" || !p[0].Since.Equal(since) || p[0].Bound != "5m" {
t.Fatalf("the statement's pending is %+v", p)
}
if held := h.Held(); len(held) != 2 {
t.Fatalf("Held answers %v", held)
} else if held[0].ID = "mutated"; len(h.Held()) != 2 {