Files
mesh-delivery/modules/mesh-delivery-builder/internal/versions/oldform.go
T
jschoubben 2274155766 DLV-B3, DLV-B3b, DLV-B9: the floor's three sources and what wakes a silent one; the old reference form's window
The floor asks the seat's versions, bridge_tags and indexer_requirements; a silent source is named in the
floor finding and woken by an event of that source (the holder's published, the forge bridge's next message, the
indexer's next manifest-accepted) or its module's condition clearing, or by hand (builder_floor_again), never by
a timer (design 51 *The floor*, ADR 0617 §1). The old form's window (ADR 0624 §1-§3, ADR 0618 §2): each counted
engine gets the newest form it reads among those written, the new form only once every present engine states
it, the oldest kept in the single reference; a node not serving manifest-reads counts as the baseline; a node
dropped by hand counts no more; old-form-closed is said once, and a node holding it seven days is a finding.

Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
2026-11-04 11:41:05 +01:00

166 lines
6.0 KiB
Go

package versions
import (
"slices"
"sort"
"time"
)
// The old reference form's window (design 51 *Every build keeps the old reference form*, ADR 0624, ADR 0618 §2-§4,
// DLV-B9). The builder writes into every build key each reference form a counted node-engine states, the oldest of them
// into the key's single reference and the others beside it; the new form only once every present node-engine states it.
// The window closes when no counted node-engine states the old form alone. What each node states is read through the
// node-engine seat's verb `manifest-reads` at the builder's start and again on the seat's event
// `manifest-reads-changed`, never by a watch of the node-engine's state and never on a timer.
// NodeReads is one counted node: what its node-engine states of the reference forms, and whether it is present. Stated
// nil is a node-engine that states nothing, or does not serve `manifest-reads` yet: read as the baseline's forms.
type NodeReads struct {
Node string `json:"node"`
Present bool `json:"present"`
Stated []string `json:"stated,omitempty"`
// Serves is false while the node-engine does not serve `manifest-reads`: it counts as stating the baseline.
Serves bool `json:"serves"`
}
// FormsAnswer is what the builder writes into a build key, and why.
type FormsAnswer struct {
// Single is the form written into the key's single reference: the oldest a counted engine states.
Single string `json:"single"`
// Beside are the other forms written beside it, oldest first.
Beside []string `json:"beside,omitempty"`
// Open is whether the old form's window is open: a counted engine states the oldest form alone.
Open bool `json:"open"`
// Holding are the counted nodes whose engine states the oldest form alone (present or away), sorted.
Holding []string `json:"holding,omitempty"`
}
// Forms decides the reference forms of new build keys. forms are every reference form the builder can write, oldest
// first; baseline what an engine stating nothing reads; dropped the nodes a person dropped from the count by hand
// (builder_old_form, a hand act), which then count no more. A node leaves the count when it is retired (by hand here),
// never because it is away (ADR 0624 §1).
func Forms(forms, baseline []string, nodes []NodeReads, dropped map[string]bool) FormsAnswer {
if len(forms) == 0 {
return FormsAnswer{}
}
oldest, newest := forms[0], forms[len(forms)-1]
type counted struct {
node string
reads []string
}
var cs []counted
everyPresentNewest := true
var holding []string
for _, n := range nodes {
if dropped[n.Node] {
continue
}
stated := n.Stated
if !n.Serves || len(stated) == 0 {
stated = baseline
}
var reads []string
for _, f := range forms {
if slices.Contains(stated, f) {
reads = append(reads, f)
}
}
if n.Present && !slices.Contains(reads, newest) {
everyPresentNewest = false
}
if len(reads) == 1 && reads[0] == oldest {
holding = append(holding, n.Node)
}
cs = append(cs, counted{n.Node, reads})
}
// The new form is written once every present engine states it (ADR 0618 §2); each counted engine then gets the
// newest form it reads among those written, so a form leaves once no counted engine needs it (ADR 0624 §1). An
// engine reading none of them is held by the assigner (ADR 0624 §2), not served by an older form here.
keep := map[string]bool{}
if everyPresentNewest {
keep[newest] = true
}
for _, c := range cs {
for i := len(c.reads) - 1; i >= 0; i-- {
if f := c.reads[i]; f != newest || everyPresentNewest {
keep[f] = true
break
}
}
}
var kept []string
for _, f := range forms {
if keep[f] {
kept = append(kept, f)
}
}
if len(kept) == 0 {
kept = []string{oldest} // nothing counted: the oldest stays, so no engine is cut off
}
sort.Strings(holding)
var beside []string
if len(kept) > 1 {
beside = kept[1:]
}
return FormsAnswer{Single: kept[0], Beside: beside, Open: len(holding) > 0, Holding: holding}
}
// OldFormWindow is the window's record: whether it is open, who holds it and since when, and the nodes dropped by
// hand; what builder_old_form answers and what `old-form-closed` carries when it closes.
type OldFormWindow struct {
Open bool `json:"open"`
Holding []string `json:"holding,omitempty"`
Since map[string]time.Time `json:"since,omitempty"`
Dropped []Dropped `json:"dropped,omitempty"`
Closed time.Time `json:"closed,omitempty"`
// LastHolding are the nodes that held it last, said when it closes.
LastHolding []string `json:"last_holding,omitempty"`
}
// Dropped is one node dropped from the count by hand: a hand act with who and why.
type Dropped struct {
Node string `json:"node"`
By string `json:"by"`
Why string `json:"why"`
At time.Time `json:"at"`
}
// FindingAfter is how long a node holds the window open before it is the builder's finding naming the node.
const FindingAfter = 7 * 24 * time.Hour
// Step moves the window to what Forms answered at now: it answers the new window, whether it closed in this step (so
// the builder says `old-form-closed` and its build-log line once), and the nodes holding it past FindingAfter (the
// finding, cleared when the window closes).
func (w OldFormWindow) Step(a FormsAnswer, now time.Time) (next OldFormWindow, closed bool, overdue []string) {
next = OldFormWindow{Dropped: w.Dropped, Since: map[string]time.Time{}}
if !a.Open {
if w.Open {
next.Closed, next.LastHolding = now, w.Holding
return next, true, nil
}
next.Closed, next.LastHolding = w.Closed, w.LastHolding
return next, false, nil
}
next.Open, next.Holding = true, a.Holding
for _, n := range a.Holding {
since, had := w.Since[n]
if !had {
since = now
}
next.Since[n] = since
if now.Sub(since) >= FindingAfter {
overdue = append(overdue, n)
}
}
return next, false, overdue
}
// DroppedSet is the dropped nodes as Forms takes them.
func (w OldFormWindow) DroppedSet() map[string]bool {
out := map[string]bool{}
for _, d := range w.Dropped {
out[d.Node] = true
}
return out
}