From ae8b85df1d45c73adca734267e6ba4e6219b028a Mon Sep 17 00:00:00 2001 From: cfdaily Date: Mon, 18 May 2026 11:36:11 +0800 Subject: [PATCH] auto-sync: 2026-05-18 11:36:11 --- src/blackboard/db.py | 100 +++++-------------------------------------- 1 file changed, 10 insertions(+), 90 deletions(-) diff --git a/src/blackboard/db.py b/src/blackboard/db.py index 6433b2c..1f8916d 100644 --- a/src/blackboard/db.py +++ b/src/blackboard/db.py @@ -14,11 +14,9 @@ def init_db(db_path: Path) -> None: try: for stmt in _SCHEMA_STATEMENTS: conn.execute(stmt) - for stmt in _CARDS_SCHEMA: - conn.execute(stmt) # v2.6.1 迁移:旧 DB 可能缺少新字段 _migrate_v261(conn) - # v2.7 迁移:cards 表 + card_id + stage + # v2.7 迁移:stages_json _migrate_v27(conn) conn.commit() finally: @@ -41,70 +39,11 @@ def _migrate_v261(conn: sqlite3.Connection) -> None: def _migrate_v27(conn: sqlite3.Connection) -> None: - """v2.7 数据迁移:cards 表 + 所有表加 card_id/stage""" - # 1. cards 表(CREATE IF NOT EXISTS 已处理) - for stmt in _CARDS_SCHEMA: - try: - conn.execute(stmt) - except sqlite3.OperationalError: - pass - - # 2. 所有表加 card_id - for table in ("tasks", "outputs", "reviews", "comments", "events", - "task_attempts", "routing_decisions"): - _safe_add_column(conn, table, "card_id", "TEXT") - - # 3. tasks 加 stage + """v2.7 数据迁移:stages_json 字段(动态 Stage 定义)""" + _safe_add_column(conn, "tasks", "stages_json", "TEXT DEFAULT '[]'") + # 确保 stage 列存在(旧 v2.7 迁移可能已添加) _safe_add_column(conn, "tasks", "stage", "TEXT") - # 4. card_id 索引 - for table in ("tasks", "events"): - try: - conn.execute( - f"CREATE INDEX IF NOT EXISTS idx_{table}_card ON {table}(card_id)") - except sqlite3.OperationalError: - pass - - # 5. 回填 card_id = 'default'(分批,避免大表锁太久) - for table in ("tasks", "outputs", "reviews", "comments", "events", - "task_attempts", "routing_decisions"): - try: - row = conn.execute( - f"SELECT COUNT(*) as cnt FROM {table} WHERE card_id IS NULL" - ).fetchone() - if row and row["cnt"] > 0: - # 分批更新,每批 500 行 - _batch_update_card_id(conn, table, "default", batch_size=500) - except sqlite3.OperationalError: - pass # 表不存在则跳过 - - # 6. 创建 default Card(如果不存在) - try: - existing = conn.execute( - "SELECT id FROM cards WHERE id='default'" - ).fetchone() - if not existing: - conn.execute( - "INSERT INTO cards (id, name, status, card_type, stages_json, labels_json, created_at) " - "VALUES ('default', 'Default', 'active', 'default', '[]', '[]', datetime('now'))" - ) - except sqlite3.OperationalError: - pass # cards 表不存在则跳过(不应该发生) - - -def _batch_update_card_id(conn: sqlite3.Connection, table: str, - card_id: str, batch_size: int = 500) -> None: - """分批更新 card_id,避免大表长时间锁""" - while True: - cursor = conn.execute( - f"UPDATE {table} SET card_id=? WHERE rowid IN (" - f"SELECT rowid FROM {table} WHERE card_id IS NULL LIMIT {batch_size})", - (card_id,), - ) - if cursor.rowcount == 0: - break - conn.commit() - def _safe_add_column(conn: sqlite3.Connection, table: str, column: str, col_type: str) -> None: @@ -141,6 +80,9 @@ VALID_STATUSES = frozenset({ TERMINAL_STATUSES = frozenset({"done", "cancelled"}) +# 手动状态(不参与聚合推导) +MANUAL_STATUSES = frozenset({"cancelled"}) + VALID_TRANSITIONS = { "pending": {"claimed", "cancelled"}, "claimed": {"working", "pending", "cancelled"}, @@ -188,8 +130,7 @@ ATTEMPT_OUTCOMES = frozenset({ # --------------------------------------------------------------------------- -# Schema - split into individual statements to avoid SQLite 3.51 CHECK bug -# (table-level CHECK as non-last column definition causes parse error) +# Schema # --------------------------------------------------------------------------- _SCHEMA_STATEMENTS = [ @@ -220,8 +161,8 @@ _SCHEMA_STATEMENTS = [ current_agent TEXT, previous_agent TEXT, next_capability TEXT, - card_id TEXT DEFAULT 'default', - stage TEXT + stage TEXT, + stages_json TEXT DEFAULT '[]' )""", "CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status)", "CREATE INDEX IF NOT EXISTS idx_tasks_assignee ON tasks(assignee)", @@ -386,24 +327,3 @@ _SCHEMA_STATEMENTS = [ "CREATE INDEX IF NOT EXISTS idx_routing_mode ON routing_decisions(mode)", "CREATE INDEX IF NOT EXISTS idx_routing_time ON routing_decisions(created_at)", ] - -# --------------------------------------------------------------------------- -# Cards Schema (v2.7) -# --------------------------------------------------------------------------- - -_CARDS_SCHEMA = [ - """CREATE TABLE IF NOT EXISTS cards ( - id TEXT PRIMARY KEY, - name TEXT NOT NULL, - description TEXT DEFAULT '', - card_type TEXT DEFAULT 'default' CHECK (card_type IN ('default','strategy','data_pipeline','research','platform','bugfix','mail')), - stages_json TEXT DEFAULT '[]', - labels_json TEXT DEFAULT '[]', - status TEXT DEFAULT 'active' CHECK (status IN ('active','pending','working','review','done','failed','blocked','cancelled','archived','deleted')), - created_at TEXT NOT NULL DEFAULT (datetime('now')), - updated_at TEXT, - archived_at TEXT - )""", - "CREATE INDEX IF NOT EXISTS idx_cards_id ON cards(id)", - "CREATE INDEX IF NOT EXISTS idx_cards_status ON cards(status)", -]