新增: TaskRecord加output_json产出字段+V17迁移(决策a AiNode自审闭环)
This commit is contained in:
@@ -188,6 +188,7 @@ mod tests {
|
||||
workflow_def_id: None,
|
||||
base_branch: None,
|
||||
review_rounds: 0,
|
||||
output_json: None,
|
||||
created_at: "0".to_string(),
|
||||
updated_at: "0".to_string(),
|
||||
}
|
||||
|
||||
@@ -340,7 +340,11 @@ pub fn allowed_columns_for(table: &str) -> Option<&'static [&'static str]> {
|
||||
// update_task/update_field 白名单均不含)。后人勿把 review_rounds 补进白名单,
|
||||
// 否则破坏「review_rounds 唯一写入路径」收口、引入旁路写导致计数错乱。
|
||||
"project_id", "title", "description", "priority", "branch_name",
|
||||
"assignee", "workflow_def_id", "base_branch", "updated_at",
|
||||
"assignee", "workflow_def_id", "base_branch",
|
||||
// output_json:ai_execute 写产出 / ai_self_review 读产出自审 / human_review 展示对象
|
||||
// (决策 a:task 中心,产出跟 task 走)。非状态机收口字段,合法可写。
|
||||
"output_json",
|
||||
"updated_at",
|
||||
// TODO(B-260616-16): project_id 跨表存在性校验待 commands/task.rs 层补。
|
||||
// 通用 CRUD 层(db repo)只懂表/列语义,不持有跨表业务约束(查 projects 表存在性)。
|
||||
// project_id 当前可在白名单内改写,合法目标存在性由上层命令层校验。
|
||||
@@ -485,6 +489,7 @@ fn task_from_row(row: &Row<'_>) -> std::result::Result<TaskRecord, rusqlite::Err
|
||||
workflow_def_id: row.get("workflow_def_id")?,
|
||||
base_branch: row.get("base_branch")?,
|
||||
review_rounds: row.get("review_rounds")?,
|
||||
output_json: row.get("output_json")?,
|
||||
created_at: row.get("created_at")?,
|
||||
updated_at: row.get("updated_at")?,
|
||||
})
|
||||
@@ -745,22 +750,22 @@ impl_repo!(
|
||||
from_row => |row| task_from_row(row),
|
||||
insert => |conn, rec| {
|
||||
conn.execute(
|
||||
"INSERT INTO tasks (id, project_id, title, description, status, priority, branch_name, assignee, workflow_def_id, base_branch, review_rounds, created_at, updated_at)
|
||||
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13)",
|
||||
"INSERT INTO tasks (id, project_id, title, description, status, priority, branch_name, assignee, workflow_def_id, base_branch, review_rounds, output_json, created_at, updated_at)
|
||||
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14)",
|
||||
params![
|
||||
rec.id, rec.project_id, rec.title, rec.description, rec.status, rec.priority,
|
||||
rec.branch_name, rec.assignee, rec.workflow_def_id, rec.base_branch,
|
||||
rec.review_rounds, rec.created_at, rec.updated_at
|
||||
rec.review_rounds, rec.output_json, rec.created_at, rec.updated_at
|
||||
],
|
||||
)
|
||||
},
|
||||
update => |conn, rec| {
|
||||
conn.execute(
|
||||
"UPDATE tasks SET project_id = ?1, title = ?2, description = ?3, status = ?4, priority = ?5, branch_name = ?6, assignee = ?7, workflow_def_id = ?8, base_branch = ?9, review_rounds = ?10, updated_at = ?11 WHERE id = ?12",
|
||||
"UPDATE tasks SET project_id = ?1, title = ?2, description = ?3, status = ?4, priority = ?5, branch_name = ?6, assignee = ?7, workflow_def_id = ?8, base_branch = ?9, review_rounds = ?10, output_json = ?11, updated_at = ?12 WHERE id = ?13",
|
||||
params![
|
||||
rec.project_id, rec.title, rec.description, rec.status, rec.priority,
|
||||
rec.branch_name, rec.assignee, rec.workflow_def_id, rec.base_branch,
|
||||
rec.review_rounds, rec.updated_at, rec.id
|
||||
rec.review_rounds, rec.output_json, rec.updated_at, rec.id
|
||||
],
|
||||
)
|
||||
}
|
||||
@@ -769,14 +774,14 @@ impl_repo!(
|
||||
impl TaskRepo {
|
||||
/// 列出未删除任务(deleted_at IS NULL)— 对标 ProjectRepo::list_active
|
||||
///
|
||||
/// 显式列出 13 个 TaskRecord 列名(同 ProjectRepo::list_active 写法),
|
||||
/// 显式列出 14 个 TaskRecord 列名(同 ProjectRepo::list_active 写法),
|
||||
/// 不 SELECT deleted_at:TaskRecord 不带该字段,取了 from_row 会因未知列报错。
|
||||
pub async fn list_active(&self) -> Result<Vec<TaskRecord>> {
|
||||
let conn = self.conn.clone();
|
||||
tokio::task::spawn_blocking(move || {
|
||||
let guard = conn.blocking_lock();
|
||||
let mut stmt = guard
|
||||
.prepare("SELECT id, project_id, title, description, status, priority, branch_name, assignee, workflow_def_id, base_branch, review_rounds, created_at, updated_at FROM tasks WHERE deleted_at IS NULL ORDER BY created_at DESC")
|
||||
.prepare("SELECT id, project_id, title, description, status, priority, branch_name, assignee, workflow_def_id, base_branch, review_rounds, output_json, created_at, updated_at FROM tasks WHERE deleted_at IS NULL ORDER BY created_at DESC")
|
||||
.map_err(storage_err)?;
|
||||
let rows = stmt
|
||||
.query_map([], |row| task_from_row(row))
|
||||
@@ -877,7 +882,7 @@ impl TaskRepo {
|
||||
}
|
||||
// 回读更新后的记录(含新 status / 累加后的 review_rounds / 新 updated_at)。
|
||||
let mut stmt = guard
|
||||
.prepare("SELECT id, project_id, title, description, status, priority, branch_name, assignee, workflow_def_id, base_branch, review_rounds, created_at, updated_at FROM tasks WHERE id = ?1")
|
||||
.prepare("SELECT id, project_id, title, description, status, priority, branch_name, assignee, workflow_def_id, base_branch, review_rounds, output_json, created_at, updated_at FROM tasks WHERE id = ?1")
|
||||
.map_err(storage_err)?;
|
||||
let row = stmt
|
||||
.query_row(params![id], |row| task_from_row(row))
|
||||
@@ -898,7 +903,7 @@ impl TaskRepo {
|
||||
tokio::task::spawn_blocking(move || {
|
||||
let guard = conn.blocking_lock();
|
||||
let mut stmt = guard
|
||||
.prepare("SELECT id, project_id, title, description, status, priority, branch_name, assignee, workflow_def_id, base_branch, review_rounds, created_at, updated_at FROM tasks WHERE deleted_at IS NOT NULL ORDER BY updated_at DESC")
|
||||
.prepare("SELECT id, project_id, title, description, status, priority, branch_name, assignee, workflow_def_id, base_branch, review_rounds, output_json, created_at, updated_at FROM tasks WHERE deleted_at IS NOT NULL ORDER BY updated_at DESC")
|
||||
.map_err(storage_err)?;
|
||||
let rows = stmt
|
||||
.query_map([], |row| task_from_row(row))
|
||||
|
||||
@@ -34,7 +34,7 @@ pub fn run(conn: &Connection) -> Result<()> {
|
||||
|
||||
// 迁移步骤链: 顺序执行,跳过已应用的版本(current_version < N 才跑)。
|
||||
// 新增版本时,在此数组追加一项 (N, migrate_vN) 即可,无需改逻辑。
|
||||
let steps: [(i32, fn(&Connection) -> Result<()>); 16] = [
|
||||
let steps: [(i32, fn(&Connection) -> Result<()>); 17] = [
|
||||
(1, migrate_v1),
|
||||
(2, migrate_v2),
|
||||
(3, migrate_v3),
|
||||
@@ -51,6 +51,7 @@ pub fn run(conn: &Connection) -> Result<()> {
|
||||
(14, migrate_v14),
|
||||
(15, migrate_v15),
|
||||
(16, migrate_v16),
|
||||
(17, migrate_v17),
|
||||
];
|
||||
|
||||
for (version, migrate_fn) in steps {
|
||||
@@ -295,6 +296,22 @@ fn migrate_v16(conn: &Connection) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// V17: 幂等补 tasks.output_json 列(AiNode 自审闭环产出,决策 a:task 中心)
|
||||
///
|
||||
/// 任务产出 JSON 字符串:ai_execute 写产出 / ai_self_review 读产出做自审 / human_review 展示对象。
|
||||
/// TEXT NULL 向后兼容(老库行默认 NULL,TaskRecord 字段为 Option<String>),
|
||||
/// 经通用 update_field 白名单写入(非 status 状态机收口字段,status 收口 F-03 不变)。
|
||||
/// 用 PRAGMA 探测列存在性,缺失才 ALTER(同 v4/v5/v6/v8/v10/v11/v14/v15/v16 模式),对新库/老库均安全。
|
||||
fn migrate_v17(conn: &Connection) -> Result<()> {
|
||||
if !column_exists(conn, "tasks", "output_json") {
|
||||
conn.execute("ALTER TABLE tasks ADD COLUMN output_json TEXT", [])?;
|
||||
tracing::info!("v17: 补建 tasks.output_json 列(AiNode 自审闭环产出)");
|
||||
}
|
||||
conn.execute("INSERT INTO schema_version (version) VALUES (?)", [17])?;
|
||||
tracing::info!("迁移 v17 完成");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// V1 建表 SQL
|
||||
const V1_SQL: &str = "
|
||||
-- 想法表
|
||||
|
||||
@@ -66,6 +66,14 @@ pub struct TaskRecord {
|
||||
/// #[serde(default)] 兼容旧前端无该字段的 JSON(老任务记录默认 0)。
|
||||
#[serde(default)]
|
||||
pub review_rounds: i32,
|
||||
/// 任务产出 JSON 字符串(AiNode 自审闭环,决策 a:task 中心,产出跟 task 走)。
|
||||
///
|
||||
/// 三方读写约定:ai_execute 写产出 / ai_self_review 读产出做自审 / human_review 展示产出对象。
|
||||
/// 经通用 update_field 写白名单(非 status 那种状态机收口字段),TEXT NULL 向后兼容。
|
||||
/// #[serde(skip_serializing_if)] 无产出不序列化(省前端字段空值),#[serde(default)] 兼容旧 JSON。
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(default)]
|
||||
pub output_json: Option<String>,
|
||||
pub created_at: String,
|
||||
pub updated_at: String,
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ fn task(id: &str, project_id: &str) -> TaskRecord {
|
||||
workflow_def_id: None,
|
||||
base_branch: None,
|
||||
review_rounds: 0,
|
||||
output_json: None,
|
||||
created_at: now_ts(),
|
||||
updated_at: now_ts(),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user