mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-29 06:31:32 +00:00
fix(kanban): migrate task session index after columns
This commit is contained in:
parent
39c41d0f23
commit
7c622b6c74
2 changed files with 59 additions and 10 deletions
|
|
@ -865,8 +865,6 @@ CREATE TABLE IF NOT EXISTS tasks (
|
|||
session_id TEXT
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_tasks_session_id ON tasks(session_id);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS task_links (
|
||||
parent_id TEXT NOT NULL,
|
||||
child_id TEXT NOT NULL,
|
||||
|
|
@ -937,8 +935,6 @@ CREATE TABLE IF NOT EXISTS kanban_notify_subs (
|
|||
|
||||
CREATE INDEX IF NOT EXISTS idx_tasks_assignee_status ON tasks(assignee, status);
|
||||
CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_tasks_tenant ON tasks(tenant);
|
||||
CREATE INDEX IF NOT EXISTS idx_tasks_idempotency ON tasks(idempotency_key);
|
||||
CREATE INDEX IF NOT EXISTS idx_links_child ON task_links(child_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_links_parent ON task_links(parent_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_comments_task ON task_comments(task_id, created_at);
|
||||
|
|
@ -1170,14 +1166,20 @@ def _migrate_add_optional_columns(conn: sqlite3.Connection) -> None:
|
|||
# created from within an agent loop that propagated
|
||||
# ``HERMES_SESSION_ID`` (e.g. ACP). NULL on legacy rows and on any
|
||||
# creation path that doesn't set the env var (CLI, dashboard).
|
||||
# Index keeps per-session list queries cheap.
|
||||
_add_column_if_missing(
|
||||
conn, "tasks", "session_id", "session_id TEXT"
|
||||
)
|
||||
conn.execute(
|
||||
"CREATE INDEX IF NOT EXISTS idx_tasks_session_id "
|
||||
"ON tasks(session_id)"
|
||||
)
|
||||
|
||||
# Indexes over additive task columns must be created after the columns
|
||||
# exist. Keeping them in SCHEMA_SQL breaks legacy boards because
|
||||
# CREATE TABLE IF NOT EXISTS does not add new columns to existing tables.
|
||||
conn.execute("CREATE INDEX IF NOT EXISTS idx_tasks_tenant ON tasks(tenant)")
|
||||
conn.execute(
|
||||
"CREATE INDEX IF NOT EXISTS idx_tasks_idempotency ON tasks(idempotency_key)"
|
||||
)
|
||||
conn.execute(
|
||||
"CREATE INDEX IF NOT EXISTS idx_tasks_session_id ON tasks(session_id)"
|
||||
)
|
||||
|
||||
# task_events gained a run_id column; back-fill it as NULL for
|
||||
# historical events (they predate runs and can't be attributed).
|
||||
|
|
|
|||
|
|
@ -48,6 +48,51 @@ def test_init_creates_expected_tables(kanban_home):
|
|||
assert {"tasks", "task_links", "task_comments", "task_events"} <= names
|
||||
|
||||
|
||||
def test_connect_migrates_legacy_db_before_optional_column_indexes(tmp_path):
|
||||
db_path = tmp_path / "legacy-kanban.db"
|
||||
conn = sqlite3.connect(str(db_path))
|
||||
conn.execute("""
|
||||
CREATE TABLE tasks (
|
||||
id TEXT PRIMARY KEY,
|
||||
title TEXT NOT NULL,
|
||||
body TEXT,
|
||||
assignee TEXT,
|
||||
status TEXT NOT NULL,
|
||||
priority INTEGER NOT NULL DEFAULT 0,
|
||||
created_by TEXT,
|
||||
created_at INTEGER NOT NULL,
|
||||
started_at INTEGER,
|
||||
completed_at INTEGER,
|
||||
workspace_kind TEXT NOT NULL DEFAULT 'scratch',
|
||||
workspace_path TEXT,
|
||||
claim_lock TEXT,
|
||||
claim_expires INTEGER
|
||||
)
|
||||
""")
|
||||
conn.execute(
|
||||
"INSERT INTO tasks (id, title, status, created_at) "
|
||||
"VALUES ('legacy', 'old board task', 'ready', 1)"
|
||||
)
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
with kb.connect(db_path) as migrated:
|
||||
task_columns = {
|
||||
row["name"] for row in migrated.execute("PRAGMA table_info(tasks)")
|
||||
}
|
||||
indexes = {
|
||||
row["name"]
|
||||
for row in migrated.execute(
|
||||
"SELECT name FROM sqlite_master WHERE type = 'index'"
|
||||
)
|
||||
}
|
||||
|
||||
assert "session_id" in task_columns
|
||||
assert "idx_tasks_session_id" in indexes
|
||||
assert "idx_tasks_tenant" in indexes
|
||||
assert "idx_tasks_idempotency" in indexes
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Task creation + status inference
|
||||
# ---------------------------------------------------------------------------
|
||||
|
|
@ -462,7 +507,7 @@ def test_detect_crashed_workers_isolated_failure_normal_retry(
|
|||
)
|
||||
|
||||
|
||||
def test_max_runtime_uses_current_run_start_after_retry(kanban_home):
|
||||
def test_max_runtime_uses_current_run_start_after_retry(kanban_home, monkeypatch):
|
||||
"""A retry should get a fresh max-runtime window.
|
||||
|
||||
``tasks.started_at`` intentionally records the first time the task ever
|
||||
|
|
@ -470,6 +515,8 @@ def test_max_runtime_uses_current_run_start_after_retry(kanban_home):
|
|||
``task_runs.started_at`` row; otherwise every retry of an old task is
|
||||
immediately timed out again.
|
||||
"""
|
||||
monkeypatch.setattr(kb, "_pid_alive", lambda _pid: False)
|
||||
|
||||
with kb.connect() as conn:
|
||||
host = kb._claimer_id().split(":", 1)[0]
|
||||
t = kb.create_task(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue