v0.1.7: bump version, add CHANGELOG, extend smoke harness
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.
CHANGELOG.md | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
package.sgl | 7 ++++++-
test/smoke-driver.sgl | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
test/smoke.sh | 7 +++++++
4 files changed, 150 insertions(+), 1 deletion(-)CHANGELOG.mdmodified
# Changelog## 0.1.7 — bug-fix-spike: spawn-worker default groups, list-members, markdown sweepThree contained tool-surface fixes surfaced 2026-04-29 during thefirst end-to-end apiary↔enclave session against the productionv0.2.3 deploy.### Fixed- **`spawn-worker` default `groups` now honors `APIARY_WORKER_GROUP` env var.** Previously, calling `spawn-worker` without a `groups` argument silently sent NO `groups:` segment to EnclaveServ, so the new bot landed in zero groups even though the tool's own description claimed `"defaults to APIARY_WORKER_GROUP server-side"`. The default-resolution now lives apiary-side: an omitted (`#f`) or empty-string `groups` arg falls back to the env var. If the env var is also unset/empty, no `groups:` segment is sent and the new bot has no group memberships (this case is documented in the tool description).- **`list-members` queries the leader's actual subordinates.** The v0.1.0 implementation issued EnclaveServ's `bot list`, which is filtered by ownership — and a leader bot doesn't *own* its workers (the human owner does), so a leader with active subordinates was always told `"You own no bots."` Switched to `bot list-reports-to <self-nick>` (added in enclave v0.2.2), which surfaces every bot whose `reports-to` matches the caller. Also swapped the result-formatting path from `(apply string-append ...)` to a `string-join` fold so long subordinate lists don't re-trip the apply-arity ceiling that bit `markdown-irc` in v0.1.3.- **`send-message` markdown→mIRC sweep.** Added regression tests for the apply-arity bug fixed in v0.1.3 — the exact trigger text from the bug-fix-spike brief plus six sweep cases (em-dash alone, em-dash + ASCII apostrophe, em-dash + curly single quote, em-dash + curly double quote, em-dash + ellipsis, em-dash + backtick, em-dash + bold) and a ~3000-char multi-sentence stress case. All translate through `markdown->irc` without hitting the Sigil-VM apply-arity ceiling.### Changed- `list-members` tool description rewritten to reflect the new semantic ("this leader's subordinates" rather than "bots known to EnclaveServ"). Leader-mode instructions in `apiary-instructions` (consumed by the MCP client during `initialize`) updated to match.- `spawn-worker`'s `groups` parameter description now states the resolution order (explicit arg → `APIARY_WORKER_GROUP` env → no group memberships) so callers know what an omitted arg means without reading the source.### Added- `dev-dependencies` declared in `package.sgl` so `sigil test` can build the test harness without a manual `--add-dependency` dance. Pulls `sigil-test`, `sigil-test-runner`, and `sigil-version` (the latter is transitively needed by `sigil-build` but isn't auto-resolved on this host).- `or-empty-env` and `env-or-false` exported from `(apiary tools)` so unit tests can directly exercise the groups-defaulting helper used by `spawn-worker`.- `test/smoke.sh` pre-creates an `ops-workers` group on the throwaway enclave and exports `APIARY_WORKER_GROUP=ops-workers` so the smoke driver can verify the env-var fallback end-to-end.- Three smoke checks in `test/smoke-driver.sgl`: `bug-A-spawn-worker-default-groups` (whois confirms the new bot landed in `ops-workers`), `bug-B-list-members-surfaces- subordinates` (the just-spawned bot shows up in the list-reports-to query), and `bug-C-send-message-markdown-em-dash` (the brief's exact trigger text rounds through `enclave-bridge-send-dm!` without raising).## 0.1.4 — registration-timeout resilience for enclave restartsThe keepalive work in v0.1.2 already covered connection-levelpackage.sglmodified
(package name: "apiary" version: "0.1.6" version: "0.1.7" description: "MCP server for Enclave-based agent coordination — leader/worker hive runtime" url: "https://codeberg.org/sigil/apiary" license: "BSD-3-Clause" (from-git url: "codeberg:sigil/sigil-mcp" version: "^0.14.0") (from-git url: "codeberg:sigil/sigil-irc" version: "^0.10.1")) dev-dependencies: (list (from-git url: "codeberg:sigil/sigil-test" package: "sigil-test" version: "^0.14") (from-git url: "codeberg:sigil/sigil-test" package: "sigil-test-runner" version: "^0.14") (from-git url: "codeberg:sigil/sigil-version" version: "^0.13.1")) tasks: (list (task name: 'buildtest/smoke-driver.sglmodified
(assert-true (enclave-conn-cap-acked? conn "message-tags"))) (display "PASS multiline-cap-negotiated\n") ;; --- Bug A smoke: spawn-worker without explicit `groups` ;; falls back to the APIARY_WORKER_GROUP env var. ;; ;; The harness sets APIARY_WORKER_GROUP=ops-workers and ;; pre-creates that group on the throwaway enclave. Spawning ;; a worker without the `groups` arg should land it in ;; ops-workers. Verified via `whois <new-nick>`. (let* ((conn (enclave-bridge-state-conn state)) (worker-nick "smoke-bee-1") (result (enclave-register-bot conn worker-nick expires-in: "2m" groups: (or-empty-env #f "APIARY_WORKER_GROUP") reports-to: +leader-nick+)) (status (or (assoc-ref "status" result) "?"))) (assert-equal "ok" status) ;; Whois the new bot — verify it landed in the env-var ;; group. The whois response surfaces a `groups: <csv>` line. (let* ((whois (enclave-services-call conn (string-append "whois " worker-nick))) (body (or (assoc-ref "body" whois) "")) (lines (or (assoc-ref "body-lines" whois) '())) (haystack (string-join (cons body (if (list? lines) lines '())) "\n"))) (assert-true (string-contains? haystack "ops-workers")))) (display "PASS bug-A-spawn-worker-default-groups\n") ;; --- Bug B smoke: list-members surfaces this leader's ;; subordinates (bots whose reports-to = self-nick), not the ;; ownership-filtered `bot list`. The just-spawned ;; smoke-bee-1 has reports-to=+leader-nick+, so the ;; list-reports-to query must include it. (let* ((conn (enclave-bridge-state-conn state)) (cmd (string-append "bot list-reports-to " +leader-nick+)) (result (enclave-services-call conn cmd)) (body (or (assoc-ref "body" result) "")) (lines (or (assoc-ref "body-lines" result) '())) (haystack (string-join (cons body (if (list? lines) lines '())) "\n"))) (assert-equal "ok" (or (assoc-ref "status" result) "?")) (assert-true (string-contains? haystack "smoke-bee-1"))) (display "PASS bug-B-list-members-surfaces-subordinates\n") ;; --- Bug C smoke: send-message with markdown prose ;; containing em-dashes + apostrophes does NOT throw the ;; apply-arity VM error. The exact trigger text from the ;; brief routes through markdown->irc → split-lines → ;; enclave-post-multiline; the call must complete. (let* ((trigger "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...") (result (enclave-bridge-send-dm! state "daviwil" trigger format: 'markdown))) (assert-true (string? result)) ;; Success path returns "DM to <nick>: ..." — error path ;; would start with "Error:". (assert-false (string-starts-with? result "Error:"))) (display "PASS bug-C-send-message-markdown-em-dash\n") ;; --- send-channel with multi-line text emits a BATCH --- ;; daviwil should observe BATCH +ref / N tagged PRIVMSGs / ;; BATCH -ref. The first body line carries an `@` mentiontest/smoke.shmodified
ENCLAVE_DB_PATH="$DB" "$ENCLAVE_BIN" \ user add daviwil --password "$DAVIWIL_PASS" --role admin > /dev/null# Pre-create the ops-workers group so the Bug-A smoke check (which# spawns a worker without an explicit `groups` arg and verifies it# lands in APIARY_WORKER_GROUP) has a real group to land in.ENCLAVE_DB_PATH="$DB" "$ENCLAVE_BIN" \ group create ops-workers > /dev/null 2>&1 || trueLEADER_OUT=$(ENCLAVE_DB_PATH="$DB" "$ENCLAVE_BIN" \ bot register leader-davos --owner daviwil --allow-services yes)LEADER_TOKEN=$(echo "$LEADER_OUT" | grep -oE '[a-f0-9]{64}' | head -1)APIARY_CHANNEL=#hive \APIARY_OWNER_NICK=daviwil \APIARY_REPORTS_TO=daviwil \APIARY_WORKER_GROUP=ops-workers \APIARY_SERVICES_TIMEOUT=8.0 \APIARY_DAVIWIL_PASS="$DAVIWIL_PASS" \sigil test test/smoke-driver.sgl > "$SMOKE_LOG" 2>&1