Skip to content

🚀 perf(claims): queue claim embeddings off the write path - #101

Merged
marcelsamyn merged 2 commits into
mainfrom
fix/claim-write-latency
Sep 24, 2026
Merged

marcelsamyn merged 2 commits into
mainfrom
fix/claim-write-latency

Conversation

@marcelsamyn

Copy link
Copy Markdown
Owner

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. createClaim called 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-claim job 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:

Call DB queries Jina calls before → after
listCommitments (open, limit 200) 2 0
getOpenCommitments / getCandidateCommitments 2 each 0
getCommitment 12 0
setCommitmentStatus 35 1 → 0
setCommitmentDue / setCommitmentOwner 38 / 33 1 → 0 each
createCommitment 91 3 → 1 (the task node embedding)

Reads 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

  • A new manual claim shows up in semantic claim search once the job runs. The batch worker runs one job at a time.
  • Claim writes now need Redis to enqueue. If Redis is down, the request waits on it. Status changes already depended on Redis.

Left out on purpose

  • About 12 of the ~35 write queries repeat partition checks (preparePartitionWrite inside both createClaim and ensureSystemSource). That code is the security boundary, so it deserves its own review.
  • 4 of the 12 getCommitment queries are redundant (about 2 ms locally).

How to test

  1. pnpm test --run src/lib/jobs/embed-claim.test.ts src/lib/query/commitment-read-queries.test.ts
  2. With a worker running, set a commitment's status and confirm the response returns without an embedding call, then that an embed-claim job writes one claim_embeddings row.

Checks (run locally with placeholder env and a throwaway Redis)

  • pnpm run build:check: pass
  • pnpm lint: pass
  • pnpm run format: pass
  • pnpm 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

marcelsamyn and others added 2 commits September 24, 2026 10:46
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>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 24, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-24T12:07:04.433996Z 9405bf1 PR opened
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@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: 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".

Comment thread src/lib/claim.ts
{
userId: claim.userId,
claimId: claim.id,
text: claimEmbeddingText(claim),

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 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 👍 / 👎.

@marcelsamyn
marcelsamyn merged commit c7e48a5 into main Sep 24, 2026
1 check passed
@marcelsamyn
marcelsamyn deleted the fix/claim-write-latency branch September 24, 2026 12:17
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