C3: the manager's two logs in the logs section the runtime issues (issue 1409)
mesh/delivery merged: source.main moved to novox/mesh-catalog@c5f684538607
mesh/check checking 636cb633acfd on c5f684538607

Live after #659 the manager, in its own runtime, was still issued none of its logs: the runtime on main issues
template states but logs only from the `logs` section. usage (35 days, 256 MiB) and audit (64 MiB) move there; the
states stay templates. The whole tests' runtime now issues logs only from `logs`, as main does, and failed on the
old manifest.

Builds: design 39 bus-and-switch C3
This commit is contained in:
2026-11-12 10:21:27 +01:00
parent 6181d9afb3
commit 636cb633ac
4 changed files with 65 additions and 26 deletions
+2 -1
View File
@@ -32,7 +32,8 @@ from a file on this module's node or sealed by a node's `claude_code_add_api_key
## What it keeps on the bus
Each piece asked for in `requires` by its template (ADR 0595), read by `licences_kept`:
Each state asked for in `requires` by its template (ADR 0595), and the two logs declared in the `logs` section, the
form the runtime issues today (design 39 bus-and-switch C3); each read by `licences_kept`:
| name | template | what |
|---|---|---|
@@ -10,7 +10,8 @@ import (
)
// design 39 bus-and-switch §1: the module moves to the new form whole — no `reads`, no old `state`, no `prepare`
// step — and asks for each piece of its kept data by template.
// step — and asks for each state it keeps by template; its two logs are in the `logs` section with their bounds, the
// form the runtime on main issues (C3).
func TestTheManifestKeepsNoOldForm(t *testing.T) {
raw, err := os.ReadFile(filepath.Join(moduleDir, "module.json"))
if err != nil {
@@ -44,15 +45,32 @@ func TestTheManifestKeepsNoOldForm(t *testing.T) {
}
}
for name, template := range map[string]string{"licences": "state", "bindings": "state", "leases": "state",
"offered": "state", "usage": "log", "audit": "log", "carried": "state", "conditions": "state"} {
"offered": "state", "usage": "", "audit": "", "carried": "state", "conditions": "state"} {
if kept[name] != template {
t.Errorf("bus-state entry %s is %q, want template %s", name, kept[name], template)
t.Errorf("bus-state entry %s is %q in requires, want %q", name, kept[name], template)
}
}
var logs []json.RawMessage
_ = json.Unmarshal(m["logs"], &logs)
declared := logsSection(logs)
for name, bounds := range map[string]map[string]float64{"usage": {"max-age-days": 35, "max-mib": 256},
"audit": {"max-mib": 64}} {
l, ok := declared[name]
if !ok {
t.Errorf("the log %s is not in the logs section", name)
continue
}
for k, v := range bounds {
if l[k] != v {
t.Errorf("the log %s has %s %v, want %v", name, k, l[k], v)
}
}
}
}
// issued is what the manager's own runtime is issued from its manifest (design 39 bus-and-switch C1): its account, the
// states and logs it keeps (`requires` by template), what it may ask (`invokes`) and say (`emits`).
// states it keeps (`requires` by template), the logs it keeps (the `logs` section, the form the runtime on main issues,
// C3; a log asked for by template in `requires` is issued nothing), what it may ask (`invokes`) and say (`emits`).
type issued struct {
RunsAs, SecretsOwner string
OwnSecrets map[string]string
@@ -72,6 +90,7 @@ func manifestIssued(t testing.TB) issued {
SecretsOwner string `json:"secrets-owner"`
OwnSecrets map[string]string `json:"own-secrets"`
Requires []json.RawMessage `json:"requires"`
Logs []json.RawMessage `json:"logs"`
Resources []map[string]any `json:"resources"`
Invokes []string `json:"invokes"`
Emits []string `json:"emits"`
@@ -86,13 +105,13 @@ func manifestIssued(t testing.TB) issued {
if json.Unmarshal(r, &e) != nil {
continue
}
switch e.Storage {
case "key-value":
if e.Storage == "key-value" {
out.States[e.Name] = true
case "stream":
out.Logs[e.Name] = true
}
}
for name := range logsSection(m.Logs) {
out.Logs[name] = true
}
for _, k := range m.Invokes {
out.Invokes[k] = true
}
@@ -102,6 +121,25 @@ func manifestIssued(t testing.TB) issued {
return out
}
// logsSection is the manifest's `logs` section by name: each a name alone or {name, max-age-days, max-mib}.
func logsSection(logs []json.RawMessage) map[string]map[string]any {
out := map[string]map[string]any{}
for _, l := range logs {
var name string
if json.Unmarshal(l, &name) == nil {
out[name] = map[string]any{}
continue
}
var e map[string]any
if json.Unmarshal(l, &e) == nil {
if n, _ := e["name"].(string); n != "" {
out[n] = e
}
}
}
return out
}
// mayAsk is whether the manager's own account may ask key: a module tool asked on one node (`<module>.<tool>@<node>`)
// is invoked as `<module>.<tool>`.
func (i issued) mayAsk(key string) bool {
@@ -203,8 +203,14 @@ func TestKeptReadsEveryEntryOfTheManifest(t *testing.T) {
}
var m struct {
Requires []json.RawMessage `json:"requires"`
Logs []json.RawMessage `json:"logs"`
}
_ = json.Unmarshal(raw, &m)
// The logs are declared in the logs section (C3), each read as a log.
for name := range logsSection(m.Logs) {
r, _ := json.Marshal(map[string]string{"name": name, "template": "log"})
m.Requires = append(m.Requires, r)
}
mm := newMesh(t)
ctx := context.Background()
_, _ = saying(mm)
+11 -17
View File
@@ -40,23 +40,6 @@
"key-ttl": true
}
},
{
"name": "usage",
"storage": "stream",
"template": "log",
"options": {
"max-age-days": 35,
"max-mib": 256
}
},
{
"name": "audit",
"storage": "stream",
"template": "log",
"options": {
"max-mib": 64
}
},
{
"name": "carried",
"storage": "key-value",
@@ -74,6 +57,17 @@
}
}
],
"logs": [
{
"name": "usage",
"max-age-days": 35,
"max-mib": 256
},
{
"name": "audit",
"max-mib": 64
}
],
"contributes": {
"postgres-database": {
"name": "claude_licences",