mirror of
https://github.com/pocketpaw/pocketpaw.git
synced 2026-05-22 17:55:03 +00:00
* feat(cloud): add Projects entity, scheduler wiring, and project_id refs
Adds the Projects entity (workspace > project > pocket/task/cycle) as a
Linear-style scoping primitive, threads optional project_id through the
existing Pocket / Task / Cycle entities, and wires an opt-in in-process
daily-snapshot scheduler for the burnup chart.
Project entity:
- 4-file shape under ee/cloud/projects/ matching pockets canonical.
- Beanie ProjectDocument indexed on (workspace, status).
- ProjectCreated / ProjectUpdated / ProjectArchived / ProjectDeleted
realtime events.
- Soft-archive (idempotent) + hard-delete with cascade soft-unassign on
Pockets, Tasks, and Cycles in the same workspace. Children keep their
data; only the project_id reference clears.
- import-linter contract entry forbids non-service.py imports of the
project Beanie doc.
project_id wired into siblings:
- Pockets, Tasks, Cycles all carry an optional project_id (default None
preserves existing rows).
- Each entity validates a supplied project_id against the current
workspace before write.
- list endpoints accept ?project_id=<id> (empty string filters for the
Mission Control "Unassigned" bucket).
- Mission Control facade threads project_id through the visible-pocket
set so Nudges inherit their parent pocket's project assignment.
Scheduler:
- ee.cloud.cycles.scheduler runs an asyncio loop that sleeps until the
next UTC midnight then calls snapshot_all_active() for every workspace
with at least one active cycle.
- Gated on POCKETPAW_CLOUD_SCHEDULER_ENABLED=true so test runs and dev
shells don't spawn a background task. Production hosts that prefer
external cron / Kubernetes CronJob / Celery beat keep the flag unset
and dispatch the same callable from their platform scheduler.
- POST /cycles/{id}/snapshot manually triggers today's snapshot for
testing and onboarding. Idempotent within a UTC day.
- list_active_workspace_ids helper exposed on cycles.service so the loop
doesn't need direct Beanie access.
Tests (78 new + adjacent passing):
- test_projects_service.py: CRUD, tenant isolation, archive idempotence,
cascade unassign on delete.
- test_projects_router.py: HTTP smoke + tenancy.
- test_cycles_snapshot_scheduler.py: manual trigger + idempotence,
workspace discovery, scheduler start/stop wiring.
- test_mission_control_project_filter.py: project_id narrows the
visible-pocket set on the items feed.
import-linter: 13 contracts kept (Projects added, all others unchanged).
* docs(advanced): add Mission Control (Cloud) operator console page
The existing /advanced/mission-control page describes the local
multi-agent orchestration framework (file-based JSON storage, single
process). This new page covers the cloud SaaS surface: workspace-scoped
REST API + MongoDB-backed entities served by ee/cloud/.
The page opens with a callout flagging the distinction so readers landing
from search don't conflate the two. It then walks through the
vocabulary (Tray, Pawprints, Snags, Projects, Cycles), the
Workspace > Project > Pocket > Cycle/Task hierarchy, the WorkItem shape,
the REST endpoint inventory across mission_control / tasks / cycles /
projects, the SSE event surface, and the scheduler wiring options
(in-process opt-in vs external cron).
Sidebar entry added to docs-config.json under Advanced, just below the
existing Mission Control entry, with a cloud-themed lucide:cloud icon.
* fix(projects): abort delete if cascade-unassign fails
The previous _unassign_project swallowed every exception per child and
let agent_delete proceed to drop the project row. If the pockets, tasks,
or cycles bulk-update failed (transient mongo error, version mismatch),
the project was gone while its children kept dangling project_id values
that resolved to nothing — only fixable by hand in mongo.
Narrow the except to ImportError (the lazy-import degrade for forks
that ship without a child entity) and let everything else propagate. A
failed cascade now aborts the delete with the children still attached,
so the caller can retry safely.
New test test_delete_aborts_if_cascade_unassign_fails monkeypatches the
tasks unassign helper to raise, asserts agent_delete raises, and
verifies the project row survives.
Addresses pocketpaw#1114 review.
* fix(mission-control): façade now composes Tasks alongside Nudges
The Mission Control items endpoint only queried Instinct (Nudges).
Any Task created via POST /api/v1/tasks landed in Mongo but never
surfaced in GET /mission-control/items. Operators creating work via
the new modal saw their task disappear from the feed on every refresh
even though the backend returned a valid Task id with status
"in_progress".
Smoke-test trace that surfaced it:
[NewWorkItemModal] created OK { id: 6a08…, status: in_progress }
[MissionControl] onCreated → refreshing feed
[WorkFeed] listWorkItems → 0 items {}
agent_list_work_items now:
- Pulls Tasks via tasks_service.agent_list_tasks (lazy import keeps
the façade installable on forks without the Tasks entity, matching
the projects/_unassign_project pattern).
- Drops the early `if not visible: return []` — that gated the whole
feed on pocket visibility, which is correct for Instinct Nudges
(pocket-scoped) but wrong for Tasks (workspace-scoped, may have
null/empty pocket_id).
- Projects each Task into a WorkItem via the new _task_to_work_item
helper. Status mapping: proposed → IN_PROGRESS, in_progress →
IN_PROGRESS, awaiting_approval → AWAITING_APPROVAL, done → DONE,
reverted → REJECTED, failed → FAILED, blocked → BLOCKED. Section
routing: agent in-flight → AGENTS, terminal → PAWPRINTS/SNAGS,
everything else → TRAY.
- ID prefix matches the convention the bulk endpoints already
expect: `task:<id>` for Tasks, `nudge:<id>` for Actions.
Test changes:
- New regression test_includes_tasks_alongside_nudges proves a Task
surfaces in the items list AND keeps surfacing when the workspace
has no visible pockets (the empty-string pocket case from the
captain's smoke test).
- Three existing autouse fixtures stub agent_list_tasks to [] so
Instinct-only test files don't need a Beanie test DB. Tests that
exercise the Tasks branch override the stub.
All 57 MC + projects + cycles tests pass; ruff clean.