Merge remote-tracking branch 'origin/main' into feat/files-through-the-store-files-verbs
mesh/repo-check head 550cf37d7109 merged into trunk d96c9f56a3f1 beside mesh-catalog#417@aef2a1a9 — pass: its merge-check.sh passed
mesh/merge-gate head 550cf37d7109 merged into trunk d96c9f56a3f1 — pass: group feat/files-through-the-store composed: every machine composes with the chang…
mesh/delivery superseded: its walk was superseded and names no walk that took it over: a walk that took it over answers its merge, and it follows that wa…
mesh/delivery-group group feat/files-through-the-store stopped: superseded, not carried by a later delivery: novox/mesh-catalog@6cf51173d586, novox/mesh-contro…
mesh/repo-check head 550cf37d7109 merged into trunk d96c9f56a3f1 beside mesh-catalog#417@aef2a1a9 — pass: its merge-check.sh passed
mesh/merge-gate head 550cf37d7109 merged into trunk d96c9f56a3f1 — pass: group feat/files-through-the-store composed: every machine composes with the chang…
mesh/delivery superseded: its walk was superseded and names no walk that took it over: a walk that took it over answers its merge, and it follows that wa…
mesh/delivery-group group feat/files-through-the-store stopped: superseded, not carried by a later delivery: novox/mesh-catalog@6cf51173d586, novox/mesh-contro…
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
module route-proxy
|
||||
|
||||
go 1.25.0
|
||||
go 1.26.0
|
||||
|
||||
require git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261018003858-f185aedbf5d6
|
||||
require git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261021114014-66e8fdaa62e2
|
||||
|
||||
@@ -1,4 +1,2 @@
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261016174426-a4e7f480b3b0 h1:EK84so3Y8JdFT3BHrzj9cPQQrDUPa/d+IdOGnerlmEI=
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261016174426-a4e7f480b3b0/go.mod h1:GFuZUElBZ9A++mxgIKo97aXXo+kV0uJ/UkbhQPPIbrY=
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261018003858-f185aedbf5d6 h1:Sv1Qzix+U1RpaUkw5IbB0IJEyZ+FqgzHmbZrCZkcWf0=
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261018003858-f185aedbf5d6/go.mod h1:GFuZUElBZ9A++mxgIKo97aXXo+kV0uJ/UkbhQPPIbrY=
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261021114014-66e8fdaa62e2 h1:Cdl5N56QPfmFBoLHrDfvvyc5Q+PUnTjf3fgYD7imcco=
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261021114014-66e8fdaa62e2/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
|
||||
|
||||
@@ -17,3 +17,5 @@ at the same version as the TypeScript package.
|
||||
What it holds, under ADR 0039's test: the stdio loop and the tool type, and `cli`, the local protocol
|
||||
`mesh-cli` speaks to the node-engine on its machine (novox/hq ADR 0272): the socket's path and one request and one
|
||||
answer; and `seal`, the mesh's sealed box (novox/hq ADR 0206: X25519, HKDF-SHA256, AES-256-GCM, `{v, eph, iv, tag, ct}`), byte for byte the box the licence manager made before it lived here and the TypeScript `@novox/mesh-sdk/seal` makes. Nothing else — no bus, no client, nothing of any module's. `go build ./example` and pipe a `tools/list` request into it.
|
||||
|
||||
From release 4a of design 47 (novox/hq ADR 0453 clause 3, ADR 0446 clause 4) it also holds the composition of a machine's declaration, over a plain input and with nothing behind it: `declaration` and `validate`, the node-engine's parser and its validator, copied from mesh-host; `catalogue`, the manifests, their resolution and rendering, and `overlay`, the private network's generator, copied from mesh-controller; `compose`, the controller's planFor, renderingFor and declarationWith as functions of an `Input` (the composition never allocates, makes, keeps or writes: what a send would do it names as foreseen or returns); `sdkversion`, which mesh-sdk version a program was built with; and, in `delivery`, the layouts of the keys the builder, the checker and the indexer write (the source fingerprint's new form, the builds, the verdicts and kept verdicts, the manifests by digest). None of them holds a bus, a store or a vault client, which `go list -deps` of `compose` shows.
|
||||
|
||||
@@ -5,16 +5,127 @@
|
||||
# seat in the mesh's Go toolchain, its own container, because the SDK's merge-check.sh declares it
|
||||
# (`# mesh-check-also: go go/merge-check.sh`) — and by hand, from anywhere: `sh go/merge-check.sh`.
|
||||
#
|
||||
# Formatted, vetted, and its whole suite run: the stdio loop and the local protocol mesh-cli speaks to the
|
||||
# node-engine. Standard library only, so nothing is fetched.
|
||||
# Formatted, vetted (with and without the build tag `integration`), and run at two levels (novox/hq ADR 0391):
|
||||
#
|
||||
# 1. the unit level: `go test ./...` untagged, no bus or other process, timed and held to a bound
|
||||
# (unit_bound below); over it the check fails and names the slowest tests (issue 895);
|
||||
# 2. the integration level: the whole suite with `-tags integration`, each test against a bus of its
|
||||
# own (internal/testbus, which issue 1171 brings with the first test that needs a bus) so nothing is
|
||||
# serialised. With no tagged test yet, the level runs the unit tests again and says their count.
|
||||
#
|
||||
# **A test that starts a bus or another process carries `//go:build integration`** as the first line of
|
||||
# its file; a file that held both kinds is two files (`<name>_integration_test.go` beside `<name>_test.go`).
|
||||
# Each level says its test count and its time.
|
||||
#
|
||||
# No dependency is committed (no vendor directory: .gitignore; the operator, 2026-10-19; issue 1304). Every dependency
|
||||
# is resolved by the version and checksum go.sum names (novox/hq ADR 0405 §5), from its public source: this binding
|
||||
# requires nothing of the mesh's own forge. `go mod verify` fails by module name when a downloaded dependency does not
|
||||
# match go.sum, and -mod=readonly fails a build whose go.sum lacks an entry instead of writing it. gofmt reads only
|
||||
# the binding's own files.
|
||||
#
|
||||
# Exit 0 is a pass; anything else fails `mesh/repo-check` with the last line printed.
|
||||
set -eu
|
||||
cd "$(dirname "$0")"
|
||||
# The toolchain the check runs in sets -mod=vendor; there is no vendor directory, so it is replaced.
|
||||
GOFLAGS="$(printf '%s' "${GOFLAGS:-}" | sed 's/-mod=[a-z]*//g') -mod=readonly"
|
||||
export GOFLAGS
|
||||
export GOPRIVATE=git.novox.be
|
||||
|
||||
unformatted=$(gofmt -l .)
|
||||
# **The unit level's bound, in seconds** (issue 895): the slowest package's own test time of the untagged run,
|
||||
# the compile not counted. A run over it fails the check and names the slowest tests. The SDK's unit suite is
|
||||
# small (its slowest package measured well under a second on a quiet machine), so 2 s leaves room for a busier
|
||||
# build node without hiding a test that should carry `integration` instead.
|
||||
unit_bound=2
|
||||
|
||||
# judge_unit_run says the unit level as `go test -v` reported it and fails when it was over the bound: $1 the
|
||||
# file holding the output of the untagged `go test -v` of every package (packages one after another, each
|
||||
# ending in its `ok <package> <time>` line), $2 the bound in seconds. Packages run side by side, so the
|
||||
# level's time is that of its slowest package; the five slowest tests of the run are named when it is over,
|
||||
# so that the bound is kept by making them cheap or by tagging them `integration`, and never by raising it
|
||||
# (issue 895).
|
||||
judge_unit_run() {
|
||||
out=$1 bound=$2
|
||||
awk '
|
||||
/^--- (PASS|FAIL|SKIP): / {
|
||||
name = $3; took = $4; gsub(/[()s]/, "", took)
|
||||
pending[++n] = took "\t" name
|
||||
if ($2 == "SKIP:") skipped++
|
||||
next
|
||||
}
|
||||
/^(ok|FAIL)[ \t]/ && NF >= 3 && $3 ~ /^[0-9.]+s$/ {
|
||||
t = $3; sub(/s$/, "", t)
|
||||
for (i = 1; i <= n; i++) print "T\t" pending[i] "\t" $2
|
||||
n = 0
|
||||
print "P\t" t "\t" $2
|
||||
}
|
||||
END { print "S\t" skipped + 0 }
|
||||
' "$out" >"$out.judged"
|
||||
tests=$(grep -c '^T' "$out.judged" || true)
|
||||
skipped=$(awk -F'\t' '$1 == "S" {print $2}' "$out.judged")
|
||||
level=$(awk -F'\t' '$1 == "P" && $2 + 0 > m {m = $2 + 0} END {printf "%.2f", m}' "$out.judged")
|
||||
echo "unit level: $tests tests ($skipped skipped), $level s (bound $bound s)"
|
||||
if awk -v t="$level" -v b="$bound" 'BEGIN {exit !(t + 0 > b + 0)}'; then
|
||||
echo "the unit level took $level s, over its bound of $bound s; the slowest tests:"
|
||||
awk -F'\t' '$1 == "T" {print $2 "\t" $4 "\t" $3}' "$out.judged" | sort -t"$(printf '\t')" -k1,1 -nr | head -n 5 |
|
||||
awk -F'\t' '{printf " %s s %s %s\n", $1, $3, $2}'
|
||||
echo "make them cheap (no wait, no process), or give their files //go:build integration if they start a bus or another process"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
# `sh go/merge-check.sh judge-unit-run <output> <bound>` runs only the judging of the unit level, on a
|
||||
# recorded output.
|
||||
if [ "${1:-}" = judge-unit-run ]; then
|
||||
shift
|
||||
judge_unit_run "$@"
|
||||
exit
|
||||
fi
|
||||
|
||||
if ! fetched=$(go mod download 2>&1); then
|
||||
echo "FAILED: the dependencies cannot be fetched: $(printf '%s\n' "$fetched" | tail -n 1)"
|
||||
exit 1
|
||||
fi
|
||||
if ! verified=$(go mod verify 2>&1); then
|
||||
echo "FAILED: a dependency does not match go.sum: $verified"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
unformatted=$(find . -name '*.go' -not -path './vendor/*' | xargs gofmt -l)
|
||||
if [ -n "$unformatted" ]; then
|
||||
echo "not gofmt'd:"
|
||||
echo "$unformatted"
|
||||
exit 1
|
||||
fi
|
||||
go vet ./...
|
||||
go test -count=1 ./...
|
||||
# The files tagged `integration` are vetted too, or nothing would read them.
|
||||
go vet -tags integration ./...
|
||||
|
||||
# NOT RACE-CHECKED here: the SDK's suite is small and carries no store or other shared state between
|
||||
# packages, so the race detector is not required of this check (novox/hq issue 1175); a module that needs
|
||||
# it asks for it in its own merge-check.sh.
|
||||
echo "NOT RACE-CHECKED: the Go binding's check runs without the race detector"
|
||||
|
||||
work=$(mktemp -d)
|
||||
trap 'rm -rf "$work"' EXIT
|
||||
|
||||
# The unit level first and alone: every package untagged, no bus or other process (judged above).
|
||||
status=0
|
||||
go test -count=1 -v ./... >"$work/unit.out" 2>&1 || status=$?
|
||||
if [ "$status" -ne 0 ]; then
|
||||
grep -vE '^(=== |[[:space:]]*--- PASS)' "$work/unit.out"
|
||||
echo "the unit level failed (go test exited $status)"
|
||||
exit 1
|
||||
fi
|
||||
judge_unit_run "$work/unit.out" "$unit_bound"
|
||||
|
||||
# The integration level: the whole suite with the tag, each test against its own bus (internal/testbus).
|
||||
integration_start=$(date +%s)
|
||||
status=0
|
||||
go test -tags integration -count=1 -v ./... >"$work/integration.out" 2>&1 || status=$?
|
||||
grep -vE '^(=== |[[:space:]]*--- PASS)' "$work/integration.out" || true
|
||||
tests=$(grep -cE '^--- (PASS|FAIL|SKIP): ' "$work/integration.out" || true)
|
||||
skipped=$(grep -cE '^--- SKIP: ' "$work/integration.out" || true)
|
||||
echo "integration level: $tests tests ($skipped skipped), $(($(date +%s) - integration_start)) s"
|
||||
if [ "$status" -ne 0 ]; then
|
||||
echo "the integration level failed (go test exited $status)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -57,7 +57,11 @@ type message struct {
|
||||
// channel is the one conversation with the runtime: what this bundle writes, serialised, and what
|
||||
// it asked and waits for.
|
||||
type channel struct {
|
||||
mu sync.Mutex
|
||||
mu sync.Mutex
|
||||
// wmu orders the writes to the runtime and nothing else: a write waits on the pipe for as long as
|
||||
// the runtime does not read, and mu must never wait with it, or the loop that reads the runtime's
|
||||
// answers stops (issue 1286).
|
||||
wmu sync.Mutex
|
||||
enc *json.Encoder
|
||||
next int
|
||||
waiting map[string]chan message
|
||||
@@ -90,8 +94,8 @@ type Envelope struct {
|
||||
|
||||
func (c *channel) say(m map[string]any) {
|
||||
m["jsonrpc"] = "2.0"
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
c.wmu.Lock()
|
||||
defer c.wmu.Unlock()
|
||||
_ = c.enc.Encode(m)
|
||||
}
|
||||
|
||||
@@ -472,10 +476,15 @@ func matchFrom(p []string, pi int, k []string, ki int) bool {
|
||||
return matchFrom(p, pi+1, k, ki+1)
|
||||
}
|
||||
|
||||
// EmitOptions is the provenance an emitter may attach (ADR 0042).
|
||||
// EmitOptions is the provenance an emitter may attach (ADR 0042), and the message id it may choose.
|
||||
type EmitOptions struct {
|
||||
CausationID string
|
||||
Schema string
|
||||
// MessageID is the id this emit is sent under, as x-event-id (and, by the tool runner, as the bus's
|
||||
// own Nats-Msg-Id): chosen by the emitter so a repeated publish inside the stream's duplicate window
|
||||
// is kept to one, never generated once an id is given (novox/hq ADR 0436 clause 4). Empty is a random
|
||||
// one, as on main.
|
||||
MessageID string
|
||||
}
|
||||
|
||||
// Emit asks the runtime to publish an event as this bundle's module, and returns once the bus has
|
||||
@@ -495,8 +504,17 @@ func Emit(eventType string, body any, opts ...EmitOptions) error {
|
||||
if node == "" {
|
||||
node = "unknown"
|
||||
}
|
||||
id := ""
|
||||
for _, o := range opts {
|
||||
if o.MessageID != "" {
|
||||
id = o.MessageID
|
||||
}
|
||||
}
|
||||
if id == "" {
|
||||
id = eventID()
|
||||
}
|
||||
headers := map[string]string{
|
||||
"x-event-id": eventID(), "x-source": source, "x-node": node,
|
||||
"x-event-id": id, "x-source": source, "x-node": node,
|
||||
"x-time": time.Now().UTC().Format(time.RFC3339Nano), "content-type": "application/json",
|
||||
}
|
||||
for _, o := range opts {
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
# git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261018003858-f185aedbf5d6
|
||||
## explicit; go 1.22
|
||||
# git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261021114014-66e8fdaa62e2
|
||||
## explicit; go 1.26.0
|
||||
git.novox.be/novox/mesh-sdk/go
|
||||
git.novox.be/novox/mesh-sdk/go/provider
|
||||
|
||||
Reference in New Issue
Block a user