Place Easy Mode projects on shared node

Task 13445 · Queued · Coder · created · updated

Part of epic "Build sponsored Easy Mode app hosting" (PRD task 13412, architecture task 13413). Architecture child **C5 Placement**. Builds on child C4's `org_comps.origin = 'easy_mode'` comp and `projects.easy_mode` column. ## Original requirement (verbatim) > Machines: Easy Mode orgs run their AI work on our shared node pool, placed automatically (Jaah picks a shared operator node with room); the operator picks no node. > 4. Automatic placement: an Easy Mode project is placed on a shared operator node with capacity, chosen by Jaah; re-placed if that node is disabled. PRD D5: each Easy Mode org gets ONE shared node of its own (a co-located node), placed automatically on an operator Shared pool host with room. A5: "Re-placed if that node is disabled" means: if the org's shared node (or its host) is disabled or removed, Jaah places a new shared node for the org on another Shared pool host with room and moves the org's Easy Mode project assignments to it; if none has room, the operator is alarmed and the org sees "no machine" on the project. ## Approach (settled by the Architect) - `easy_mode.shared_node(session, org_id) -> Node | None` = the live copy of the org's `origin="easy_mode"` comp. - `easy_mode.assign_project(session, project_id)` → `node_projects` row on that node (`models/node_groups.py:152-181`, converge via `slot_allocation.converge`). C6's create calls it. - Re-placement: in `plan_bundles.reconcile_org` (cron `plan-bundles`), for an `easy_mode` comp whose copy's node is disabled/removed/its host failed → place a new copy automatically (not operator Retry; the current `REMOVED_NOTE` path, `plan_bundles.py:111-120`, gets an `origin == "easy_mode"` branch) and move every `projects.easy_mode` project's `node_projects` row to the new node. No room → operator alarm (existing node alarm channel) and the project's Nodes view shows "No machine". - No schema migration in this child (C6 carries this wave's migration). ## Acceptance criteria (verbatim, BA) - **AC-6 Placement.** Every Easy Mode project of the org is assigned to the org's shared node with no node question; coder tasks in it dispatch there. → verify: dev, create an Easy Mode project, open its Nodes/assignment view, observe the org's shared node; start a task, observe the session on that node. - **AC-7 Re-placement.** Disabling the org's shared node (or its host) results within one placement pass in a new shared node for the org on another pool host with room, with the Easy Mode projects re-assigned; with no room left, the operator is alarmed and the project shows "No machine" readably. → verify: dev, operator disables the node; observe a new node and the reassignment within the pass interval. No UI flow can create an Easy Mode project until C6+C7 land, so this child proves its seams with tests and the node-level half on dev; the end-to-end AC-6 and AC-7 (with projects) runs are owned by the wizard child C7. Credentials & reach: - AC-1…AC-9, AC-14…AC-20, AC-22, AC-23, AC-3b (dev UI) — `me/jaah/debug/main/operator-login` (operator; switches into the test tenant, covers member role) on `app.dev.jaah.ai`; member view also via `org/console/dev-tpl-member-login` — verified — both on roster, `credential_get` ok; operator login `POST /api/auth/login` 200 from this node. - AC-5 / AC-6 / AC-7 shared pool — dev operator API `GET /api/vnode-hosts` — verified — `pool-c-host` shared_capacity 4. - Live DB reads — `tools/cp_psql.sh dev` — deferred — broker refused for this task; every oracle above uses the console/API instead. Out of scope: a separate GitHub org; a separate app apex domain; custom domains, registrar purchase and paid hosting after sponsorship (draft task 10233 stays as that later work); the always-on shared-box hosting tier. Do NOT change placement, comps or re-placement for non-Easy-Mode orgs (only the `origin == "easy_mode"` branch is new); do NOT add a node question anywhere; do NOT build the wizard (C7) or hosted-app routes (C6). Done means: - AC-6 (seam) — api tests: `assign_project` puts an `easy_mode` project on the org's shared node and the scheduler dispatches its tasks only there; `shared_node` returns None when the copy is gone. - AC-7 — api tests: disabled node / removed node / failed host each yield a new copy on another host with room within one `reconcile_org` pass and every `projects.easy_mode` project's `node_projects` row moves; no room → one operator alarm and the project's Nodes view model reads "No machine"; non-Easy-Mode comps keep today's `REMOVED_NOTE` behavior (existing tests unchanged). - AC-7 (dev, node level) — on dev with a test org that C4's action turned on: operator disables its shared node; within one `plan-bundles` pass a new `<org>-shared-<n>` node is live on another pool host (cite before/after node lists). The same run with Easy Mode projects attached is re-run by C7. - `./dc check quick` green.

Activity

  • Draft
  • Ready