Repository navigation
🚀 perf(claims): queue claim embeddings off the write path - #101
Conversation
Every manual claim write, including each Tasks checkbox tap, waited for a synchronous Jina embedding request after the claim had committed. The request had no timeout, and an embedding failure returned an error for a write that had already succeeded. Claim writes now enqueue an embed-claim batch job with the embedding text captured at write time. The job skips deleted, foreign, and already embedded claims, and an advisory lock keeps a stalled duplicate run from adding a second vector. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Seed 150 open and 300 done tasks with owners, due dates, status history, and presentation sources, then assert that the list, open, and candidate views each stay at two queries in workspace scope. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9405bf1e8b
ℹ️ 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".
| { | ||
| userId: claim.userId, | ||
| claimId: claim.id, | ||
| text: claimEmbeddingText(claim), |
There was a problem hiding this comment.
Remove claim text from retained queue payloads
If an embedding job exhausts its retries and its source is subsequently tombstoned, this payload leaves the original claim statement recoverable in Redis: EMBED_CLAIM_JOB_OPTIONS retains the last 100 failed jobs, while eraseSourceReadModels only deletes the sourced claim and related database projections. Store only the claim ID in the job and load the text while the claim still exists, or explicitly purge these jobs during source erasure.
Useful? React with 👍 / 👎.
What and why
Every Tasks write in Petals (check off, change a due date or owner, create) waited on a call to the Jina embedding API inside the request.
createClaimcalled Jina after the claim had already committed, with no timeout, so a slow or failing Jina made a saved write look slow or failed.Claim writes now queue an
embed-claimjob on the existing batch queue and return. The job writes the same embedding text as before, skips deleted, foreign and already-embedded claims, and takes an advisory lock so a retried job cannot write a second row.Where the time goes (measured locally)
Test database with 150 open tasks, 1,500 done tasks and 46k claims, workspace scope:
listCommitments(open, limit 200)getOpenCommitments/getCandidateCommitmentsgetCommitmentsetCommitmentStatussetCommitmentDue/setCommitmentOwnercreateCommitmentReads are healthy: the open-list query runs in about 6 ms plus 5 ms planning on
claims_trusted_open_task_status_idx. A new test pins the list, open and candidate reads at 2 queries each.Not measured: Jina's own latency in production (no production timings exist). The size of the speed-up for a checkbox tap in production is therefore unproven.
Trade-offs
Left out on purpose
preparePartitionWriteinside bothcreateClaimandensureSystemSource). That code is the security boundary, so it deserves its own review.getCommitmentqueries are redundant (about 2 ms locally).How to test
pnpm test --run src/lib/jobs/embed-claim.test.ts src/lib/query/commitment-read-queries.test.tsembed-claimjob writes oneclaim_embeddingsrow.Checks (run locally with placeholder env and a throwaway Redis)
pnpm run build:check: passpnpm lint: passpnpm run format: passpnpm test --run: pass (1046 tests)Context: this came out of the Petals Tasks overhaul, where Tasks now updates the screen before the server answers; this change makes the server side of each tap shorter too.
🤖 Generated with Claude Code