Commit05551a37Recorded5 May 2026Repositoryapiary

v0.1.7: bump version, add CHANGELOG, extend smoke harness

Message

Patch release covering the three bugs landed in the prior commits.

CHANGELOG entry under v0.1.7 documents all three fixes plus the infrastructure changes (dev-dependencies declared so 'sigil test' can build the harness without a manual --add-dependency dance, including an explicit sigil-version dep that's transitively needed by sigil-build but not auto-resolved on this host).

Smoke harness extensions: - test/smoke.sh pre-creates the ops-workers group on the throwaway enclave-server and exports APIARYWORKERGROUP=ops-workers so the smoke driver can verify the env-var fallback end-to-end. - test/smoke-driver.sgl adds three live checks: bug-A-spawn-worker-default-groups: spawn a worker without explicit groups, then whois the new bot and confirm it landed in ops-workers. bug-B-list-members-surfaces-subordinates: query bot list-reports-to <leader-nick> and confirm the just- spawned smoke-bee-1 shows up. * bug-C-send-message-markdown-em-dash: the brief's exact trigger text rounds through enclave-bridge-send-dm! with format: 'markdown without raising the apply-arity error.

All three smoke checks PASS against a local enclave v0.3.0 provisioned by test/smoke.sh.

Changed
 CHANGELOG.md          | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 package.sgl           |  7 ++++++-
 test/smoke-driver.sgl | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 test/smoke.sh         |  7 +++++++
 4 files changed, 150 insertions(+), 1 deletion(-)
Diff
CHANGELOG.mdmodified
@@ -1,5 +1,78 @@
1
# Changelog
2
+3
## 0.1.7 — bug-fix-spike: spawn-worker default groups, list-members, markdown sweep
+4
+5
Three contained tool-surface fixes surfaced 2026-04-29 during the
+6
first end-to-end apiary↔enclave session against the production
+7
v0.2.3 deploy.
+8
+9
### Fixed
+10
+11
- **`spawn-worker` default `groups` now honors `APIARY_WORKER_GROUP`
+12
env var.** Previously, calling `spawn-worker` without a `groups`
+13
argument silently sent NO `groups:` segment to EnclaveServ, so
+14
the new bot landed in zero groups even though the tool's own
+15
description claimed `"defaults to APIARY_WORKER_GROUP
+16
server-side"`. The default-resolution now lives apiary-side: an
+17
omitted (`#f`) or empty-string `groups` arg falls back to the
+18
env var. If the env var is also unset/empty, no `groups:`
+19
segment is sent and the new bot has no group memberships
+20
(this case is documented in the tool description).
+21
- **`list-members` queries the leader's actual subordinates.**
+22
The v0.1.0 implementation issued EnclaveServ's `bot list`,
+23
which is filtered by ownership — and a leader bot doesn't
+24
*own* its workers (the human owner does), so a leader with
+25
active subordinates was always told `"You own no bots."`
+26
Switched to `bot list-reports-to <self-nick>` (added in
+27
enclave v0.2.2), which surfaces every bot whose `reports-to`
+28
matches the caller. Also swapped the result-formatting path
+29
from `(apply string-append ...)` to a `string-join` fold so
+30
long subordinate lists don't re-trip the apply-arity ceiling
+31
that bit `markdown-irc` in v0.1.3.
+32
- **`send-message` markdown→mIRC sweep.** Added regression tests
+33
for the apply-arity bug fixed in v0.1.3 — the exact trigger
+34
text from the bug-fix-spike brief plus six sweep cases
+35
(em-dash alone, em-dash + ASCII apostrophe, em-dash + curly
+36
single quote, em-dash + curly double quote, em-dash +
+37
ellipsis, em-dash + backtick, em-dash + bold) and a
+38
~3000-char multi-sentence stress case. All translate through
+39
`markdown->irc` without hitting the Sigil-VM apply-arity
+40
ceiling.
+41
+42
### Changed
+43
+44
- `list-members` tool description rewritten to reflect the new
+45
semantic ("this leader's subordinates" rather than "bots known
+46
to EnclaveServ"). Leader-mode instructions in `apiary-instructions`
+47
(consumed by the MCP client during `initialize`) updated to
+48
match.
+49
- `spawn-worker`'s `groups` parameter description now states
+50
the resolution order (explicit arg → `APIARY_WORKER_GROUP` env
+51
→ no group memberships) so callers know what an omitted arg
+52
means without reading the source.
+53
+54
### Added
+55
+56
- `dev-dependencies` declared in `package.sgl` so `sigil test`
+57
can build the test harness without a manual `--add-dependency`
+58
dance. Pulls `sigil-test`, `sigil-test-runner`, and
+59
`sigil-version` (the latter is transitively needed by
+60
`sigil-build` but isn't auto-resolved on this host).
+61
- `or-empty-env` and `env-or-false` exported from `(apiary
+62
tools)` so unit tests can directly exercise the
+63
groups-defaulting helper used by `spawn-worker`.
+64
- `test/smoke.sh` pre-creates an `ops-workers` group on the
+65
throwaway enclave and exports `APIARY_WORKER_GROUP=ops-workers`
+66
so the smoke driver can verify the env-var fallback end-to-end.
+67
- Three smoke checks in `test/smoke-driver.sgl`:
+68
`bug-A-spawn-worker-default-groups` (whois confirms the new
+69
bot landed in `ops-workers`), `bug-B-list-members-surfaces-
+70
subordinates` (the just-spawned bot shows up in the
+71
list-reports-to query), and
+72
`bug-C-send-message-markdown-em-dash` (the brief's exact
+73
trigger text rounds through `enclave-bridge-send-dm!` without
+74
raising).
+75
76
## 0.1.4 — registration-timeout resilience for enclave restarts
77
78
The keepalive work in v0.1.2 already covered connection-level
package.sglmodified
@@ -6,7 +6,7 @@
6
7
(package
8
name: "apiary"
9
version: "0.1.6"
+9
version: "0.1.7"
10
description: "MCP server for Enclave-based agent coordination — leader/worker hive runtime"
11
url: "https://codeberg.org/sigil/apiary"
12
license: "BSD-3-Clause"
@@ -39,6 +39,11 @@
39
(from-git url: "codeberg:sigil/sigil-mcp" version: "^0.14.0")
40
(from-git url: "codeberg:sigil/sigil-irc" version: "^0.10.1"))
41
+42
dev-dependencies: (list
+43
(from-git url: "codeberg:sigil/sigil-test" package: "sigil-test" version: "^0.14")
+44
(from-git url: "codeberg:sigil/sigil-test" package: "sigil-test-runner" version: "^0.14")
+45
(from-git url: "codeberg:sigil/sigil-version" version: "^0.13.1"))
+46
47
tasks: (list
48
(task
49
name: 'build
test/smoke-driver.sglmodified
@@ -306,6 +306,70 @@
306
(assert-true (enclave-conn-cap-acked? conn "message-tags")))
307
(display "PASS multiline-cap-negotiated\n")
308
+309
;; --- Bug A smoke: spawn-worker without explicit `groups`
+310
;; falls back to the APIARY_WORKER_GROUP env var.
+311
;;
+312
;; The harness sets APIARY_WORKER_GROUP=ops-workers and
+313
;; pre-creates that group on the throwaway enclave. Spawning
+314
;; a worker without the `groups` arg should land it in
+315
;; ops-workers. Verified via `whois <new-nick>`.
+316
(let* ((conn (enclave-bridge-state-conn state))
+317
(worker-nick "smoke-bee-1")
+318
(result (enclave-register-bot conn worker-nick
+319
expires-in: "2m"
+320
groups: (or-empty-env #f "APIARY_WORKER_GROUP")
+321
reports-to: +leader-nick+))
+322
(status (or (assoc-ref "status" result) "?")))
+323
(assert-equal "ok" status)
+324
;; Whois the new bot — verify it landed in the env-var
+325
;; group. The whois response surfaces a `groups: <csv>` line.
+326
(let* ((whois (enclave-services-call conn
+327
(string-append "whois " worker-nick)))
+328
(body (or (assoc-ref "body" whois) ""))
+329
(lines (or (assoc-ref "body-lines" whois) '()))
+330
(haystack
+331
(string-join
+332
(cons body
+333
(if (list? lines) lines '()))
+334
"\n")))
+335
(assert-true
+336
(string-contains? haystack "ops-workers"))))
+337
(display "PASS bug-A-spawn-worker-default-groups\n")
+338
+339
;; --- Bug B smoke: list-members surfaces this leader's
+340
;; subordinates (bots whose reports-to = self-nick), not the
+341
;; ownership-filtered `bot list`. The just-spawned
+342
;; smoke-bee-1 has reports-to=+leader-nick+, so the
+343
;; list-reports-to query must include it.
+344
(let* ((conn (enclave-bridge-state-conn state))
+345
(cmd (string-append "bot list-reports-to " +leader-nick+))
+346
(result (enclave-services-call conn cmd))
+347
(body (or (assoc-ref "body" result) ""))
+348
(lines (or (assoc-ref "body-lines" result) '()))
+349
(haystack
+350
(string-join
+351
(cons body
+352
(if (list? lines) lines '()))
+353
"\n")))
+354
(assert-equal "ok" (or (assoc-ref "status" result) "?"))
+355
(assert-true (string-contains? haystack "smoke-bee-1")))
+356
(display "PASS bug-B-list-members-surfaces-subordinates\n")
+357
+358
;; --- Bug C smoke: send-message with markdown prose
+359
;; containing em-dashes + apostrophes does NOT throw the
+360
;; apply-arity VM error. The exact trigger text from the
+361
;; brief routes through markdown->irc → split-lines →
+362
;; enclave-post-multiline; the call must complete.
+363
(let* ((trigger
+364
"Got it via DM. The fix landed — does Goguma's conversations list now show this thread? That's the actual test — message delivery was always working...")
+365
(result (enclave-bridge-send-dm! state "daviwil" trigger
+366
format: 'markdown)))
+367
(assert-true (string? result))
+368
;; Success path returns "DM to <nick>: ..." — error path
+369
;; would start with "Error:".
+370
(assert-false (string-starts-with? result "Error:")))
+371
(display "PASS bug-C-send-message-markdown-em-dash\n")
+372
373
;; --- send-channel with multi-line text emits a BATCH ---
374
;; daviwil should observe BATCH +ref / N tagged PRIVMSGs /
375
;; BATCH -ref. The first body line carries an `@` mention
test/smoke.shmodified
@@ -59,6 +59,12 @@ DAVIWIL_PASS=admin
59
ENCLAVE_DB_PATH="$DB" "$ENCLAVE_BIN" \
60
user add daviwil --password "$DAVIWIL_PASS" --role admin > /dev/null
61
+62
# Pre-create the ops-workers group so the Bug-A smoke check (which
+63
# spawns a worker without an explicit `groups` arg and verifies it
+64
# lands in APIARY_WORKER_GROUP) has a real group to land in.
+65
ENCLAVE_DB_PATH="$DB" "$ENCLAVE_BIN" \
+66
group create ops-workers > /dev/null 2>&1 || true
+67
68
LEADER_OUT=$(ENCLAVE_DB_PATH="$DB" "$ENCLAVE_BIN" \
69
bot register leader-davos --owner daviwil --allow-services yes)
70
LEADER_TOKEN=$(echo "$LEADER_OUT" | grep -oE '[a-f0-9]{64}' | head -1)
@@ -86,6 +92,7 @@ APIARY_TOKEN="$LEADER_TOKEN" \
92
APIARY_CHANNEL=#hive \
93
APIARY_OWNER_NICK=daviwil \
94
APIARY_REPORTS_TO=daviwil \
+95
APIARY_WORKER_GROUP=ops-workers \
96
APIARY_SERVICES_TIMEOUT=8.0 \
97
APIARY_DAVIWIL_PASS="$DAVIWIL_PASS" \
98
sigil test test/smoke-driver.sgl > "$SMOKE_LOG" 2>&1