From 493e69e883d70437f345db986d37f791a56a2b36 Mon Sep 17 00:00:00 2001 From: jochen Date: Tue, 3 Nov 2026 13:54:35 +0100 Subject: [PATCH] =?UTF-8?q?A=20module=20value=20carries=20the=20source=20r?= =?UTF-8?q?evision=20at=20which=20its=20fingerprint=20last=20changed,=20a?= =?UTF-8?q?=20have=20says=20what=20the=20node=20keeps=20as=20it=20runs=20f?= =?UTF-8?q?or=20a=20manifest=20that=20does=20not=20yet=20say=20it,=20and?= =?UTF-8?q?=20a=20want=20names=20a=20release=20only=20beside=20the=20yes?= =?UTF-8?q?=20it=20gave=20(ADR=200601=20=C2=A71,=20=C2=A74;=20review=20rou?= =?UTF-8?q?nd=201)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go/delivery/assigner.go | 2 ++ go/delivery/delivery.go | 4 ++++ go/delivery/delivery_test.go | 6 ++++++ go/delivery/source.go | 13 +++++++++---- go/delivery/source_test.go | 2 +- go/delivery/want_composed_test.go | 1 + 6 files changed, 23 insertions(+), 5 deletions(-) diff --git a/go/delivery/assigner.go b/go/delivery/assigner.go index 3fbe5be..3f439a2 100644 --- a/go/delivery/assigner.go +++ b/go/delivery/assigner.go @@ -234,6 +234,8 @@ func (w Want) check() error { if err := checkDigest(w.Yes, "the digest a want's yes allows"); err != nil { return err } + } else if w.Release != "" { + return fmt.Errorf("delivery: the want of %s names the release %s and no yes it gave", w.FP, w.Release) } switch w.Backup { case "", BackupAgain, BackupSkip: diff --git a/go/delivery/delivery.go b/go/delivery/delivery.go index 10d23a9..bd84f9c 100644 --- a/go/delivery/delivery.go +++ b/go/delivery/delivery.go @@ -356,6 +356,10 @@ type Have struct { // release that carries the new build answers the yes. False when a setting or a secret changed too, or the node could // not tell: the move is then asked of a person as before. BuildAlone bool `json:"build-alone,omitempty"` + // Kept says, in words, what the node keeps of the module as it runs because its manifest does not yet say what shared + // code no longer infers (that it is the tool runner, that its own secrets are the core's credentials; novox/hq ADR 0601 + // §4): the watchman raises a condition from it, cleared once the have says none. Empty in every other have. + Kept []string `json:"kept,omitempty"` // Sealed is, for a module the node composes itself, each value its running composition carries sealed to the node's // key (a secret, a credential, a vault box), as applied (ADR 0547 §3, issue 1126): what the node's composer reuses // after a restart while it opens to the vault's value, so a value sealed again moves no composition. Openable by the diff --git a/go/delivery/delivery_test.go b/go/delivery/delivery_test.go index 1d341a6..c54fdbd 100644 --- a/go/delivery/delivery_test.go +++ b/go/delivery/delivery_test.go @@ -388,6 +388,12 @@ func testPhaseHealthRefused(t *testing.T) { } else if back, err := DecodeHave(raw); err != nil || !back.BuildAlone { t.Errorf("a have waiting for a yes to its build alone came back %+v, %v", back, err) } + // ADR 0601 §4: what the node keeps as it runs, read back as said. + if raw, err := EncodeHave(Have{Phase: PhaseRunning, Health: HealthOK, Kept: []string{"runs the tool runner"}}); err != nil { + t.Errorf("a have keeping what runs: %v", err) + } else if back, err := DecodeHave(raw); err != nil || len(back.Kept) != 1 { + t.Errorf("a have keeping what runs came back %+v, %v", back, err) + } for name, h := range map[string]Have{ "running build alone": {Phase: PhaseRunning, Health: HealthOK, BuildAlone: true}, "neither judged": {Phase: PhaseWaitingYes, Health: HealthOK, Judgement: JudgedNeither, Waits: waits.Waits}, diff --git a/go/delivery/source.go b/go/delivery/source.go index c872d5a..efa2e7f 100644 --- a/go/delivery/source.go +++ b/go/delivery/source.go @@ -404,10 +404,15 @@ type Module struct { Manifest string `json:"manifest,omitempty"` // Inputs2 are the new-form inputs the merge gave the module, kept so the indexer computes FP2 again when a build // module's toolchain versions appear, with no merge (novox/hq ADR 0465 clause 2). It needs Manifest. - Inputs2 *KeptInputs2 `json:"inputs2,omitempty"` - Src uint64 `json:"src,omitempty"` - Repository string `json:"repository"` - Commit string `json:"commit"` + Inputs2 *KeptInputs2 `json:"inputs2,omitempty"` + Src uint64 `json:"src,omitempty"` + // FPSrc is the source revision at which FP2 last changed (novox/hq ADR 0601 §1): Src when a merge of the module's own + // repository moved it, the source revision of the moment when a recompute with no such merge moved it (a toolchain, + // a package, a base). The release that moved the source to it is the one that carries the build; 0 is not known, and + // no release is taken to carry it. Src and Commit stay where the module was last merged and say nothing of that. + FPSrc uint64 `json:"fp-src,omitempty"` + Repository string `json:"repository"` + Commit string `json:"commit"` // Path is the module's directory in its repository, trimmed of slashes, and RootPath (".") when its manifest is the // repository's root (novox/hq ADR 0478 clause 9, issue 1615): the build tools need it. Empty means not known: a value // written before the indexer learned paths has none. diff --git a/go/delivery/source_test.go b/go/delivery/source_test.go index 498a8a9..33d1c12 100644 --- a/go/delivery/source_test.go +++ b/go/delivery/source_test.go @@ -179,7 +179,7 @@ func TestSourceValuesRoundTrip(t *testing.T) { // 1200/AC3 t.Errorf("candidate round trip: %+v %v", got, err) } for _, m := range []Module{ - {FP: "src1:abc", Src: 5, Repository: "novox/mesh-sdk", Commit: "cccc"}, + {FP: "src1:abc", Src: 5, FPSrc: 5, Repository: "novox/mesh-sdk", Commit: "cccc"}, {None: "a build that resolves packages when built", Repository: "novox/mesh-sdk", Commit: "cccc"}, } { data, err = EncodeModule(m) diff --git a/go/delivery/want_composed_test.go b/go/delivery/want_composed_test.go index eec127f..77b9bf6 100644 --- a/go/delivery/want_composed_test.go +++ b/go/delivery/want_composed_test.go @@ -46,6 +46,7 @@ func TestAWantNamesItsComposition(t *testing.T) { {Want{FP: fp2of('a'), Self: true, Yes: "sha256:12"}, "a want's yes allows"}, {Want{Removed: true, Self: true}, "removed want names no"}, {Want{Removed: true, Release: "feat/l3b-bus"}, "removed want names no"}, + {Want{FP: fp2of('a'), Self: true, Release: "feat/l3b-bus"}, "and no yes it gave"}, {Want{FP: fp2of('a'), Composed: "sha256:12"}, "not sha256"}, {Want{Removed: true, Composed: hashOf('1')}, "removed want names no"}, {Want{FP: fp2of('a'), Composed: hashOf('1'), Backup: "later"}, `backup answer "later"`},