plans/2026-05-07-finish-bullmq-branch-ship-plan.md
Date: 2026-05-07
Branch: bullmq-vs-bee-queue-for-claude-mem-observation-que
Base: origin/main @ 0a43ab76
Parent plan: plans/2026-05-07-server-beta-independent-bullmq-observation-runtime.md
The prior session believed Phase 1 was ungated because two reviewer agents failed (one returned not_found, "Carver" was user-aborted at 111.9s). That belief was based on a stale snapshot that predated commit 4e0fc77a Add Postgres observation storage foundation. Phase 1 is committed. git status shows zero uncommitted changes under src/storage/postgres/.
What is actually dirty in the worktree is Phase 2: Define Server Runtime Boundary. The dirty files map 1:1 to that phase's "What To Implement" section. The remaining work to "finish this branch" is: confirm Phase 1 with concrete checks (not another reviewer agent), land Phase 2, push.
Phases 3–13 (BullMQ queue, event-to-job pipeline, provider extraction, hook routing, MCP, compat, Docker, team auth, observability, final verification) are explicitly out of scope for this branch. The PR is already 167 files / 23.5K insertions. Continuing past Phase 2 here would make review impossible.
plans/2026-05-07-server-beta-independent-bullmq-observation-runtime.md (parent plan, 987 lines, all 14 sections from Phase 0 through Phase 13)PR_REORIENTATION_REPORT.md (660 lines) — independent inventory of committed + dirty surfacesgit status, git log --oneline -15, git diff --stat HEADsrc/server/runtime/{ServerBetaService.ts,create-server-beta-service.ts,types.ts}src/storage/postgres/ — already in commit 4e0fc77a4e0fc77a. Includes scoped addSource, transitionStatus, generation-job event append, FTS via generated content_search tsvector + GIN index, tenant-scoped uniqueness constraints, and 20 integration tests including the negative-scope mutation test.ServerBetaService, create-server-beta-service, disabled boundary types, .server-beta.{pid,port,runtime.json} paths, runtime labels in /api/health and /v1/info, server-beta CLI lifecycle, build-hooks split into a separate server-beta-service.cjs bundle, ephemeral-port test for /api/health and /v1/info.AGENTS.md, PR_REORIENTATION_REPORT.md) are also untracked. Decide before push.4e0fc77a to "tidy" Phase 1; create new commits.WorkerService (the entire point of Phase 2 is independence).tsc --noEmit scoped to Postgres storage:
bunx tsc --noEmit src/storage/postgres/*.ts
DATABASE_URL or local Postgres on default port):
bun test tests/storage/postgres
src/storage/postgres/):
rg -n "UNIQUE\s*\(\s*source_type\s*,\s*source_id\s*,\s*job_type\s*\)" src/storage/postgres
rg -n "UNIQUE\s*\(\s*observation_id\s*,\s*source_type\s*,\s*source_id\s*\)" src/storage/postgres
projectId/teamId parameters):
rg -n "addSource|transitionStatus|append" src/storage/postgres
projectId/teamId in every signature.src/storage/postgres/*.ts in this phase. If Phase A fails, open a separate fix-up commit; do not amend 4e0fc77a.rg -n "WorkerService|services/worker-service|worker/http" \
src/server/runtime src/npx-cli/commands/server.ts
src/services/worker-service.ts itself (delegation back to server-beta is fine). Forbidden: any import inside src/server/runtime/.bun test tests/server/server-beta-service.test.ts
bun test tests/npx-cli-server-namespace.test.ts
server-beta-service.cjs bundle is produced:
npm run build-and-sync
ls -la plugin/scripts/server-beta-service.cjs
npx claude-mem server status # before start
npx claude-mem server start
npx claude-mem server status # running, runtime=server-beta
curl -s http://127.0.0.1:$(cat ~/.claude-mem/.server-beta.port)/healthz
curl -s http://127.0.0.1:$(cat ~/.claude-mem/.server-beta.port)/v1/info
npx claude-mem server stop
start|stop|status must remain functional throughout.Two commits, in order:
feat(server-beta): add independent runtime service
src/server/runtime/ServerBetaService.tssrc/server/runtime/create-server-beta-service.tssrc/server/runtime/types.tssrc/server/routes/v1/ServerV1Routes.ts (runtime label)src/services/server/Server.ts (runtime option)src/shared/paths.ts (.server-beta.{pid,port,runtime.json})tests/server/server-beta-service.test.tsfeat(server-beta): route CLI lifecycle and build a separate bundle
scripts/build-hooks.js (server-beta bundle output)src/npx-cli/commands/runtime.ts (server-beta lifecycle commands)src/npx-cli/commands/server.ts (CLI routing)src/services/worker-service.ts (delegate server-start|stop|restart|status to sibling bundle)tests/npx-cli-server-namespace.test.tssrc/services/server/Server.ts: existing route-composition style to copy.src/services/infrastructure/ProcessManager.ts: PID-file safety patterns.--amend or force operations.WorkerService from src/server/runtime/.| File | Recommendation | Rationale |
|---|---|---|
PR_REORIENTATION_REPORT.md | Use as PR body, then delete (or move to docs/internal/). | It's a snapshot, not durable docs. Useful for the PR reviewer; rots in-tree. |
AGENTS.md | Read first, then either commit (if generally useful guidance) or move under .scratch/. | Decision depends on content. |
git status shows only intended doc artifacts (or none)..scratch/ is gitignored if used.PR_REORIENTATION_REPORT.md to main as a doc; it has a date and a HEAD SHA, it ages immediately.git push -u origin bullmq-vs-bee-queue-for-claude-mem-observation-quegh pr view --web (if PR exists) or gh pr create with body sourced from PR_REORIENTATION_REPORT.md.plans/2026-05-07-server-beta-independent-bullmq-observation-runtime.md. Phases 3–13 are follow-ups on separate branches."Once the PR merges, this branch is done. Phase 3 (BullMQ-First Server Queue) starts on a fresh branch off main. Do not reuse this branch for Phase 3 work — keep the queue/runtime split visible in history.
Run after Phases A–D:
git status # clean or only intended doc artifacts
git log --oneline origin/main..HEAD # 4e0fc77a + Phase 2 commits, no force-push markers
bun test tests/storage/postgres tests/server tests/npx-cli-server-namespace.test.ts
rg -n "WorkerService|services/worker-service|worker/http" src/server/runtime
rg -n "PendingMessageStore|SessionQueueProcessor" src/server/runtime
Expected:
AGENTS.md + PR_REORIENTATION_REPORT.md: discard before commit.rm AGENTS.md PR_REORIENTATION_REPORT.md
Verification: git status shows neither file.
Source: parent plan lines 515–570.
src/server/jobs/types.ts — job-shape types:
ServerGenerationJob (base)GenerateObservationsForEventJobGenerateObservationsForEventBatchJobGenerateSessionSummaryJobReindexObservationJobteam_id, project_id, source_type, source_id, generation_job_id. Event jobs add agent_event_id. Summary jobs add server_session_id. Reindex jobs add target observation ID or deterministic reindex scope ID.src/server/jobs/job-id.ts — deterministic, colon-free job IDs (port the SHA-256-safe pattern from src/server/queue/BullMqObservationQueueEngine.ts).src/server/jobs/ServerJobQueue.ts — thin wrapper around BullMQ Queue, Worker, QueueEvents. Use autorun: false, explicit concurrency: 1 default per lane, and an error listener on every Worker.src/server/jobs/outbox.ts — durable outbox over ObservationGenerationJobRepository. Statuses: queued, processing, completed, failed, cancelled. Tracks attempts, last error, timestamps, and tenant/project/session IDs.queued or stale processing.completed./v1/info, /api/health, and claude-mem server status via the existing runtime label hook.ServerBetaService (Phase 2 left it disabled). Provide a real adapter when CLAUDE_MEM_QUEUE_ENGINE=bullmq and REDIS_URL are present; keep the disabled adapter as the fallback.src/server/queue/BullMqObservationQueueEngine.ts — copy deterministic job-ID + Redis health patterns; do not copy the worker-iterator compatibility shape.src/server/queue/redis-config.ts — Valkey/Redis health checks.src/storage/postgres/generation-jobs.ts — outbox repository (already committed in 4e0fc77a).Unit tests under tests/server/jobs/:
job-id.test.ts — deterministic IDs, no colons, stable across runs, content-derived.server-job-queue.test.ts — Queue/Worker lifecycle, error listener attached, concurrency honored, autorun false.outbox.test.ts — duplicate enqueue suppression, terminal job replacement, status transitions, attempt counting.Integration tests under tests/server/queue-bootstrap/:
ServerBetaService with Postgres + Valkey + queue boundary enabled.ObservationGenerationJobRepository.completed exactly once.CLAUDE_MEM_QUEUE_ENGINE=bullmq; no silent fallback to SQLite.Greps:
rg -n "Bull(MQ|Mq).*\.add\(" src/server/jobs # uses BullMQ Queue.add
rg -n "autorun" src/server/jobs # workers explicitly set autorun
rg -n "on\(['\"]error" src/server/jobs # error listener attached
rg -n ":job:|:obs:" src/server/jobs # NO colons in deterministic IDs
The colon-grep must return zero matches.
CLAUDE_MEM_QUEUE_ENGINE=bullmq is set.Two commits:
feat(server-beta): add BullMQ job queue primitives
src/server/jobs/types.tssrc/server/jobs/job-id.tssrc/server/jobs/ServerJobQueue.tssrc/server/jobs/outbox.tstests/server/jobs/*.test.tsfeat(server-beta): activate queue boundary in runtime service
src/server/runtime/ServerBetaService.ts (queue boundary wiring)src/server/runtime/create-server-beta-service.ts (boundary selection from env)src/server/runtime/types.ts (active queue manager interface)/v1/info and /api/health if not already covered by Phase 2 runtime label.tests/server/queue-bootstrap/*.test.tsgit push -u origin bullmq-vs-bee-queue-for-claude-mem-observation-que
gh pr view --web # if PR exists
# else:
gh pr create --title "Server-beta: Postgres storage + independent runtime + BullMQ queue (Phases 1–3)"
PR body must list:
plans/2026-05-07-server-beta-independent-bullmq-observation-runtime.md.git status clean.git log --oneline origin/main..HEAD shows all expected commits, no force-push markers.git status # clean
bun test tests/storage/postgres tests/server tests/npx-cli-server-namespace.test.ts
rg -n "WorkerService|services/worker-service|worker/http" src/server/runtime # zero
rg -n "PendingMessageStore|SessionQueueProcessor" src/server/runtime src/server/jobs # zero