c89d6d129c
## 变更摘要 ### 1. 项目级可配重试上限与超时 - `Project` 新增 `maxRetries`(默认 2)和 `timeoutMs`(默认 30min = 1800000ms)字段 - SQLite schema:`projects` 表补 `max_retries` / `timeout_ms` 列(带 DEFAULT 的轻量迁移) - `createProject` / `patchProject` 支持设置 / 校验新字段(maxRetries>=0, timeoutMs>=1000) - API `POST /api/projects` 与 `PATCH /api/projects/:id` 透传新字段 - `runner.ts` 将 `project.timeoutMs` 传给 `runClaude`,不再固定 30min ### 2. 失败重试指数退避 - 编排器内存维护 `backoffUntil` Map(taskId → nextRetryAt),daemon 重启后清空 - 退避公式:`min(30s * 2^(attempt-1), 10min)`,第 1 次 30s / 第 2 次 60s / ... - `claimable()` 过滤退避冷却中的任务 - `nowMs` 注入点(默认 `Date.now`)使测试可快进时钟验证退避行为 ### 3. needs_attention 一键重投 - `Task` 新增 `retryBaseline` 字段(默认 0):记录上次重投时的失败 run 基线 - `Store.requeueTask(taskId)`:设置基线 = 当前失败 run 数 → 转 `queued`(仅限 needs_attention) - 编排器用净失败数(`allFailed - retryBaseline`)判断是否已耗尽重试次数 - API `POST /api/tasks/:id/requeue` + MCP `requeue_task` 工具 ### 4. 测试 - 重命名 `MAX_RETRIES` → `DEFAULT_MAX_RETRIES`,新增导出 `computeBackoffMs` - 新增测试(共 +18):maxRetries=1/0、退避时序(精确 ms 边界)、重投后基线重置 - 迁移测试扩展:验证旧库补列后 maxRetries/timeoutMs/retryBaseline 使用默认值 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
83 lines
3.9 KiB
SQL
83 lines
3.9 KiB
SQL
-- maestro · SQLite schema v0.1(设计见 DESIGN.md §6/§9)
|
||
PRAGMA journal_mode = WAL;
|
||
PRAGMA foreign_keys = ON;
|
||
|
||
CREATE TABLE IF NOT EXISTS projects (
|
||
id TEXT PRIMARY KEY,
|
||
name TEXT NOT NULL,
|
||
repo_path TEXT NOT NULL UNIQUE,
|
||
default_branch TEXT NOT NULL DEFAULT 'main',
|
||
verify_cmd TEXT,
|
||
autonomy TEXT NOT NULL DEFAULT 'manual', -- manual | auto-easy | auto-approved
|
||
model TEXT,
|
||
concurrency INTEGER NOT NULL DEFAULT 1,
|
||
max_retries INTEGER NOT NULL DEFAULT 2, -- 失败后最大自动重试次数
|
||
timeout_ms INTEGER NOT NULL DEFAULT 1800000, -- 单次执行超时毫秒(默认 30min)
|
||
status TEXT NOT NULL DEFAULT 'active', -- active | paused
|
||
created_at TEXT NOT NULL,
|
||
last_sync_at TEXT, -- 最近一次 todo.json 同步时间
|
||
logo TEXT, -- 自定义 logo(URL / 仓库内相对路径;null=自动)
|
||
sort_order INTEGER NOT NULL DEFAULT 0 -- 侧栏排序(小在前)
|
||
);
|
||
|
||
CREATE TABLE IF NOT EXISTS tasks (
|
||
id TEXT PRIMARY KEY,
|
||
project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
||
parent_id TEXT REFERENCES tasks(id) ON DELETE CASCADE,
|
||
depth INTEGER NOT NULL DEFAULT 1, -- 1..4
|
||
title TEXT NOT NULL,
|
||
complexity TEXT NOT NULL, -- hard | medium | easy
|
||
status TEXT NOT NULL DEFAULT 'init',
|
||
priority INTEGER NOT NULL DEFAULT 1, -- P0 最高 / P1 中 / P2 最低
|
||
deps TEXT NOT NULL DEFAULT '[]', -- JSON array of task ids
|
||
plan TEXT, -- Hard:分析 + 拆解
|
||
spec TEXT, -- Medium:改动 + 理由
|
||
operations TEXT, -- Easy:将执行的操作
|
||
result TEXT, -- JSON TaskResult
|
||
assignee TEXT, -- agent | human
|
||
retry_baseline INTEGER NOT NULL DEFAULT 0, -- 上次手动重投时已有的失败 run 数(重置重试计数用)
|
||
created_at TEXT NOT NULL,
|
||
updated_at TEXT NOT NULL,
|
||
source_ref TEXT -- 旧 todo 来源标识(todo:17 / todo:17/1A),项目内唯一
|
||
);
|
||
CREATE INDEX IF NOT EXISTS idx_tasks_project ON tasks(project_id, status);
|
||
CREATE INDEX IF NOT EXISTS idx_tasks_parent ON tasks(parent_id);
|
||
CREATE INDEX IF NOT EXISTS idx_tasks_source ON tasks(project_id, source_ref);
|
||
|
||
CREATE TABLE IF NOT EXISTS approvals (
|
||
id TEXT PRIMARY KEY,
|
||
task_id TEXT NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
|
||
gate TEXT NOT NULL, -- plan | spec | exec
|
||
action TEXT NOT NULL, -- accept | reject
|
||
actor TEXT NOT NULL,
|
||
reason TEXT, -- reject 必填
|
||
at TEXT NOT NULL
|
||
);
|
||
CREATE INDEX IF NOT EXISTS idx_approvals_task ON approvals(task_id, at);
|
||
|
||
CREATE TABLE IF NOT EXISTS runs (
|
||
id TEXT PRIMARY KEY,
|
||
task_id TEXT NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
|
||
kind TEXT NOT NULL, -- planner | executor | reviewer | security
|
||
worktree TEXT,
|
||
branch TEXT,
|
||
status TEXT NOT NULL, -- started | succeeded | failed | cancelled
|
||
started_at TEXT NOT NULL,
|
||
ended_at TEXT,
|
||
transcript_ref TEXT,
|
||
claude_session_id TEXT,
|
||
error TEXT
|
||
);
|
||
CREATE INDEX IF NOT EXISTS idx_runs_task ON runs(task_id, started_at);
|
||
|
||
-- 追加型事件日志:审计 + 实时看板推送源
|
||
CREATE TABLE IF NOT EXISTS events (
|
||
id TEXT PRIMARY KEY,
|
||
project_id TEXT NOT NULL,
|
||
task_id TEXT,
|
||
type TEXT NOT NULL,
|
||
payload TEXT NOT NULL DEFAULT '{}',
|
||
at TEXT NOT NULL
|
||
);
|
||
CREATE INDEX IF NOT EXISTS idx_events_project ON events(project_id, at);
|