Files
mesh-catalog/merge-check.sh
T
jochen c0a24882f4
mesh/merge-gate pass: builds artifact-store-tools → novox; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: THE CHANGE ALTERS ITS OWN CHECK (merge-check.sh): main's version judged it; the change's judges the pull requests after it merges; it…
mesh/delivery stopped: the pull request closed unmerged
artifact-store-tools: say an image a definition pins is named by a definition, under any name the store has had (issue 323)
No record names an image the mesh did not make, so one a definition pins under an
older name of the store read as unrecorded, the same word as an image nothing
uses. The tool now reads every definition through the catalogue and says
named-by-a-definition with the module. The store's older names are the mesh's
setting older-store-names, since a catalogue names no installation. The
catalogue's check warns of a pin under an older name with the current one.
2026-10-12 14:32:31 +02:00

124 lines
7.4 KiB
Bash
Executable File

#!/bin/sh
# mesh-check-toolchain: go
# mesh-check-also: typescript merge-check-typescript.sh
#
# The catalogue's own check (novox/hq ADR 0237 as amended): the second layer of a pull request's merge
# check, `mesh/repo-check`, run by the build seat in the mesh's Go toolchain.
#
# The gate — the manifests the change touches through the running controller's module check, every machine
# of the facts snapshot composed with them and validated by the node-engine's own validator, the replays
# against this tree — is the build seat's first layer (`mesh/merge-gate`), run because the mesh's module
# graph builds these modules from here. It is not repeated here. This is the repository's own:
#
# 1. every manifest through the controller's module check, so one module's change cannot leave another
# it shares a rule with refused (MESH_GATE is the controller the mesh runs) — and the count of
# long-running resources without `health` held to the number in health-undeclared, which only goes down;
# 2. the Go tests of every module the change touches that has them, under the race detector when the
# toolchain has a C compiler. A requirement of the mesh's own forge the module cache does not hold (a
# pinned SDK commit) is taken from its repository's clone beside the check (checks/deps); a module whose
# dependencies still cannot be had **fails the check**, by name and why — its tests could not run, and a
# test that could not run is a failure, never a note (novox/hq issue 385). A module written in
# TypeScript is type-checked and tested by
# merge-check-typescript.sh, declared above, in the TypeScript toolchain (novox/hq issues 302, 311);
# 3. the words (novox/hq ADR 0244): no word the glossary retired for the tools, as copied in
# retired-words, in any text a module's tools can show an agent — every string in its own code that is
# not a test, and every description in its manifest. Run over every module, not only the touched ones,
# so a word newly retired is found everywhere it stands. The check's own test runs first.
# 4. the paths (novox/hq ADR 0260): no module names a path under /run, /var/lib, /usr/local/lib or /etc
# that another module's manifest places — modules talk over the bus, not through each other's files.
# Over every module; checks/paths/shared and checks/paths/known narrow it, and known only shrinks.
# 5. the agent's home (novox/hq ADR 0266): no module unpacks an archive, or writes into a file, under
# ${machine:agent-home} — the node-engine does both after checking the path, and the agent account owns
# that home and could swap a link in between.
# 6. the store's names (novox/hq issue 323): an image pinned by digest under a name the artifact store had
# before is warned of, with the store's current name — never refused, as the image runs. The older names
# are listed in checks/storenames/older-names, as the mesh's setting older-store-names gives them to
# artifact-store-tools.
set -eu
(cd checks/words && go test -count=1 . && go run . ../..)
# The agent's home (novox/hq ADR 0266): no archive, and no file written into, under it.
(cd checks/agenthome && go test -count=1 . && go run . ../..)
# The store's names (novox/hq issue 323): a pin under an older name is warned of, never refused.
(cd checks/storenames && go test -count=1 . && go run . ../..)
# The lists that narrow the paths check may not grow unseen: the base branch's copies are what they are
# judged against (MESH_CHECK_BASE, main when unset), read from the clone the check runs in.
base_lists=""
base_ref="origin/${MESH_CHECK_BASE:-main}"
if git rev-parse --verify --quiet "$base_ref^{commit}" >/dev/null 2>&1 &&
git cat-file -e "$base_ref:checks/paths/known" 2>/dev/null && git cat-file -e "$base_ref:checks/paths/shared" 2>/dev/null; then
base_lists=$(mktemp -d)
git show "$base_ref:checks/paths/known" >"$base_lists/known"
git show "$base_ref:checks/paths/shared" >"$base_lists/shared"
fi
(cd checks/paths && go test -count=1 . && if [ -n "$base_lists" ]; then go run . -base "$base_lists" ../..; else go run . ../..; fi)
if [ -n "${MESH_GATE:-}" ]; then
checked=$("$MESH_GATE" module check modules/*/module.json) || { printf '%s\n' "$checked"; exit 1; }
# **The count only goes down** (novox/hq ADR 0240 rule 8): the long-running resources that do not say how
# they are ready, as the controller counts them, against the number kept in health-undeclared. A change
# that raises it fails; one that lowers it writes the new number there, so it can never rise again.
kept=$(sed -n 's/^\([0-9][0-9]*\).*/\1/p' health-undeclared | head -n 1)
counted=$(printf '%s\n' "$checked" | sed -n 's/^long-running resources without health: \([0-9][0-9]*\)$/\1/p')
if [ -z "$counted" ]; then
echo "NOT COUNTED: the controller the mesh runs is older than the count of resources without health (ADR 0240 Phase B)"
elif [ "$counted" -gt "$kept" ]; then
echo "the long-running resources without health rose from $kept to $counted: declare how each new one is ready (ADR 0240 rule 8)"
exit 1
elif [ "$counted" -lt "$kept" ]; then
echo "the long-running resources without health fell from $kept to $counted: write $counted in health-undeclared, so the count cannot rise again"
exit 1
else
echo "long-running resources without health: $counted, as kept"
fi
else
echo "NOT CHECKED: no controller was built beside this check, so the manifests were not read by one"
fi
race=""
if command -v gcc >/dev/null 2>&1; then race="-race"; else echo "NOT RACE-CHECKED: the toolchain holds no C compiler"; fi
# The modules the change reaches are the controller's planner's answer (MESH_CHECK_MODULES, hq ADR 0238):
# a module by its name, a new one by its directory. By hand, without it, the directories the changed files
# are in.
if [ -n "${MESH_CHECK_MODULES:-}" ]; then
touched=$(printf '%s\n' "$MESH_CHECK_MODULES" | tr ',' '\n' | sed -e 's#^modules/##' -e '/\//d' | sort -u)
else
touched=$(printf '%s\n' "${MESH_CHECK_CHANGED:-}" | tr ',' '\n' | sed -n 's#^modules/\([^/]*\)/.*#\1#p' | sort -u)
fi
# A module's dependencies: fetched, or a forge requirement taken from its clone beside the check
# (MESH_CHECK_BESIDE); its tests run against them (checks/deps, novox/hq issue 385). The helper's own test
# runs first.
(cd checks/deps && go test -count=1 .)
deps=$(mktemp -d)
trap 'rm -rf "$deps"' EXIT
(cd checks/deps && go build -o "$deps/deps" .)
untestable=""
for m in $touched; do
[ -d "modules/$m" ] || continue
if [ ! -f "modules/$m/go.mod" ]; then
[ -f "modules/$m/package.json" ] && echo "modules/$m is TypeScript: merge-check-typescript.sh type-checks and tests it"
continue
fi
if ! modfile=$(GOPRIVATE=git.novox.be "$deps/deps" -beside "${MESH_CHECK_BESIDE:-}" -work "$deps" "modules/$m"); then
echo "FAILED: modules/$m could not be tested — $modfile"
untestable="$untestable modules/$m"
continue
fi
[ -n "$modfile" ] && echo "modules/$m takes its forge dependencies from the clones beside the check"
echo "testing modules/$m"
unformatted=$(cd "modules/$m" && gofmt -l .)
if [ -n "$unformatted" ]; then
echo "modules/$m is not gofmt'd: $unformatted"
exit 1
fi
cgo=0
[ -n "$race" ] && cgo=1
(cd "modules/$m" && CGO_ENABLED=$cgo GOPRIVATE=git.novox.be go vet ${modfile:+"-modfile=$modfile"} ./... &&
CGO_ENABLED=$cgo GOPRIVATE=git.novox.be go test ${modfile:+"-modfile=$modfile"} $race -count=1 ./...)
done
if [ -n "$untestable" ]; then
echo "the check fails: the tests of$untestable could not run (novox/hq issue 385)"
exit 1
fi