The SDK part of novox/hq ADR 0297 (a module may declare a log of operations), clause 5: the Go SDK gains stdio.Log(name) next to stdio.State(name). It fixes nothing alone; it is one of four parts (controller, runtime in mesh-tools, SDK, catalogue's mesh-issues) toward issue 501 (the tracker's bucket fills toward its cap with no warning) and issue 502 (the audit trail lasts only seven days).
What
go/log.go: Log(name) KeptLog with Append, AppendAt, Read, Last, Info, and the types LogEntry, LogPage, LogInfo, built exactly like KeptState: each method is one ask over stdio, mesh/log.append|read|last|info, with log set to the local name, 30 s timeout.
Wire as the shared contract fixes it: append {log,key,value,expect?} -> {sequence}, read {log,from,keys?,limit?} -> {entries:[{sequence,key,value,at}],next,last}, last {log,key} -> entry | null, info {log} -> {entries,bytes,max_bytes,first,last}. Append sends no expect; AppendAt always sends it (0 = the key has no entry yet). Read sends keys only when non-empty and limit only when above 0 (0 = the runtime's page of 100); a negative limit is refused before asking.
A stale expect is answered by the runtime with CodeChanged, the code a lost mesh/state.update has, so errors.Is(err, stdio.ErrChanged) holds through the existing refused.Is; no new code.
go/README.md names stdio.Log.
Checked
go/log_test.go, against a fake stdio runtime the way state_counter_test.go does it: every method and its exact params; paging two at a time through six entries via Next until 0, every entry once and in order; a narrowed read by key; Last nil for a key with no entry; Info's fields incl. max_bytes; AppendAt on a stale sequence and on expect 0 for a key that has one both errors.Is(ErrChanged) and write nothing; a log not issued is refused with the runtime's reason and is not ErrChanged.
sh merge-check.sh (TypeScript suite 37/37 and the Go check: gofmt, vet, all Go packages) and sh go/merge-check.sh pass locally.
No other language SDK is touched. conformance/ lists no state verbs (it holds only the event envelope), so no log verbs were added there.
Release
This becomes go/v0.1.14, a patch, as Increment went out in go/v0.1.12. Note: main already carries two untagged Go changes since go/v0.1.13 (#18 go/health, #20 CallerOf); go/v0.1.14 tagged after this merge carries them too. Not tagged here; tagging happens after merge.
The SDK part of novox/hq ADR 0297 (a module may declare a log of operations), clause 5: the Go SDK gains `stdio.Log(name)` next to `stdio.State(name)`. It fixes nothing alone; it is one of four parts (controller, runtime in mesh-tools, SDK, catalogue's mesh-issues) toward issue 501 (the tracker's bucket fills toward its cap with no warning) and issue 502 (the audit trail lasts only seven days).
## What
- `go/log.go`: `Log(name) KeptLog` with `Append`, `AppendAt`, `Read`, `Last`, `Info`, and the types `LogEntry`, `LogPage`, `LogInfo`, built exactly like `KeptState`: each method is one ask over stdio, `mesh/log.append|read|last|info`, with `log` set to the local name, 30 s timeout.
- Wire as the shared contract fixes it: `append {log,key,value,expect?} -> {sequence}`, `read {log,from,keys?,limit?} -> {entries:[{sequence,key,value,at}],next,last}`, `last {log,key} -> entry | null`, `info {log} -> {entries,bytes,max_bytes,first,last}`. `Append` sends no `expect`; `AppendAt` always sends it (0 = the key has no entry yet). `Read` sends `keys` only when non-empty and `limit` only when above 0 (0 = the runtime's page of 100); a negative limit is refused before asking.
- A stale `expect` is answered by the runtime with `CodeChanged`, the code a lost `mesh/state.update` has, so `errors.Is(err, stdio.ErrChanged)` holds through the existing `refused.Is`; no new code.
- `go/README.md` names `stdio.Log`.
## Checked
- `go/log_test.go`, against a fake stdio runtime the way `state_counter_test.go` does it: every method and its exact params; paging two at a time through six entries via `Next` until 0, every entry once and in order; a narrowed read by key; `Last` nil for a key with no entry; `Info`'s fields incl. `max_bytes`; `AppendAt` on a stale sequence and on `expect` 0 for a key that has one both `errors.Is(ErrChanged)` and write nothing; a log not issued is refused with the runtime's reason and is not `ErrChanged`.
- `sh merge-check.sh` (TypeScript suite 37/37 and the Go check: gofmt, vet, all Go packages) and `sh go/merge-check.sh` pass locally.
- No other language SDK is touched. `conformance/` lists no state verbs (it holds only the event envelope), so no log verbs were added there.
## Release
This becomes **go/v0.1.14**, a patch, as `Increment` went out in go/v0.1.12. Note: main already carries two untagged Go changes since go/v0.1.13 (#18 go/health, #20 CallerOf); go/v0.1.14 tagged after this merge carries them too. Not tagged here; tagging happens after merge.
Deliverynovox/mesh-sdk@eaed93462975 — delivered since 2026-10-11T18:17:18Z
Delivery plan — builds mesh-sdk, sent nowhere; no bus step
tier 0: mesh-sdk
Machines
mesh-sdk on every machine running it: sent
Transitions
2026-10-11 17:17 (new) → proposed (announced): novox/mesh-sdk#21's head announced
2026-10-11 17:19 proposed → checked (checked): the verdict names this commit
2026-10-11 17:19 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
2026-10-11 18:16 ready → published (merged): on the trunk its modules follow: merged there, and its walk opened — or nothing for a walk to move
2026-10-11 18:16 published → delivering (go): its walk started: let go by this owner in its group's order, by a person, or on the controller's own path — not a failed walk that carried a later commit for it, after which it waits for a walk of its own commit
2026-10-11 18:17 delivering → delivered (done): its walk is done, carrying its own commit: every machine of its deploy plan passed, or was left as its policy says
The commit's note under refs/notes/mesh-plan keeps every transition: git log --notes=mesh-plan.
<!-- mesh-delivery:view -->
**Delivery** `novox/mesh-sdk@eaed93462975` — **delivered** since 2026-10-11T18:17:18Z
**Delivery plan** — builds mesh-sdk, sent nowhere; no bus step
- tier 0: mesh-sdk
**Machines**
- mesh-sdk on every machine running it: sent
**Transitions**
- 2026-10-11 17:17 (new) → proposed (announced): novox/mesh-sdk#21's head announced
- 2026-10-11 17:19 proposed → checked (checked): the verdict names this commit
- 2026-10-11 17:19 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
- 2026-10-11 18:16 ready → published (merged): on the trunk its modules follow: merged there, and its walk opened — or nothing for a walk to move
- 2026-10-11 18:16 published → delivering (go): its walk started: let go by this owner in its group's order, by a person, or on the controller's own path — not a failed walk that carried a later commit for it, after which it waits for a walk of its own commit
- 2026-10-11 18:17 delivering → delivered (done): its walk is done, carrying its own commit: every machine of its deploy plan passed, or was left as its policy says
The commit's note under `refs/notes/mesh-plan` keeps every transition: `git log --notes=mesh-plan`.
mesh/merge-gate: PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: mesh-sdk)
mesh/repo-check: PASS — its merge-check.sh passed, each part in its toolchain: merge-check.sh (typescript), go/merge-check.sh (go)
Delivery plan — builds mesh-sdk, sent nowhere; no bus step
tier 0: mesh-sdk
Run by the build seat on shanks as build-1791739026967803279 (builds --log build-1791739026967803279).
ok 11 - a waiting set the mesh asks for again settles, and nothing is retired
---
duration_ms: 67.316096
type: 'test'
...
# Subtest: delete refuses an active consumer and deletes only the named retired one
ok 12 - delete refuses an active consumer and deletes only the named retired one
---
duration_ms: 53.499862
type: 'test'
...
# Subtest: an addition acts on the first pass
ok 13 - an addition acts on the first pass
---
duration_ms: 12.097917
type: 'test'
...
# Subtest: what the backend holds at start is retired by the same rules
ok 14 - what the backend holds at start is retired by the same rules
---
duration_ms: 46.30102
type: 'test'
...
# Subtest: the four tools are registered for the module and answer
ok 15 - the four tools are registered for the module and answer
---
duration_ms: 1.876679
type: 'test'
...
# [tools] broken: contributor failed, exposing none: Error: no token
# Subtest: semver orders releases
ok 16 - semver orders releases
---
duration_ms: 1.041116
type: 'test'
...
# Subtest: module tools register and collect, a thrower is skipped not fatal
ok 17 - module tools register and collect, a thrower is skipped not fatal
---
duration_ms: 0.65323
type: 'test'
...
# [provisioner:analytics] webapp-anchor: no longer in /tmp/prov-YMJnzt/analytics.json; RETIRED, MARK ONLY — this provider cannot disable a consumer (its adapter has no retire), so webapp-anchor KEEPS ITS ACCESS and its data until a person deletes it with `cleanup delete`. Nothing was changed in the backend (novox/hq ADR 0230): the mesh stopped asking for it: the same answer in 5 passes over 0s, from 2026-10-11T17:19:14.771Z
# [provisioner:analytics] webapp-anchor: DELETING, asked by someone: gone for good
# Subtest: provisioner creates each consumer with the mesh's login and password; remove waits for a person's delete
ok 18 - provisioner creates each consumer with the mesh's login and password; remove waits for a person's delete
---
duration_ms: 218.03575
type: 'test'
...
# [provisioner:s3-bucket] mesh_anchor_ncloud: no longer in /tmp/prov-derived-8unqcO/store.json; RETIRED, MARK ONLY — this provider cannot disable a consumer (its adapter has no retire), so mesh_anchor_ncloud KEEPS ITS ACCESS and its data until a person deletes it with `cleanup delete`. Nothing was changed in the backend (novox/hq ADR 0230): the mesh stopped asking for it: the same answer in 5 passes over 0s, from 2026-10-11T17:19:15.004Z
# [provisioner:s3-bucket] mesh_anchor_ncloud: DELETING, asked by someone: unassigned
# Subtest: provisioner hands the adapter what the mesh derived, and still has it at withdrawal
ok 19 - provisioner hands the adapter what the mesh derived, and still has it at withdrawal
---
duration_ms: 124.673419
type: 'test'
...
# Subtest: provisioner stops calling an unreadable secret a race, and says what to look at
ok 20 - provisioner stops calling an unreadable secret a race, and says what to look at
---
duration_ms: 70.388514
type: 'test'
...
# [provisioner:postgres-database] contributions file unreadable (/tmp/prov-7T2ndE/postgres-database.json): ENOENT: no such file or directory, open '/tmp/prov-7T2ndE/postgres-database.json'; nothing applied or removed until it can be read
# [provisioner:postgres-database] contributions file readable again
# [provisioner:postgres-database] contributions file is not JSON (/tmp/prov-7T2ndE/postgres-database.json): SyntaxError: Expected property name or '}' in JSON at position 2 (line 1 column 3); nothing applied or removed until it can be read
# [provisioner:postgres-database] contributions file readable again
# [provisioner:postgres-database] /tmp/prov-7T2ndE/postgres-database.json is for s3-bucket, not postgres-database; nothing applied or removed until it can be read
# [provisioner:postgres-database] contributions file readable again
# [provisioner:postgres-database] /tmp/prov-7T2ndE/postgres-database.json has no given list; nothing applied or removed until it can be read
# [provisioner:postgres-database] contributions file readable again
# [provisioner:postgres-database] RETIREMENT WAITS FOR A PERSON: the mesh no longer asks for 2 of the 2 consumer(s) this provider holds (mesh_anchor_forge, mesh_anchor_mail), more than 3, or more than 50% of the 2 held. Nothing is retired until `retire approve` or `retire reject` (novox/hq ADR 0230)
# [provisioner:postgres-database] retirement of mesh_anchor_forge, mesh_anchor_mail approved by test: both unassigned on purpose
# [provisioner:postgres-database] mesh_anchor_forge: no longer in /tmp/prov-7T2ndE/postgres-database.json; RETIRED, MARK ONLY — this provider cannot disable a consumer (its adapter has no retire), so mesh_anchor_forge KEEPS ITS ACCESS and its data until a person deletes it with `cleanup delete`. Nothing was changed in the backend (novox/hq ADR 0230): approved by test: both unassigned on purpose
# [provisioner:postgres-database] mesh_anchor_mail: no longer in /tmp/prov-7T2ndE/postgres-database.json; RETIRED, MARK ONLY — this provider cannot disable a consumer (its adapter has no retire), so mesh_anchor_mail KEEPS ITS ACCESS and its data until a person deletes it with `cleanup delete`. Nothing was changed in the backend (novox/hq ADR 0230): approved by test: both unassigned on purpose
# Subtest: provisioner removes nothing while its contributions file cannot be used (novox/hq issue 241)
ok 21 - provisioner removes nothing while its contributions file cannot be used (novox/hq issue 241)
---
duration_ms: 1317.398221
type: 'test'
...
# [provisioner:cache] webapp-anchor: the backend no longer holds it; applying again
# Subtest: provisioner applies again what the backend no longer holds, and trusts memory without holds
ok 22 - provisioner applies again what the backend no longer holds, and trusts memory without holds
---
duration_ms: 211.406027
type: 'test'
...
# [provisioner:cache] webapp-anchor: could not check the backend, will ask again: Error: connection refused
# [provisioner:cache] webapp-anchor: could not check the backend, will ask again: Error: connection refused
# [provisioner:cache] webapp-anchor: could not check the backend, will ask again: Error: connection refused
# Subtest: provisioner keeps a consumer applied when the backend cannot be asked
ok 23 - provisioner keeps a consumer applied when the backend cannot be asked
---
duration_ms: 71.442421
type: 'test'
...
# Subtest: provisioner backs off when create does not satisfy holds, and says so
ok 24 - provisioner backs off when create does not satisfy holds, and says so
---
duration_ms: 401.766707
type: 'test'
...
# Subtest: provisioner treats a failed or hung holds as could-not-ask, and never logs the password
ok 25 - provisioner treats a failed or hung holds as could-not-ask, and never logs the password
---
duration_ms: 402.759471
type: 'test'
...
# Subtest: provisioner stops a verify pass at a timeout, and retries a failed re-apply at the next check
ok 26 - provisioner stops a verify pass at a timeout, and retries a failed re-apply at the next check
---
duration_ms: 301.951843
type: 'test'
...
# Subtest: modules can SERVE: a real async tool, loaded and invoked over the broker
ok 27 - modules can SERVE: a real async tool, loaded and invoked over the broker
---
duration_ms: 33.120784
type: 'test'
...
# Subtest: serving refuses one module exposing two tools of the same name
ok 28 - serving refuses one module exposing two tools of the same name
---
duration_ms: 0.319925
type: 'test'
...
# Subtest: events: a module emits, a listener and the audit sink (\#) both receive it, with metadata
ok 29 - events: a module emits, a listener and the audit sink (\#) both receive it, with metadata
---
duration_ms: 0.677281
type: 'test'
...
# Subtest: each registration is given the environment asked for it, and sees no other's (ADR 0192)
ok 30 - each registration is given the environment asked for it, and sees no other's (ADR 0192)
---
duration_ms: 0.234434
type: 'test'
...
# Subtest: a bundle on stdio lists its tools and answers a call, a seat's verb among them
ok 31 - a bundle on stdio lists its tools and answers a call, a seat's verb among them
---
duration_ms: 127.323079
type: 'test'
...
# Subtest: a bundle served as its module lists the seat's verbs as the seat's, whichever registered first (ADR 0193)
ok 32 - a bundle served as its module lists the seat's verbs as the seat's, whichever registered first (ADR 0193)
---
duration_ms: 83.650521
type: 'test'
...
# Subtest: a launched tool's emit is asked of the runtime, and the call answers once the runtime has published (ADR 0193)
ok 33 - a launched tool's emit is asked of the runtime, and the call answers once the runtime has published (ADR 0193)
---
duration_ms: 84.128298
type: 'test'
...
# Subtest: a launched bundle subscribes as it is imported, handles events the runtime hands it, and asks through it (ADR 0198)
ok 34 - a launched bundle subscribes as it is imported, handles events the runtime hands it, and asks through it (ADR 0198)
---
duration_ms: 3202.520866
type: 'test'
...
# Subtest: a subscribe the runtime refused leaves no handler behind, so one event is handled once (novox/hq issue 276)
ok 35 - a subscribe the runtime refused leaves no handler behind, so one event is handled once (novox/hq issue 276)
---
duration_ms: 84.89237
type: 'test'
...
# Subtest: a launched bundle watches its state as it is imported, has the current values before it goes on, and keeps state through the runtime (ADR 0201)
ok 36 - a launched bundle watches its state as it is imported, has the current values before it goes on, and keeps state through the runtime (ADR 0201)
---
duration_ms: 285.857374
type: 'test'
...
# Subtest: topics match as the runtime's do: * one segment, \# and ** any number
ok 37 - topics match as the runtime's do: * one segment, \# and ** any number
---
duration_ms: 2.505069
type: 'test'
...
1..37
# tests 37
# suites 0
# pass 37
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 3969.198375
NOT TESTED HERE: go/ (the Go binding) — the Go toolchain runs it from go/merge-check.sh
NOT TESTED HERE: python/, rust/, c/ — no toolchain of theirs runs a merge check
--- its go/merge-check.sh (go toolchain)
ok git.novox.be/novox/mesh-sdk/go 0.141s
ok git.novox.be/novox/mesh-sdk/go/asker 0.003s
ok git.novox.be/novox/mesh-sdk/go/asks 0.003s
ok git.novox.be/novox/mesh-sdk/go/cli 1.025s
? git.novox.be/novox/mesh-sdk/go/example [no test files]
ok git.novox.be/novox/mesh-sdk/go/health 0.003s
**Merge check** at `eaed9346`
- `mesh/merge-gate`: **PASS** — every machine composes with the change as it did without (4 of 4 compose) (modules: mesh-sdk)
- `mesh/repo-check`: **PASS** — its merge-check.sh passed, each part in its toolchain: merge-check.sh (typescript), go/merge-check.sh (go)
**Delivery plan** — builds mesh-sdk, sent nowhere; no bus step
- tier 0: mesh-sdk
Run by the build seat on shanks as `build-1791739026967803279` (`builds --log build-1791739026967803279`).
```
ok 11 - a waiting set the mesh asks for again settles, and nothing is retired
---
duration_ms: 67.316096
type: 'test'
...
# Subtest: delete refuses an active consumer and deletes only the named retired one
ok 12 - delete refuses an active consumer and deletes only the named retired one
---
duration_ms: 53.499862
type: 'test'
...
# Subtest: an addition acts on the first pass
ok 13 - an addition acts on the first pass
---
duration_ms: 12.097917
type: 'test'
...
# Subtest: what the backend holds at start is retired by the same rules
ok 14 - what the backend holds at start is retired by the same rules
---
duration_ms: 46.30102
type: 'test'
...
# Subtest: the four tools are registered for the module and answer
ok 15 - the four tools are registered for the module and answer
---
duration_ms: 1.876679
type: 'test'
...
# [tools] broken: contributor failed, exposing none: Error: no token
# Subtest: semver orders releases
ok 16 - semver orders releases
---
duration_ms: 1.041116
type: 'test'
...
# Subtest: module tools register and collect, a thrower is skipped not fatal
ok 17 - module tools register and collect, a thrower is skipped not fatal
---
duration_ms: 0.65323
type: 'test'
...
# [provisioner:analytics] webapp-anchor: no longer in /tmp/prov-YMJnzt/analytics.json; RETIRED, MARK ONLY — this provider cannot disable a consumer (its adapter has no retire), so webapp-anchor KEEPS ITS ACCESS and its data until a person deletes it with `cleanup delete`. Nothing was changed in the backend (novox/hq ADR 0230): the mesh stopped asking for it: the same answer in 5 passes over 0s, from 2026-10-11T17:19:14.771Z
# [provisioner:analytics] webapp-anchor: DELETING, asked by someone: gone for good
# Subtest: provisioner creates each consumer with the mesh's login and password; remove waits for a person's delete
ok 18 - provisioner creates each consumer with the mesh's login and password; remove waits for a person's delete
---
duration_ms: 218.03575
type: 'test'
...
# [provisioner:s3-bucket] mesh_anchor_ncloud: no longer in /tmp/prov-derived-8unqcO/store.json; RETIRED, MARK ONLY — this provider cannot disable a consumer (its adapter has no retire), so mesh_anchor_ncloud KEEPS ITS ACCESS and its data until a person deletes it with `cleanup delete`. Nothing was changed in the backend (novox/hq ADR 0230): the mesh stopped asking for it: the same answer in 5 passes over 0s, from 2026-10-11T17:19:15.004Z
# [provisioner:s3-bucket] mesh_anchor_ncloud: DELETING, asked by someone: unassigned
# Subtest: provisioner hands the adapter what the mesh derived, and still has it at withdrawal
ok 19 - provisioner hands the adapter what the mesh derived, and still has it at withdrawal
---
duration_ms: 124.673419
type: 'test'
...
# Subtest: provisioner stops calling an unreadable secret a race, and says what to look at
ok 20 - provisioner stops calling an unreadable secret a race, and says what to look at
---
duration_ms: 70.388514
type: 'test'
...
# [provisioner:postgres-database] contributions file unreadable (/tmp/prov-7T2ndE/postgres-database.json): ENOENT: no such file or directory, open '/tmp/prov-7T2ndE/postgres-database.json'; nothing applied or removed until it can be read
# [provisioner:postgres-database] contributions file readable again
# [provisioner:postgres-database] contributions file is not JSON (/tmp/prov-7T2ndE/postgres-database.json): SyntaxError: Expected property name or '}' in JSON at position 2 (line 1 column 3); nothing applied or removed until it can be read
# [provisioner:postgres-database] contributions file readable again
# [provisioner:postgres-database] /tmp/prov-7T2ndE/postgres-database.json is for s3-bucket, not postgres-database; nothing applied or removed until it can be read
# [provisioner:postgres-database] contributions file readable again
# [provisioner:postgres-database] /tmp/prov-7T2ndE/postgres-database.json has no given list; nothing applied or removed until it can be read
# [provisioner:postgres-database] contributions file readable again
# [provisioner:postgres-database] RETIREMENT WAITS FOR A PERSON: the mesh no longer asks for 2 of the 2 consumer(s) this provider holds (mesh_anchor_forge, mesh_anchor_mail), more than 3, or more than 50% of the 2 held. Nothing is retired until `retire approve` or `retire reject` (novox/hq ADR 0230)
# [provisioner:postgres-database] retirement of mesh_anchor_forge, mesh_anchor_mail approved by test: both unassigned on purpose
# [provisioner:postgres-database] mesh_anchor_forge: no longer in /tmp/prov-7T2ndE/postgres-database.json; RETIRED, MARK ONLY — this provider cannot disable a consumer (its adapter has no retire), so mesh_anchor_forge KEEPS ITS ACCESS and its data until a person deletes it with `cleanup delete`. Nothing was changed in the backend (novox/hq ADR 0230): approved by test: both unassigned on purpose
# [provisioner:postgres-database] mesh_anchor_mail: no longer in /tmp/prov-7T2ndE/postgres-database.json; RETIRED, MARK ONLY — this provider cannot disable a consumer (its adapter has no retire), so mesh_anchor_mail KEEPS ITS ACCESS and its data until a person deletes it with `cleanup delete`. Nothing was changed in the backend (novox/hq ADR 0230): approved by test: both unassigned on purpose
# Subtest: provisioner removes nothing while its contributions file cannot be used (novox/hq issue 241)
ok 21 - provisioner removes nothing while its contributions file cannot be used (novox/hq issue 241)
---
duration_ms: 1317.398221
type: 'test'
...
# [provisioner:cache] webapp-anchor: the backend no longer holds it; applying again
# Subtest: provisioner applies again what the backend no longer holds, and trusts memory without holds
ok 22 - provisioner applies again what the backend no longer holds, and trusts memory without holds
---
duration_ms: 211.406027
type: 'test'
...
# [provisioner:cache] webapp-anchor: could not check the backend, will ask again: Error: connection refused
# [provisioner:cache] webapp-anchor: could not check the backend, will ask again: Error: connection refused
# [provisioner:cache] webapp-anchor: could not check the backend, will ask again: Error: connection refused
# Subtest: provisioner keeps a consumer applied when the backend cannot be asked
ok 23 - provisioner keeps a consumer applied when the backend cannot be asked
---
duration_ms: 71.442421
type: 'test'
...
# Subtest: provisioner backs off when create does not satisfy holds, and says so
ok 24 - provisioner backs off when create does not satisfy holds, and says so
---
duration_ms: 401.766707
type: 'test'
...
# Subtest: provisioner treats a failed or hung holds as could-not-ask, and never logs the password
ok 25 - provisioner treats a failed or hung holds as could-not-ask, and never logs the password
---
duration_ms: 402.759471
type: 'test'
...
# Subtest: provisioner stops a verify pass at a timeout, and retries a failed re-apply at the next check
ok 26 - provisioner stops a verify pass at a timeout, and retries a failed re-apply at the next check
---
duration_ms: 301.951843
type: 'test'
...
# Subtest: modules can SERVE: a real async tool, loaded and invoked over the broker
ok 27 - modules can SERVE: a real async tool, loaded and invoked over the broker
---
duration_ms: 33.120784
type: 'test'
...
# Subtest: serving refuses one module exposing two tools of the same name
ok 28 - serving refuses one module exposing two tools of the same name
---
duration_ms: 0.319925
type: 'test'
...
# Subtest: events: a module emits, a listener and the audit sink (\#) both receive it, with metadata
ok 29 - events: a module emits, a listener and the audit sink (\#) both receive it, with metadata
---
duration_ms: 0.677281
type: 'test'
...
# Subtest: each registration is given the environment asked for it, and sees no other's (ADR 0192)
ok 30 - each registration is given the environment asked for it, and sees no other's (ADR 0192)
---
duration_ms: 0.234434
type: 'test'
...
# Subtest: a bundle on stdio lists its tools and answers a call, a seat's verb among them
ok 31 - a bundle on stdio lists its tools and answers a call, a seat's verb among them
---
duration_ms: 127.323079
type: 'test'
...
# Subtest: a bundle served as its module lists the seat's verbs as the seat's, whichever registered first (ADR 0193)
ok 32 - a bundle served as its module lists the seat's verbs as the seat's, whichever registered first (ADR 0193)
---
duration_ms: 83.650521
type: 'test'
...
# Subtest: a launched tool's emit is asked of the runtime, and the call answers once the runtime has published (ADR 0193)
ok 33 - a launched tool's emit is asked of the runtime, and the call answers once the runtime has published (ADR 0193)
---
duration_ms: 84.128298
type: 'test'
...
# Subtest: a launched bundle subscribes as it is imported, handles events the runtime hands it, and asks through it (ADR 0198)
ok 34 - a launched bundle subscribes as it is imported, handles events the runtime hands it, and asks through it (ADR 0198)
---
duration_ms: 3202.520866
type: 'test'
...
# Subtest: a subscribe the runtime refused leaves no handler behind, so one event is handled once (novox/hq issue 276)
ok 35 - a subscribe the runtime refused leaves no handler behind, so one event is handled once (novox/hq issue 276)
---
duration_ms: 84.89237
type: 'test'
...
# Subtest: a launched bundle watches its state as it is imported, has the current values before it goes on, and keeps state through the runtime (ADR 0201)
ok 36 - a launched bundle watches its state as it is imported, has the current values before it goes on, and keeps state through the runtime (ADR 0201)
---
duration_ms: 285.857374
type: 'test'
...
# Subtest: topics match as the runtime's do: * one segment, \# and ** any number
ok 37 - topics match as the runtime's do: * one segment, \# and ** any number
---
duration_ms: 2.505069
type: 'test'
...
1..37
# tests 37
# suites 0
# pass 37
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 3969.198375
NOT TESTED HERE: go/ (the Go binding) — the Go toolchain runs it from go/merge-check.sh
NOT TESTED HERE: python/, rust/, c/ — no toolchain of theirs runs a merge check
--- its go/merge-check.sh (go toolchain)
ok git.novox.be/novox/mesh-sdk/go 0.141s
ok git.novox.be/novox/mesh-sdk/go/asker 0.003s
ok git.novox.be/novox/mesh-sdk/go/asks 0.003s
ok git.novox.be/novox/mesh-sdk/go/cli 1.025s
? git.novox.be/novox/mesh-sdk/go/example [no test files]
ok git.novox.be/novox/mesh-sdk/go/health 0.003s
```
Review (independent): APPROVE at eaed934629, checked against the ADR 0297 contract. (The forge refuses an APPROVED review from a tool under ADR 0266, so this is a comment.)
Wire names and shapes: pass. go/log.go:16-38 (sequence, key, value, at; entries, next, last; entries, bytes, max_bytes, first, last) match mesh-tools node-tools/internal/bus/log.go:35-57 field for field. Methods are mesh/log., with log added (log.go:48-55).
expect presence: pass. Append sends no expect (log.go:71-73). AppendAt always sends it, 0 included (log.go:79-81). The test checks both on the wire (log_test.go:250-255).
A stale expect maps to ErrChanged: pass. The runtime answers code -32010 (mesh-tools bus/seat.go:404 through launch.go:627 errorCode). stdio.go:139 makes refused{code: CodeChanged} errors.Is ErrChanged. log_test.go:332 checks it, and log_test.go:335 checks that a log the module was not issued is not ErrChanged.
Last answers nil for an empty or null result (log.go:108), which is what the runtime answers.
The tests do real work: a fake runtime pages, filters keys and refuses stale expects, and the paging loop proves that every entry is read once, in order (log_test.go:260-275).
I ran merge-check.sh locally and it passed (gofmt, go vet, go test, and 37 TypeScript tests). Forge checks at this head: mesh/merge-gate success 'pass: builds mesh-sdk, sent nowhere; no bus step; every machine composes with the change as it did without (4 of 4 compose)'; mesh/repo-check success 'pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (typescript), go/merge-check.sh (go)'.
Non-blocking findings: none.
Review (independent): APPROVE at eaed93462975b573a9a2e7677704b9dae60ec96f, checked against the ADR 0297 contract. (The forge refuses an APPROVED review from a tool under ADR 0266, so this is a comment.)
1. Wire names and shapes: pass. go/log.go:16-38 (sequence, key, value, at; entries, next, last; entries, bytes, max_bytes, first, last) match mesh-tools node-tools/internal/bus/log.go:35-57 field for field. Methods are mesh/log.<verb>, with `log` added (log.go:48-55).
2. expect presence: pass. Append sends no expect (log.go:71-73). AppendAt always sends it, 0 included (log.go:79-81). The test checks both on the wire (log_test.go:250-255).
3. A stale expect maps to ErrChanged: pass. The runtime answers code -32010 (mesh-tools bus/seat.go:404 through launch.go:627 errorCode). stdio.go:139 makes refused{code: CodeChanged} errors.Is ErrChanged. log_test.go:332 checks it, and log_test.go:335 checks that a log the module was not issued is not ErrChanged.
4. Last answers nil for an empty or `null` result (log.go:108), which is what the runtime answers.
5. The tests do real work: a fake runtime pages, filters keys and refuses stale expects, and the paging loop proves that every entry is read once, in order (log_test.go:260-275).
I ran merge-check.sh locally and it passed (gofmt, go vet, go test, and 37 TypeScript tests). Forge checks at this head: mesh/merge-gate success 'pass: builds mesh-sdk, sent nowhere; no bus step; every machine composes with the change as it did without (4 of 4 compose)'; mesh/repo-check success 'pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (typescript), go/merge-check.sh (go)'.
Non-blocking findings: none.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
The SDK part of novox/hq ADR 0297 (a module may declare a log of operations), clause 5: the Go SDK gains
stdio.Log(name)next tostdio.State(name). It fixes nothing alone; it is one of four parts (controller, runtime in mesh-tools, SDK, catalogue's mesh-issues) toward issue 501 (the tracker's bucket fills toward its cap with no warning) and issue 502 (the audit trail lasts only seven days).What
go/log.go:Log(name) KeptLogwithAppend,AppendAt,Read,Last,Info, and the typesLogEntry,LogPage,LogInfo, built exactly likeKeptState: each method is one ask over stdio,mesh/log.append|read|last|info, withlogset to the local name, 30 s timeout.append {log,key,value,expect?} -> {sequence},read {log,from,keys?,limit?} -> {entries:[{sequence,key,value,at}],next,last},last {log,key} -> entry | null,info {log} -> {entries,bytes,max_bytes,first,last}.Appendsends noexpect;AppendAtalways sends it (0 = the key has no entry yet).Readsendskeysonly when non-empty andlimitonly when above 0 (0 = the runtime's page of 100); a negative limit is refused before asking.expectis answered by the runtime withCodeChanged, the code a lostmesh/state.updatehas, soerrors.Is(err, stdio.ErrChanged)holds through the existingrefused.Is; no new code.go/README.mdnamesstdio.Log.Checked
go/log_test.go, against a fake stdio runtime the waystate_counter_test.godoes it: every method and its exact params; paging two at a time through six entries viaNextuntil 0, every entry once and in order; a narrowed read by key;Lastnil for a key with no entry;Info's fields incl.max_bytes;AppendAton a stale sequence and onexpect0 for a key that has one botherrors.Is(ErrChanged)and write nothing; a log not issued is refused with the runtime's reason and is notErrChanged.sh merge-check.sh(TypeScript suite 37/37 and the Go check: gofmt, vet, all Go packages) andsh go/merge-check.shpass locally.conformance/lists no state verbs (it holds only the event envelope), so no log verbs were added there.Release
This becomes go/v0.1.14, a patch, as
Incrementwent out in go/v0.1.12. Note: main already carries two untagged Go changes since go/v0.1.13 (#18 go/health, #20 CallerOf); go/v0.1.14 tagged after this merge carries them too. Not tagged here; tagging happens after merge.Delivery
novox/mesh-sdk@eaed93462975— delivered since 2026-10-11T18:17:18ZDelivery plan — builds mesh-sdk, sent nowhere; no bus step
Machines
Transitions
The commit's note under
refs/notes/mesh-plankeeps every transition:git log --notes=mesh-plan.Merge check at
eaed9346mesh/merge-gate: PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: mesh-sdk)mesh/repo-check: PASS — its merge-check.sh passed, each part in its toolchain: merge-check.sh (typescript), go/merge-check.sh (go)Delivery plan — builds mesh-sdk, sent nowhere; no bus step
Run by the build seat on shanks as
build-1791739026967803279(builds --log build-1791739026967803279).Review (independent): APPROVE at
eaed934629, checked against the ADR 0297 contract. (The forge refuses an APPROVED review from a tool under ADR 0266, so this is a comment.)logadded (log.go:48-55).nullresult (log.go:108), which is what the runtime answers.I ran merge-check.sh locally and it passed (gofmt, go vet, go test, and 37 TypeScript tests). Forge checks at this head: mesh/merge-gate success 'pass: builds mesh-sdk, sent nowhere; no bus step; every machine composes with the change as it did without (4 of 4 compose)'; mesh/repo-check success 'pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (typescript), go/merge-check.sh (go)'.
Non-blocking findings: none.