An address is read from the node's settings where it is used, never recorded with a port

Three readers did not follow a moved foundation port (novox/hq 04-ISSUES/102),
and each took the control-node down in its own way: the control plane's own
store and broker connections, sealed at genesis with the port inside; and every
build the mesh ever recorded, kept as `<registry>:<port>/<module>/<artifact>@…`.

The control plane cannot open its own sealed connections to move a port, and it
cannot bind the store as a consumer would — a binding mints a credential. So its
settings get a third twin, `NAME_PORT`, read on top of the sealed value by the
store, the broker, the management API and the bus connection, and filled into
its container by a placeholder that names a seat, `${seat:mesh-store:5432}`,
from the node's given or mesh-assigned ports — never the manifest's number, and
empty when the mesh has nothing to add, so what genesis wrote stands. A value
that is still a placeholder is nothing said, aloud: the manifest naming it lands
in the next commit, once every control plane that composes it knows it.

A build is now recorded by digest and path — `artifact-store://<module>/<artifact>@…`
— and the store's address is composed in where a reference is used: the
declaration, the trust file, the bases a build is handed, a replay to the
catalogue. Over the network as `<node>.internal:<port>`; on the store's own node
before any network exists — every genesis push before its "network" step — by
loopback. A reference recorded before this, with an address, is re-routed the
same way when the mesh built it. The trust file and every provider's address
come from one derivation: the node's given port, over the mesh's assignment,
over the manifest's number.

novox/hq 04-ISSUES/102
This commit is contained in:
2026-09-23 23:49:31 +02:00
parent 8fb32d7ee0
commit e07b56ce43
19 changed files with 1736 additions and 45 deletions
+14 -1
View File
@@ -173,11 +173,21 @@ func sayUpgrade(module string, u inventory.Upgrade) string {
// catalogue misses nothing — but the modules built before it first ran were announced to a queue
// that did not exist, and on a fresh mesh those are always the same three: the shared base, the
// store the catalogue runs on, and the catalogue itself.
//
// **Announced as fetchable, recorded as what it is** (novox/hq 04-ISSUES/102). A build is
// recorded by digest and path; the catalogue hears the builder's own announcements, which name
// the store's address, so a replay composes the address back in — the store's address as the
// network reaches it NOW, which is the whole point of not having recorded the old one. With no
// store on the network yet, the recorded form goes as it is.
func (f following) Announceable(ctx context.Context) ([]link.Announcement, error) {
builds, err := f.open.inventory.Announceable(ctx)
if err != nil {
return nil, err
}
address, err := whereTheStoreIs(ctx, f.open.inventory, "")
if err != nil {
return nil, err
}
out := make([]link.Announcement, 0, len(builds))
for _, b := range builds {
a := link.Announcement{
@@ -186,8 +196,11 @@ func (f following) Announceable(ctx context.Context) ([]link.Announcement, error
}
if len(b.Manifest) > 0 {
a.Manifest = b.Manifest
if address != "" {
a.Manifest = routedManifest(b.Manifest, b.Made, address)
}
}
for _, made := range b.Made {
for _, made := range routedArtifacts(b.Made, address) {
a.Made = append(a.Made, link.MadeArtifact{
Name: made.Name, Kind: made.Kind, Reference: made.Reference,
})