Skip to content

feat(backend): migrate agentflare-backend onto rusqlite_migration - #166

Merged
getappz merged 1 commit into
masterfrom
feat/agentflare-backend-rusqlite-migration
Jul 13, 2026
Merged

feat(backend): migrate agentflare-backend onto rusqlite_migration#166
getappz merged 1 commit into
masterfrom
feat/agentflare-backend-rusqlite-migration

Conversation

@getappz

@getappz getappz commented Jul 13, 2026

Copy link
Copy Markdown
Owner

What

Switches agentflare-backend's db.rs from ad-hoc Connection::open + execute_batch(schema.sql) onto agentflare-db-kit's rusqlite_migration wiring (open_file/open_memory), as flagged as a follow-up during #165's review.

  • schema.sql renamed to migrations/0001_initial.sql (content unchanged) — future schema changes become new numbered files here, not edits to this one.
  • db.rs builds a const MIGRATIONS: Migrations from that file and calls db_kit::open_file/open_memory instead of raw execute_batch.
  • open_db/open_in_memory now return Result<_, db_kit::open::Error> instead of rusqlite::Result — all 3 call sites in src/mcp_server.rs only use .to_string()/.unwrap(), so this is a no-op for them.

Why

SQLite has no ALTER COLUMN IF NOT EXISTS, so CREATE TABLE IF NOT EXISTS re-runs stop covering schema changes the moment anything needs to modify/drop a column. agentflare-db-kit already had rusqlite_migration support built for this; agentflare-backend just hadn't adopted it yet.

The pre-existing-DB question

Existing installed backend.db files (from #162/#165) were created via the old execute_batch path and have no migration bookkeeping. rusqlite_migration tracks applied version via SQLite's own PRAGMA user_version (confirmed by reading the vendored crate source — no separate bookkeeping table). Since user_version defaults to 0 and was never touched by the old path, and 0001_initial.sql's CREATE TABLE/INDEX IF NOT EXISTS statements are already idempotent, running migration 0001 against an already-populated DB is a harmless no-op that just stamps it to user_version = 1. No baseline/backfill step needed.

Added a test (migrate_is_safe_against_a_pre_migration_db) that reproduces this exact scenario: seeds a DB via the old execute_batch path with data, then opens it through the new migration-aware open_db, and asserts the data survives and user_version ends up at 1.

Testing

  • cargo test -p agentflare-backend — 57/57 pass
  • cargo build --workspace
  • cargo clippy --locked --workspace --all-targets --all-features -- -D warnings -A unsafe_code -A clippy::pedantic (CI's exact flags)
  • cargo fmt --check
  • cargo deny check

Summary by CodeRabbit

  • New Features

    • Added the initial database structure for workspaces, projects, workflows, tasks, labels, integrations, assets, and related records.
    • Added support for safe, versioned database migrations.
    • Enabled improved database reliability with foreign-key enforcement and WAL journaling.
  • Bug Fixes

    • Improved migration handling for existing databases, including databases that have not yet been migrated.

@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown

Review Change Stack

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 174a1b29-f15f-43b2-92d1-7b9dcc8d7b10

📥 Commits

Reviewing files that changed from the base of the PR and between b98e52d and 1c0ec64.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (3)
  • crates/agentflare-backend/Cargo.toml
  • crates/agentflare-backend/src/db.rs
  • crates/agentflare-backend/src/migrations/0001_initial.sql

📝 Walkthrough

Walkthrough

The backend replaces custom SQLite migration handling with rusqlite_migration, adds an initial schema migration, opens databases through db_kit, enables foreign keys, and tests migration versioning, data preservation, and WAL mode.

Changes

SQLite migration adoption

Layer / File(s) Summary
Core workspace and task schema
crates/agentflare-backend/src/migrations/0001_initial.sql
Creates workspace, project, sequence, state, and item tables with constraints and indexes.
Relationships and integration tables
crates/agentflare-backend/src/migrations/0001_initial.sql
Adds labels, item associations, webhooks, assets, webhook logs, and item claims.
Managed database opening and migration validation
crates/agentflare-backend/Cargo.toml, crates/agentflare-backend/src/db.rs
Configures managed migrations, updates file and in-memory database opening, enables foreign keys, and validates migration versioning, data preservation, and WAL mode.

Estimated code review effort: 3 (Moderate) | ~20 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly states the main backend migration to rusqlite_migration and matches the changeset.
Description check ✅ Passed The description covers the change, rationale, migration behavior, pre-existing DB handling, and testing, so it is mostly complete.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/agentflare-backend-rusqlite-migration

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
crates/agentflare-backend/src/migrations/0001_initial.sql (2)

103-107: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

No guard against item_id == depends_on_item_id.

Nothing prevents an item from depending on itself, which could create a degenerate/self-referential entry that downstream dependency-graph traversal must special-case.

🔧 Proposed fix
 CREATE TABLE IF NOT EXISTS item_dependencies (
   item_id TEXT NOT NULL REFERENCES items(id),
   depends_on_item_id TEXT NOT NULL REFERENCES items(id),
+  CHECK (item_id != depends_on_item_id),
   PRIMARY KEY (item_id, depends_on_item_id)
 );
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/agentflare-backend/src/migrations/0001_initial.sql` around lines 103 -
107, Add a table-level CHECK constraint to item_dependencies that rejects rows
where item_id equals depends_on_item_id, while preserving the existing foreign
keys and composite primary key.

140-156: 🗄️ Data Integrity & Integration | 🔵 Trivial

Unbounded retention of raw webhook payloads.

request_headers/request_body/response_headers/response_body are stored indefinitely with no deleted_at/TTL column, and headers/bodies may carry secrets or PII (auth tokens, user data) forwarded through webhooks. Worth considering redaction before storage or a retention/purge policy for this table.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/agentflare-backend/src/migrations/0001_initial.sql` around lines 140 -
156, Update the webhook_logs schema to support bounded retention of raw webhook
data by adding a deleted_at or equivalent expiration column, and ensure the
migration includes the index needed for purge queries. Preserve the existing
payload fields and webhook log relationships while enabling scheduled deletion
of expired records.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/agentflare-backend/src/migrations/0001_initial.sql`:
- Around line 74-90: Update the labels table definition so labels.project_id
declares a foreign-key reference to projects(id), while preserving its nullable
behavior for workspace-only labels and leaving the existing indexes unchanged.
- Around line 140-156: Update the webhook_logs table definition to make
webhook_id a foreign key referencing webhooks(id), while preserving its existing
nullability and indexing. Add the constraint alongside the existing workspace_id
reference in CREATE TABLE webhook_logs.

---

Nitpick comments:
In `@crates/agentflare-backend/src/migrations/0001_initial.sql`:
- Around line 103-107: Add a table-level CHECK constraint to item_dependencies
that rejects rows where item_id equals depends_on_item_id, while preserving the
existing foreign keys and composite primary key.
- Around line 140-156: Update the webhook_logs schema to support bounded
retention of raw webhook data by adding a deleted_at or equivalent expiration
column, and ensure the migration includes the index needed for purge queries.
Preserve the existing payload fields and webhook log relationships while
enabling scheduled deletion of expired records.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 174a1b29-f15f-43b2-92d1-7b9dcc8d7b10

📥 Commits

Reviewing files that changed from the base of the PR and between b98e52d and 1c0ec64.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (3)
  • crates/agentflare-backend/Cargo.toml
  • crates/agentflare-backend/src/db.rs
  • crates/agentflare-backend/src/migrations/0001_initial.sql

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 2

🧹 Nitpick comments (2)
crates/agentflare-backend/src/migrations/0001_initial.sql (2)

103-107: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

No guard against item_id == depends_on_item_id.

Nothing prevents an item from depending on itself, which could create a degenerate/self-referential entry that downstream dependency-graph traversal must special-case.

🔧 Proposed fix
 CREATE TABLE IF NOT EXISTS item_dependencies (
   item_id TEXT NOT NULL REFERENCES items(id),
   depends_on_item_id TEXT NOT NULL REFERENCES items(id),
+  CHECK (item_id != depends_on_item_id),
   PRIMARY KEY (item_id, depends_on_item_id)
 );
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/agentflare-backend/src/migrations/0001_initial.sql` around lines 103 -
107, Add a table-level CHECK constraint to item_dependencies that rejects rows
where item_id equals depends_on_item_id, while preserving the existing foreign
keys and composite primary key.

140-156: 🗄️ Data Integrity & Integration | 🔵 Trivial

Unbounded retention of raw webhook payloads.

request_headers/request_body/response_headers/response_body are stored indefinitely with no deleted_at/TTL column, and headers/bodies may carry secrets or PII (auth tokens, user data) forwarded through webhooks. Worth considering redaction before storage or a retention/purge policy for this table.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/agentflare-backend/src/migrations/0001_initial.sql` around lines 140 -
156, Update the webhook_logs schema to support bounded retention of raw webhook
data by adding a deleted_at or equivalent expiration column, and ensure the
migration includes the index needed for purge queries. Preserve the existing
payload fields and webhook log relationships while enabling scheduled deletion
of expired records.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/agentflare-backend/src/migrations/0001_initial.sql`:
- Around line 74-90: Update the labels table definition so labels.project_id
declares a foreign-key reference to projects(id), while preserving its nullable
behavior for workspace-only labels and leaving the existing indexes unchanged.
- Around line 140-156: Update the webhook_logs table definition to make
webhook_id a foreign key referencing webhooks(id), while preserving its existing
nullability and indexing. Add the constraint alongside the existing workspace_id
reference in CREATE TABLE webhook_logs.

---

Nitpick comments:
In `@crates/agentflare-backend/src/migrations/0001_initial.sql`:
- Around line 103-107: Add a table-level CHECK constraint to item_dependencies
that rejects rows where item_id equals depends_on_item_id, while preserving the
existing foreign keys and composite primary key.
- Around line 140-156: Update the webhook_logs schema to support bounded
retention of raw webhook data by adding a deleted_at or equivalent expiration
column, and ensure the migration includes the index needed for purge queries.
Preserve the existing payload fields and webhook log relationships while
enabling scheduled deletion of expired records.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 174a1b29-f15f-43b2-92d1-7b9dcc8d7b10

📥 Commits

Reviewing files that changed from the base of the PR and between b98e52d and 1c0ec64.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (3)
  • crates/agentflare-backend/Cargo.toml
  • crates/agentflare-backend/src/db.rs
  • crates/agentflare-backend/src/migrations/0001_initial.sql
🛑 Comments failed to post (2)
crates/agentflare-backend/src/migrations/0001_initial.sql (2)

74-90: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

labels.project_id lacks a foreign key.

Every other tenant-scoped column in this table (workspace_id) and table (parent_id) declares REFERENCES, but project_id doesn't reference projects(id). Since db.rs now turns on PRAGMA foreign_keys = ON, this column silently escapes referential-integrity enforcement, allowing labels to point at nonexistent/deleted projects.

🔧 Proposed fix
 CREATE TABLE IF NOT EXISTS labels (
   id TEXT PRIMARY KEY,
-  project_id TEXT,
+  project_id TEXT REFERENCES projects(id),
   workspace_id TEXT NOT NULL REFERENCES workspaces(id),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

CREATE TABLE IF NOT EXISTS labels (
  id TEXT PRIMARY KEY,
  project_id TEXT REFERENCES projects(id),
  workspace_id TEXT NOT NULL REFERENCES workspaces(id),
  name TEXT NOT NULL,
  color TEXT NOT NULL DEFAULT '`#60646C`',
  parent_id TEXT REFERENCES labels(id),
  sort_order REAL NOT NULL DEFAULT 65535,
  external_source TEXT,
  external_id TEXT,
  created_at INTEGER NOT NULL,
  updated_at INTEGER NOT NULL,
  deleted_at INTEGER
);
CREATE UNIQUE INDEX IF NOT EXISTS idx_labels_name_project ON labels(name, project_id) WHERE deleted_at IS NULL AND project_id IS NOT NULL;
CREATE UNIQUE INDEX IF NOT EXISTS idx_labels_name_workspace_only ON labels(name, workspace_id) WHERE deleted_at IS NULL AND project_id IS NULL;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/agentflare-backend/src/migrations/0001_initial.sql` around lines 74 -
90, Update the labels table definition so labels.project_id declares a
foreign-key reference to projects(id), while preserving its nullable behavior
for workspace-only labels and leaving the existing indexes unchanged.

140-156: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

webhook_logs.webhook_id lacks a foreign key.

workspace_id on this same table references workspaces(id), but webhook_id doesn't reference webhooks(id), so log rows can outlive/point past a deleted webhook without any DB-level guarantee.

🔧 Proposed fix
   workspace_id TEXT NOT NULL REFERENCES workspaces(id),
-  webhook_id TEXT NOT NULL,
+  webhook_id TEXT NOT NULL REFERENCES webhooks(id),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

CREATE TABLE IF NOT EXISTS webhook_logs (
  id TEXT PRIMARY KEY,
  workspace_id TEXT NOT NULL REFERENCES workspaces(id),
  webhook_id TEXT NOT NULL REFERENCES webhooks(id),
  event_type TEXT,
  request_method TEXT,
  request_headers TEXT,
  request_body TEXT,
  response_status TEXT,
  response_headers TEXT,
  response_body TEXT,
  retry_count INTEGER NOT NULL DEFAULT 0,
  created_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_webhook_logs_webhook ON webhook_logs(webhook_id);
CREATE INDEX IF NOT EXISTS idx_webhook_logs_workspace ON webhook_logs(workspace_id);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/agentflare-backend/src/migrations/0001_initial.sql` around lines 140 -
156, Update the webhook_logs table definition to make webhook_id a foreign key
referencing webhooks(id), while preserving its existing nullability and
indexing. Add the constraint alongside the existing workspace_id reference in
CREATE TABLE webhook_logs.

@getappz
getappz merged commit a833965 into master Jul 13, 2026
15 checks passed
@getappz
getappz deleted the feat/agentflare-backend-rusqlite-migration branch July 13, 2026 10:13
getappz pushed a commit that referenced this pull request Aug 25, 2026
Discovery tick dispatches purely on the ready-for-work label, so items
#184/#185/#186/#187 (go/no-go candidates from #166's spec) whose own
description says "Decision pending — not dispatched" got auto-dispatched
and re-dispatched across multiple agents anyway -- the prose was never
actually enforced.

Add a needs-decision label that blocks run_discovery_tick even while
ready-for-work is also present. Stripping ready-for-work alone wouldn't
have been durable: redispatch unconditionally re-attaches it, so the new
label has to keep gating on its own until a human clears it.

Agentflare-Agent: claude-code
Agentflare-Branch: fix/dispatch-failure-ceiling-any-reason
getappz added a commit that referenced this pull request Aug 26, 2026
Adds semantic (embedding-based) recall to skill search, reusing
agentflare-store's existing embedding infrastructure as a library
rather than building anything new -- per item #166's design-spec
(candidate d).

- crates/skill-registry: new skills_vec table (0003_vec.sql) mirroring
  observations_vec in src/memory/schema.rs. New embed_store module
  (upsert/delete/missing/candidates/backfill) built on
  agentflare_store::embed's cosine-similarity/blob-codec primitives --
  these are always-compiled pure math in agentflare-store, not gated
  behind its `embeddings` feature, so skill-registry takes an
  unconditional dependency on them.
- search::search_semantic blends BM25 hits with vector candidates via
  agentflare_store::retrieval::merge_ranked, backfilling any vector-only
  match's full SkillHit row. Degrades byte-identically to plain search()
  when the caller's embed_query returns None (feature off, no model, or
  a failed call) -- same graceful-degradation contract src/memory uses.
- Registry gets search_semantic/backfill_embeddings methods. Like
  skill_detect::find_skills already does, the embedding functions are
  caller-supplied closures (crate::memory::engine::embed_query/embed_doc)
  rather than a dependency skill-registry can't have on the binary crate.
- Wired into the `skill` MCP tool's search action: a small bounded
  backfill (25/call) runs before each search so the semantic index
  catches up lazily on first use, no separate background job needed.

Verified: cargo build/clippy/fmt clean against CI's exact invocations;
63 skill-registry tests (9 new) + 246 mcp_server tests + 39
skill-related binary tests all pass.

Agentflare-Branch: task/187-semantic-embedding-search-spike-go-no-go
Agentflare-Item: 187-semantic-embedding-search-spike-go-no-go

Co-authored-by: shiva <shiva@gosysinfo.tech>
getappz pushed a commit that referenced this pull request Aug 26, 2026
Reimplemented from scratch against current master -- the prior branch
had overwritten sources.rs's SkillEntry scanning adapter (load.rs's
default_sources/scan_sources/validate_entry dependency) with an
unrelated SkillSpec/TOML module and committed a pile of debug scratch
scripts, and was badly stale besides. See PR #614's close comment.

Per item #185 (candidate b of item #166's design-spec): a `category`
frontmatter field, defaulting to the first tag when unset, plus one
read-only skill_categories MCP tool.

- crates/skill-registry: category column (0004_category.sql), threaded
  through Frontmatter/SkillEntry/BundleEntry (so it round-trips through
  hub export/import, not just local scans) and db::rebuild's insert.
  New search::list_categories/skills_in_category read helpers and
  matching Registry methods.
- skill_categories MCP tool: omit `category` for every category with
  its skill count (most populated first); pass one to list its skills.
- Three pre-existing SkillEntry literals in src/cli/skill.rs (export,
  hub push, DB-only-source carry-forward) updated for the new field.

Verified: cargo build/clippy/fmt clean against CI's exact invocations;
70 skill-registry tests (7 new) + 246 mcp_server tests + 12 cli::skill
tests all pass.

Agentflare-Branch: task/185-category-taxonomy-skill-categories-tool
Agentflare-Item: 185-category-taxonomy-skill-categories-tool
getappz added a commit that referenced this pull request Aug 26, 2026
Reimplemented from scratch against current master -- the prior branch
had overwritten sources.rs's SkillEntry scanning adapter (load.rs's
default_sources/scan_sources/validate_entry dependency) with an
unrelated SkillSpec/TOML module and committed a pile of debug scratch
scripts, and was badly stale besides. See PR #614's close comment.

Per item #185 (candidate b of item #166's design-spec): a `category`
frontmatter field, defaulting to the first tag when unset, plus one
read-only skill_categories MCP tool.

- crates/skill-registry: category column (0004_category.sql), threaded
  through Frontmatter/SkillEntry/BundleEntry (so it round-trips through
  hub export/import, not just local scans) and db::rebuild's insert.
  New search::list_categories/skills_in_category read helpers and
  matching Registry methods.
- skill_categories MCP tool: omit `category` for every category with
  its skill count (most populated first); pass one to list its skills.
- Three pre-existing SkillEntry literals in src/cli/skill.rs (export,
  hub push, DB-only-source carry-forward) updated for the new field.

Verified: cargo build/clippy/fmt clean against CI's exact invocations;
70 skill-registry tests (7 new) + 246 mcp_server tests + 12 cli::skill
tests all pass.

Agentflare-Branch: task/185-category-taxonomy-skill-categories-tool
Agentflare-Item: 185-category-taxonomy-skill-categories-tool

Co-authored-by: shiva <shiva@gosysinfo.tech>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant