feat(FN-3415): add todo documentation contract test
Adds a contract test for todo documentation in the core task store, covering the behavior documented in the system. Fusion-Task-Id: FN-3415
This commit is contained in:
@@ -28,6 +28,7 @@ For a full walkthrough (installation, onboarding, first task, and daily workflow
|
||||
| Guide | Description |
|
||||
|---|---|
|
||||
| [Task Management](./task-management.md) | Task creation modes, lifecycle, prompt specs, comments, archiving, and GitHub integration |
|
||||
| [Todo View](./todo-view.md) | Canonical guide for the experimental Todo View, including enablement, usage, API routes, and storage |
|
||||
| [Missions](./missions.md) | Mission hierarchy, planning flow, activation, progress tracking, and autopilot behavior |
|
||||
| [Research](./research.md) | Research runs, provider setup, dashboard/CLI usage, findings, exports, and task integration |
|
||||
| [Workflow Steps](./workflow-steps.md) | Reusable quality gates, templates, pre/post-merge phases, and workflow execution results |
|
||||
|
||||
@@ -116,6 +116,18 @@ Documents view supports toggling between raw text and formatted markdown when vi
|
||||
|
||||
The toggle button is accessible with `aria-pressed` for screen readers. Toggle state is scoped per-document, so switching between documents resets the view to raw mode.
|
||||
|
||||
## Todo View
|
||||
|
||||
Todo View is an experimental dashboard surface for managing per-project todo lists and turning items into planning or task workflows.
|
||||
|
||||
> Available when `experimentalFeatures.todoView` is enabled.
|
||||
|
||||
Navigation:
|
||||
- Desktop: **Header → More views → Todos**
|
||||
- Mobile: **More** sheet → **Todos**
|
||||
|
||||
For full behavior, API contracts, and storage details, use the canonical [Todo View guide](./todo-view.md).
|
||||
|
||||
## Research View
|
||||
|
||||
Research view is a standalone dashboard surface for creating and managing research runs.
|
||||
|
||||
@@ -834,7 +834,7 @@ Common built-in dashboard flags include:
|
||||
- `skillsView`
|
||||
- `nodesView`
|
||||
- `devServerView`
|
||||
- `todoView`
|
||||
- `todoView` (enables dashboard Todo View; see [Todo View](./todo-view.md))
|
||||
- `researchView`
|
||||
- `remoteAccess`
|
||||
- `agentOnboarding` (gates the planning-style New Agent onboarding flow in Agents view)
|
||||
|
||||
@@ -37,6 +37,8 @@ In **Todos** view, each todo item includes a planning action:
|
||||
|
||||
This action starts a planning session; it does **not** immediately create a task.
|
||||
|
||||
For full Todo View behavior (enablement, list/item actions, API routes, and storage), see [Todo View](./todo-view.md).
|
||||
|
||||
### 4) Subtask Breakdown Dialog
|
||||
|
||||
Use the 🌳 button:
|
||||
|
||||
137
docs/todo-view.md
Normal file
137
docs/todo-view.md
Normal file
@@ -0,0 +1,137 @@
|
||||
# Todo View
|
||||
|
||||
[← Docs index](./README.md)
|
||||
|
||||
Todo View is an experimental dashboard surface for personal/project todo lists that can feed directly into Fusion planning and task workflows.
|
||||
|
||||
## Overview
|
||||
|
||||
Todo View lets you:
|
||||
|
||||
- Create multiple todo lists per project
|
||||
- Add, edit, complete, delete, and reorder todo items
|
||||
- Start Planning Mode from any todo item (💡)
|
||||
- Create a triage task from a todo item
|
||||
- Create and immediately assign a task to an agent from a todo item
|
||||
|
||||
The feature is implemented in `TodoView.tsx` with data/state orchestration in `useTodoLists.ts` and backend routes in `packages/dashboard/src/todo-routes.ts`.
|
||||
|
||||
## Enablement (`experimentalFeatures.todoView`)
|
||||
|
||||
Todo View is hidden unless the global experimental flag is enabled:
|
||||
|
||||
```json
|
||||
{
|
||||
"experimentalFeatures": {
|
||||
"todoView": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Behavior when disabled:
|
||||
|
||||
- Todo navigation entry is hidden from dashboard navigation menus
|
||||
- If a user is currently on Todo View and the flag is turned off, the app redirects back to board view
|
||||
|
||||
## Accessing Todo View
|
||||
|
||||
When enabled:
|
||||
|
||||
- Desktop: header overflow menu (**More views**) → **Todos**
|
||||
- Mobile: **More** sheet in the mobile nav bar → **Todos**
|
||||
|
||||
## List management
|
||||
|
||||
In the left sidebar:
|
||||
|
||||
- **Create list**: plus button or empty-state action
|
||||
- **Rename list**: pencil action
|
||||
- **Delete list**: trash action (with confirm dialog)
|
||||
- **Select active list**: clicking a list switches the main panel
|
||||
|
||||
Validation/API constraints:
|
||||
|
||||
- `title` is required
|
||||
- `title` is trimmed
|
||||
- `title` max length is 200 characters
|
||||
|
||||
## Item management
|
||||
|
||||
Within the selected list:
|
||||
|
||||
- **Add item** using input + Add button (or Enter)
|
||||
- **Edit item text** inline
|
||||
- **Toggle completion** via checkbox
|
||||
- **Move up/down** to reorder items
|
||||
- **Delete item** via trash action
|
||||
|
||||
Validation/API constraints:
|
||||
|
||||
- `text` is required
|
||||
- `text` is trimmed
|
||||
- `text` max length is 2000 characters
|
||||
- Completion toggling uses `PATCH /api/todos/items/:id` with `completed: boolean` (no separate toggle endpoint)
|
||||
|
||||
## Planning integration
|
||||
|
||||
Each item has a planning action (💡):
|
||||
|
||||
- Opens Planning Mode with todo text as the initial plan
|
||||
- Starts a planning interview flow
|
||||
- Does not create a task until you complete planning and explicitly create one
|
||||
|
||||
See also: [Task Management → Todo item → Plan Mode](./task-management.md#3-todo-item--plan-mode).
|
||||
|
||||
## Task creation and agent delegation actions
|
||||
|
||||
Each item also has task actions:
|
||||
|
||||
- **Create task** (`+`): creates a new task in `triage` with todo text as description
|
||||
- **Assign to agent** (bot icon): loads agents, then creates a new task in `triage` with `assignedAgentId`
|
||||
|
||||
Both actions use dashboard task creation APIs and preserve project scoping when a project is selected.
|
||||
|
||||
## API reference (current implementation)
|
||||
|
||||
Base prefix: `/api/todos`
|
||||
|
||||
### Lists
|
||||
|
||||
- `GET /api/todos` — list lists with embedded items
|
||||
- `POST /api/todos` — create list (`{ title }`)
|
||||
- `PATCH /api/todos/:id` — update list title (`{ title }`)
|
||||
- `DELETE /api/todos/:id` — delete list
|
||||
|
||||
### Items
|
||||
|
||||
- `POST /api/todos/:id/items` — create item in list (`{ text }`)
|
||||
- `PATCH /api/todos/items/:id` — update item (`{ text?; completed? }`)
|
||||
- `DELETE /api/todos/items/:id` — delete item
|
||||
- `POST /api/todos/:id/items/reorder` — reorder full list (`{ itemIds: string[] }`)
|
||||
|
||||
### Project scoping
|
||||
|
||||
`projectId` may be provided:
|
||||
|
||||
- Query parameter (for reads and route calls that include query string)
|
||||
- Request body (supported by route resolver for mutating calls)
|
||||
|
||||
When omitted, Todo APIs operate against the default/local project scope (`""` project ID in TodoStore).
|
||||
|
||||
## Storage linkage
|
||||
|
||||
Todo data is persisted in the project SQLite database (`.fusion/fusion.db`) via:
|
||||
|
||||
- `todo_lists`
|
||||
- `todo_items`
|
||||
|
||||
See [Storage](./storage.md) for the broader database/storage model.
|
||||
|
||||
## Related source-of-truth files
|
||||
|
||||
- `packages/dashboard/app/components/TodoView.tsx`
|
||||
- `packages/dashboard/app/hooks/useTodoLists.ts`
|
||||
- `packages/dashboard/src/todo-routes.ts`
|
||||
- `packages/core/src/todo-store.ts`
|
||||
- `packages/dashboard/src/__tests__/todo-routes.test.ts`
|
||||
- `packages/dashboard/app/components/__tests__/TodoView.test.tsx`
|
||||
68
packages/dashboard/src/__tests__/todo-documentation.test.ts
Normal file
68
packages/dashboard/src/__tests__/todo-documentation.test.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
// @vitest-environment node
|
||||
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { readFileSync } from "node:fs";
|
||||
import path from "node:path";
|
||||
|
||||
const repoRoot = path.resolve(__dirname, "../../../../");
|
||||
|
||||
function readDoc(relativePath: string): string {
|
||||
return readFileSync(path.join(repoRoot, relativePath), "utf8");
|
||||
}
|
||||
|
||||
function normalizeRoutePath(routePath: string): string {
|
||||
return routePath === "/" ? "" : routePath;
|
||||
}
|
||||
|
||||
describe("todo documentation contract", () => {
|
||||
it("includes canonical Todo View guide and required cross-references", () => {
|
||||
const todoGuide = readDoc("docs/todo-view.md");
|
||||
const docsIndex = readDoc("docs/README.md");
|
||||
const dashboardGuide = readDoc("docs/dashboard-guide.md");
|
||||
const taskManagement = readDoc("docs/task-management.md");
|
||||
const settingsReference = readDoc("docs/settings-reference.md");
|
||||
|
||||
expect(todoGuide).toContain("# Todo View");
|
||||
expect(todoGuide).toContain("## Overview");
|
||||
expect(todoGuide).toContain("## Enablement (`experimentalFeatures.todoView`)");
|
||||
expect(todoGuide).toContain("## List management");
|
||||
expect(todoGuide).toContain("## Item management");
|
||||
expect(todoGuide).toContain("## Planning integration");
|
||||
expect(todoGuide).toContain("## Task creation and agent delegation actions");
|
||||
expect(todoGuide).toContain("## API reference (current implementation)");
|
||||
expect(todoGuide).toContain("## Storage linkage");
|
||||
|
||||
expect(docsIndex).toContain("[Todo View](./todo-view.md)");
|
||||
expect(dashboardGuide).toContain("canonical [Todo View guide](./todo-view.md)");
|
||||
expect(taskManagement).toContain("see [Todo View](./todo-view.md)");
|
||||
expect(settingsReference).toContain("todoView` (enables dashboard Todo View; see [Todo View](./todo-view.md))");
|
||||
});
|
||||
|
||||
it("documents the same todo API endpoints implemented by todo-routes", () => {
|
||||
const todoGuide = readDoc("docs/todo-view.md");
|
||||
const routeSource = readDoc("packages/dashboard/src/todo-routes.ts");
|
||||
|
||||
const implementedRoutes = new Set<string>();
|
||||
const routeRegex = /router\.(get|post|patch|delete)\(\s*"([^"]+)"/g;
|
||||
|
||||
for (const match of routeSource.matchAll(routeRegex)) {
|
||||
const method = match[1].toUpperCase();
|
||||
const pathLiteral = normalizeRoutePath(match[2]);
|
||||
implementedRoutes.add(`${method} /api/todos${pathLiteral}`);
|
||||
}
|
||||
|
||||
const documentedRoutes = new Set<string>();
|
||||
const documentedRegex = /- `([A-Z]+)\s+([^`]+)`/g;
|
||||
for (const match of todoGuide.matchAll(documentedRegex)) {
|
||||
const method = match[1];
|
||||
const routePath = match[2].trim();
|
||||
if (routePath.startsWith("/api/todos")) {
|
||||
documentedRoutes.add(`${method} ${routePath}`);
|
||||
}
|
||||
}
|
||||
|
||||
expect(documentedRoutes).toEqual(implementedRoutes);
|
||||
expect(todoGuide).toContain("PATCH /api/todos/items/:id");
|
||||
expect(todoGuide).not.toContain("/api/todos/items/:id/toggle");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user