diff --git a/modules/mesh-delivery-builder/cmd/mesh-delivery-builder/main.go b/modules/mesh-delivery-builder/cmd/mesh-delivery-builder/main.go index cef81c7..54bf5fa 100644 --- a/modules/mesh-delivery-builder/cmd/mesh-delivery-builder/main.go +++ b/modules/mesh-delivery-builder/cmd/mesh-delivery-builder/main.go @@ -188,8 +188,8 @@ func run(ctx context.Context, getenv func(string) string, logOut io.Writer) erro } defer cc.Stop() } - // The controller says artifacts-gone when its take-in found a key's blob gone (issue 1937): the builder's durable - // consumer on EVENTS, made by the controller from the manifest's consumes. Where it is not there yet the builder says + // The seat mesh-artifact-sweep says artifacts-gone when it found a key's blob gone (issue 1937, ADR 0571 §2): the + // builder's durable consumer on EVENTS, made by the grants part from the manifest's consumes. Where it is not there yet the builder says // so; it still asks held at its start and at every module value. switch cons, err := cred.EventConsumer(ctx, js, eventsStream); { case err != nil: diff --git a/modules/mesh-delivery-builder/cmd/mesh-delivery-builder/stored.go b/modules/mesh-delivery-builder/cmd/mesh-delivery-builder/stored.go index dfad767..c5fc876 100644 --- a/modules/mesh-delivery-builder/cmd/mesh-delivery-builder/stored.go +++ b/modules/mesh-delivery-builder/cmd/mesh-delivery-builder/stored.go @@ -15,8 +15,8 @@ import ( "mesh-delivery-builder/internal/build" ) -// eventsStream is the stream every module's and role's events are on, where the controller makes the builder's durable -// consumer of artifacts-gone (mesh-controller internal/broker EventsStream). +// eventsStream is the stream every module's and role's events are on, where the grants part makes the builder's durable +// consumer of artifacts-gone (mesh-sdk buscompose EventsStream). const eventsStream = "EVENTS" // SeatHeld is the seat mesh-artifact-sweep's verb held (ADR 0571 §2). @@ -27,8 +27,7 @@ type toolCaller func(key string, body any) (json.RawMessage, error) // storedVia is build.Builder's Stored: it asks the seat mesh-artifact-sweep's `held` (novox/hq ADR 0571 §2, issue 1937) // and answers the references the store no longer holds. One it could not ask about, with none gone, is an error: the key -// is then left done, and the controller's take-in still refuses a gone blob. The controller's `held` is not asked: it -// is no longer a fallback (issue 1955). +// is then left done, and asked again at the next module value or artifacts-gone. func storedVia(call toolCaller) func(ctx context.Context, references []string) ([]string, error) { return func(_ context.Context, references []string) ([]string, error) { body := map[string]any{"references": references} diff --git a/modules/mesh-delivery-builder/internal/build/run.go b/modules/mesh-delivery-builder/internal/build/run.go index c7b812b..ed12024 100644 --- a/modules/mesh-delivery-builder/internal/build/run.go +++ b/modules/mesh-delivery-builder/internal/build/run.go @@ -260,8 +260,8 @@ func (b *Builder) storedOnce(key string) func(ctx context.Context, references [] } } -// ArtifactsGone takes the controller's event artifacts-gone in (issue 1937): a take-in found that the store does not -// hold what the module's key names. The module is looked at again, which asks the store (ClaimOptions.Stored) and +// ArtifactsGone takes the seat mesh-artifact-sweep's event artifacts-gone in (issue 1937, ADR 0571 §2): the sweep found +// that the store does not hold what the module's key names. The module is looked at again, which asks the store (ClaimOptions.Stored) and // builds the key again; an event for a fingerprint the module no longer has is said and left. The event only wakes the // builder: what is built rests on the store's answer, never on the event alone. func (b *Builder) ArtifactsGone(ctx context.Context, e delivery.ArtifactsGone) { diff --git a/modules/mesh-delivery-builder/manifest_test.go b/modules/mesh-delivery-builder/manifest_test.go index 9839cd0..f94b172 100644 --- a/modules/mesh-delivery-builder/manifest_test.go +++ b/modules/mesh-delivery-builder/manifest_test.go @@ -112,9 +112,9 @@ func TestManifestDeclarations(t *testing.T) { // 1607/AC1 t.Errorf("invokes = %v, config = %v, want %v and no config", m.Invokes, m.Config, want) } // The builder is woken by a build module's report of a toolchain, as the indexer is: the bucket may not exist when it - // starts; and by the controller's artifacts-gone, a take-in refused for a gone blob (1937/AC4). - // 1955/L7: and the seat mesh-artifact-sweep's, the controller's until the lease write (its take-in sweeps until then). - if want := []string{"mesh-artifact-sweep.artifacts-gone", "mesh-build-go.toolchain.reported", "mesh-build-node.toolchain.reported", "mesh-controller.artifacts-gone"}; !reflect.DeepEqual(sorted(m.Consumes), want) { + // starts; and by the seat mesh-artifact-sweep's artifacts-gone, a blob the sweep found gone (1937/AC4, 1955/L7), the + // controller's no longer (1126/B9, ADR 0590). + if want := []string{"mesh-artifact-sweep.artifacts-gone", "mesh-build-go.toolchain.reported", "mesh-build-node.toolchain.reported"}; !reflect.DeepEqual(sorted(m.Consumes), want) { t.Errorf("consumes = %v, want %v", m.Consumes, want) } if b, ok := m.OwnSecrets["broker"]; !ok || len(m.OwnSecrets) != 1 || b != "${dir:state}/broker" { diff --git a/modules/mesh-delivery-builder/module.json b/modules/mesh-delivery-builder/module.json index 3145361..4440f86 100644 --- a/modules/mesh-delivery-builder/module.json +++ b/modules/mesh-delivery-builder/module.json @@ -16,8 +16,7 @@ "consumes": [ "mesh-artifact-sweep.artifacts-gone", "mesh-build-go.toolchain.reported", - "mesh-build-node.toolchain.reported", - "mesh-controller.artifacts-gone" + "mesh-build-node.toolchain.reported" ], "invokes": [ "seat:mesh-artifact-sweep.held" diff --git a/modules/mesh-delivery-watchman/cmd/mesh-delivery-watchman/main_test.go b/modules/mesh-delivery-watchman/cmd/mesh-delivery-watchman/main_test.go index 892c16a..a5804e4 100644 --- a/modules/mesh-delivery-watchman/cmd/mesh-delivery-watchman/main_test.go +++ b/modules/mesh-delivery-watchman/cmd/mesh-delivery-watchman/main_test.go @@ -37,6 +37,13 @@ func TestRunNeedsItsCredential(t *testing.T) { // 1135/AC6 if routeOf("mesh.mod.web.event.started") != "" { t.Error("another module's event goes to a row") } + // 1126/B9 (ADR 0590 §3): the lease write's events went with it; the grants part says no lease event any more. + for _, gone := range []string{"mesh.seat.mesh-grants.event.lease-altered", "mesh.seat.mesh-grants.event.removal-failed", + "$JS.EVENT.ADVISORY.STREAM.DELETED.ASSIGNMENTS"} { + if r := routeOf(gone); r != "" && r != routeAdvisory { + t.Errorf("%s goes to the row %s", gone, r) + } + } }) err := run(context.Background(), func(string) string { return "" }, io.Discard) if err == nil || !strings.Contains(err.Error(), "MESH_BROKER_FILE") { diff --git a/modules/mesh-delivery-watchman/cmd/mesh-delivery-watchman/signals.go b/modules/mesh-delivery-watchman/cmd/mesh-delivery-watchman/signals.go index d2b9913..119b9b5 100644 --- a/modules/mesh-delivery-watchman/cmd/mesh-delivery-watchman/signals.go +++ b/modules/mesh-delivery-watchman/cmd/mesh-delivery-watchman/signals.go @@ -13,7 +13,6 @@ import ( "github.com/nats-io/nats.go/jetstream" "git.novox.be/novox/mesh-sdk/go/buscompose" - "git.novox.be/novox/mesh-sdk/go/catalogue" "git.novox.be/novox/mesh-sdk/go/health" "mesh-delivery-watchman/internal/deadletters" @@ -39,13 +38,6 @@ const ( routeDead = "dead-letter" routeBusFault = "bus-fault" routeProv = "provisioned" - routeLease = "lease" -) - -// The lease write's subjects (ADR 0582 clauses 4, 6): the seat mesh-grants' events, and ASSIGNMENTS deleted. -var ( - leaseEventPrefix = "mesh.seat." + catalogue.GrantsSeat + ".event." - assignmentsGone = "$JS.EVENT.ADVISORY.STREAM.DELETED." + buscompose.AssignmentsStream ) // The bus module's events of the connections the bus closed (S9). @@ -69,8 +61,6 @@ func routeOf(subject string) string { return routeTools case subject == CheckedSubject: return routeChecked - case strings.HasPrefix(subject, leaseEventPrefix) || subject == assignmentsGone: - return routeLease case strings.HasPrefix(subject, "$JS.EVENT.ADVISORY."): return routeAdvisory case strings.HasPrefix(subject, "mesh.events.dead."): @@ -106,7 +96,6 @@ func heard(w *watch.Watchman, dead *deadKeeper, m *nats.Msg, logf func(string, . } if dead.isTheControllersNotices(a.ID) { dead.check() // the controller's consumer removed: the watchman may take the notices now - w.RemovalGone(watch.RemovalConsumer) return } w.Advised(a) @@ -121,22 +110,6 @@ func heard(w *watch.Watchman, dead *deadKeeper, m *nats.Msg, logf func(string, . kind = watch.KindConnectionClosed } w.Closed(kind, c) - case routeLease: - var body struct { - Altered string `json:"altered"` - Failed string `json:"failed"` - } - _ = json.Unmarshal(m.Data, &body) - switch m.Subject { - case assignmentsGone: - w.RemovalGone(watch.RemovalStream) - case leaseEventPrefix + catalogue.GrantsEventLeaseAltered: - w.LeaseAltered(body.Altered) - case leaseEventPrefix + catalogue.GrantsEventLeaseHanded: - w.LeaseHanded() - case leaseEventPrefix + catalogue.GrantsEventRemovalFailed: - w.RemovalFailed(body.Failed) - } case routeProv: var r watch.ProvReport if err := json.Unmarshal(m.Data, &r); err != nil { diff --git a/modules/mesh-delivery-watchman/internal/deadletters/deadletters.go b/modules/mesh-delivery-watchman/internal/deadletters/deadletters.go index 4ad045a..c7c3015 100644 --- a/modules/mesh-delivery-watchman/internal/deadletters/deadletters.go +++ b/modules/mesh-delivery-watchman/internal/deadletters/deadletters.go @@ -1,13 +1,11 @@ -// Package deadletters is what a consumer gave up on, kept by the watchman from the lease write (novox/hq ADR 0564 §5, +// Package deadletters is what a consumer gave up on, kept by the watchman since the controller's end (novox/hq ADR 0564 §5, // ADR 0264, ADR 0376, issue 1952 WM5): ported from mesh-controller internal/link/deadletters.go at e04846e9 with nothing // changed in what is kept, aged or withheld, on the jetstream API. // -// DEAD_LETTER_NOTICES is a work queue that holds one consumer. The controller's consumer `controller` never expires, so -// the watchman makes its own (Consumer) only when the lease names no controller and `controller` is gone (Gate); while -// `controller` still stands after the lease write it says so as a finding. Removing `controller` is a step of the lease -// write, with the bus module's tool. Before the lease write the watchman only lists and shows DEAD_LETTERS, which the -// controller still fills, and refuses to deliver or drop, naming the controller's verb; from it, delivering and dropping -// wait for the hand-act log's home (issue 1953), so they are refused naming that. +// DEAD_LETTER_NOTICES is a work queue that holds one consumer. The ended controller's consumer `controller` never +// expires, so the watchman makes its own (Consumer) only once `controller` is gone (Gate); while it stands the watchman says +// so as a finding. Removing `controller` is a hand act with the bus module's tool (novox/hq ADR 0590 clause 6). Delivering +// and dropping wait for the hand-act log's home (issue 1953), so they are refused naming that. package deadletters import ( @@ -317,9 +315,8 @@ func Refusal(act string) error { } // Gate is whether the watchman takes the notices itself: once the controller's consumer is gone. waiting says `controller` -// still stands, which is the watchman's finding: each notice waits in the queue until that consumer is removed. The lease -// is not read: the controller ended by its unassignment, never by the lease write (issue 1126), and mesh-sdk's -// buscompose.LeaseHandedAway answers false for the absent key, which would keep the notices the controller's for good. +// still stands, which is the watchman's finding: each notice waits in the queue until that consumer is removed (the +// controller ended by its unassignment, issue 1126). func Gate(controllerStands bool) (take, waiting bool) { return !controllerStands, controllerStands } diff --git a/modules/mesh-delivery-watchman/internal/watch/advisories.go b/modules/mesh-delivery-watchman/internal/watch/advisories.go index d4d0057..91591ca 100644 --- a/modules/mesh-delivery-watchman/internal/watch/advisories.go +++ b/modules/mesh-delivery-watchman/internal/watch/advisories.go @@ -8,7 +8,7 @@ import ( // The bus's advisories the watchman hears (S9, mesh-controller internal/link/advisories.go at e04846e9): a durable consumer // the mesh defines deleted is `consumer-lost`. A message given up on is said from DEAD_LETTERS, where it is kept, for as -// long as it is kept (DeadLettersHeld), not from its advisory. The controller's own slow consumer and refused subjects end +// long as it is kept (DeadLettersHeld), not from its advisory. The controller's own slow consumer and refused subjects ended // with it (ADR 0564 §4). // Advisory subjects the watchman subscribes. @@ -48,7 +48,9 @@ func MeshNamed(stream, name string) bool { case strings.HasPrefix(stream, "SEAT_"): return strings.HasSuffix(name, "_worker") case name == "controller" || name == "controller-merges": - return true + // The ended controller's consumers are removed as hand acts (novox/hq ADR 0590 clause 6), never lost; its consumer on + // DEAD_LETTER_NOTICES alone is read, whose removal tells the watchman to take the notices. + return stream == "DEAD_LETTER_NOTICES" && name == "controller" case stream == "EVENTS": return strings.Contains(name, "_") } diff --git a/modules/mesh-delivery-watchman/internal/watch/dead.go b/modules/mesh-delivery-watchman/internal/watch/dead.go index 51b0747..d4b7d87 100644 --- a/modules/mesh-delivery-watchman/internal/watch/dead.go +++ b/modules/mesh-delivery-watchman/internal/watch/dead.go @@ -8,15 +8,15 @@ import ( ) // The dead letters' findings (novox/hq ADR 0564 §5, issue 330): a consumer DEAD_LETTERS holds a message for is said for as -// long as it holds any, `bus...max-deliveries`, and the notices waiting behind the controller's consumer -// after the lease write are said as `bus.DEAD_LETTER_NOTICES.controller.notices-waiting`. +// long as it holds any, `bus...max-deliveries`, and the notices waiting behind the ended controller's +// consumer are said as `bus.DEAD_LETTER_NOTICES.controller.notices-waiting`. // DeadRecountEvery is how often DEAD_LETTERS is counted again while a consumer's finding stands: a letter delivered again // or dropped by the controller's verb, which the watchman does not hear, ends its finding within it. The expiry of the // watchman's own pulse, never a loop. const DeadRecountEvery = 5 * time.Minute -// KindNoticesWaiting is the finding of notices waiting while the controller's consumer stands after the lease write. +// KindNoticesWaiting is the finding of notices waiting while the ended controller's consumer stands. const KindNoticesWaiting = "notices-waiting" // DeadLettersHeld is DEAD_LETTERS' count per consumer, `.`, read whole: each consumer held writes its @@ -73,16 +73,16 @@ func consumerMachine(stream, consumer string) string { return "" } -// NoticesWaiting says whether the lease is handed away while the controller's consumer on DEAD_LETTER_NOTICES still -// stands: every notice then waits in the queue, kept a week, until the lease write's step removes the consumer. +// NoticesWaiting says whether the ended controller's consumer on DEAD_LETTER_NOTICES still stands: every notice then waits +// in the queue, kept a week, until that consumer is removed (novox/hq ADR 0590 clause 6). func (w *Watchman) NoticesWaiting(waiting bool) { w.mu.Lock() defer w.mu.Unlock() f := Finding{Scope: ScopeBus, ID: "DEAD_LETTER_NOTICES.controller", Kind: KindNoticesWaiting, Severity: Warning, Source: "dead-letters", - Summary: "the lease names no controller but the controller's consumer on DEAD_LETTER_NOTICES still stands, so every " + - "notice of a message given up on waits in the queue, kept a week, and nothing keeps it in DEAD_LETTERS", - Said: "the consumer controller on DEAD_LETTER_NOTICES stands after the lease write", - Needs: "remove the consumer controller on DEAD_LETTER_NOTICES with the bus module's tool, the lease write's step."} + Summary: "the controller is unassigned but its consumer on DEAD_LETTER_NOTICES still stands, so every notice of a " + + "message given up on waits in the queue, kept a week, and nothing keeps it in DEAD_LETTERS", + Said: "the consumer controller on DEAD_LETTER_NOTICES stands after the controller's end", + Needs: "remove the consumer controller on DEAD_LETTER_NOTICES with the bus module's tool, recorded as a hand act (ADR 0590)."} if waiting { w.find(f) return diff --git a/modules/mesh-delivery-watchman/internal/watch/findings_test.go b/modules/mesh-delivery-watchman/internal/watch/findings_test.go index e1f83c2..91e165f 100644 --- a/modules/mesh-delivery-watchman/internal/watch/findings_test.go +++ b/modules/mesh-delivery-watchman/internal/watch/findings_test.go @@ -59,23 +59,6 @@ func TestTheWatchmansFindings(t *testing.T) { } w.ModuleVerdict("node-tools", value(""), Put) }, map[string]string{}}, - {"774/S22/AC1, AC2: lease-altered and removal-failed are findings; lease-handed and the removal read gone clear them", func(t *testing.T, w *Watchman, o *fakeOut, c *clock) { - w.LeaseAltered("the key holder names controller@a pid 9, not mesh-grants by lease-write-1") - if f := o.findings[FindingKey(ScopeBus, "mesh-controller_lease", KindLeaseAltered)]; !strings.Contains(f.Summary, "controller@a pid 9") { - t.Fatalf("findings = %v", o.findings) - } - w.LeaseHanded() - w.RemovalFailed("the stream ASSIGNMENTS: ASSIGNMENTS has 1 consumers") - k := FindingKey(ScopeBus, "lease-removal", KindRemovalFailed) - if f := o.findings[k]; !strings.Contains(f.Summary, "ASSIGNMENTS has 1 consumers") { - t.Fatalf("findings = %v", o.findings) - } - w.RemovalGone(RemovalConsumer) // not what it waits on - if _, ok := o.findings[k]; !ok { - t.Fatal("cleared by the consumer, while the stream it names stands") - } - w.RemovalGone(RemovalStream) - }, map[string]string{}}, {"WM4: a stuck key not moved is its finding, and its move deletes it", func(t *testing.T, w *Watchman, o *fakeOut, c *clock) { w.Step("go", "n1.ask1", runningStep("ask1", t0), Put) expire(w, c, pulseKeyOf(t, checksKey, "ask1"), 120*time.Second) @@ -157,6 +140,18 @@ func TestTheWatchmansFindings(t *testing.T) { if _, ok := ReadAdvisory("$JS.EVENT.ADVISORY.CONSUMER.DELETED.KV_x.abc", []byte(`{"stream":"KV_x","consumer":"abc"}`), nil); ok { t.Fatal("a reader's own consumer is said") } + // 1126/B9 (ADR 0590 clause 6): the ended controller's consumers are removed as hand acts, never lost; only its + // consumer on DEAD_LETTER_NOTICES is still read, which tells the watchman to take the notices. + for _, gone := range [][2]string{{"EVENTS", "controller"}, {"EVENTS", "controller-merges"}, {"CONTROL", "controller"}} { + body := []byte(`{"stream":"` + gone[0] + `","consumer":"` + gone[1] + `"}`) + if _, ok := ReadAdvisory("$JS.EVENT.ADVISORY.CONSUMER.DELETED."+gone[0]+"."+gone[1], body, func(s, c string) string { return c }); ok { + t.Errorf("the removal of %s.%s is said as a consumer lost", gone[0], gone[1]) + } + } + if _, ok := ReadAdvisory("$JS.EVENT.ADVISORY.CONSUMER.DELETED.DEAD_LETTER_NOTICES.controller", + []byte(`{"stream":"DEAD_LETTER_NOTICES","consumer":"controller"}`), func(s, c string) string { return c }); !ok { + t.Error("the removal of the controller's consumer on DEAD_LETTER_NOTICES is not read") + } w.Advised(a) w.Advised(a) k := "bus.EVENTS.ace_web.consumer-lost" diff --git a/modules/mesh-delivery-watchman/internal/watch/lease.go b/modules/mesh-delivery-watchman/internal/watch/lease.go deleted file mode 100644 index 5142c9d..0000000 --- a/modules/mesh-delivery-watchman/internal/watch/lease.go +++ /dev/null @@ -1,80 +0,0 @@ -package watch - -import ( - "strings" -) - -// **The lease write's findings** (novox/hq ADR 0582 clauses 4 and 6, issue 774): mesh-grants says lease-altered when the -// lease key or its bucket's expiry differs from what it wrote, and removal-failed when the day-later removal of the -// controller's consumer of DEAD_LETTER_NOTICES or the stream ASSIGNMENTS failed; the watchman raises each as a finding. -// lease-altered clears when lease-handed is said again (the operator asked the write again); removal-failed clears when -// what it names reads gone: the consumer's deletion advisory and ASSIGNMENTS' deletion advisory, each heard. - -// The two kinds. -const ( - KindLeaseAltered = "lease-altered" - KindRemovalFailed = "removal-failed" -) - -// The finding's IDs: the lease's bucket, and the removal. -const ( - leaseID = "mesh-controller_lease" - removalID = "lease-removal" -) - -// What a failed removal still waits on. -const ( - RemovalConsumer = "DEAD_LETTER_NOTICES.controller" - RemovalStream = "ASSIGNMENTS" -) - -// LeaseAltered raises the finding that the lease differs from what mesh-grants wrote, naming what changed. -func (w *Watchman) LeaseAltered(what string) { - w.mu.Lock() - defer w.mu.Unlock() - w.find(Finding{Scope: ScopeBus, ID: leaseID, Kind: KindLeaseAltered, Severity: Warning, Source: "mesh-grants", - Summary: "the controller's lease differs from what mesh-grants wrote: " + what, - Said: what, - Needs: "a look at who changed the lease; mesh-grants writes nothing until lease-write is asked again.", - Resolved: "lease-write is asked and warranted again, and the lease reads as written"}) -} - -// LeaseHanded clears the lease-altered finding: the lease reads as written again. -func (w *Watchman) LeaseHanded() { - w.mu.Lock() - defer w.mu.Unlock() - w.unfind(FindingKey(ScopeBus, leaseID, KindLeaseAltered)) -} - -// RemovalFailed raises the finding that the day-later removal failed, naming what failed; it waits on each of the -// consumer and the stream the failure names. -func (w *Watchman) RemovalFailed(failed string) { - w.mu.Lock() - defer w.mu.Unlock() - if w.removalWaits == nil { - w.removalWaits = map[string]bool{} - } - for _, what := range []string{RemovalConsumer, RemovalStream} { - if strings.Contains(failed, strings.SplitN(what, ".", 2)[0]) { - w.removalWaits[what] = true - } - } - if len(w.removalWaits) == 0 { // names neither: waits on both - w.removalWaits[RemovalConsumer], w.removalWaits[RemovalStream] = true, true - } - w.find(Finding{Scope: ScopeBus, ID: removalID, Kind: KindRemovalFailed, Severity: Warning, Source: "mesh-grants", - Summary: "the day-later removal of the controller's consumer and stream failed: " + failed, - Said: failed, - Needs: "a look at why; mesh-grants tries again in a day, and grants_removal_due starts it sooner.", - Resolved: "the controller's consumer of DEAD_LETTER_NOTICES and the stream ASSIGNMENTS read gone"}) -} - -// RemovalGone hears one of the two removed (RemovalConsumer or RemovalStream), and clears the finding once neither waits. -func (w *Watchman) RemovalGone(what string) { - w.mu.Lock() - defer w.mu.Unlock() - delete(w.removalWaits, what) - if len(w.removalWaits) == 0 { - w.unfind(FindingKey(ScopeBus, removalID, KindRemovalFailed)) - } -} diff --git a/modules/mesh-delivery-watchman/internal/watch/watch.go b/modules/mesh-delivery-watchman/internal/watch/watch.go index a8d355e..fa6d5b7 100644 --- a/modules/mesh-delivery-watchman/internal/watch/watch.go +++ b/modules/mesh-delivery-watchman/internal/watch/watch.go @@ -86,8 +86,6 @@ type Watchman struct { recount func() // waiting is, by `.`, each of its provisions in waits, with its words. waiting map[string]map[string]string - // removalWaits is what a failed removal of the lease write still waits on to read gone (lease.go). - removalWaits map[string]bool // health is each node's own health report, and tunnels each node's tunnel key from its record. health map[string]delivery.NodeHealth tunnels map[string]string diff --git a/modules/mesh-enrolment/cmd/mesh-enrolment/holder.go b/modules/mesh-enrolment/cmd/mesh-enrolment/holder.go index 1523556..35c5270 100644 --- a/modules/mesh-enrolment/cmd/mesh-enrolment/holder.go +++ b/modules/mesh-enrolment/cmd/mesh-enrolment/holder.go @@ -158,13 +158,6 @@ func checkTunnelKey(k string) error { return nil } -// issuing says whether issue is on, and why: always, since the controller ended by its unassignment, never by the lease -// write (issue 1126), so the seat is the only issuer (ADR 0587 §4). The lease is no longer read: mesh-sdk's -// buscompose.LeaseHandedAway answers false for the absent key, which would keep issuing off for good. -func (h *Holder) issuing() (bool, string) { - return true, "the seat is the only issuer: the controller ended by its unassignment (issue 1126)" -} - // openEnrolments reads every node key of the bucket. func (h *Holder) openEnrolments() (map[string]Row, map[string]Enrolment, error) { keys, err := h.Store.Keys() diff --git a/modules/mesh-enrolment/cmd/mesh-enrolment/tokens.go b/modules/mesh-enrolment/cmd/mesh-enrolment/tokens.go index a153797..79f6513 100644 --- a/modules/mesh-enrolment/cmd/mesh-enrolment/tokens.go +++ b/modules/mesh-enrolment/cmd/mesh-enrolment/tokens.go @@ -26,12 +26,6 @@ type TokenRow struct { Unsealed string `json:"unsealed,omitempty"` } -// Issuing is whether issue is on, and why. -type Issuing struct { - On bool `json:"on"` - Why string `json:"why"` -} - // Fill is how full the bucket is: its keys and the bytes of their values (the state's cap is the bus's, which no bundle // can read, so the fill is stated without it). type Fill struct { @@ -42,14 +36,13 @@ type Fill struct { // TokensAnswer is what `tokens` answers. type TokensAnswer struct { Open []TokenRow `json:"open"` - Issuing Issuing `json:"issuing"` Fill Fill `json:"fill"` History []json.RawMessage `json:"history,omitempty"` // HistoryFrom says where the history comes from, when one was asked for. HistoryFrom string `json:"history-from,omitempty"` } -// Tokens answers one open enrolment or all, with the bucket's fill, whether issuing is on and why, and with history the +// Tokens answers one open enrolment or all, with the bucket's fill, and with history the // ended enrolments the holder's own events say (ADR 0587 §8). func (h *Holder) Tokens(node string, history bool) (TokensAnswer, error) { rows, open, err := h.openEnrolments() @@ -57,8 +50,6 @@ func (h *Holder) Tokens(node string, history bool) (TokensAnswer, error) { return TokensAnswer{}, err } var out TokensAnswer - on, why := h.issuing() - out.Issuing = Issuing{On: on, Why: why} if keys, err := h.Store.Keys(); err == nil { out.Fill.Keys = len(keys) for _, k := range keys { diff --git a/modules/mesh-enrolment/cmd/mesh-enrolment/tokens_test.go b/modules/mesh-enrolment/cmd/mesh-enrolment/tokens_test.go index 9fd86e8..668f193 100644 --- a/modules/mesh-enrolment/cmd/mesh-enrolment/tokens_test.go +++ b/modules/mesh-enrolment/cmd/mesh-enrolment/tokens_test.go @@ -5,6 +5,7 @@ import ( "os" "path/filepath" "slices" + "strings" "testing" "time" @@ -25,7 +26,7 @@ func (r *rig) seed(node, address string, stage string) { } } -// 774/S54/AC1 and AC2: tokens answers each stage with its expiry, ask and revision, the fill and whether issuing is on; +// 774/S54/AC1 and AC2: tokens answers each stage with its expiry, ask and revision, and the fill; // for one node at live it relays the vault's sealed token and keeps nothing; and the manifest says what the code does. func tokensAnswersEachStageAndRelaysTheSealedTokenOfOneNode(t *testing.T) { r := newRig(t) @@ -43,8 +44,8 @@ func tokensAnswersEachStageAndRelaysTheSealedTokenOfOneNode(t *testing.T) { t.Errorf("row %+v lacks revision, expiry or ask, or relays a token for a list of all", row) } } - if !slices.Equal(stages, []string{"ace:asked", "g14:live", "novox:redeeming"}) || all.Fill.Keys != 6 || !all.Issuing.On { - t.Errorf("tokens %v, fill %+v, issuing %+v", stages, all.Fill, all.Issuing) + if !slices.Equal(stages, []string{"ace:asked", "g14:live", "novox:redeeming"}) || all.Fill.Keys != 6 { + t.Errorf("tokens %v, fill %+v", stages, all.Fill) } one, err := r.h.Tokens("g14", false) if err != nil || len(one.Open) != 1 || one.Open[0].Sealed != "sealed-for-g14" { @@ -59,11 +60,11 @@ func tokensAnswersEachStageAndRelaysTheSealedTokenOfOneNode(t *testing.T) { } } } - // 1126/A2/AC1: with no lease key issuing is on, and says why. + // 1126/B9 (ADR 0590 clause 4): the seat is the only issuer since the controller's unassignment, so tokens says no + // gate of issuing any more: nothing turns it off. on, _ := r.h.Tokens("", false) - mustContain(t, on.Issuing.Why, "unassignment") - if !on.Issuing.On { - t.Errorf("issuing is off with no lease key: %s", on.Issuing.Why) + if raw, _ := json.Marshal(on); strings.Contains(string(raw), `"issuing"`) { + t.Errorf("tokens still says a gate of issuing: %s", raw) } } diff --git a/modules/mesh-enrolment/cmd/mesh-enrolment/tools.go b/modules/mesh-enrolment/cmd/mesh-enrolment/tools.go index bc7a800..68a57e9 100644 --- a/modules/mesh-enrolment/cmd/mesh-enrolment/tools.go +++ b/modules/mesh-enrolment/cmd/mesh-enrolment/tools.go @@ -106,7 +106,7 @@ func Tools(h *Holder) []stdio.Tool { Run: func(a map[string]any) (any, error) { return h.Again(arg(a, "node")) }}, {Name: TokensTool, Description: "What the seat holds (novox/hq ADR 0587 §8): every open enrolment, or one node's, with its stage (asked, live or " + - "redeeming), address, expiry, ask, revision and age; whether issuing is on and why; the bucket's fill. With a node at stage live, the token sealed to the operator key, asked of the vault at " + + "redeeming), address, expiry, ask, revision and age; the bucket's fill. With a node at stage live, the token sealed to the operator key, asked of the vault at " + "this moment and relayed as the vault sealed it: the one route by which the operator gets a token, which this seat never " + "reads and keeps nowhere. With history=true the ended enrolments its events say. A machine stuck at redeeming shows here " + "with its age; revoke ends it. Read-only.",