The packages port given at genesis is a module's setting, like every other

Every foundation port given at genesis became a per-node setting of the module
that binds it, except the package registry's: that one was fixed by rewriting
the builder's manifest when the installer registered it. Registering the builder
again from the catalogue undid it, and the forge's own module, when it took the
bootstrap forge over, came up on the catalogue's port — which on a machine where
a predecessor holds 3000 points the builder at the predecessor's forge.

So the rewrite is gone, and the port is recorded twice as a setting, both from
the one input:

- the forge's module is registered at genesis — not assigned, nothing of it runs
  — so the controller has something to hold `{"ports": {"3000": <given>}}`
  against. Assigning the forge later raises it on the port this machine was
  given, and its container, its filter rule, its opening, what it serves and
  what consumers are told all read it from there.
- the builder is given `{"serves": {"port": <given>}}`, which merges into the
  binding it carries in place of one nothing can resolve yet.

A genesis on the catalogue's port records nothing and registers nothing, so it
does exactly what it did before.

novox/hq 04-ISSUES/085, ADR 0100
This commit is contained in:
2026-09-22 21:40:02 +02:00
parent 0db1fbdb3b
commit c4ce57997e
6 changed files with 179 additions and 70 deletions
-27
View File
@@ -1,10 +1,8 @@
package bootstrap
import (
"bytes"
"context"
"fmt"
"strconv"
"strings"
)
@@ -55,9 +53,6 @@ func InstallBuilder(ctx context.Context, o Options, d Deps, control controlPlane
"This is the manifest that makes the builder an ordinary module. Without it the mesh "+
"has the image and no way to run it, so nothing can be built here", err)
}
if manifest, err = followPackagesPort(manifest, o.Ports.orDefaults().Packages); err != nil {
return out, err
}
pinned, places, err := pinPlaceholder(manifest, published.Reference, BuilderModule)
if err != nil {
return out, err
@@ -89,25 +84,3 @@ func InstallBuilder(ctx context.Context, o Options, d Deps, control controlPlane
out.Installed.Pushed, err = pushNode(ctx, o, control, say)
return out, err
}
// packagesPortInBinding is the package registry's port as the builder's manifest names it, in the
// binding file it carries — JSON inside a JSON string, so its quotes are escaped.
const packagesPortInBinding = `\"port\": 3000`
// followPackagesPort points the builder's package binding at the port the node gave the package
// registry (novox/hq ADR 0100). Genesis raises the registry by hand before gitea is a module, so no
// binding the controller resolves can say where it is; the builder carries the address in its own
// manifest, and a port given at genesis must reach it there or the base build dials a port nothing
// answers on. At the default it is left byte for byte as the catalogue has it.
func followPackagesPort(manifest []byte, port int) ([]byte, error) {
if port == defaultGiteaPort {
return manifest, nil
}
if n := bytes.Count(manifest, []byte(packagesPortInBinding)); n != 1 {
return nil, fmt.Errorf("the builder's manifest names the package registry's port %d time(s) where "+
"this installer looks for it once (%s), so the port given with --packages-port cannot reach "+
"it; nothing was changed", n, packagesPortInBinding)
}
return bytes.Replace(manifest, []byte(packagesPortInBinding),
[]byte(`\"port\": `+strconv.Itoa(port)), 1), nil
}