From d8052a17428f2b0488218ab2fe6fffb8210bea8a Mon Sep 17 00:00:00 2001 From: Tonio Date: Wed, 12 Aug 2026 11:49:15 -0700 Subject: [PATCH] docs(server): pin the no-first-task contract on the cloud seed path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PAP-67 r17.4. #11101 added a server-owned onboarding first-task path (`POST /issues` with `onboardingFirstTask: true`, board actor + zero issues) that stamps `ONBOARDING_FIRST_TASK_ORIGIN_KIND` and races safely on the partial unique index `issues_onboarding_first_task_uq`. The seed receiver creates an unstamped issue, so if it ever created the first task on the cloud walk the company would get a *second*, greeting-less task rendered as a user bubble — silently, because the uq index only guards origin-stamped rows. The seed Cloud sends is mission-only (`agent`/`firstTask` are never populated by the signup wizard; a paperclip-cloud `node:test` pins it), so `firstTaskTitle` is null on the cloud path and this branch stays inert. Document that contract at the branch it protects; the branch is retained for the endpoint's documented body. Co-Authored-By: Paperclip --- server/src/services/onboarding-seed.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/server/src/services/onboarding-seed.ts b/server/src/services/onboarding-seed.ts index 9e3b5ee958c..c13d827f2f8 100644 --- a/server/src/services/onboarding-seed.ts +++ b/server/src/services/onboarding-seed.ts @@ -224,6 +224,22 @@ export function onboardingSeedService(db: Db) { // 3. First task → an issue in the Onboarding project, assigned to the // lead so the dashboard opens with work on it. + // + // No-first-task contract (PAP-67 r17.4): on the Cloud walk this branch + // never runs. The seed Cloud sends is mission-only — `agent` and + // `firstTask` are unpopulated by the signup wizard and a paperclip-cloud + // `node:test` in `src/onboarding/` pins that — so `firstTaskTitle` is + // null here and the first task stays owned by the tenant's own + // server-owned onboarding path (`POST /issues` with + // `onboardingFirstTask: true`). That path is the only one that stamps + // `ONBOARDING_FIRST_TASK_ORIGIN_KIND` and races safely on the partial + // unique index `issues_onboarding_first_task_uq`. If this receiver ever + // created the first task on the cloud walk it would produce a *second*, + // unstamped one: no agent-authored greeting, the brief rendered as a + // right-aligned user bubble, and two onboarding tasks — silently, + // because the uq index only guards origin-stamped rows. The branch is + // retained for the endpoint's documented body contract, but the + // mission-only seed is what keeps it inert on the cloud path. let issueId = existing?.issueId ?? null; if (firstTaskTitle) { if (await issueStillExists(companyId, issueId)) {