Skip to content

Fix code correctness: schema trigger, error types, dead code, assertions#10

Merged
drewburchfield merged 3 commits intomasterfrom
fix/code-correctness
Apr 3, 2026
Merged

Fix code correctness: schema trigger, error types, dead code, assertions#10
drewburchfield merged 3 commits intomasterfrom
fix/code-correctness

Conversation

@drewburchfield
Copy link
Copy Markdown
Owner

@drewburchfield drewburchfield commented Apr 3, 2026

Closes NAS-995

Summary

  • Remove schema trigger that overwrites file mtime with CURRENT_TIMESTAMP
  • Add DROP TRIGGER/FUNCTION migration for existing databases
  • Change hub analyzer ValueError to DatabaseError (matches server error handler)
  • Fix validation docstrings (said "clamped" but code raises)
  • Remove dead code in indexer.py and hub_analyzer.py
  • Preserve connection_count on upsert instead of resetting to 0
  • Add ORDER BY chunk_index to graph_builder LIMIT 1 query
  • Fix weak test assertion in test_error_paths.py

Test plan

  • All 133 tests pass
  • Quality gate review: migration for existing DBs added
  • Braintrust consultation: aligned on trigger removal and count preservation

Open with Devin

- Remove schema trigger that overwrites modified_at with CURRENT_TIMESTAMP,
  preserving the real file mtime passed by the indexer
- Change hub_analyzer error type from ValueError to DatabaseError for
  consistency with the exception hierarchy
- Fix validation docstrings: document that functions raise ValidationError
  instead of claiming they clamp values
- Remove dead empty-content filter in indexer.py (already filtered at
  lines 119-122)
- Remove unused _refresh_all_counts method from hub_analyzer and update
  test to call _do_refresh directly
- Preserve connection_count on upsert (use notes.connection_count instead
  of resetting to 0) to avoid unnecessary full refreshes
- Add ORDER BY chunk_index to graph_builder LIMIT 1 query for deterministic
  chunk selection
- Fix weak test assertion: "pool" or "timeout" always evaluates True,
  changed to check membership in actual response text
Existing databases retain the mtime-overwriting trigger even after
the schema file is updated. Add DROP TRIGGER/FUNCTION IF EXISTS
so the init script cleans up on restart. Also fix stale comment.
Copy link
Copy Markdown

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 2 potential issues.

View 5 additional findings in Devin Review.

Open in Devin Review

Comment on lines +9 to +11
-- Migration: remove trigger that overwrites file mtime with DB timestamp
DROP TRIGGER IF EXISTS trigger_update_notes_modified_at ON notes;
DROP FUNCTION IF EXISTS update_modified_at();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Schema migration DROP TRIGGER is unreachable for existing databases

The DROP TRIGGER IF EXISTS migration at src/schema.sql:10-11 is placed inside the init schema file, which is mounted at docker-entrypoint-initdb.d/schema.sql (docker-compose.yml:54). Docker's PostgreSQL entrypoint only executes init scripts on first database creation (when the data volume is empty). For existing databases that already have the trigger, this migration never runs.

This means existing deployments will retain the old trigger_update_notes_modified_at trigger, which overwrites modified_at with CURRENT_TIMESTAMP on every UPDATE — including the _do_refresh batch UPDATE in src/hub_analyzer.py:225-244. This causes all notes' modified_at to be silently reset to the DB timestamp whenever connection counts are refreshed, making the orphaned notes' modified_at display meaningless.

Prompt for agents
The DROP TRIGGER/FUNCTION migration at schema.sql:10-11 is placed in a Docker init script that only runs on fresh database creation. Existing databases that have the trigger will never get it removed.

To fix this, consider one of:
1. Add a separate migration script (e.g., migrations/001_drop_modified_at_trigger.sql) that can be run manually or via a startup migration check in the Python code (e.g., in vector_store.py initialize() method).
2. Add the DROP TRIGGER logic to the Python store initialization code (PostgreSQLVectorStore.initialize), which runs on every server start and can check if the trigger exists before dropping it.
3. Document in the README/CHANGELOG that existing users must manually run: DROP TRIGGER IF EXISTS trigger_update_notes_modified_at ON notes; DROP FUNCTION IF EXISTS update_modified_at();
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

…me migration

- Revert connection_count back to = 0 on upsert (preserving counts breaks
  staleness detection which checks WHERE connection_count = 0; PR #8's
  inline-await already ensures fresh counts before queries)
- Add DROP TRIGGER/FUNCTION to initialize() so existing databases get the
  migration on server start, not just from schema.sql
Copy link
Copy Markdown

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 2 new potential issues.

View 6 additional findings in Devin Review.

Open in Devin Review

Comment on lines +10 to +11
DROP TRIGGER IF EXISTS trigger_update_notes_modified_at ON notes;
DROP FUNCTION IF EXISTS update_modified_at();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔴 schema.sql DROP TRIGGER runs before CREATE TABLE, failing on fresh databases

DROP TRIGGER IF EXISTS trigger_update_notes_modified_at ON notes at line 10 executes before CREATE TABLE IF NOT EXISTS notes at line 15. In PostgreSQL, IF EXISTS on DROP TRIGGER only suppresses errors when the trigger doesn't exist — the referenced table must still exist. On a fresh database, the notes table hasn't been created yet, so this statement fails with ERROR: relation "notes" does not exist. Per docker-compose.yml:54, this file is mounted as /docker-entrypoint-initdb.d/schema.sql, meaning it's specifically designed to run on fresh database initialization — the exact scenario where it breaks.

Prompt for agents
The DROP TRIGGER IF EXISTS and DROP FUNCTION IF EXISTS statements at lines 10-11 of schema.sql run before the CREATE TABLE IF NOT EXISTS at line 15. On a fresh database where the notes table does not yet exist, DROP TRIGGER IF EXISTS ... ON notes will fail because PostgreSQL requires the table to exist (IF EXISTS only applies to the trigger, not the table).

The fix is to move these DROP statements after the CREATE TABLE IF NOT EXISTS notes statement. That way, on a fresh DB the table is created first (no trigger exists so the DROPs are no-ops), and on an existing DB the table already exists so the DROPs safely remove the old trigger/function before the CREATE TABLE IF NOT EXISTS is a no-op.

Alternatively, wrap the DROP TRIGGER in a DO block that checks for table existence first, but simply reordering the statements is the simplest fix.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +128 to +132
# Migration: remove trigger that overwrites file mtime (existing databases)
await conn.execute(
"DROP TRIGGER IF EXISTS trigger_update_notes_modified_at ON notes"
)
await conn.execute("DROP FUNCTION IF EXISTS update_modified_at()")
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔴 initialize() runs DROP TRIGGER on potentially non-existent table

The migration code at lines 129-132 runs DROP TRIGGER IF EXISTS ... ON notes unconditionally, even when the table_exists check at src/vector_store.py:122-126 determined the notes table does not exist. PostgreSQL's IF EXISTS on DROP TRIGGER only suppresses errors for a missing trigger — the table itself must exist. When the table doesn't exist, this raises an asyncpg.PostgresError which is caught at line 136 and re-raised as VectorStoreError, causing initialize() to fail and preventing the server from starting on a fresh database.

Suggested change
# Migration: remove trigger that overwrites file mtime (existing databases)
await conn.execute(
"DROP TRIGGER IF EXISTS trigger_update_notes_modified_at ON notes"
)
await conn.execute("DROP FUNCTION IF EXISTS update_modified_at()")
# Migration: remove trigger that overwrites file mtime (existing databases)
if table_exists:
await conn.execute(
"DROP TRIGGER IF EXISTS trigger_update_notes_modified_at ON notes"
)
await conn.execute("DROP FUNCTION IF EXISTS update_modified_at()")
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@drewburchfield drewburchfield merged commit 1bff09a into master Apr 3, 2026
4 checks passed
@drewburchfield drewburchfield deleted the fix/code-correctness branch April 3, 2026 19:09
drewburchfield added a commit that referenced this pull request Apr 3, 2026
…ng table

- diagnose_vault.py: compute rel_path before try block to avoid NameError
  when file open/read fails (Devin PR #9)
- schema.sql: move DROP TRIGGER after CREATE TABLE so fresh databases
  don't fail on non-existent table (Devin PR #10)
- vector_store.py: guard DROP TRIGGER migration behind table_exists check
  to prevent initialize() failure on fresh databases (Devin PR #10)
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