Repository navigation
feat(api): add canon consistency and search - #28
Conversation
|
Implemented the three selected Web 5 cards in this PR:
Verification run locally:
The API suite reports one skipped test because TEST_DATABASE_ADMIN_URL is not configured for the live PostgreSQL concurrency test. |
318c648 to
6a4c642
Compare
|
Rebased onto latest origin/develop after resolving the app route registration conflict by keeping both profile and search routes. PR is now mergeable. Post-rebase verification:
|
|
Vercel preview is ready: https://hivelore-la8qo17xz-kareemn1936s-projects.vercel.app Commit: 86fda6a |
48d9b15 to
69b87d8
Compare
mcfarhat
left a comment
There was a problem hiding this comment.
Approving. Three cards' worth of work and it holds up — reviewed against the code and a real Postgres, not just read.
Search — the part I pushed hardest on
Raw SQL taking user input is where this could have gone badly, and it doesn't:
$queryRawtagged template, not$queryRawUnsafe, so${q}is a bound parameter — no injection surfacewebsearch_to_tsquery, which is the right choice overto_tsquery: it's the user-facing parser and won't throw on malformed input like a stray&or unbalanced quote- pagination bounded twice over — zod
max(50)at the route andMath.min(Math.max(...), MAX_PAGE_SIZE)in the lib, withqcapped at 120 chars. No route to an unboundedLIMIT.
The migration is the strongest piece. Maintaining the tsvector in a trigger rather than application code means no future write path can forget to update it, the setweight A/B correctly ranks title above content, existing rows are backfilled in the same migration, and the GIN index is there. That's how this should be done.
Consistency check
Deterministic, no LLM call — no key, no latency, no spend, and reproducible, which matters for something attached to canon voting.
Crucially it's a separate /ai-consistency endpoint; the vote path never calls it. So a false positive from a regex heuristic cannot block a vote at the API level — the UI asks for acknowledgement instead. That's the right shape for advisory tooling, and the decision I'd have argued for.
The greedy {2,80} capture makes the matcher low-recall rather than noisy: it'll miss contradictions more often than invent them. For a warning shown next to a vote, failing quiet is the correct direction.
One observation rather than a request: every finding is hardcoded severity: 'high'. If this ever gains a second category, that field will need to mean something.
Migration guard (R4) — approving on reasoning, and I want to be honest about why
Re-running migrate deploy on the base schema after migrate resolve --rolled-back is exactly the step I identified as missing, and it's a no-op when nothing failed, so it cannot regress anything.
But I could not demonstrate it catching a regression. I stood up a real Postgres and tried an A/B: inject a collision against ProposalComment (migration 16 of develop's 19) and compare the guard with and without the fix. Both runs failed identically — because the base chain applied all 19 migrations cleanly, so the resolve path was never entered and Re-running base branch… never printed in either run. The P3018 in my logs came from my own injected migration in the branch stage, not from the base chain.
So the failure mode the fix guards against doesn't reproduce in a clean environment today. Either develop's history has since been repaired, or my original diagnosis of the mechanism was wrong. I'm approving this change because it is correct and safe, not because I proved it works — and I'd rather say so than imply a verification I don't have.
Verified locally
proposal-consistency 2/2, search-index 4/4, and the full upgrade guard passes end-to-end against a real database. CI green on 69b87d8, the current head.
Summary
pm run search:reindex --workspace=@hivelore/api.
Trello
Verification
Note: the API test suite skips the live PostgreSQL concurrency test when TEST_DATABASE_ADMIN_URL is not configured.