Skip to content

Commit f385358

Browse files
p4w4nclaude
andcommitted
fix: e2e-surfaced bootstrap bugs across the new Tier-1 services
Two issues caught by an end-to-end smoke run that unit tests missed: 1. /preview/:artifactId/* in artifacts.ts blew up at app.use() time on Express 5 — path-to-regexp v8 requires named splats. Fix: rename to /preview/:artifactId/*splat. 2. Server boot only initialized MemoryService + ArtifactsService. PlanService, OrgLearningService, WorkQueueService, and the suggest cache were defined but never wired up, so every REST call to /api/plans/*, /api/playbooks/*, /api/companies/:cid/ work-queue/*/items hit getFooService() with no singleton and 500'd. Adds the missing initializers next to the existing memory + artifacts inits in server/src/index.ts. The PlanService init also wires the onPlanCompleted hook to call ingestCompletedPlan(memoryService, planId), so plan-completion → memory-ingestion (DP-10 + L-10) now actually fires in production. Verified via /tmp/paperclip-e2e/run-e2e.sh: company → agent → issue → plan(2 phases + decision) → playbook + suggest → work- queue enqueue with Idempotency-Key dedup → artifacts list. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent c99f673 commit f385358

2 files changed

Lines changed: 38 additions & 1 deletion

File tree

server/src/index.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,42 @@ export async function startServer(): Promise<StartedServer> {
688688
"./services/memory/reflection-worker.js"
689689
);
690690
startReflectionWorker({ db: db as any, embedder: embedder ?? undefined });
691+
692+
// Work-queue service singleton. The scheduler integration into
693+
// the heartbeat tick lands when the heartbeat refactor consolidates
694+
// the existing dispatch loop; for now the service is initialized
695+
// so REST + plugin SDK paths work.
696+
const { initializeWorkQueueService } = await import(
697+
"./services/work-queue/service.js"
698+
);
699+
initializeWorkQueueService({ db: db as any });
700+
701+
// Plan service singleton. onPlanCompleted hook wires Memory's
702+
// ingestCompletedPlan when the plan transitions to completed.
703+
const { initializePlanService } = await import("./services/plans/service.js");
704+
const { ingestCompletedPlan } = await import("./services/plans/memory-ingest.js");
705+
const { getMemoryService } = await import("./services/memory/service.js");
706+
initializePlanService({
707+
db: db as any,
708+
onPlanCompleted: async (planId: string) => {
709+
try {
710+
await ingestCompletedPlan(db as any, getMemoryService(), planId);
711+
} catch (err) {
712+
logger.warn({ err, planId }, "memory-ingest of completed plan failed");
713+
}
714+
},
715+
});
716+
717+
// OrgLearningService singleton + suggest cache.
718+
const { initializeOrgLearningService } = await import(
719+
"./services/learning/service.js"
720+
);
721+
const { initializeSuggestCache } = await import(
722+
"./services/learning/suggest-cache.js"
723+
);
724+
initializeOrgLearningService({ db: db as any });
725+
initializeSuggestCache();
726+
691727
const app = await createApp(db as any, {
692728
uiMode,
693729
serverPort: listenPort,

server/src/routes/artifacts.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,8 @@ export function artifactsRoutes(db: Db) {
7474
res.json({ artifact: hydrated });
7575
});
7676

77-
router.get("/preview/:artifactId/*", async (req, res) => {
77+
// path-to-regexp v8 (Express 5) requires named wildcards.
78+
router.get("/preview/:artifactId/*splat", async (req, res) => {
7879
const id = req.params.artifactId as string;
7980
const row = await peekArtifact(db, id);
8081
if (!row) throw notFound("artifact not found");

0 commit comments

Comments
 (0)