Self-upgrade installer: SDK-by-version, mesh-controller rename, foundation adopted #26

Merged
jschoubben merged 17 commits from feat/a-bed-that-hands-over-nothing into main 2026-09-16 21:21:34 +00:00
3 changed files with 65 additions and 3 deletions
Showing only changes of commit 2b82872ac3 - Show all commits
+6
View File
@@ -72,6 +72,12 @@ func buildFrom(result link.BuildResult) inventory.Build {
kept := inventory.Build{
ID: result.ID, Repository: result.Repository, Ref: result.Ref,
Commit: result.Commit, On: result.On, Failed: result.Failed,
// **What the announcement carries, kept rather than discarded** (novox/hq 04-ISSUES/050).
// The catalogue turns the manifest into requires/provides edges and `against` into build
// edges, and it is not always listening when a build happens — on a fresh mesh it cannot
// be, for exactly the modules it needs most. Keeping them is what makes a replay able to
// rebuild the graph rather than a list of names.
Path: result.Path, Manifest: result.Manifest, Against: result.Against,
}
for _, made := range result.Made {
kept.Made = append(kept.Made, inventory.Artifact{
+33 -3
View File
@@ -23,6 +23,18 @@ type Build struct {
Commit string
// On is the machine that did it.
On string
// Path is where inside the repository the module lives (novox/hq ADR 0069).
Path string
// Manifest is the declaration the builder resolved, as it announced it.
//
// **Kept because the catalogue may not have been listening.** The announcement carries this
// and the catalogue turns it into the module's requires/provides edges. On a fresh mesh the
// modules built before the catalogue exists are exactly the ones it most needs, so the mesh
// has to be able to say afterwards what they declared (novox/hq 04-ISSUES/050).
Manifest []byte
// Against is every artifact this build stood on, as references rather than module names —
// what makes a build edge derived rather than declared (ADR 0009).
Against []string
// Failed is the builder's own words, empty when it worked.
Failed string
Made []Artifact
@@ -49,15 +61,21 @@ func (i *Inventory) RecordBuild(ctx context.Context, b Build) error {
if err != nil {
return err
}
against, err := json.Marshal(b.Against)
if err != nil {
return err
}
var module *string
if b.Module != "" {
module = &b.Module
}
_, err = i.store.Pool().Exec(ctx,
`insert into build (id, repository, ref, module, commit_hash, built_on, failed, made)
values ($1, $2, $3, $4, $5, $6, $7, $8)
`insert into build (id, repository, ref, module, commit_hash, built_on, failed, made,
source_path, manifest, built_against)
values ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
on conflict (id) do nothing`,
b.ID, b.Repository, b.Ref, module, b.Commit, b.On, b.Failed, made)
b.ID, b.Repository, b.Ref, module, b.Commit, b.On, b.Failed, made,
b.Path, manifestOrNil(b.Manifest), against)
return err
}
@@ -144,3 +162,15 @@ func (i *Inventory) Held(ctx context.Context) (map[string]string, error) {
}
return held, rows.Err()
}
// manifestOrNil keeps the difference between "declared nothing" and "predates this being kept".
//
// A build recorded before the mesh kept manifests has no manifest, and that is not the same as one
// whose manifest was empty. A replay can then say which it is holding instead of inventing an
// empty declaration for a module that certainly had one.
func manifestOrNil(raw []byte) any {
if len(raw) == 0 {
return nil
}
return raw
}
@@ -0,0 +1,26 @@
-- What a build result carried and the mesh threw away.
--
-- novox/hq 04-ISSUES/050. The builder announces a build with the resolved manifest, the path
-- inside the repository, and every artifact it was built against. The control plane receives all
-- of it and kept none of it: `build` held the repository, the ref, the commit and what was made.
--
-- That was survivable while the catalogue heard the same announcement directly. It stops being
-- survivable the moment the catalogue was not there to hear it — which on a fresh mesh is always,
-- and always for the same modules. The shared base, the store the catalogue itself runs on, and
-- the catalogue: each is necessarily built BEFORE the catalogue exists to hear about it, so the
-- graph's foundation is the part the graph never sees.
--
-- Replaying those builds needs what they said, not a summary of it. Without the manifest there
-- are no requires/provides edges; without `against` there are no build edges, which are the ones
-- that answer "a base moved, what must be rebuilt". A replay carrying neither would restore the
-- module list and leave the question the catalogue exists for still wrong, while looking fixed.
--
-- Empty and null-free, so every build recorded before this keeps exactly the meaning it had: a
-- row with no manifest is one that predates this, and a replay says so rather than inventing an
-- empty declaration.
--
-- `built_against` rather than `built_on`: that column already exists and means the MACHINE that
-- did the build, which is a different fact about a different subject.
alter table build add column source_path text not null default '';
alter table build add column manifest jsonb;
alter table build add column built_against jsonb;