Verification and support matrix
Say precisely what this section’s deployment recipe was checked against — platforms, configurations, versions, and executable checks with expected results — and what turns the word “verified” from a compliment into a test outcome.
Two branches, one per server. The serve branch covers the
section’s main route — law serve with a journal on one Linux
host, serving the known world with the kit fixture. The MCP
branch covers law-mcp-server (crate law-mcp) as a sliced
container image, built by the checkout’s image build and checked
by the profile checker. Nothing here covers SDKs or desktop
builds — those have their own articles.
Section vocabulary (binding)
Section titled “Section vocabulary (binding)”These four words mean the same in every Operate article. Existence of code alone never earns a stronger word.
| Word | Meaning |
|---|---|
| Implemented | the mechanism exists in the named source revision |
| Described | an instruction for it is published in this section |
| Verified | the named configuration passed the listed checks and the run record is available |
| Supported | the team commits to keep this scenario working inside the stated boundaries |
Prerequisites
Section titled “Prerequisites”Serve branch:
- The reference kit (
kit/secure-deploy/next to these articles, tracked in git withMANIFEST.sha256) at the pinned revision; tool0.1.1; the known worldpacks/examples/cases/kompaniyawith the recorded pin. - A Linux host for checks S4–S10 (socket binds are required);
checks S1–S3 run anywhere the
lawbinary runs.
MCP branch:
- The image digest under test and the profile it claims (the profile’s slice pin file present in the tree).
docker,curl,jq,python3on the checking host (operator tools).
- Pick the branch for the deployment under test and confirm its platform, configuration, and version cells below. Deviations under test must be named with the check run, or the run does not count as this matrix.
- Run that branch’s executable checks in order; each names its command and expected result. Stop at the first red cell and triage with Troubleshooting.
- Apply the recipe-verified conditions at the end before writing “verified” anywhere.
Serve branch (main route)
Section titled “Serve branch (main route)”Platform cell: Linux x64 host (systemd-shaped layout per the kit;
the served binary is the pinned law build). Configuration cells:
loopback bind 127.0.0.1:8480, token file set, journal directory
set, known world examples.cases.kompaniya@0.1.0, workers 2,
call timeout 30 s. Version cells: tool 0.1.1; world pin and
programHash from the kit’s expected/serve-ask-expected.json.
Getting the kit: it lives in git next to these articles — no
local overlay needed. The deployment record that qualifies a
release names two values: the checkout revision and the kit
digest. Fetch exactly that kit — not “current main” — and
verify it before use. From any clone:
CLONE=<path-to-clone> # any clone containing the revision below; every # git call names it via -C, so this sequence never # depends on the current directoryREV=<revision-from-the-deployment-record> # full 40-hex, e.g. the S1 row belowgit -C "$CLONE" cat-file -t "$REV" >/dev/null || git -C "$CLONE" fetch origingit -C "$CLONE" cat-file -t "$REV" >/dev/null || { echo "revision not found" >&2; exit 1; }DEST=$(mktemp -d /tmp/kit-under-test.XXXXXX) || exit 1git -C "$CLONE" archive --output="$DEST/kit.tar" "$REV" \ docs/operate/secure-deployment/kit || { echo "kit archive failed" >&2; exit 1; }tar -xf "$DEST/kit.tar" -C "$DEST" || { echo "kit extraction failed" >&2; exit 1; }KIT="$DEST/docs/operate/secure-deployment/kit"[ -f "$KIT/secure-deploy/MANIFEST.sha256" ] || { echo "kit layout unexpected" >&2; exit 1; }(cd "$KIT/secure-deploy" && shasum -a 256 -c MANIFEST.sha256) || exit 1shasum -a 256 "$KIT/secure-deploy/MANIFEST.sha256" # must equal the digest in the deployment record(cd "$KIT" && sh tests/test-rotate-token.sh && sh tests/test-list-decisions.sh) || exit 1git archive takes the revision, not the worktree, so a dirty
checkout cannot leak into the kit under test; the digest check
then binds the extracted files to the recorded run. All paths
derive from the computed $KIT root — no relative-cd
chain to miscount. The helpers under kit/bin/ travel in
the same archive (outside MANIFEST.sha256 scope, which
covers secure-deploy/ only) and are qualified by their
committed suites, not by the digest.
A run record filed in expected/RUN-RECORD.md at a new
revision + digest is what turns S4–S10 from NOT-RUN to green.
Executable checks (each names what was executed where):
- S1. Local smoke (executed at revision
ab75e84c, tool0.1.1):law ask packs/examples/cases/kompaniya --query-json packs/examples/cases/kompaniya/queries/zaregistrirovana.json --out <dir> --format brief→TRUE_ONLY,resultHash sha256:b6094c8e…64487. - S2. Fixture validity (executed): both
requests/serve-ask*.jsonparse, and the stale-pin file differs from the positive one inpin.resolutionHashonly. - S3. Pin provenance (executed): the fixture pin equals the
world’s
law.lockresolutionHashandname@version. - S4. Start on the Linux host per the kit unit;
GET /readyz→200after workers warm (needs the Linux run). - S5.
GET /v1/worldreports the fixture pin andprogramHash(needs the Linux run). - S6. Fixture ask through the ingress →
200, servedresultHashequals the recordedsha256:b6094c8e…64487(needs the Linux run). - S7. Stale-pin fixture →
409 SERVE_PIN_MISMATCH; missing/wrong token →401 SERVE_UNAUTHORIZED(needs the Linux run). - S8. Restart:
/readyz→200again with the same pin andprogramHashbefore ingress re-enable (needs the Linux run). - S9. Journal holds one fsynced
segment-*.jsonlline per served decision;law replay-record --world <dir> --journal <dir> --decision <id>replays green (needs the Linux run). - S10. Kit
check-postflight.shgreen end to end (needs the Linux run).
Limits that bound the branch: 1 MiB max body, 16 MiB max response, queue depth 64, 10 000 max assertions, no graceful drain (signals kill in-flight calls), one shared journal across generations with per-record pins.
MCP branch
Section titled “MCP branch”Platform cell: linux/amd64 only (builder
rust:1.94.1-alpine). Any other architecture is not checked —
do not report it as supported. Executable defaults (what the
binary does with no flags or env): host 127.0.0.1, port
8722, profile all, no token, no call limit, journal on,
journal body cap 64 KiB per side, journal socket
/run/systemd/journal/socket. Effective configuration of the
image under test (what M4–M8 run against — these override the
defaults and the run record must name them): a sliced profile
(a fixed non-all name; all is refused at build per M1), a
token set (M8’s 401 probe needs a tokened instance), an
origin allowlist set to a fixed list (M8’s 403 probe needs a
disallowed Origin to exist), loopback-only publish per M4.
Version cells: serverInfo.version "0.1.0; protocol revisions
2025-11-25, 2025-06-18, 2025-03-26, 2024-11-05;
slice-pin schema arxo.mcp-slice-pin/1.
Executable checks. Run M1–M3 on the build host, M4–M8 against the running image:
- M1.
python3 <checkout>/image_tree.py <profile> --out <fresh>(the image-tree helper in the checkout’s MCP deploy directory), then--check-pin <fresh>→ exit0both (mismatch exits1with a path diff — real). Profileallis refused at build (real). - M2. The profile checker passes on the profile under test (real check).
- M3.
law-mcp-server --help→ usage line on stderr, exit2(real quirk: help exits through the error path). - M4. Full launch with the effective configuration stated inline
(no hidden entrypoint state — token, profile, and origin
allowlist come from the env file the run record names):
then poll
Terminal TOKEN=$(cat <run-record-token-file>) # 0600, run-record names itCID=$(docker run -d -p 127.0.0.1::8722 \-e LAW_MCP_TOKEN="$TOKEN" \-e LAW_MCP_PROFILE=<sliced-profile> \-e LAW_MCP_ALLOWED_ORIGINS=<fixed-allowlist> \<digest>)PORT=$(docker port "$CID" 8722 | sed 's/.*://')GET /healthzon127.0.0.1:$PORTup to ~60 s →200with"status":"ok"and"oracleGuard":"absent"(real assertions; any other guard value means the slice composition is violated). The run record keepsCID,PORT, the digest, the profile, the allowlist, and the token-file reference; M5–M8 below all address127.0.0.1:$PORT. - M5.
GET /healthzfull shape →200JSON containingstatus,pid,profile,verificationPending: 0,verified: 0,engineOwnsIr: true,oracleGuard: "absent",driftScope: "semanticHash",overrunCalls(real route). - M6. Smoke
POST /mcptools/calllaw_search{"query":"Vertrag"}(real CI query) →200,.result.content[0].textpresent,.result.isError != true(real CI assertion). - M7.
law-mcp-server --healthcheck --port <port>against the running instance → exit0(real; it dials127.0.0.1,GET /healthz, 4 s timeouts, and requiresHTTP/1.1 200plus"status":"ok"). - M8. Negative probes (real statuses), each violating exactly one
condition against the M4 instance on
127.0.0.1:$PORT(valid token + allowed origin + known version unless the probe is about that field): missing/wrong token →401; disallowedOrigin→403; unknownmcp-protocol-versionon non-initialize→400; body over 1 MiB →413;GET /mcp→405;POST /elsewhere→404.
Limits that bound the branch (implementation-limits, real):
request MAX_BODY 1 MiB; journal default 64 KiB per side;
answers-service 30 s / 32 MiB; healthcheck 4 s legs; no in-code
connection, memory, or per-user caps; no worker cancellation.
Expected result
Section titled “Expected result”Serve branch: S1–S10 green on the pinned runtime + world; the run recorded with revision, pin, deviations, and date. MCP branch: all checks green on one pinned digest; the run recorded with digest, profile, deviations, and date.
Failures and diagnostics
Section titled “Failures and diagnostics”- M4 orange past 60 s: image never healthy —
docker logs, then Memory/Filesystem areas of Troubleshooting. - M6 red while M4–M5 green: slice serves but the canon does not cover the probe query — wrong profile for the question, or a regressed slice; compare against the previous digest.
- M8 wrong status: the instance is not the code this matrix describes (stale digest, patched build) — stop, re-pin, restart the matrix from M1.
- S6 hash differs from the recorded
resultHash: the served world is not the fixture world (drifted copy, wrong target) — stop, re-derive the pin from the servedlaw.lock, restart from S3. - Any deviation from the configuration cells (different timeout, token, origins) without a record: the run is evidence for that deviation only, not for this matrix.
Support boundaries
Section titled “Support boundaries”- Supported, serve branch: Linux x64, pinned
lawbuild, known world served per Deploy a private HTTP service, upgraded per Upgrades and compatibility, backed up per Backup and restore, within the serve-branch limits. - Supported, MCP branch:
linux/amd64sliced images of the profiles with committed slice pins, run per Deploy a private MCP server, sized per Capacity and scaling, within the MCP-branch limits. - A serve deployment counts as verified only if S1–S10 are green on the pinned runtime + world and the run record names the revision, pin, deviations, and date. An MCP deployment counts as verified only if M1–M8 are green on the pinned digest with the same record discipline. Drop any check and the word is “unverified”, however healthy the instance looks.
- “Secure” in this section means only the mechanisms named in its articles (token check, loopback default, public-bind refusal, origin allow-list, unprivileged image user, pinned bytes). It does not mean audited, certified, or penetration-tested.
- Out of matrix: other architectures, unpinned builds, profile
allin images, shared artifact directories, modified sources, and anything the checks above did not execute.
Next step
Section titled “Next step”File the matrix run (revision/digest, pin/profile, deviations, green/red per check) with the release it qualifies; re-run it for every new build — a green matrix never transfers to another one.
Documentation for Arxo. Writings — blog.arxo.io.
Anonymous visit counts on stats.arxo.io, no cookies.