Skip to content

fix: complete the predicate event taxonomy across SDKs - #574

Merged
kartikeya-27 merged 7 commits into
ByteVeda:masterfrom
stromanni:fix/predicate-event-taxonomy
Jul 28, 2026
Merged

fix: complete the predicate event taxonomy across SDKs#574
kartikeya-27 merged 7 commits into
ByteVeda:masterfrom
stromanni:fix/predicate-event-taxonomy

Conversation

@stromanni

@stromanni stromanni commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Closes #570. Closes #571. Unblocks #535.

The decision

#570 asked to settle on one wire name for predicate.skipped vs predicate.cancelled. The premise doesn't hold — they denote different phases, not the same outcome:

Python Node Java
enqueue blocked, throws predicate.rejected predicate.rejected predicate.rejected
enqueue dropped, no throw predicate.skipped
enqueue delayed predicate.deferred predicate.deferred
dispatch-time job cancelled predicate.cancelled

A Cancel at enqueue in Python emits predicate.rejected and raises PredicateRejectedError (sdks/python/taskito/mixins/predicates.py:276); predicate.cancelled fires only at dispatch and carries job_id. Renaming either would have merged two distinct events and broken existing Node subscribers.

The actual defect

Each SDK's subscription API is typed on its own enum, so a wire name that SDK doesn't declare is unsubscribable there — Webhook.Builder.on(EventName...) in Java, WebhookInput.events: EventName[] in Node, add_webhook(events: list[EventType]) in Python. Java's subscribedTo swallows unknown stored tokens (sdks/java/.../webhooks/WebhookManager.java:288), so a subscription written by Node silently never matches.

Fixed by completing the contract to 29 names in all three SDKs, each marked emitted-here or reserved (the pattern Java already used for worker.unhealthy):

  • Java: PREDICATE_DEFERRED, PREDICATE_SKIPPED, PREDICATE_CANCELLED (all reserved — gates are pass/reject only)
  • Node: predicate.cancelled (reserved — no dispatch-time gates)
  • Python: PREDICATE_SKIPPED (reserved — enqueue Cancel rejects rather than skips)

Also corrects sdks/node/src/predicates/metrics.ts, which claimed Python uses "cancelled for skipped". Python counts by outcome sentinel, not decision kind, so its denied and cancelled both land on Node's rejected, and it has no enqueue-time skip.

Docs (#571)

The Node events page predated predicate.skipped/deferred landing in #543: it claimed 26 wire names, listed only predicate.rejected, and showed PredicateEvent without reason/delayMs. Java and Python pages document their reserved entries.

Verification

  • Node: 40 tests pass (webhooks, predicates, queue-events, webhookStoreContract)
  • Python: 45 tests pass; ruff and mypy clean
  • Java: compiles, spotlessCheck and checkstyleMain green

Java tests were not executed: :compileTestJava is disabled in the local environment (Skipping task ':compileTestJava' as task onlyIf 'Task is enabled' is false), reproducible on a clean master worktree, so it predates this branch. EventNameTest is updated to assert 29 and needs CI to confirm.

Summary by CodeRabbit

  • New Features

    • Expanded event support across SDKs to include predicate deferred, skipped, and cancelled lifecycle events.
    • Webhook subscriptions now recognize 29 event names, including predicate.cancelled.
    • Node.js predicate event payloads document optional rejection reasons and defer delays.
  • Documentation

    • Clarified predicate behavior, cross-SDK compatibility, filtering, and delivery-log details across Java, Node.js, and Python guides.

Java gates only at enqueue and only pass/reject, but a webhook row written
by another SDK filters on the wire name, and an unknown token silently
never matches. Declaring all four keeps such a subscription portable.
Reserved here: it means a dispatch-time predicate cancelled an already
enqueued job, which only Python produces. Declaring it lets a Python-authored
webhook subscription load and validate against this SDK.
Reserved here: a Cancel at enqueue raises PredicateRejectedError and emits
PREDICATE_REJECTED, so nothing drops an enqueue silently. Declaring it lets a
Node-authored webhook subscription round-trip.
Python counts by outcome sentinel, not decision kind, so the mapping was
wrong: its denied and cancelled both land on rejected here, and it has no
enqueue-time skip at all.
The page predated predicate.skipped/deferred landing: it claimed 26 wire
names, listed only predicate.rejected, and showed PredicateEvent without
reason or delayMs.
@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@stromanni, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 40 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f15a430e-8c93-473f-adee-6e7b9af33a19

📥 Commits

Reviewing files that changed from the base of the PR and between f036200 and 0d21e40.

📒 Files selected for processing (3)
  • docs/content/docs/java/guides/extensibility/events.mdx
  • docs/content/docs/node/guides/extensibility/webhooks.mdx
  • sdks/java/src/main/java/org/byteveda/taskito/events/EventName.java
📝 Walkthrough

Walkthrough

The PR aligns predicate event names and compatibility handling across Java, Node, and Python SDKs. It updates event mappings, tests, predicate payload documentation, webhook filtering descriptions, and cross-SDK lifecycle documentation.

Changes

Predicate event contract

Layer / File(s) Summary
SDK event taxonomy
sdks/java/..., sdks/node/..., sdks/python/...
Adds reserved predicate lifecycle names, maps predicate.cancelled to the Node payload type, updates enum documentation, and expands event-name tests.
Extensibility documentation and payload semantics
docs/content/docs/{java,node,python}/guides/extensibility/*
Documents 29 wire names, predicate lifecycle behavior, optional Node payload fields, webhook filtering, and delivery-log semantics.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Suggested reviewers: pratyush618

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the cross-SDK predicate event taxonomy update.
Linked Issues check ✅ Passed The PR covers the predicate taxonomy and Node docs/type updates required by [#570, #571], including reserved event names and payload fields.
Out of Scope Changes check ✅ Passed All edits stay within predicate events, webhook portability, docs, and tests; nothing unrelated was added.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 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 `@sdks/java/src/main/java/org/byteveda/taskito/events/EventName.java`:
- Around line 74-78: Update the shared predicate-event descriptions to preserve
dispatch-time semantics: in
sdks/java/src/main/java/org/byteveda/taskito/events/EventName.java lines 74-78,
make PREDICATE_DEFERRED phase-neutral or explicitly include dispatch-time
deferral; in docs/content/docs/java/guides/extensibility/events.mdx lines
140-146, replace “a deferred enqueue” with wording covering both enqueue- and
dispatch-time deferral; and in
docs/content/docs/node/guides/extensibility/webhooks.mdx line 76, limit the
missing-jobId statement to enqueue-time predicate events because dispatch-time
events may include jobId.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d60fe035-3ab0-45ab-9e1a-59c77412e113

📥 Commits

Reviewing files that changed from the base of the PR and between 9cad290 and f036200.

📒 Files selected for processing (12)
  • docs/content/docs/java/guides/extensibility/events.mdx
  • docs/content/docs/java/guides/extensibility/webhooks.mdx
  • docs/content/docs/node/guides/extensibility/events.mdx
  • docs/content/docs/node/guides/extensibility/webhooks.mdx
  • docs/content/docs/python/guides/extensibility/events.mdx
  • sdks/java/src/main/java/org/byteveda/taskito/events/EventName.java
  • sdks/java/src/test/java/org/byteveda/taskito/events/EventNameTest.java
  • sdks/node/src/events.ts
  • sdks/node/src/predicates/metrics.ts
  • sdks/node/test/core/webhooks.test.ts
  • sdks/python/taskito/events.py
  • sdks/python/tests/observability/test_events.py

Comment thread sdks/java/src/main/java/org/byteveda/taskito/events/EventName.java
Python emits it at dispatch as well as enqueue, carrying job_id, so a
contract-level description scoped to enqueue was wrong. The Node delivery-log
note now says why its predicate events have no jobId rather than claiming none
ever do.
@kartikeya-27
kartikeya-27 merged commit 1278d76 into ByteVeda:master Jul 28, 2026
29 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Node events docs stale after predicate events landed Predicate skip event has two wire names across SDKs

2 participants