fix(supabase): seeding closeout — bootstrap auth, kong migration, + 5 repaired migrations - #2216
Conversation
…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>
📝 WalkthroughWalkthroughAdds 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. ChangesSupabase migration and bootstrap updates
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
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
💡 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".
| 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"; }; \ |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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>
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (1)
.claude/hooks/damage-control/known_roads.py (1)
144-149: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDuplicate "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 allDOMAIN_PATTERNSpredicates 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
📒 Files selected for processing (7)
.claude/hooks/damage-control/known_roads.pypmoves/Makefilepmoves/supabase/migrations/2025-12-08_seed_work_items.sqlpmoves/supabase/migrations/20250204000000_channel_monitor_tables.sqlpmoves/supabase/migrations/20260420000000_rls_hardening.sqlpmoves/supabase/migrations/20260425000200_chit_phrases.sqlpmoves/supabase/migrations/20260702000000_semantic_cache.sql
| 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) |
There was a problem hiding this comment.
🔒 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.
| 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/...`.
| 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 |
There was a problem hiding this comment.
🗄️ 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.
| 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.
| 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); |
There was a problem hiding this comment.
🚀 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 || trueRepository: 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
doneRepository: 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:
- 1: https://www.postgresql.org/docs/18/sql-createindex.html
- 2: https://www.postgresql.org/docs/19/sql-createindex.html
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_hnswpmoves/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.
| CREATE UNIQUE INDEX IF NOT EXISTS idx_chit_phrases_canonical | ||
| ON pmoves_core.chit_phrases (phrase_canonical); |
There was a problem hiding this comment.
🗄️ 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 200Repository: 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
PYRepository: 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()}")
PYRepository: 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.
Complete Supabase seeding closeout. Supersedes #2212 (which carried a redundant already-merged commit).
Make-target fixes
${POSTGRES_USER:-pmoves}— shell-default syntax Make evaluates to empty (-U -dmisparse + peer-auth fail). Now runs as supabase_admin over TCP (container password), per-file error tolerance,pmoves_bootstrap_historytracking. Seeds pmoves DB 36→123 tables, 0→172 rows.KONG_PG_DATABASE=postgres+ stalekong:3.7.1, but compose runskong/kong:3.9.1on 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)
CREATE UNIQUE INDEX;jwt_claim_role()(undefined anywhere) →auth.role();DROP POLICY IF EXISTSbefore each CREATE;CREATE OR REPLACE TRIGGER.CREATE POLICY IF NOT EXISTS(invalid PG syntax) → DROP+CREATE ×15.integration_work_itemswas never created (docs claim this seed creates it; file only INSERTed) → addCREATE TABLE IF NOT EXISTS+ON CONFLICT.vector(2560)(>2000-dim limit) →::halfvec(2560); fixed no-op ON CONFLICT.vector(3072)→::halfvec(3072).🤖 Generated with Claude Code
Summary by CodeRabbit
Bug Fixes
Performance