H-4: running says stopped, with no fingerprint, once the have no longer holds the module

Builds: design 47 G §365, §404

Claude-Session: https://claude.ai/code/session_01JG73KEq4zoDfM9WtYpcQgZ
This commit is contained in:
2026-11-11 12:06:10 +01:00
parent 26581d87ed
commit 420087ab14
2 changed files with 15 additions and 2 deletions
+11 -2
View File
@@ -444,7 +444,7 @@ func (q *Session) writeHaves(ctx context.Context, bus Bus) {
said = append(said, func() { q.sayRunning(ev) })
}
}
if !q.writeRemoved(write, bucket, node) {
if !q.writeRemoved(write, bucket, node, &said) {
return
}
if !q.writeUserListsAlone(write, bucket, node) {
@@ -521,7 +521,7 @@ func (q *Session) haveSucceeded() {
// writeRemoved writes, once, each module the applied declaration no longer holds and this node-engine wrote a have key
// for, with the phase removed over the revision it reads (issue 1369). The key is never deleted, and a key that is not
// in the bucket is not created. False when the pass should stop. The caller holds the lock of the haves.
func (q *Session) writeRemoved(ctx context.Context, b HaveBucket, node string) bool {
func (q *Session) writeRemoved(ctx context.Context, b HaveBucket, node string, said *[]func()) bool {
s := &q.haves
gone := make([]string, 0, len(s.removed))
for module := range s.removed {
@@ -567,10 +567,19 @@ func (q *Session) writeRemoved(ctx context.Context, b HaveBucket, node string) b
return false
}
delete(s.removed, module)
// The module no longer runs here: running says stopped, with no fingerprint, on its own subject (design 47 G §365, §404).
delete(s.runningSaid, module)
*said = append(*said, func() { q.sayRunning(stoppedRunning(node, module)) })
}
return true
}
// stoppedRunning is the event running of a module the node-engine's have no longer holds: stopped, with no fingerprint
// and no manifest (design 47 G §365, §404).
func stoppedRunning(node, module string) nodeengine.Running {
return nodeengine.Running{V: sdkkeys.Version, Node: node, Module: module, Stopped: true}
}
// writeUserListsAlone writes the user list of each module this node-engine holds no fact of (no apply here said its have)
// into that module's key as the bucket holds it, keeping every other field the key says (novox/hq ADR 0547 §8). The have
// of a module is one value with parts from more than one source: the apply's (fingerprint, digest, build, phase, health)
+4
View File
@@ -552,6 +552,10 @@ func TestAModuleLeavingTheDeclarationIsWrittenRemoved(t *testing.T) {
if l.kv["n1.b"].rev != revB+1 {
t.Errorf("b was written at revision %d, want one over %d", l.kv["n1.b"].rev, revB)
}
// Design 47 G §365: a module the have no longer holds says running stopped, with no fingerprint, once, on its own subject.
if got := l.saidOn("mesh.seat.node-engine.event.running.n1.b "); len(got) != 1 || !strings.Contains(got[0], `"stopped":true`) || strings.Contains(got[0], `"fingerprint"`) {
t.Errorf("running said %v for b, want one stopped with no fingerprint", got)
}
if l.kv["n1.a"].rev != revA || l.have(t, "n1.a").Phase != nodeengineclient.PhaseRunning {
t.Errorf("a changed: %+v at %d", l.have(t, "n1.a"), l.kv["n1.a"].rev)
}