From 860ccd7e300a703f8456872770e9e42bee91b66a Mon Sep 17 00:00:00 2001 From: jochen Date: Thu, 12 Nov 2026 23:12:41 +0100 Subject: [PATCH] H9: an entry asked again by hand is asked again in the shadow's cache too, so a candidate waits no longer on a not-found it holds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Builds: design 47 G §698 (entry-again), §421 (A-308: the shadow reads the entries its wants name) Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h --- cmd/mesh-host/nodeagent.go | 1 + internal/selfcompose/entries.go | 3 +++ internal/selfcompose/selfcompose.go | 4 +++- internal/selfcompose/shadow.go | 6 ++++++ 4 files changed, 13 insertions(+), 1 deletion(-) diff --git a/cmd/mesh-host/nodeagent.go b/cmd/mesh-host/nodeagent.go index 8a256529..29a2822d 100644 --- a/cmd/mesh-host/nodeagent.go +++ b/cmd/mesh-host/nodeagent.go @@ -689,6 +689,7 @@ func nodeAgent(ctx context.Context, opts options, signer ed25519.PublicKey, trus // composition bucket) is never applied. While the seat's assignment holds no key for this node it composes // nothing and keeps running what it runs; a assignment it cannot watch stops the agent, said, and it begins again. composer := selfComposer(session, node, hooks, say) + composer.AlsoEntryAgain = shadow.EntryAgain composer.OnEngine = session.Own.Set // the first composing names the engine's own module on a first start (§527, §634) machinesNow.Store(composer) // the machines a failing network part points at, by the assignments (issue 774) composerNow.Store(composer) // what the verb compose asks a pass of, this run's alone diff --git a/internal/selfcompose/entries.go b/internal/selfcompose/entries.go index c45daa2e..bcc6e610 100644 --- a/internal/selfcompose/entries.go +++ b/internal/selfcompose/entries.go @@ -505,6 +505,9 @@ func (c *Composer) FirstViews() (views []map[string]any, entries []EntryRow, wan // EntryAgain asks fp's entry of the catalog half again now (the seat's verb entry-again, §698): one the composer keeps, whatever // its state. The entry kept of it is dropped, so a pass holds the module until the answer. func (c *Composer) EntryAgain(ctx context.Context, fp string) error { + if c.AlsoEntryAgain != nil { + c.AlsoEntryAgain(ctx, fp) + } if !c.byEntries() { return fmt.Errorf("this engine reads no entry by fingerprint") } diff --git a/internal/selfcompose/selfcompose.go b/internal/selfcompose/selfcompose.go index 02b63622..ed533851 100644 --- a/internal/selfcompose/selfcompose.go +++ b/internal/selfcompose/selfcompose.go @@ -163,7 +163,9 @@ type Composer struct { // OnEngine is told the node-engine's own module each time a composing finds it (design 47 G §527, §634); set before the // composer runs. OnEngine func(module string) - env Env + // AlsoEntryAgain is told each entry asked again by hand, so the shadow's own cache of entries asks it again too. + AlsoEntryAgain func(ctx context.Context, fp string) + env Env mu sync.Mutex wants map[string]meshwants.WantsByWantNodeModuleValue // by module, the node's own under agent.NodeModule diff --git a/internal/selfcompose/shadow.go b/internal/selfcompose/shadow.go index 1fff9c71..9c58e4c2 100644 --- a/internal/selfcompose/shadow.go +++ b/internal/selfcompose/shadow.go @@ -825,3 +825,9 @@ func (c *Composer) sameValue(a, b string) (same, known bool) { } return bytes.Equal(x, y), true } + +// EntryAgain asks fp's entry of the catalog half again in the shadow's own cache, where the node's own composer was asked +// again by hand: an entry the shadow holds as not found stays so until it is asked (a build the half had not yet taken in). +func (s *Shadow) EntryAgain(ctx context.Context, fp string) { + _ = s.c.EntryAgain(ctx, fp) // refuses only an entry the shadow keeps none of +}