## Summary
This PR is Phase 4 of 13 in the larger [Human Task Assignment from Aerie](https://linear.app/builder-team/project/human-task-assignment-from-aerie-b3582376ae6e) project.
It adds and gates one canonical Task create/edit flow shared by My Tasks, a top-level site action, the existing Work Plan, and the evolving public Task API. This phase is tracked by [AERIE-2736 — Create and edit canonical Tasks from every entry point](https://linear.app/builder-team/issue/AERIE-2736/create-and-edit-canonical-tasks-from-every-entry-point).
Production effect: dormant/additive. The new Task UI, anchorless writes, expanded API contract, and agent discovery are blocked by the default-off server gate. The dedicated Task capability becomes visible in capability administration, but no existing role receives it until the explicit reviewed migration is run. Current Task creation also records requester as the authenticated creator when no requester is supplied; that internal foundation field is not exposed through the current off-gate UI or API response. Existing Work Plan and public Task API behavior remain available while the gate is off.
## Why
Every entry point must create the same Task rather than introducing separate UI, API, and agent meanings. This slice establishes that shared write boundary, permits site-level Tasks without inventing Work Plan anchors, and gives Task management its own permission before assignments and lifecycle actions are added.
## Business Value
- Lets authorized people and their agents use one Task model from every entry point once launched.
- Supports site-level work that does not belong to a Quality Bar, Work Unit Group, or Work Unit.
- Keeps the familiar compact Work Plan flow while making richer fields available when needed.
- Adds a dedicated Task permission without widening diligence, DRI, Work Unit, or Work Unit Group authority.
- Preserves current production behavior until the complete Task Board is ready.
## How does it work
1. The shared Task writer accepts an optional Work Plan anchor while preserving the existing anchored payload.
2. Authenticated creation derives the creator from the current user or API credential owner; requester defaults to that creator and may be changed.
3. Gated My Tasks, site, and Work Plan forms all call the same canonical create/edit mutations.
4. The existing public Task endpoints widen in place behind the gate, retaining public IDs, idempotency, ETags, audit attribution, and current off-gate behavior.
5. operations.tasks.write is registered across capability presentation and API-key scope checks; a dry-run/confirmed migration can grant it to approved roles later.
6. Agent discovery uses that Task capability and remains hidden while the launch gate is off.
## Scope
### Included in this phase
- Site-level Tasks with optional Work Plan anchors across storage, projection, reads, writes, and verification.
- Reusable gated Task editor in My Tasks and as a top-level site action.
- Compact existing Work Plan creation with an optional expanded Task section.
- Actor-derived creator and requester defaulting.
- Dedicated operations.tasks.write capability, role migration, API metadata, and credential-owner checks.
- One gated evolving public Task API with existing ID, retry, concurrency, and audit behavior preserved.
- Separate gated agent discovery for Tasks.
- Exact final diff paths:
chat/app/(main)/admin/__tests__/role-editor.test.tsxchat/components/dashboards/portfolio/__tests__/portfolio-rhodes-workbench.test.tsx
chat/components/dashboards/portfolio/portfolio-rhodes-workbench.tsx
chat/components/task-board/my-tasks-view.tsx
chat/components/task-board/task-editor.test.tsx
chat/components/task-board/task-editor.tsx
chat/convex/_generated/api.d.ts
chat/convex/migrations/taskWriteCapability.test.ts
chat/convex/migrations/taskWriteCapability.ts
chat/convex/migrations/workManagementPublicIds.ts
chat/convex/publicApi/v2/domains/workManagementTaskBoardWrites.test.ts
chat/convex/publicApi/v2/workManagement.test.ts
chat/convex/publicApi/v2/workManagementData.ts
chat/convex/publicApi/v2/workManagementWrites.ts
chat/convex/rhodes/portfolioWorkbench.ts
chat/convex/rhodes/runtime/writes/taskWrites.ts
chat/convex/rhodes/workManagementPublicId.ts
chat/convex/rhodesPortfolioWorkbench.test.ts
chat/convex/taskBoard/gate.ts
chat/convex/taskBoard/mutations.test.ts
chat/convex/taskBoard/mutations.ts
chat/convex/taskBoard/queries.test.ts
chat/convex/taskBoard/queries.ts
chat/convex/users/roles.test.ts
chat/convex/users/roles.ts
chat/lib/public-api/v2/domains/work-management-schemas.ts
chat/lib/public-api/v2/domains/work-management-task-board.node.test.ts
chat/lib/public-api/v2/domains/work-management.ts
chat/lib/task-board/gate.ts
packages/contracts/src/capabilities.test.ts
packages/contracts/src/capabilities.ts
### Deliberately excluded for later phases
- Enabling the Task Board or running the role-grant migration in production.
- Internal and external assignment management — AERIE-2737.
- Lifecycle actions and transition enforcement — AERIE-2738.
- Completion submissions, evidence, approvals, watchers, notifications, Team Tasks, digests, and final DSS launch.
- Any second or legacy Task API.
## Test plan
### Automated validation
- Current-head Task Board, public API, Work Plan, migration, role, and component tests — 12 files, 272/272 passed (cd chat && pnpm exec vitest run lib/public-api/v2/domains/work-management-task-board.node.test.ts convex/taskBoard/mutations.test.ts convex/taskBoard/queries.test.ts convex/publicApi/v2/domains/workManagementTaskBoardWrites.test.ts convex/publicApi/v2/workManagement.test.ts convex/rhodesPortfolioWorkbench.test.ts convex/migrations/taskWriteCapability.test.ts convex/users/roles.test.ts components/dashboards/portfolio/__tests__/portfolio-rhodes-workbench.test.tsx components/task-board/task-editor.test.tsx components/task-board/task-detail.test.tsx app/'(main)'/admin/__tests__/role-editor.test.tsx).
- Overlapping existing public write and Rhodes MCP validation — 2 files, 102/102 passed (cd chat && pnpm exec vitest run convex/publicApi/v2/domains/workManagementWrites.test.ts convex/rhodesMcpMutationParity.test.ts).
- Capability contract validation — 1 file, 49/49 passed (cd chat && pnpm --filter @bran/contracts exec vitest run src/capabilities.test.ts).
- Independent current-head review — 195/195 focused tests passed, with no findings.
- Chat and Convex typecheck — passed, then passed again in the final commit hook (pnpm --filter @bran/chat typecheck).
- Full lint, Biome, architecture boundaries, Convex paths, read bounds, test architecture, and knowledge hygiene — passed across 3,081 files with two pre-existing Sindri warnings (pnpm lint).
- git diff --check — passed.
- Exact-head diff scope — only the 31 authorized paths listed above.
No current production caller can reach the richer flow while the gate is off. /tasks returns Not Found; Work Plan renders the expanded editor only after an authenticated server availability query returns enabled; both new mutations independently enforce the server gate; the public API and agent catalog branch on the same gate; and the shared writer rejects anchorless creation while disabled.
### Time for Implementation
About 3 weeks for an engineer without AI assistance, including repository investigation, UI and API implementation, authorization work, migration design, compatibility testing, review, and validation.
## What it means for end users/consumers
| Area | What changes when this deploys | What does not change yet |
| --- | --- | --- |
| Existing Work Plan users | No visible change while the Task Board gate is off. Current compact Task creation and payloads keep working. | The optional expanded Task fields stay hidden until launch. |
| My Tasks and site pages | The shared create/edit components are installed behind the server gate. | Users cannot reach or call the new creation flow yet. |
| Site-level Tasks | Storage and shared code can represent a Task attached only to a site. | No production user can create an anchorless Task while the gate is off. |
| Public Task API | The same endpoints are prepared to accept the richer canonical Task shape when enabled. | Current callers keep the existing off-gate contract; there is no second API. |
| Permissions | A dedicated Task write capability becomes visible in capability administration. | Existing roles do not receive it automatically; the migration is explicit and dormant. |
| Agents | Task-specific discovery and credential-owner authorization are prepared. | Agents do not see or use the new Task workflow before launch. |
| Existing Tasks | Their IDs, status, anchors, assignments, and current behavior remain unchanged. New Tasks created through current flows record requester as the authenticated creator internally. | This PR does not rewrite existing Tasks, expose requester through the current API response, or run a data backfill or lifecycle migration. |
## Review repairs and contract clarifications
[First Mercy review](https://github.com/AI-Builder-Team/Aerie/pull/1698#pullrequestreview-5436802465) and [second Mercy review](https://github.com/AI-Builder-Team/Aerie/pull/1698#pullrequestreview-5436936808), tracked under [AERIE-2736](https://linear.app/builder-team/issue/AERIE-2736/create-and-edit-canonical-tasks-from-every-entry-point):
- listAssignableUsers applies the same operations.tasks.write boundary as the creation-site query, so an authenticated participant without Task management authority cannot enumerate the assignable staff directory.
- Public Task projection budgets unique referenced user identities across assignees, approvers, approved-by, creator, and requester. Repeated identities share the existing cache and no longer cause valid pages to be rejected as over budget.
- Work Plan keeps its existing site-edit authorization for the unchanged compact Task payload. Supplying the new gated requester field additionally requires operations.tasks.write; server-projected availability hides the requester control and skips its directory query when that capability is absent.
- Requester updates now distinguish omission from an explicit clear across the standalone editor, Work Plan, and public API. Omission preserves the current requester; clearing resets it to the Task's stored creator; create omission continues to default requester to the authenticated creator. The UI now describes the reset accurately.
- Negative coverage now includes the disabled gate, missing Task-write capability, invalid or deleted requesters, completed Task edits, Work Plan requester authorization, hidden requester controls, stored-creator reset, and nullable public API PATCH.
- The claimed off-gate My Tasks creation flow is unreachable: MyTasksView is imported only by /tasks, and that server page returns Not Found before rendering when the gate is disabled.
- Missing creator or requester directory rows are not silently omitted: projectTask returns null, and both list and detail callers convert that result to integrity_error.
Validation: 147/147 focused repair tests, 272/272 current-head feature tests, 102/102 overlapping public-write and Rhodes MCP tests, 49/49 capability contract tests, Chat/Convex typecheck, full lint/boundary checks, and git diff --check all pass. Existing compact Work Plan authorization, the launch gate, dormant production state, public API activation boundary, role migration, and Task ownership rules remain unchanged.
### Third review repair
The latest review identified that default-role seeding still included operations.tasks.write even though this phase reserves every production grant for the explicit reviewed migration. The grant is now absent from both default seeding and the generic capability backfill; migrations/taskWriteCapability is the sole initial grant path and still requires its execute flag and confirmation token. Regression coverage proves both dormant paths remain grant-free.
The gate-off anchor validation now uses the shared clean user-error pathway. The full 12-file feature suite remains green at 272/272, and Chat/Convex typecheck, focused Biome checks, and git diff --check pass.
### Fourth review clarification
The latest requester-edit finding is rejected because it conflicts with the approved Task authority model. FEATURE.md grants creators and requesters authority to update, assign, and reassign their own Tasks without operations.tasks.write; that capability governs global Task management. The standalone mutation preserves that distinction: it requires the caller to be the stored creator or requester, rejects closed Tasks, and validates every replacement requester as an assignable Aerie user. Unrelated users still cannot edit the Task, and the operation does not grant site-wide access.
No code change is warranted for this finding. Exact head f41e51e3a remains fully green across all required CI checks.
### Fifth review repair
The claimed option-query gate bypass was already prevented by the shared boundary: both listCreationSites and listAssignableUsers begin with requireTaskBoardUser, which calls taskBoardEnabled() and fails with the clean unavailable error before capability checks or database reads. Explicit gate-off regression assertions now lock that inherited behavior for both queries.
Public API regression coverage now proves the required capability intersection in both directions: a scoped key is denied when its owner lacks operations.tasks.write, and a capable owner is denied when the key omits that scope. The full feature suite passes 272/272, with Chat/Convex typecheck, focused Biome checks, and git diff --check also green.
### Sixth review repair
The reusable editor now initializes draft state only when the dialog opens or its Task/fixed-site identity changes. Fresh object allocation by a parent rerender no longer retriggers initialization, so live query updates and unrelated parent state changes cannot erase in-progress user input. A browser regression test recreates the same Task prop after typing and proves the unsaved title remains intact.
Validation is green at 272/272 feature tests, plus Chat/Convex typecheck, focused Biome checks, and git diff --check.
### Seventh review repair
The shared Task writer now treats a missing record immediately after create or update as a clean operation failure, so its success contract is non-null. Standalone mutations return the persisted Task ID directly and can no longer translate a nullable writer result into a successful response with taskId: undefined. Public API and Work Plan callers inherit the same fail-closed shared boundary.
Validation is green at 272/272 feature tests, including 71/71 focused mutation, public API, and Rhodes tests, plus Chat/Convex typecheck, focused Biome checks, and git diff --check.