Skip to content

feat: emit exiting{reason:"requested"} on clean shutdown - #164

Merged
solderzzc merged 3 commits into
mainfrom
feat/engine-protocol-exiting-event
Aug 31, 2026
Merged

feat: emit exiting{reason:"requested"} on clean shutdown#164
solderzzc merged 3 commits into
mainfrom
feat/engine-protocol-exiting-event

Conversation

@solderzzc

Copy link
Copy Markdown
Member

Summary

Aegis-AI's daemon (aegis-daemon, the W7 Rust rewrite) needs to tell a clean, planned shutdown apart from a real crash. Today SwiftLM's SIGTERM/SIGINT handlers print plain text and exit(0) with no machine-readable signal at all.

  • Adds a small shared emitEvent(_:) helper (used by both the existing ready event and this new one, replacing ready's inline JSONSerialization call).
  • Emits {"event":"exiting","reason":"requested"} on both signal handlers before exiting. Consumers should ignore unrecognized future reason values rather than error on them.
  • docs/AEGIS_INTEGRATION.md updated alongside the existing ready event documentation.

This is Phase 1 of a larger plan (see Aegis-AI's daemon/spec/engine-protocol.md §3/§4) — self-reporting a specific failure reason on a real crash (OOM, model load failure, etc.) is separate, larger follow-up work, since none of those paths have any error handling to build on today.

Test plan

  • swift build --target SwiftLM (debug) — green
  • swift build -c release --product SwiftLM — green
  • Smoke-tested against a real Aegis-AI daemon build in an isolated sandbox: reached ready normally, and a real SIGTERM via the daemon's stop endpoint exited the process cleanly with the new event observed, without the daemon misclassifying it as a crash.

🤖 Generated with Claude Code

solderzzc and others added 3 commits August 29, 2026 06:40
…x-swift submodule pins

mlx-swift-lm was uncommitted-pinned backward past the commit that introduced
DualModelMTP/MTPTokenIterator/Gemma4AssistantModel, breaking
Gemma4MTPBench and forcing MTP speculative decoding to be commented out in
InferenceEngine.swift as a workaround. Repointing both submodules to their
current origin/main tips (mlx-swift-lm past the merged DSA stage-2 PR #61,
mlx-swift past the matching MLXFast.fromFp8 addition) restores those types
and lets the benchmark build again — no source workaround needed.

Also adds scripts/bootstrap_local_tests.sh, which mirrors CI's "Install MLX
Metal library" step (pip install mlx, copy its bundled metallib into every
built .xctest bundle) so `swift test` is runnable locally without the
manual cmake+make dance. Addresses the Tier 3 item in #128.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…e Protocol v1)

Aegis-AI's daemon (aegis-daemon, W7 Rust rewrite) needs to tell a clean,
planned shutdown apart from a real crash. Today SwiftLM's SIGTERM/SIGINT
handlers print plain text and exit(0) with no machine-readable signal at
all.

Adds a small shared emitEvent(_:) helper (used by both the existing ready
event and this new one, replacing ready's inline JSONSerialization call)
and emits {"event":"exiting","reason":"requested"} on both signal handlers
before exiting. Consumers should ignore unrecognized future reason values
rather than error on them.

This is Phase 1 of a larger plan (see Aegis-AI's daemon/spec/engine-protocol.md
§3/§4) — self-reporting a SPECIFIC failure reason on a real crash (OOM,
model load failure, etc.) is separate, larger follow-up work, since none
of those paths have any error handling to build on today.

Verified: swift build --target SwiftLM (debug) and swift build -c release
--product SwiftLM both green. Smoke-tested against a real Aegis-AI daemon
build in an isolated sandbox: reached ready normally, and a real SIGTERM
via the daemon's stop endpoint exited the process cleanly with the new
event observed, without the daemon misclassifying it as a crash.
- emitEvent() used to silently swallow any JSON encoding failure with no
  diagnostic trail, for a function that's now the sole path for a
  protocol-critical signal. Now logs a message to stderr on failure.
- Ignore SIGPIPE before the SIGTERM/SIGINT handlers are wired up: if the
  daemon's read end of our stdout pipe is already gone by the time a
  shutdown signal arrives, the exiting-event print/fflush could raise
  SIGPIPE, whose default disposition kills the process via signal instead
  of reaching Darwin.exit(0) -- producing exactly the ambiguous "was this
  a crash?" signature this feature exists to eliminate.
- docs/AEGIS_INTEGRATION.md: reworded reason:"requested" to not imply it
  proves the daemon itself initiated the shutdown (any SIGTERM/SIGINT
  sender produces the identical event), and added that the event is
  best-effort (dispatched on the main queue, so a busy queue delays
  emission) rather than a synchronous guarantee at signal-delivery time.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@solderzzc
solderzzc merged commit 1def008 into main Aug 31, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant