From ee54bae09f1bff4b2b7f0eb04f8ad30fd5c98d05 Mon Sep 17 00:00:00 2001 From: jochen Date: Wed, 4 Nov 2026 12:49:55 +0100 Subject: [PATCH] =?UTF-8?q?CAT-N8:=20the=20keeper's=20rows=20for=20each=20?= =?UTF-8?q?refusal=20ADR=200626=20=C2=A74=20names:=20a=20drop=20naming=20n?= =?UTF-8?q?o=20ask,=20a=20warrant=20at=20another=20level=20or=20from=20ano?= =?UTF-8?q?ther=20asker,=20a=20create=20no=20accepted=20manifest=20asks=20?= =?UTF-8?q?for,=20a=20snapshot=20that=20fails;=20each=20said=20why=20and?= =?UTF-8?q?=20deleting=20nothing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The keeper already reads the router's record of the ask on its own account and verifies the warrant itself (bound to this act on this entry, at the destroy level), so only the rows are new. Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig --- modules/nats/internal/keeper/keeper_test.go | 23 +++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/modules/nats/internal/keeper/keeper_test.go b/modules/nats/internal/keeper/keeper_test.go index 0453ea43e..6c273871c 100644 --- a/modules/nats/internal/keeper/keeper_test.go +++ b/modules/nats/internal/keeper/keeper_test.go @@ -69,6 +69,9 @@ func (b *fakeBus) Snapshot(_ context.Context, streams []string) (string, error) b.mu.Lock() defer b.mu.Unlock() b.snaps = append(b.snaps, streams) + if err := b.refuse["snapshot"]; err != nil { + return "", err + } return "/snapshots/" + strings.Join(streams, "+") + ".tar", nil } @@ -487,7 +490,27 @@ func TestTheKeeperMakesWhatAVerdictAsksForAndSaysIt(t *testing.T) { if got := put(Request{ID: "r1", Verb: VerbDrop, Module: "m", Local: "drafts", Ask: "bus-1", Caller: "person.jo"}); !strings.Contains(got.Error, "bound") || len(bus.deleted) != 0 { t.Fatalf("acted on a warrant for another act: %+v, deleted %v", got, bus.deleted) } + // ADR 0626 ยง4: the keeper trusts nothing in the request; each of these is refused, said why, and deletes nothing. + refused := func(r Request, why string) { + t.Helper() + if got := put(r); got.Done.IsZero() || !strings.Contains(got.Error, why) || len(bus.deleted) != 0 { + t.Errorf("%s: ended %+v, deleted %v: refused for %q", r.ID, got, bus.deleted, why) + } + } + refused(Request{ID: "r1a", Verb: VerbDrop, Module: "m", Local: "drafts", Caller: "person.jo"}, "names no ask") choose(asks.Act{"verb": "drop", "module": "m", "local": "drafts"}) + w.Level, w.Label, ask.Options[0].Level = asks.Approve, "Keep", asks.Approve + w.AskDigest = ask.Digest() + refused(Request{ID: "r1b", Verb: VerbDrop, Module: "m", Local: "drafts", Ask: "bus-1", Caller: "person.jo"}, "nothing is removed") + choose(asks.Act{"verb": "drop", "module": "m", "local": "drafts"}) + w.Asker = "mesh-grants" + refused(Request{ID: "r1c", Verb: VerbDrop, Module: "m", Local: "drafts", Ask: "bus-1", Caller: "person.jo"}, "no warrant") + refused(Request{ID: "r1d", Verb: VerbCreate, Module: "m", Local: "drafts", Caller: "person.jo"}, "no accepted manifest of m asks for drafts") + choose(asks.Act{"verb": "drop", "module": "m", "local": "drafts"}) + bus.refuse["snapshot"] = errors.New("no space") + refused(Request{ID: "r1e", Verb: VerbDrop, Module: "m", Local: "drafts", Ask: "bus-1", Caller: "person.jo"}, "the snapshot before drop failed, so nothing was removed") + delete(bus.refuse, "snapshot") + bus.snaps = nil out.reset() got := put(Request{ID: "r2", Verb: VerbDrop, Module: "m", Local: "drafts", Ask: "bus-1", Caller: "person.jo", Why: "unused"}) if got.Error != "" || fmt.Sprint(bus.snaps) != "[[KV_m_drafts]]" || fmt.Sprint(bus.deleted) != "[KV_m_drafts]" ||