Compare commits

...
1 Commits
Author SHA1 Message Date
jschoubben a98b6ba77e S6: the bus keeper treats a none-yet catalog half as not yet viewed
PlanCatalog plans nothing, deletes no plans key and orphans no entry while the
catalog half lists no module before any was seen; the first revision with
entries plans as before.

Builds: design 47 G A-367 (G-22-lead-answers-2.md), W22/Q4 of start-waits.md

Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
2026-11-13 20:48:04 +01:00
2 changed files with 50 additions and 4 deletions
+11 -1
View File
@@ -456,7 +456,8 @@ func (k *Keeper) statusWritten(s Status, err error) {
// watched branch's newest revision is applied (Heard), a module of the new form that sends gets its sent store, a drift // watched branch's newest revision is applied (Heard), a module of the new form that sends gets its sent store, a drift
// between branches is said once, and a module in no watched branch's newest revision has its plans key deleted, its // between branches is said once, and a module in no watched branch's newest revision has its plans key deleted, its
// entries then orphans. Before every watched branch has its first view it plans nothing, and says what it waits for in // entries then orphans. Before every watched branch has its first view it plans nothing, and says what it waits for in
// its status; the first plan checks what is held. // its status, and an answer listing no module before one has listed any is the same (none-yet); the first plan checks what
// is held.
func (k *Keeper) PlanCatalog() error { func (k *Keeper) PlanCatalog() error {
at := k.now() at := k.now()
view, err := k.Catalog() view, err := k.Catalog()
@@ -466,6 +467,15 @@ func (k *Keeper) PlanCatalog() error {
} }
k.mu.Lock() k.mu.Lock()
first := !k.viewed first := !k.viewed
// A catalog half with no module in it before any has been seen is a trunk with no revision yet (`none-yet`, design 47
// G A-367): not yet viewed, so nothing is planned, no plan deleted and no entry made an orphan for want of knowledge.
if first && len(view.Modules) == 0 {
k.mu.Unlock()
k.setStatus(func(s *Status) {
s.FirstView.Asked, s.FirstView.Error = at, "the catalog half lists no module yet (none-yet): nothing is planned or orphaned until a revision lists one"
})
return nil
}
k.viewed = true k.viewed = true
k.mu.Unlock() k.mu.Unlock()
var revision uint64 var revision uint64
+39 -3
View File
@@ -450,6 +450,9 @@ func TestTheKeeperMakesWhatAVerdictAsksForAndSaysIt(t *testing.T) {
if len(bus.created) != 0 { if len(bus.created) != 0 {
t.Fatalf("created %v before the first view", bus.created) t.Fatalf("created %v before the first view", bus.created)
} }
k.Catalog = func() (CatalogView, error) {
return CatalogView{Modules: []CatalogModule{{Accepted: Accepted{Module: "m", Digest: "d1", Revision: 3, BusState: []catalogue.BusStateEntry{drafts}}}}}, nil
}
if err := k.PlanCatalog(); err != nil { if err := k.PlanCatalog(); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -541,6 +544,37 @@ func TestTheKeeperMakesWhatAVerdictAsksForAndSaysIt(t *testing.T) {
t.Errorf("old sections %d: 8 MiB counted", k.Status().OldBytes) t.Errorf("old sections %d: 8 MiB counted", k.Status().OldBytes)
} }
}}, }},
// A-367: a trunk with no revision yet (none-yet) is not yet viewed: nothing is planned, deleted or orphaned.
{"a none-yet catalog half plans nothing and orphans nothing until a module is listed", func(t *testing.T, k *Keeper, bus *fakeBus, out *said) {
k.Heard(Accepted{Module: "m", Revision: 9, BusState: []catalogue.BusStateEntry{drafts}})
k.Catalog = func() (CatalogView, error) {
return CatalogView{Modules: []CatalogModule{{Accepted: Accepted{Module: "m", Revision: 9, BusState: []catalogue.BusStateEntry{drafts}}}}}, nil
}
_ = k.PlanCatalog()
k.mu.Lock()
k.viewed = false
k.mu.Unlock()
k.Catalog = func() (CatalogView, error) { return CatalogView{}, nil }
if err := k.PlanCatalog(); err != nil {
t.Fatal(err)
}
if _, ok := k.planned("m"); !ok {
t.Error("m's plan is deleted by a none-yet view")
}
if a := k.Held()["m"]; a.Made["drafts"].Orphaned {
t.Errorf("held %+v: drafts orphaned by a none-yet view", a)
}
if k.Viewed() || !strings.Contains(k.Status().FirstView.Error, "none-yet") {
t.Errorf("viewed %v, status %+v: none-yet is not a first view and says so", k.Viewed(), k.Status().FirstView)
}
k.Catalog = func() (CatalogView, error) {
return CatalogView{Modules: []CatalogModule{{Accepted: Accepted{Module: "m", Revision: 10, BusState: []catalogue.BusStateEntry{drafts}}}}}, nil
}
_ = k.PlanCatalog()
if !k.Viewed() || k.Status().FirstView.Error != "" {
t.Error("the first revision with entries is viewed and plans as before")
}
}},
// §538: a module in no watched branch's newest revision has its plans key deleted, its entries then orphans. // §538: a module in no watched branch's newest revision has its plans key deleted, its entries then orphans.
{"a module no watched branch lists loses its plan, its entries orphans", func(t *testing.T, k *Keeper, bus *fakeBus, out *said) { {"a module no watched branch lists loses its plan, its entries orphans", func(t *testing.T, k *Keeper, bus *fakeBus, out *said) {
k.Catalog = func() (CatalogView, error) { k.Catalog = func() (CatalogView, error) {
@@ -1240,9 +1274,11 @@ func TestTheKeeperMakesWhatAVerdictAsksForAndSaysIt(t *testing.T) {
} { } {
t.Run(row.name, func(t *testing.T) { t.Run(row.name, func(t *testing.T) {
k, bus, _, out := newKeeper(CatalogView{}) k, bus, _, out := newKeeper(CatalogView{})
if err := k.PlanCatalog(); err != nil { // The rows start after the first view: an empty answer is none-yet (A-367), so the view is marked answered here.
t.Fatal(err) k.mu.Lock()
} k.viewed = true
k.mu.Unlock()
k.setStatus(func(s *Status) { s.FirstView.Asked, s.FirstView.Answered = k.now(), k.now() })
row.run(t, k, bus, out) row.run(t, k, bus, out)
}) })
} }