diff --git a/core/context_builder.py b/core/context_builder.py index 96c3ae8..da2cf9f 100644 --- a/core/context_builder.py +++ b/core/context_builder.py @@ -117,6 +117,8 @@ def _slim_task(task: dict) -> dict: } if task.get("revise_comment"): result["revise_comment"] = task["revise_comment"] + if task.get("acceptance_criteria"): + result["acceptance_criteria"] = task["acceptance_criteria"] return result diff --git a/core/db.py b/core/db.py index 2433d08..bcd09d8 100644 --- a/core/db.py +++ b/core/db.py @@ -29,6 +29,8 @@ CREATE TABLE IF NOT EXISTS projects ( ssh_key_path TEXT, ssh_proxy_jump TEXT, description TEXT, + autocommit_enabled INTEGER DEFAULT 0, + obsidian_vault_path TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP ); @@ -56,6 +58,7 @@ CREATE TABLE IF NOT EXISTS tasks ( revise_comment TEXT, category TEXT DEFAULT NULL, telegram_sent BOOLEAN DEFAULT 0, + acceptance_criteria TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ); @@ -290,6 +293,10 @@ def _migrate(conn: sqlite3.Connection): conn.execute("ALTER TABLE tasks ADD COLUMN telegram_sent BOOLEAN DEFAULT 0") conn.commit() + if "acceptance_criteria" not in task_cols: + conn.execute("ALTER TABLE tasks ADD COLUMN acceptance_criteria TEXT") + conn.commit() + if "obsidian_vault_path" not in proj_cols: conn.execute("ALTER TABLE projects ADD COLUMN obsidian_vault_path TEXT") conn.commit() diff --git a/core/models.py b/core/models.py index 5ec21ee..ceb1672 100644 --- a/core/models.py +++ b/core/models.py @@ -197,16 +197,17 @@ def create_task( forgejo_issue_id: int | None = None, execution_mode: str | None = None, category: str | None = None, + acceptance_criteria: str | None = None, ) -> dict: """Create a task linked to a project.""" conn.execute( """INSERT INTO tasks (id, project_id, title, status, priority, assigned_role, parent_task_id, brief, spec, forgejo_issue_id, - execution_mode, category) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""", + execution_mode, category, acceptance_criteria) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""", (id, project_id, title, status, priority, assigned_role, parent_task_id, _json_encode(brief), _json_encode(spec), - forgejo_issue_id, execution_mode, category), + forgejo_issue_id, execution_mode, category, acceptance_criteria), ) conn.commit() return get_task(conn, id) diff --git a/tests/test_models.py b/tests/test_models.py index 7f4ad4f..6ea342c 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -58,9 +58,9 @@ def test_update_project_tech_stack_json(conn): # -- project_type and SSH fields (KIN-071) -- def test_create_operations_project(conn): - """KIN-071: operations project stores SSH fields.""" + """KIN-071: operations project stores SSH fields. KIN-ARCH-005: path не передаётся.""" p = models.create_project( - conn, "srv1", "My Server", "", + conn, "srv1", "My Server", project_type="operations", ssh_host="10.0.0.1", ssh_user="root", @@ -72,6 +72,7 @@ def test_create_operations_project(conn): assert p["ssh_user"] == "root" assert p["ssh_key_path"] == "~/.ssh/id_rsa" assert p["ssh_proxy_jump"] == "jumpt" + assert p["path"] is None def test_create_development_project_defaults(conn): @@ -521,3 +522,45 @@ def test_update_task_category_preserves_status_and_priority(conn): assert updated["category"] == "UI" assert updated["status"] == "in_progress" assert updated["priority"] == 3 + + +# -- KIN-ARCH-006: autocommit_enabled и obsidian_vault_path в SCHEMA -- + +def test_schema_project_has_autocommit_enabled_column(conn): + """KIN-ARCH-006: таблица projects содержит колонку autocommit_enabled.""" + cols = {r[1] for r in conn.execute("PRAGMA table_info(projects)").fetchall()} + assert "autocommit_enabled" in cols + + +def test_schema_project_has_obsidian_vault_path_column(conn): + """KIN-ARCH-006: таблица projects содержит колонку obsidian_vault_path.""" + cols = {r[1] for r in conn.execute("PRAGMA table_info(projects)").fetchall()} + assert "obsidian_vault_path" in cols + + +def test_autocommit_enabled_default_is_zero(conn): + """KIN-ARCH-006: autocommit_enabled по умолчанию равен 0.""" + models.create_project(conn, "p1", "P1", "/p1") + p = models.get_project(conn, "p1") + assert p["autocommit_enabled"] == 0 + + +def test_obsidian_vault_path_default_is_none(conn): + """KIN-ARCH-006: obsidian_vault_path по умолчанию равен NULL.""" + models.create_project(conn, "p1", "P1", "/p1") + p = models.get_project(conn, "p1") + assert p["obsidian_vault_path"] is None + + +def test_autocommit_enabled_can_be_set_to_one(conn): + """KIN-ARCH-006: autocommit_enabled можно установить в 1 через update_project.""" + models.create_project(conn, "p1", "P1", "/p1") + updated = models.update_project(conn, "p1", autocommit_enabled=1) + assert updated["autocommit_enabled"] == 1 + + +def test_obsidian_vault_path_can_be_set(conn): + """KIN-ARCH-006: obsidian_vault_path можно установить через update_project.""" + models.create_project(conn, "p1", "P1", "/p1") + updated = models.update_project(conn, "p1", obsidian_vault_path="/vault/my-notes") + assert updated["obsidian_vault_path"] == "/vault/my-notes"