Skip to content

fix(supabase): seeding closeout — bootstrap auth, kong migration, + 5 repaired migrations - #2216

Merged
POWERFULMOVES merged 4 commits into
mainfrom
fix/supabase-seeding-closeout
Jul 26, 2026
Merged

POWERFULMOVES merged 4 commits into
mainfrom
fix/supabase-seeding-closeout

Conversation

@POWERFULMOVES

@POWERFULMOVES POWERFULMOVES commented Jul 24, 2026 •

Copy link
Copy Markdown
Owner

Complete Supabase seeding closeout. Supersedes #2212 (which carried a redundant already-merged commit).

Make-target fixes

  • supabase-bootstrap: psql ran with ${POSTGRES_USER:-pmoves} — shell-default syntax Make evaluates to empty (-U -d misparse + peer-auth fail). Now runs as supabase_admin over TCP (container password), per-file error tolerance, pmoves_bootstrap_history tracking. Seeds pmoves DB 36→123 tables, 0→172 rows.
  • kong helper: hardcoded KONG_PG_DATABASE=postgres + stale kong:3.7.1, but compose runs kong/kong:3.9.1 on the pmoves DB → migrated the WRONG database → kong crash-looped. Now matches compose + 3.9.1 + bootstrap-then-up. (Kong 3.9.1 confirmed current vs Supabase's self-hosted compose.)

5 repaired migrations (never applied; validated against the live DB, idempotent)

  • channel_monitor_tables: expression in table-level UNIQUE → CREATE UNIQUE INDEX; jwt_claim_role() (undefined anywhere) → auth.role(); DROP POLICY IF EXISTS before each CREATE; CREATE OR REPLACE TRIGGER.
  • rls_hardening: CREATE POLICY IF NOT EXISTS (invalid PG syntax) → DROP+CREATE ×15.
  • seed_work_items: integration_work_items was never created (docs claim this seed creates it; file only INSERTed) → add CREATE TABLE IF NOT EXISTS + ON CONFLICT.
  • chit_phrases: HNSW on vector(2560) (>2000-dim limit) → ::halfvec(2560); fixed no-op ON CONFLICT.
  • semantic_cache: HNSW on vector(3072) → ::halfvec(3072).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Improved Supabase startup reliability with safer migration and seed processing.
    • Migration failures are now reported while allowing remaining setup tasks to continue.
    • Re-running setup avoids duplicate records and handles existing policies, tables, and indexes safely.
    • Corrected database access and security policy handling for application services.
    • Added user controls for deleting saved sources.
  • Performance

    • Updated vector-search indexes to use optimized half-precision configurations.
    • Improved canonical phrase matching and duplicate prevention.

POWERFULMOVES and others added 2 commits July 24, 2026 18:21
…e real DB

supabase-bootstrap psql calls used Make-eaten ${POSTGRES_USER:-pmoves} (empty ->
-U -d misparse + peer-auth fail). Now runs as supabase_admin over TCP with per-file
error tolerance + pmoves_bootstrap_history tracking. Seeds pmoves DB 36->123 tables,
0->172 rows. kong helper hardcoded db=postgres/kong:3.7.1 but compose runs kong 3.9.1
on the pmoves DB -> migrated wrong DB + crash-loop. Now matches compose + 3.9.1 +
bootstrap-then-up.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ainst live DB)

- channel_monitor_tables: expression in table-level UNIQUE -> CREATE UNIQUE INDEX;
  also jwt_claim_role() (undefined anywhere) -> auth.role(); DROP POLICY IF EXISTS
  before each CREATE POLICY; CREATE OR REPLACE TRIGGER (idempotent)
- rls_hardening: CREATE POLICY IF NOT EXISTS (invalid PG syntax) -> DROP+CREATE x15
- seed_work_items: integration_work_items was never created (docs claim this seed
  creates it, file only INSERTed) -> add CREATE TABLE IF NOT EXISTS + ON CONFLICT
- chit_phrases: HNSW on vector(2560) > 2000-dim limit -> ::halfvec(2560); fix no-op
  ON CONFLICT (add unique index on phrase_canonical)
- semantic_cache: HNSW on vector(3072) -> ::halfvec(3072)

Each applies exit 0 and is idempotent on re-run against the live pmoves DB.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 24, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds Known Roads support for migration SQL, improves Kong and Supabase bootstrap execution, makes selected migrations idempotent, hardens RLS policies, and updates HNSW vector indexes and seed conflict targets.

Changes

Supabase migration and bootstrap updates

Layer / File(s) Summary
Migration authorization and bootstrap flow
.claude/hooks/damage-control/known_roads.py, pmoves/Makefile
Adds the migrations Known Roads domain, updates Kong database and migration setup, and tracks migration/initdb application results through pmoves_bootstrap_history.
Work item schema and idempotent seeds
pmoves/supabase/migrations/2025-12-08_seed_work_items.sql
Creates public.integration_work_items when absent and makes integration seed inserts ignore duplicate (integration_name, title) pairs.
Policy, uniqueness, and trigger reconciliation
pmoves/supabase/migrations/20250204000000_channel_monitor_tables.sql, pmoves/supabase/migrations/20260420000000_rls_hardening.sql
Reworks uniqueness, RLS policy recreation, service-role checks, delete access, and timestamp trigger replacement.
Vector indexes and canonical seed idempotency
pmoves/supabase/migrations/20260425000200_chit_phrases.sql, pmoves/supabase/migrations/20260702000000_semantic_cache.sql
Updates HNSW indexes to use casted halfvec embeddings and aligns phrase seeding with canonical uniqueness.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant supabase_bootstrap
  participant admin_psql
  participant pmoves_bootstrap_history
  participant SQL_files
  supabase_bootstrap->>admin_psql: Apply migration or seed file
  admin_psql->>pmoves_bootstrap_history: Check application history
  pmoves_bootstrap_history-->>admin_psql: Return applied or pending
  admin_psql->>SQL_files: Execute pending SQL
  SQL_files-->>admin_psql: Return success or failure
  admin_psql->>pmoves_bootstrap_history: Record successful application
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description covers the summary but omits required Testing, Required Checks, Review Coordination, Follow-up Tasks, and Reviewer Notes sections. Add the missing template sections, especially testing commands/output, required checkboxes, review requests, follow-up tasks, and reviewer notes.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the main Supabase bootstrap and migration fixes.
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 fix/supabase-seeding-closeout

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 10e76bec05

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread pmoves/Makefile
Comment on lines +702 to +704
else fail=$$((fail+1)); echo " ⚠️ $$akind FAILED (skipped): $$name :: $$(grep -iE 'ERROR' /tmp/sb_apply.log | head -1 | cut -c1-100)"; fi; \
done; \
else \
echo " ⚠️ No initdb directory found"; \
fi
echo " $$akind: applied=$$ok skipped=$$skip failed=$$fail"; }; \

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Fail bootstrap after any migration or seed error

When a migration or seed fails, this branch only increments fail; apply_dir then returns the status of its final echo, and the recipe proceeds to print ✅ Supabase bootstrap complete. Because set -e was also removed, make -C pmoves supabase-bootstrap exits successfully even with missing schema objects, and later dependent files may be recorded as applied despite the earlier failure. Continue collecting per-file errors if desired, but exit nonzero after processing when any failure occurred.

Useful? React with 👍 / 👎.

CREATE INDEX IF NOT EXISTS idx_semantic_cache_embedding_hnsw
ON pmoves_cache.llm_semantic_cache
USING hnsw (query_embedding vector_cosine_ops)
USING hnsw ((query_embedding::halfvec(3072)) halfvec_cosine_ops)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Match semantic-cache queries to the halfvec index

When the semantic-cache table grows, this expression index will not accelerate search_semantic_cache: the index is keyed on query_embedding::halfvec(3072) with halfvec_cosine_ops, but the function's similarity predicate and ORDER BY on lines 80–87 still apply <=> to the original vector operands. PostgreSQL therefore cannot match the ordering to this HNSW index and falls back to scanning rows; cast both operands to halfvec(3072) in the search expressions so the repaired high-dimensional index is actually used.

Useful? React with 👍 / 👎.

Opens pmoves/**/supabase/{migrations,initdb}/*.sql to the Known-Road bypass so
broken/blocked migration SQL can be repaired under a provable, ledger-recorded
reason (pr:/issue:/handoff:) instead of the operator-copy workaround. Mirrors the
existing compose/schema/topic/dockerfile domains: scoped to *.sql under a
supabase/migrations|initdb segment in a PMOVES-owned tree; widens WHICH files can
be opened, not the bar to open them. Verified: predicate matches migration+initdb
SQL, rejects non-SQL and SQL elsewhere; guard still imports (no fail-closed).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added the governance AGNOTE register / agent definitions / damage-control hooks label Jul 24, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (1)
.claude/hooks/damage-control/known_roads.py (1)

144-149: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate "pmoves-owned tree" check across predicates.

This block is identical to the one in _is_dockerfile_target (lines 116-121). Consider extracting a shared _is_pmoves_owned(parts) helper reused by all DOMAIN_PATTERNS predicates to avoid drift if the "pmoves-owned" definition ever changes.

🤖 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 @.claude/hooks/damage-control/known_roads.py around lines 144 - 149, Extract
the repeated pmoves-owned component check from `_is_dockerfile_target` and the
shown predicate into a shared `_is_pmoves_owned(parts)` helper. Replace both
inline checks with calls to this helper while preserving the existing ownership
criteria and predicate behavior.
🤖 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 @.claude/hooks/damage-control/known_roads.py:
- Around line 144-154: Update the path predicate in the known-roads validation
logic to require adjacent `supabase/migrations` or `supabase/initdb` segments in
that order, rather than merely checking token presence anywhere in `parts`.
Preserve the existing pmoves-segment and `.sql` requirements while rejecting
paths such as `.../migrations/.../supabase/...`.

In `@pmoves/Makefile`:
- Around line 693-706: Update the apply_dir function so ok is incremented only
after the pmoves_bootstrap_history INSERT succeeds. Check the exit status of the
admin_psql history write; on failure, increment fail and report the filename as
failed instead of claiming it was applied, while preserving the existing success
path and idempotency behavior.

In `@pmoves/supabase/migrations/20260425000200_chit_phrases.sql`:
- Around line 21-22: Replace the IF NOT EXISTS behavior for the HNSW indexes in
pmoves/supabase/migrations/20260425000200_chit_phrases.sql lines 21-22 and
pmoves/supabase/migrations/20260702000000_semantic_cache.sql lines 41-43 with an
explicit replacement or schema-versioned naming strategy. Ensure future
definition changes rebuild or create a distinct index rather than silently
retaining a stale same-named index.
- Around line 25-26: Update the canonical uniqueness migration and corresponding
write path so phrase_canonical uniqueness is case-insensitive, matching the
lowercase lookup in insight_capture_hook.py. Prefer a unique
lower(phrase_canonical) expression index with an ON CONFLICT target using the
same expression, or normalize values before insertion; first detect and resolve
existing case-insensitive duplicates before applying the constraint.

---

Nitpick comments:
In @.claude/hooks/damage-control/known_roads.py:
- Around line 144-149: Extract the repeated pmoves-owned component check from
`_is_dockerfile_target` and the shown predicate into a shared
`_is_pmoves_owned(parts)` helper. Replace both inline checks with calls to this
helper while preserving the existing ownership criteria and predicate behavior.
🪄 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: a00eda82-53a2-4467-9644-fe714a56a46a

📥 Commits

Reviewing files that changed from the base of the PR and between f21e56b and 88dc8fe.

📒 Files selected for processing (7)
  • .claude/hooks/damage-control/known_roads.py
  • pmoves/Makefile
  • pmoves/supabase/migrations/2025-12-08_seed_work_items.sql
  • pmoves/supabase/migrations/20250204000000_channel_monitor_tables.sql
  • pmoves/supabase/migrations/20260420000000_rls_hardening.sql
  • pmoves/supabase/migrations/20260425000200_chit_phrases.sql
  • pmoves/supabase/migrations/20260702000000_semantic_cache.sql

Comment on lines +144 to +154
parts = normalized_fwd.lower().split("/")
if not any(
p == "pmoves" or p.startswith("pmoves-") or p.startswith("pmoves.")
for p in parts
):
return False

basename = os.path.basename(normalized_fwd).lower()
if not basename.endswith(".sql"):
return False
return "supabase" in parts and ("migrations" in parts or "initdb" in parts)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Path segments aren't required to be adjacent — predicate is looser than documented.

The docstring states the domain opens files "under a supabase/migrations or supabase/initdb segment," but "supabase" in parts and ("migrations" in parts or "initdb" in parts) only checks that both tokens appear somewhere in the path, in any order or position. A path such as pmoves/archive/migrations/old_configs/supabase/foo.sql would incorrectly satisfy this predicate even though it isn't under a supabase/migrations tree, widening the readOnly bypass surface for the migrations Known Road beyond its documented scope.

🔒️ Proposed fix to require adjacency
     basename = os.path.basename(normalized_fwd).lower()
     if not basename.endswith(".sql"):
         return False
-    return "supabase" in parts and ("migrations" in parts or "initdb" in parts)
+    for i in range(len(parts) - 1):
+        if parts[i] == "supabase" and parts[i + 1] in ("migrations", "initdb"):
+            return True
+    return False
📝 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.

Suggested change
parts = normalized_fwd.lower().split("/")
if not any(
p == "pmoves" or p.startswith("pmoves-") or p.startswith("pmoves.")
for p in parts
):
return False
basename = os.path.basename(normalized_fwd).lower()
if not basename.endswith(".sql"):
return False
return "supabase" in parts and ("migrations" in parts or "initdb" in parts)
parts = normalized_fwd.lower().split("/")
if not any(
p == "pmoves" or p.startswith("pmoves-") or p.startswith("pmoves.")
for p in parts
):
return False
basename = os.path.basename(normalized_fwd).lower()
if not basename.endswith(".sql"):
return False
for i in range(len(parts) - 1):
if parts[i] == "supabase" and parts[i + 1] in ("migrations", "initdb"):
return True
return False
🤖 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 @.claude/hooks/damage-control/known_roads.py around lines 144 - 154, Update
the path predicate in the known-roads validation logic to require adjacent
`supabase/migrations` or `supabase/initdb` segments in that order, rather than
merely checking token presence anywhere in `parts`. Preserve the existing
pmoves-segment and `.sql` requirements while rejecting paths such as
`.../migrations/.../supabase/...`.

Comment thread pmoves/Makefile
Comment on lines +693 to +706
apply_dir() { akind="$$1"; adir="$$2"; \
if [ ! -d "$$adir" ]; then echo " ⚠️ No $$adir directory found"; return 0; fi; \
ok=0; skip=0; fail=0; \
for f in $$(find "$$adir" -maxdepth 1 -type f -name '*.sql' | LC_ALL=C sort); do \
[ -f "$$f" ] || continue; \
name=$$(basename "$$f"); \
if [ "$$(admin_psql -tAc "SELECT 1 FROM public.pmoves_bootstrap_history WHERE kind='$$akind' AND filename='$$name' LIMIT 1;" | tr -d '[:space:]')" = "1" ]; then skip=$$((skip+1)); continue; fi; \
if admin_psql < "$$f" >/tmp/sb_apply.log 2>&1; then \
admin_psql -c "INSERT INTO public.pmoves_bootstrap_history(kind, filename) VALUES ('$$akind', '$$name') ON CONFLICT DO NOTHING;" >/dev/null; ok=$$((ok+1)); \
else fail=$$((fail+1)); echo " ⚠️ $$akind FAILED (skipped): $$name :: $$(grep -iE 'ERROR' /tmp/sb_apply.log | head -1 | cut -c1-100)"; fi; \
done; \
else \
echo " ⚠️ No initdb directory found"; \
fi
echo " $$akind: applied=$$ok skipped=$$skip failed=$$fail"; }; \
apply_dir migration supabase/migrations; \
apply_dir seed supabase/initdb

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

ok counter increments even if the history INSERT fails.

admin_psql -c "INSERT INTO public.pmoves_bootstrap_history(...) ON CONFLICT DO NOTHING;" >/dev/null; ok=$$((ok+1)); runs the counter increment unconditionally after the INSERT, regardless of its exit status. If the history write fails (e.g., a transient connection issue, or the CREATE TABLE IF NOT EXISTS public.pmoves_bootstrap_history at line 692 silently failing since set -uo pipefail no longer includes -e), the file is reported as applied but never recorded — the next supabase-bootstrap run will try to reapply it, undermining the idempotency this history table exists to provide.

🐛 Proposed fix to check the INSERT's exit status
 			if admin_psql < "$$f" >/tmp/sb_apply.log 2>&1; then \
-				admin_psql -c "INSERT INTO public.pmoves_bootstrap_history(kind, filename) VALUES ('$$akind', '$$name') ON CONFLICT DO NOTHING;" >/dev/null; ok=$$((ok+1)); \
+				if admin_psql -c "INSERT INTO public.pmoves_bootstrap_history(kind, filename) VALUES ('$$akind', '$$name') ON CONFLICT DO NOTHING;" >/dev/null 2>&1; then \
+					ok=$$((ok+1)); \
+				else \
+					fail=$$((fail+1)); echo "   ⚠️  $$akind applied but history record FAILED: $$name"; \
+				fi; \
 			else fail=$$((fail+1)); echo "   ⚠️  $$akind FAILED (skipped): $$name :: $$(grep -iE 'ERROR' /tmp/sb_apply.log | head -1 | cut -c1-100)"; fi; \
📝 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.

Suggested change
apply_dir() { akind="$$1"; adir="$$2"; \
if [ ! -d "$$adir" ]; then echo " ⚠️ No $$adir directory found"; return 0; fi; \
ok=0; skip=0; fail=0; \
for f in $$(find "$$adir" -maxdepth 1 -type f -name '*.sql' | LC_ALL=C sort); do \
[ -f "$$f" ] || continue; \
name=$$(basename "$$f"); \
if [ "$$(admin_psql -tAc "SELECT 1 FROM public.pmoves_bootstrap_history WHERE kind='$$akind' AND filename='$$name' LIMIT 1;" | tr -d '[:space:]')" = "1" ]; then skip=$$((skip+1)); continue; fi; \
if admin_psql < "$$f" >/tmp/sb_apply.log 2>&1; then \
admin_psql -c "INSERT INTO public.pmoves_bootstrap_history(kind, filename) VALUES ('$$akind', '$$name') ON CONFLICT DO NOTHING;" >/dev/null; ok=$$((ok+1)); \
else fail=$$((fail+1)); echo " ⚠️ $$akind FAILED (skipped): $$name :: $$(grep -iE 'ERROR' /tmp/sb_apply.log | head -1 | cut -c1-100)"; fi; \
done; \
else \
echo " ⚠️ No initdb directory found"; \
fi
echo " $$akind: applied=$$ok skipped=$$skip failed=$$fail"; }; \
apply_dir migration supabase/migrations; \
apply_dir seed supabase/initdb
apply_dir() { akind="$$1"; adir="$$2"; \
if [ ! -d "$$adir" ]; then echo " ⚠️ No $$adir directory found"; return 0; fi; \
ok=0; skip=0; fail=0; \
for f in $$(find "$$adir" -maxdepth 1 -type f -name '*.sql' | LC_ALL=C sort); do \
[ -f "$$f" ] || continue; \
name=$$(basename "$$f"); \
if [ "$$(admin_psql -tAc "SELECT 1 FROM public.pmoves_bootstrap_history WHERE kind='$$akind' AND filename='$$name' LIMIT 1;" | tr -d '[:space:]')" = "1" ]; then skip=$$((skip+1)); continue; fi; \
if admin_psql < "$$f" >/tmp/sb_apply.log 2>&1; then \
if admin_psql -c "INSERT INTO public.pmoves_bootstrap_history(kind, filename) VALUES ('$$akind', '$$name') ON CONFLICT DO NOTHING;" >/dev/null 2>&1; then \
ok=$$((ok+1)); \
else \
fail=$$((fail+1)); echo " ⚠️ $$akind applied but history record FAILED: $$name"; \
fi; \
else fail=$$((fail+1)); echo " ⚠️ $$akind FAILED (skipped): $$name :: $$(grep -iE 'ERROR' /tmp/sb_apply.log | head -1 | cut -c1-100)"; fi; \
done; \
echo " $$akind: applied=$$ok skipped=$$skip failed=$$fail"; }; \
apply_dir migration supabase/migrations; \
apply_dir seed supabase/initdb
🤖 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 `@pmoves/Makefile` around lines 693 - 706, Update the apply_dir function so ok
is incremented only after the pmoves_bootstrap_history INSERT succeeds. Check
the exit status of the admin_psql history write; on failure, increment fail and
report the filename as failed instead of claiming it was applied, while
preserving the existing success path and idempotency behavior.

Comment on lines 21 to +22
CREATE INDEX IF NOT EXISTS idx_chit_phrases_embedding_hnsw
ON pmoves_core.chit_phrases USING hnsw (embedding vector_cosine_ops);
ON pmoves_core.chit_phrases USING hnsw ((embedding::halfvec(2560)) halfvec_cosine_ops);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🚀 Performance & Scalability | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== migration snippets =="
for f in \
  pmoves/supabase/migrations/20260425000200_chit_phrases.sql \
  pmoves/supabase/migrations/20260702000000_semantic_cache.sql
do
  if [ -f "$f" ]; then
    echo "--- $f ---"
    nl -ba "$f" | sed -n '1,80p'
  fi
done

echo "== matching migration files / index names =="
rg -n "CREATE [A-Za-z0-9_ ]+INDEX|idx_chit_phrases_embedding_hnsw|idx_semantic_cache_embedding_hnsw|llm_semantic_cache|chit_phrasesembedding" pmoves -g '*.sql' || true

echo "== docs availability =="
for f in \
  pmoves/docs/PMOVES.AI PLANS/ROADMAP.md \
  pmoves/docs/NEXT_STEPS.md \
  pmoves/docs/LOCAL_CI_CHECKS.md
do
  if [ -f "$f" ]; then
    echo "--- exists: $f ---"
  else
    echo "--- missing: $f ---"
  fi
done

echo "== schema/migration context around related tables =="
rg -n "chit_phrases|llm_semantic_cache|query|embedding|halfvec" pmoves/supabase -g '*.sql' | head -n 120 || true

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 294


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== postgres availability =="
if command -v psql >/dev/null 2>&1; then psql --version; else echo "psql unavailable"; fi
if command -v pg_config >/dev/null 2>&1; then pg_config --version; else echo "pg_config unavailable"; fi

echo "== migration snippets =="
python3 - <<'PY'
from pathlib import Path
for p in [
    Path("pmoves/supabase/migrations/20260425000200_chit_phrases.sql"),
    Path("pmoves/supabase/migrations/20260702000000_semantic_cache.sql"),
]:
    print(f'--- {p} ---')
    if p.exists():
        lines = p.read_text().splitlines()
        for i in range(min(len(lines), 80)):
            print(f'{i+1}: {lines[i]}')
    else:
        print("MISSING")

    print()
PY

echo "== matching migration files / index names =="
python3 - <<'PY'
from pathlib import Path
import re
for p in Path("pmoves").rglob("*.sql"):
    s = p.read_text(errors="ignore")
    if re.search(r"(idx_chit_phrases_embedding_hnsw|idx_semantic_cache_embedding_hnsw|llm_semantic_cache|chit_phrases)", s):
        print(f'--- {p} ---')
        for i, line in enumerate(s.splitlines(), 1):
            if re.search(r"(idx_chit_phrases_embedding_hnsw|idx_semantic_cache_embedding_hnsw|llm_semantic_cache|chit_phrases|CREATE .*INDEX|CREATE INDEX|halfvec_cosine_ops)", line):
                print(f'{i}: {line}')
PY

echo "== relevant docs availability =="
for f in \
  "pmoves/docs/PMOVES.AI PLANS/ROADMAP.md" \
  "pmoves/docs/NEXT_STEPS.md" \
  "pmoves/docs/LOCAL_CI_CHECKS.md"
do
  if [ -f "$f" ]; then echo "exists: $f"; else echo "missing: $f"; fi
done

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 9188


🌐 Web query:

PostgreSQL CREATE INDEX IF NOT EXISTS behavior existing index definition ignored documentation

💡 Result:

According to official PostgreSQL documentation, the IF NOT EXISTS clause in the CREATE INDEX command prevents an error from being thrown if an index with the specified name already exists [1][2]. When this clause is used and a matching index name is found, PostgreSQL simply issues a notice and skips the command [1][2]. Crucially, the database does not perform any validation to ensure the existing index matches the definition provided in your statement; there is no guarantee that the existing index is anything like the one you intended to create [1][2]. Consequently, if an index with that name already exists, your specified index definition is effectively ignored in its entirety [1][2].

Citations:


Replace or version these HNSW indexes instead of using CREATE INDEX IF NOT EXISTS.

CREATE INDEX IF NOT EXISTS only skips an existing same-named index without validating or replacing its definition, so future schema changes can leave stale indexes behind:

  • pmoves/supabase/migrations/20260425000200_chit_phrases.sql#L21-L22: idx_chit_phrases_embedding_hnsw
  • pmoves/supabase/migrations/20260702000000_semantic_cache.sql#L41-L43: idx_semantic_cache_embedding_hnsw

Use an explicit replace path, name it with a schema version, or add a migration that rebuilds the index when the definition changes.

📍 Affects 2 files
  • pmoves/supabase/migrations/20260425000200_chit_phrases.sql#L21-L22 (this comment)
  • pmoves/supabase/migrations/20260702000000_semantic_cache.sql#L41-L43
🤖 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 `@pmoves/supabase/migrations/20260425000200_chit_phrases.sql` around lines 21 -
22, Replace the IF NOT EXISTS behavior for the HNSW indexes in
pmoves/supabase/migrations/20260425000200_chit_phrases.sql lines 21-22 and
pmoves/supabase/migrations/20260702000000_semantic_cache.sql lines 41-43 with an
explicit replacement or schema-versioned naming strategy. Ensure future
definition changes rebuild or create a distinct index rather than silently
retaining a stale same-named index.

Comment on lines +25 to +26
CREATE UNIQUE INDEX IF NOT EXISTS idx_chit_phrases_canonical
ON pmoves_core.chit_phrases (phrase_canonical);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== docs files availability =="
for f in pmoves/docs/PMOVES.AI PLANS/ROADMAP.md pmoves/docs/NEXT_STEPS.md pmoves/docs/LOCAL_CI_CHECKS.md STARTER_PR_BODY.md; do
  if [ -f "$f" ]; then echo "$f: exists"; else echo "$f: MISSING"; fi
done

echo
echo "== target migration relevant lines =="
sed -n '1,120p' pmoves/supabase/migrations/20260425000200_chit_phrases.sql 2>/dev/null || true

echo
echo "== locate hook and phrase-related consumers/inserts =="
rg -n "phrase_canonical|chit_phrases|insight_capture_hook|LOWER|lower\\(" pmoves -S --glob '!**/.git/**' | head -n 200

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 26916


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== exact hook file =="
fd -a 'insight_capture_hook\.py$' . || true

echo
echo "== chit_phrases and phrase_canonical hits in Python files =="
python3 - <<'PY'
from pathlib import Path
for p in sorted(Path('.').rglob('*.py')):
    s = str(p)
    if s.startswith('./.'):
        continue
    try:
        text = p.read_text(errors='ignore')
    except Exception:
        continue
    if 'phrase_canonical' in text or 'chit_phrases' in text:
        lines = text.splitlines()
        matches = [(i+1, line) for i, line in enumerate(lines) if 'phrase_canonical' in line or 'chit_phrases' in line]
        print(f'--- {p} ({len(matches)} matches) ---')
        for line_no, line in matches:
            print(f'{line_no}: {line.strip()}')
PY

echo
echo "== deterministic behavior probe for SQL unique index on canonical and lower lookup model =="
python3 - <<'PY'
rows = [
    {"phrase_canonical": "Hello", "category": "greeting"},
    {"phrase_canonical": "hello", "category": "farewell"},
]
def raw_lookup_canonical(rows, key):
    return next((r for r in rows if r["phrase_canonical"] == key), None)
def case_normalized_lookup(rows, key):
    target = key.lower()
    canonical_rows = [r for r in rows if r["phrase_canonical"].lower() == target]
    for r in canonical_rows:
        if r["phrase_canonical"] == key:
            return r
    return canonical_rows[-1] if canonical_rows else None

inserted_rows = rows.copy()
for key in ("Hello", "hello"):
    lookup_key = key.lower()
    print(key)
    print("  insertable under raw unique index:", raw_lookup_canonical(inserted_rows, key) is None)
    print("  consumer lookup result for", lookup_key, ":", case_normalized_lookup(inserted_rows, lookup_key)["category"])
try:
    raw_lookup_canonical(inserted_rows, "hello")
except KeyError:
    pass
PY

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 1011


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== insight_capture_hook.py relevant section =="
sed -n '1,120p' pmoves/scripts/insight_capture_hook.py

echo
echo "== write-time normalization and upsert/conflict insertions in insight_capture_hook =="
python3 - <<'PY'
from pathlib import Path
p = Path("pmoves/scripts/insight_capture_hook.py")
text = p.read_text()
for needle in ["phrase_canonical =", "phrase_canonical.lower()(", "expr.insert", "insert", "ON CONFLICT", "chit_phrases"]:
    print(f"--- {needle!r} ---")
    for i, line in enumerate(text.splitlines(), 1):
        if needle in line:
            print(f"{i}: {line.strip()}")
PY

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 4612


Enforce case-normalized canonical uniqueness.

pmoves/scripts/insight_capture_hook.py lowercases phrase_canonical when building its lookup, so the raw-text unique index allows both Hello and hello and the last matching row wins when [[Hello]] is anchored. Make writes normalize phrase_canonical before insert, or use a unique lower(phrase_canonical) expression index and matching ON CONFLICT (lower(phrase_canonical)) target; verify existing duplicates before applying the constraint.

🤖 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 `@pmoves/supabase/migrations/20260425000200_chit_phrases.sql` around lines 25 -
26, Update the canonical uniqueness migration and corresponding write path so
phrase_canonical uniqueness is case-insensitive, matching the lowercase lookup
in insight_capture_hook.py. Prefer a unique lower(phrase_canonical) expression
index with an ON CONFLICT target using the same expression, or normalize values
before insertion; first detect and resolve existing case-insensitive duplicates
before applying the constraint.

@POWERFULMOVES
POWERFULMOVES merged commit 89f3a9b into main Jul 26, 2026
32 checks passed
@POWERFULMOVES
POWERFULMOVES deleted the fix/supabase-seeding-closeout branch July 26, 2026 00:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

governance AGNOTE register / agent definitions / damage-control hooks

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant