Replace Qdrant memory stack with ClawMem#28
Conversation
Remove the raw Anthropic API dependency entirely. Judge calls now use the Claude Agent SDK query() with native json_schema outputFormat, tools disabled (tools: []), and maxTurns: 1 for sandboxed single-pass evaluation. JudgeError class carries cost info on failures so the daily cap tracks actual spend even when parsing fails. All ANTHROPIC_API_KEY references removed from code, tests, config, and docs. Author: Steve Nahrup
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b3c48319f0
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| "@anthropic-ai/sdk": "^0.80.0", | ||
| "@modelcontextprotocol/sdk": "^1.28.0", | ||
| "@slack/bolt": "^4.6.0", | ||
| "clawmem": "file:../ClawMem", |
There was a problem hiding this comment.
Use a resolvable ClawMem dependency source
Pointing clawmem to file:../ClawMem makes installs fail for a normal clone/CI checkout where no sibling ../ClawMem repo exists, which in turn breaks runtime imports like clawmem/src/llm.ts and prevents tests/startup from running. This effectively turns the project into a non-self-contained build unless every environment is manually prepared with that external path.
Useful? React with 👍 / 👎.
| : { clawmem: false, configured: false }; | ||
|
|
||
| const uptimeSeconds = Math.floor((Date.now() - deps.startedAt) / 1000); | ||
| const allHealthy = memoryHealth.qdrant && memoryHealth.ollama; | ||
| const status = memoryHealth.clawmem ? "ok" : memoryHealth.configured ? "down" : "ok"; |
There was a problem hiding this comment.
Report memory outage in MCP health fallback
When deps.memory is unavailable (for example after memory init fails and MCP is created without a ready memory instance), this fallback sets configured: false, so the status expression returns "ok" even though memory is down. That causes phantom://health to falsely report healthy state and hides a real backend failure from monitoring/clients.
Useful? React with 👍 / 👎.
…ecretNamesMirror (#110) R7 Phase 8a (multi-agent Slack flow, dated 2026-04-30) hardens the existing Socket Mode receiver with Prometheus-grade observability and locks the cross-repo allowlist mirror against phantomd's AllowedSecretNames. Metrics surface (new /metrics endpoint): - phantom_slack_socket_state{state} (gauge, 7 series). Exactly one series is 1.0 at any instant. Powers "tenant offline" alerts. - phantom_slack_socket_reconnects_total (counter). Bolt's auto- reconnect runs under the hood; this measures wobble rate. - phantom_slack_socket_connection_seconds (histogram). Connection lifetime from connect to disconnect; long-tail SLO. - phantom_slack_event_dispatch_seconds{event_type} (histogram). End-to-end Bolt middleware time. Slack ack deadline is 3s. Implementation: - New SocketModeReceiver hookup (vs. socketMode: true shorthand) to reach receiver.client and subscribe lifecycle events. The State enum is verbatim from @slack/socket-mode SocketModeClient.js: connecting, authenticated, connected, reconnecting, disconnecting, disconnected. - The unrecoverable start() error path maps to a synthetic "error" state on the gauge so the fleet view does not silently flatline when the receiver never gets past handshake. - Dispatch timing via app.use() global middleware: try/await next() / finally observe(). Captures handler completion including any async LLM/memory work the agent does in response. - prom-client backed; the metrics module owns its own Registry so Telegram/email can plug in via parallel registries without name collisions on the global registry. AllowedSecretNamesMirror cross-repo invariant: - New frozen const exported from slack-channel-factory.ts listing slack_bot_token + slack_app_token + slack_gateway_signing_secret. - The phantomd side ships in the symmetric PR (phantomd #28, TestIsAllowedName_AcceptsSlackAppToken pins the assertion). - Drift on either side breaks tenant boot with HTTP 404 (the metadata gateway maps ErrInvalidName to 404 to defeat name enumeration). The factory test pins the Mirror against the SECRET_RESPONSES test fixture so a future production-side rename fails loud in CI. Tests (29 net-new): - 24 in slack-metrics.test.ts: each metric family, the noop emitter, the dispatch middleware including throw-path, the lifecycle hooks including disconnect-without-prior-connect. - 5 in slack-channel-factory.test.ts: AllowedSecretNamesMirror contains all three names, matches SECRET_RESPONSES, is frozen. - All 2111 existing tests still green; full suite: 2111 pass / 0 fail / 0 errors. Bun-mock cross-suite hygiene: every test that previously mocked @slack/bolt now also exports SocketModeReceiver in its mock object. Without this, a test file that ran AFTER one of those partial mocks would import the real module and hit "Export named 'SocketModeReceiver' not found" at module load time. Caught by running the full channels/ suite together. Net diff: 11 files, ~390 LOC. Follows R7 §3.1's "150 net-new" floor; the rest is test mirror coverage and documentation.
Summary
Verification