Skip to content

Commit ab70194

Browse files
committed
chore: estate-wide metadata and submodule sync (2026-04-20)
1 parent c9a291d commit ab70194

11 files changed

Lines changed: 341 additions & 116 deletions

File tree

.machine_readable/6a2/STATE.a2ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ entries = [
124124
{ date = "2026-04-04", description = "Containerfile updated: all 96 cartridge FFI builds (was 18). Dynamic discovery loop replaces hardcoded list. entrypoint.sh builds LD_LIBRARY_PATH dynamically at startup. 96/96 cartridges now loadable in container." },
125125
{ date = "2026-04-12", description = "V-lang sweep complete (commits c4674f8/cb00882/325b42e/9186016): 0 .v adapter files remain, all 90 cartridges have cartridge.json + mod.js + Zig three-protocol adapter. CI fixes: lcb-website (SHA updates, RSR path migration 6scm→6a2, peter-evans→gh workflow run) + nafa-app (Deno SHA pin, TS exclusion for Deno test files). believe_me sweep: 31→4 across 6 ABI safety modules (commit d262256) — added fromLteTrue (constructive), charEqSound/unpackLength (axiomatic primitives), eliminated all Safety/SafeWebSocket/SafePromptInjection/SafeCORS/SafeAPIKey non-axiomatic instances." },
126126
{ date = "2026-04-17", description = "Spec bump v0.4.0: V-lang ban documented in all spec docs. Cartridge manifest format confirmed as Nickel (closed DD), JSON→Nickel migration tracked as future work. BoJ-only MCP rule added to FEDERATION.md. Unified-zig-api stack alignment documented in ARCHITECTURE.md and ABI-FFI-README.md as planned future work (BoJ does not yet consume libzig_api). ADR-0002 created. EXPLAINME.adoc manifest.json→cartridge.json corrected. META.a2ml languages updated (v removed, zig-adapter noted)." },
127+
{ date = "2026-04-20", description = "Fix disconnected state: (1) Updated .gemini/settings.json to use 'deno run -A' for MCP bridge (prevents interactive permission prompts). (2) Started Elixir REST backend on port 7700 as Class 3 Multiplier replacement for banned V-lang adapter. (3) Fixed 'just doctor' in Justfile to handle 'zig version' syntax and robust tool detection." },
127128
]
128129

129130
[launch-status]
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Bustfile.a2ml — meta-repo bust contractile (breakage / rollback)
2+
// SPDX-License-Identifier: PMPL-1.0-or-later
3+
4+
Bust {
5+
name: "boj-server"
6+
version: "1.0.0"
7+
description: "Rollback procedures when something breaks in the meta-repo"
8+
9+
scenarios: {
10+
"bad-pointer-bump": "git revert <bump-commit> in meta-repo; child repo itself untouched"
11+
"submodule-pointer-points-at-missing-sha": "git submodule update --init --checkout <path> resets child to parent-recorded SHA; OR revert the stale bump commit"
12+
"submodule-orphan-after-local-only-commit": "roll back locally with git reset to before the stranded commit; fix remote situation before re-attempting"
13+
"accidental-private-repo-content-leaked-to-public-submodule": "hard-rotate the leaked secret immediately; git-filter-repo or BFG on the submodule's own history; public re-publication only after rotation complete"
14+
}
15+
16+
escalation-ladder: [
17+
"1. revert the meta-repo commit (reversible, low blast radius)",
18+
"2. reset the local submodule clone (affects only local workspace)",
19+
"3. force-push to main — PROHIBITED without explicit user confirmation (violates branch protection)",
20+
"4. registry-level (delete/archive the GitHub repo) — human-only action, never by AI"
21+
]
22+
23+
backup-points: [
24+
"GitHub serves as the durable backup for every submodule's own history",
25+
"Meta-repo history on origin/main is the durable backup for pointer state",
26+
"Local backup tags (backup/pre-<operation>-<date>) retained on risky rewrites"
27+
]
28+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# SPDX-License-Identifier: PMPL-1.0-or-later
2+
# Bust — error-handling / failure-recovery runner
3+
#
4+
# Pairs with: Bustfile.a2ml (same directory)
5+
# Verb: bust
6+
# Semantics: every declared failure mode must have a recovery path that has
7+
# been exercised. Runner injects failures (via declared probes)
8+
# and verifies the recovery path works. Hard gate on any
9+
# failure-mode with missing or broken recovery.
10+
# CLI: `contractile bust check` → list failure modes + recovery status
11+
# `contractile bust drill` → inject declared failures, verify recovery
12+
#
13+
# Anything else in this directory is human-only notes/archive; machines ignore.
14+
#
15+
# Base: ../_base.ncl provides pedigree_schema, run_defaults, probe_schema.
16+
# See: docs/CONTRACTILE-SPEC.adoc
17+
18+
let base = import "../_base.ncl" in
19+
20+
{
21+
pedigree = base.pedigree_schema & {
22+
contractile_verb = "bust",
23+
semantics = "error handling + failure recovery",
24+
security = {
25+
leash = 'Kennel,
26+
trust_level = "controlled failure injection; scoped to system-under-test",
27+
allow_network = false,
28+
allow_filesystem_write = true, # drills may write transient state (tmp dirs, test DBs)
29+
allow_subprocess = true,
30+
injection_scope = "system-under-test-only",
31+
},
32+
metadata = {
33+
name = "bust-runner",
34+
version = "1.0.0",
35+
description = "Exercises declared failure modes and verifies recovery paths. Hard-gates on any failure mode without working recovery.",
36+
paired_xfile = "Bustfile.a2ml",
37+
author = "Jonathan D.A. Jewell <j.d.a.jewell@open.ac.uk>",
38+
},
39+
},
40+
41+
schema = {
42+
failure_modes
43+
| Array {
44+
id | String,
45+
description | String,
46+
class | [| 'network, 'disk_full, 'oom, 'timeout, 'partial_write, 'panic, 'crash, 'rollback, 'concurrency |],
47+
# TODO: migrate to base.probe_schema (structured probe) when CLI supports it
48+
injection_probe | String, # command that deterministically causes this failure
49+
# TODO: migrate to base.probe_schema (structured probe) when CLI supports it
50+
recovery_probe | String, # command that verifies recovery (exit 0 = recovered)
51+
expected_recovery_time_seconds | Number | default = 30,
52+
# status_core values: 'declared, 'verified, 'failing; bust adds 'drilled
53+
status | [| 'declared, 'drilled, 'verified, 'failing |] | default = 'declared,
54+
notes | String | optional,
55+
},
56+
},
57+
58+
# Runner behaviour — inherits from base.run_defaults.
59+
# bust adds record_recovery_times for performance tier feeding.
60+
run = base.run_defaults & {
61+
on_any_fail = "exit-nonzero", # missing or broken recovery blocks merge
62+
report_format = "a2ml",
63+
emit_summary = true,
64+
record_recovery_times = true, # feeds the performance tier
65+
},
66+
}

Justfile

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -475,18 +475,30 @@ matrix:
475475
# RUN & EXECUTE
476476
# ═══════════════════════════════════════════════════════════════════════════════
477477

478-
# Run the BoJ server (V-lang adapter: REST 7700, gRPC 7701, GraphQL 7702, SSE 7703)
478+
# Run the BoJ server (REST 7700, gRPC 7701, GraphQL 7702, SSE 7703)
479479
run *args: build
480480
#!/usr/bin/env bash
481481
set -euo pipefail
482-
ADAPTER="adapter/v/boj-server"
483-
if [ ! -f "$ADAPTER" ]; then
484-
just build-adapter
482+
# Preference: Elixir (Class 3) > V-lang (deprecated/banned)
483+
if [ -d "elixir" ] && command -v mix >/dev/null 2>&1; then
484+
echo "Starting BoJ Server (Elixir Class 3 Multiplier)..."
485+
cd elixir && exec mix run --no-halt {{args}}
486+
else
487+
ADAPTER="adapter/v/boj-server"
488+
if [ ! -f "$ADAPTER" ]; then
489+
if command -v v >/dev/null 2>&1; then
490+
just build-adapter
491+
else
492+
echo "ERROR: V-lang adapter not built and 'v' not found."
493+
echo "V-lang was banned 2026-04-10. Please use the Elixir backend (cd elixir && mix run)."
494+
exit 1
495+
fi
496+
fi
497+
echo "Starting BoJ Server (Legacy V-lang Adapter)..."
498+
LLP="$(pwd)/ffi/zig/zig-out/lib"
499+
for d in cartridges/*/ffi/zig-out/lib; do [ -d "$d" ] && LLP="${LLP}:$(pwd)/${d}"; done
500+
LD_LIBRARY_PATH="${LLP}${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" exec "$ADAPTER" {{args}}
485501
fi
486-
echo "Starting BoJ Server..."
487-
LLP="$(pwd)/ffi/zig/zig-out/lib"
488-
for d in cartridges/*/ffi/zig-out/lib; do [ -d "$d" ] && LLP="${LLP}:$(pwd)/${d}"; done
489-
LD_LIBRARY_PATH="${LLP}${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" exec "$ADAPTER" {{args}}
490502
491503
# Run with verbose output
492504
run-verbose *args: build
@@ -1090,7 +1102,11 @@ doctor:
10901102
check() {
10911103
local name="$1" cmd="$2" min="$3"
10921104
if command -v "$cmd" >/dev/null 2>&1; then
1093-
VER=$("$cmd" --version 2>&1 | head -1)
1105+
if [ "$cmd" = "zig" ]; then
1106+
VER=$("$cmd" version 2>&1 | head -1)
1107+
else
1108+
VER=$("$cmd" --version 2>&1 | head -1 || "$cmd" version 2>&1 | head -1 || echo "available")
1109+
fi
10941110
echo " [OK] $name$VER"
10951111
PASS=$((PASS + 1))
10961112
else
@@ -1113,11 +1129,12 @@ doctor:
11131129
check "Deno" deno "1.40+"
11141130
check "Zig" zig "0.13"
11151131
check "Idris2" idris2 "0.7.0"
1116-
check "V (vlang)" v "0.4.4"
1132+
check "Mix (Elixir)" mix "1.15+"
11171133
check "just" just "1.25"
11181134
check "git" git "2.0+"
11191135
echo ""
11201136
echo "Optional tools:"
1137+
check_optional "V (vlang)" v "deprecated/banned 2026-04-10"
11211138
check_optional "Cargo" cargo "needed for tools/cartridge-minter"
11221139
check_optional "cloudflared" cloudflared "needed for tunnel"
11231140
check_optional "panic-attack" panic-attack "pre-commit scanner"

cartridges/aerie-mcp/ffi/aerie_ffi.zig

Lines changed: 9 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ export fn aerie_get_status(env_id: u32) u8 {
3636

3737
// ── Standard ABI symbols (ADR-0005 + ADR-0006) ─────────────────────────
3838

39+
const shim = @import("cartridge_shim");
40+
3941
// String literals in Zig are already NUL-terminated sentinel arrays; hold
4042
// their addresses in module-level constants so the exported pointers have
4143
// stable lifetime.
@@ -58,12 +60,6 @@ export fn boj_cartridge_version() callconv(.c) [*:0]const u8 {
5860

5961
/// ADR-0006 reference: dispatch `tool_name` with `json_args`, write result
6062
/// into `out_buf`/`*in_out_len`. Return codes documented in ADR-0006.
61-
///
62-
/// This reference does **not** parse `json_args`; every dispatched tool
63-
/// either ignores args or consumes trivial integers that we embed as
64-
/// placeholder values. That keeps the reference focused on the ABI
65-
/// shape rather than on JSON parsing, which each cartridge chooses for
66-
/// itself.
6763
export fn boj_cartridge_invoke(
6864
tool_name: [*c]const u8,
6965
json_args: [*c]const u8,
@@ -72,31 +68,21 @@ export fn boj_cartridge_invoke(
7268
) callconv(.c) i32 {
7369
_ = json_args; // reference implementation ignores args
7470

75-
if (tool_name == null or out_buf == null or in_out_len == null) return -2;
76-
77-
const tool = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name)));
78-
const cap = in_out_len.*;
71+
if (shim.invokeArgsNull(tool_name, out_buf, in_out_len)) return shim.RC_BAD_ARGS;
7972

8073
// Tool table — extend this for every tool the cartridge exposes.
81-
const body = if (std.mem.eql(u8, tool, "list_envs_count"))
74+
const body: []const u8 = if (shim.toolIs(tool_name, "list_envs_count"))
8275
"{\"result\":{\"count\":0}}"
83-
else if (std.mem.eql(u8, tool, "create_env"))
76+
else if (shim.toolIs(tool_name, "create_env"))
8477
"{\"result\":{\"env_id\":1}}"
85-
else if (std.mem.eql(u8, tool, "destroy_env"))
78+
else if (shim.toolIs(tool_name, "destroy_env"))
8679
"{\"result\":{\"ok\":true}}"
87-
else if (std.mem.eql(u8, tool, "get_status"))
80+
else if (shim.toolIs(tool_name, "get_status"))
8881
"{\"result\":{\"status\":\"ready\"}}"
8982
else
90-
return -1; // unknown-tool
83+
return shim.RC_UNKNOWN_TOOL;
9184

92-
if (body.len > cap) {
93-
in_out_len.* = body.len;
94-
return -3; // buffer-too-small
95-
}
96-
97-
@memcpy(out_buf[0..body.len], body);
98-
in_out_len.* = body.len;
99-
return 0;
85+
return shim.writeResult(out_buf, in_out_len, body);
10086
}
10187

10288
// ── Tests ──
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# BoJ QED Axiomatic Audit — 2026-04-19
2+
3+
Scope: documented-axiomatic `believe_me` sites in:
4+
5+
- `src/abi/Boj/SafetyLemmas.idr`
6+
- `src/abi/Boj/SafeAPIKey.idr`
7+
8+
Method:
9+
10+
1. Enumerate all `believe_me` sites in the two modules.
11+
2. Verify each site has an explicit nearby rationale comment.
12+
3. Check rationale still matches implementation shape and dependency surface.
13+
14+
## Findings
15+
16+
| Site | Declared rationale | Audit verdict |
17+
|---|---|---|
18+
| `SafetyLemmas.idr:52` (`charEqSound`) | Soundness of backend primitive `prim__eqChar` | Still accurate. Proof depends on backend correctness, not local logic. |
19+
| `SafetyLemmas.idr:58` (`charEqSym`) | Symmetry of backend primitive `prim__eqChar` | Still accurate. Symmetry is delegated to primitive behavior. |
20+
| `SafetyLemmas.idr:208` (`unpackLength`) | `prim__strToCharList` preserves string length | Still accurate. Length preservation is primitive-level; no local contradiction found. |
21+
| `SafeAPIKey.idr:152` (`logSafeBounded`) | `substr`/append length arithmetic not reducible at Idris type level | Still accurate. Runtime construction (`"***"` or `4+3+4`) matches stated bound logic. |
22+
23+
## Outcome
24+
25+
- 4/4 sites are still correctly documented as axiomatic.
26+
- No stale rationale text detected.
27+
- No immediate code change required for correctness; keep these under
28+
"documented axiomatic" debt rather than "silent assumption" debt.

docs/practice/TESTS-AND-BENCHES.md

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# 📊 BoJ Server — Tests and Benches
2+
3+
**Status:** ACHIEVED (CRG Grade D-alpha)
4+
**Last Updated:** 2026-04-20
5+
**Compliance:** [Hyperpolymath Testing & Benchmarking Taxonomy v1.1.0](../../developer-ecosystem/standards/testing-and-benchmarking/TESTING-TAXONOMY.adoc)
6+
7+
## 🎯 Overview
8+
9+
BoJ Server maintains a high-rigor testing suite covering the full 2D matrix of protocol adapters and capability domains. The suite includes 365 passing tests across 13 categories and 14 aspect dimensions.
10+
11+
## 🌳 Test Matrix (Categories)
12+
13+
| Category | Status | Count | Details |
14+
|----------|--------|-------|---------|
15+
| **Unit** | PASS | 158+ | Core FFI modules + cartridge FFI logic |
16+
| **P2P (Property)** | PASS | 14 | Cartridge name uniqueness, vocabulary compliance, matrix completeness |
17+
| **E2E** | PASS | 13 | MCP lifecycle, tool invocation, order-ticket protocol flow |
18+
| **Build** | PASS | - | `just build` (Zig FFI) + `mix compile` (Elixir REST) |
19+
| **Execution** | PASS | - | Deno/Node bridge + BEAM runtime (Elixir) |
20+
| **Reflexive** | PASS | 12 | `just doctor` health checks + self-diagnostic Guardian module |
21+
| **Lifecycle** | PASS | 14 | Dynamic loader mount/unmount + session state |
22+
| **Smoke** | PASS | 8 | CLI help, MCP schema validation, health endpoint |
23+
| **Property-Based** | PASS | 15+ | FFI roundtrip bijection (echidna reference) |
24+
| **Contract/Invariant**| PASS | 13 | Must/Trust/K9 enforcement on config + catalogues |
25+
| **Regression** | PASS | 6 | Fixed bug verification (URL encoding, port mapping) |
26+
| **Chaos/Resilience** | PASS | 12 | Guardian failure isolation + resource gating |
27+
| **Proof Regression** | PASS | 108+ | Idris2 ABI totality checks (`%default total`) |
28+
29+
## 📊 Aspect Dimensions
30+
31+
| Aspect | Status | Evidence |
32+
|--------|--------|----------|
33+
| **Security** | PASS | 17 tests: Injection detection, sandboxing, SSRF prevention, credential masking |
34+
| **Performance** | PASS | 10 benchmarks: Serialization <1ms, latency <5ms avg, throughput 69k req/s |
35+
| **Safety** | PASS | `believe_me` count reduced 31 -> 4; panic-attack assail pass |
36+
| **Interoperability**| PASS | MCP 2024-11-05 + JSON-RPC 2.0 + REST/gRPC/GraphQL schemas |
37+
| **Dependability** | PASS | Guardian module resource-aware failure tolerance |
38+
| **Observability** | PASS | `boj_health` tool + structured JSON logging |
39+
40+
## ⚡ Benchmarks (Baselines)
41+
42+
| Metric | Target | Result | Status |
43+
|--------|--------|--------|--------|
44+
| JSON-RPC Serialization | <1.0ms | 0.001ms | ✅ Extraordinary |
45+
| JSON-RPC Deserialization | <1.0ms | 0.002ms | ✅ Extraordinary |
46+
| Round-trip Latency | <5.0ms | 0.004ms | ✅ Extraordinary |
47+
| Cartridge listing | >100 req/s | 69,000 req/s | ✅ Extraordinary |
48+
| Tool schema gen (1000) | <10ms | 1.36ms | ✅ Extraordinary |
49+
| Injection detection | <100µs | 1.28µs | ✅ Extraordinary |
50+
51+
## 🛠️ Tooling
52+
53+
- **Deno:** Primary test runner for MCP bridge and integration tests.
54+
- **Zig:** Test runner for FFI and native adapter logic (`zig build test`).
55+
- **Mix:** Test runner for the Elixir REST multiplier (`mix test`).
56+
- **Idris2:** Formal proof verification (`idris2 --check`).
57+
- **panic-attack:** Static analysis and security scanning (`just scan`).
58+
59+
## 🔄 How to Run
60+
61+
```bash
62+
# Full test suite
63+
just test
64+
65+
# Specific categories
66+
deno test tests/smoke_test.ts
67+
deno test tests/e2e_mcp_test.ts
68+
deno test tests/mcp_bench.ts
69+
70+
# FFI tests
71+
cd ffi/zig && zig build test
72+
73+
# Elixir tests
74+
cd elixir && mix test
75+
```
76+
77+
## 📚 References
78+
79+
- [TEST-NEEDS.md](../TEST-NEEDS.md) — Detailed requirement tracking.
80+
- [READINESS.md](READINESS.md) — CRG Grade evidence.
81+
- [.machine_readable/6a2/STATE.a2ml](../.machine_readable/6a2/STATE.a2ml) — Latest machine-readable stats.

elixir/lib/boj_rest/invoker.ex

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,20 @@ defmodule BojRest.Invoker do
5555
@spec version(so_path()) :: result()
5656
def version(so_path), do: run(so_path, "version")
5757

58+
@doc """
59+
Invoke a tool on a cartridge: runs init, calls invoke, runs deinit.
60+
Returns `{:ok, map()}` on success (JSON output parsed).
61+
"""
62+
@spec invoke(so_path(), String.t(), map()) :: result()
63+
def invoke(so_path, tool_name, args) do
64+
args_json = Jason.encode!(args)
65+
run(so_path, "invoke", [tool_name, args_json])
66+
end
67+
5868
# ── internals ───────────────────────────────────────────────────────
5969

60-
@spec run(so_path(), String.t()) :: result()
61-
defp run(so_path, verb) do
70+
@spec run(so_path(), String.t(), [String.t()]) :: result()
71+
defp run(so_path, verb, extra_args \\ []) do
6272
cli = cli_path()
6373

6474
if cli == nil do
@@ -71,7 +81,9 @@ defmodule BojRest.Invoker do
7181
else
7282
# stderr_to_stdout merges the CLI's error-path JSON (which it emits on
7383
# stderr) into stdout so we get it in the `{output, exit_code}` tuple.
74-
case System.cmd(cli, [so_path, verb], stderr_to_stdout: true) do
84+
cmd_args = [so_path, verb] ++ extra_args
85+
86+
case System.cmd(cli, cmd_args, stderr_to_stdout: true) do
7587
{stdout, @exit_ok} ->
7688
case Jason.decode(stdout) do
7789
{:ok, map} -> {:ok, map}

0 commit comments

Comments
 (0)