Repository navigation
feat: drive the credly badge poll from the badge state table - #5139
Conversation
A new badge is stored with the segment of its first sight and emits issued plus its state; a known badge emits a state activity only when the stored state differs, on the stored segment and with the stored earner; pending badges are stored silently. The poll no longer emits expired-badge, the daily expiry sync will. A shadow run neither reads nor writes the table. Refs linuxfoundation/lfx-cdp-insights-ops#873 Signed-off-by: Umberto Sgueglia <usgueglia@contractor.linuxfoundation.org>
PR SummaryMedium Risk Overview Expired-badge activities are removed from the poll (deferred to a follow-up expiry sync). The migration adds Reviewed by Cursor Bugbot for commit 9ce2ffa. Bugbot is set up for automated code reviews on this repo. Configure here. |
There was a problem hiding this comment.
🟡 Changes recommended
Invalid badge timestamps can reach the DAL bulk cast, aborting the target group and blocking watermark progress on retries because per-badge validation is incomplete.
1 open issue
What changed in this PR
Moves Credly badge polling onto the badge state table so CDP can suppress unchanged-state activities and preserve each badge’s original routing and recipient.
Changes:
- Reads and persists badge state, handles pending-to-active transitions, and deduplicates badges within each page.
- Stores template metadata for the planned expiry sync and removes expiry emission from the poll.
- Adds state-aware polling tests and dependency wiring while keeping shadow runs isolated from persistence.
| File | Description |
|---|---|
services/libs/data-access-layer/src/credly/badges.ts |
Adds badge lookup and persists template metadata. |
services/libs/data-access-layer/src/credly/badges.test.ts |
Tests badge lookup and stored metadata. |
services/libs/connectors/src/connectors/credly/syncs/badgePoll.ts |
Implements state-aware emission, locking, and persistence. |
services/libs/connectors/src/connectors/credly/syncs/badgePoll.test.ts |
Covers state transitions, original recipients, deduplication, and shadow runs. |
services/libs/connectors/src/connectors/credly/deps.ts |
Connects polling to badge-state database operations. |
services/libs/connectors/src/connectors/credly/deps.test.ts |
Verifies badge persistence dependency wiring. |
services/apps/connectors_worker/src/bin/dry-run-credly-badge-poll.ts |
Adds no-op badge-state dependencies for dry runs. |
backend/src/database/migrations/V1793181595__credly-badges-template.sql |
Adds template name and URL columns. |
Review effort: Balanced
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 600422d. Configure here.
Pending and unchanged badges no longer go through the mapper, so the row dates are parsed inside the per-badge guard: a malformed date skips that badge instead of failing the group save. Refs linuxfoundation/lfx-cdp-insights-ops#873 Signed-off-by: Umberto Sgueglia <usgueglia@contractor.linuxfoundation.org>


Refs linuxfoundation/lfx-cdp-insights-ops#873
What
Second PR for the badge state table: the poll reads and writes
integration."credlyBadges".pendingbadge is stored and emits nothing.lastSeenAtmoves (this is the Credly re-touch case:state_updated_atchanges, state does not). Different state → only the state activity, on the stored segment and with the stored earner email and name, never the routing of today. A storedpendingthat gets accepted emits issued plus accepted.expired-badgewill come from the daily expiry sync (next PR), which also picks up expiries already past.badgeTemplateNameandbadgeTemplateUrlon the table, so the expired-badge can be built months later without reading Credly.recipientEmailstored normalised.stateChanges,unchanged,pendingStored.Code review triage
Applied: issued-badge not lost for badges first seen pending; lock also for pending and stored rows; first-sight member on state activities; per-group save after emit; page deduplicated; comment trimmed.
Not applied: comparing
stateUpdatedAtas well (same state with a new timestamp is the re-touch to ignore; a full state cycle between two polls is accepted); keeping the immediate expired-badge in the poll (the expiry sync emits past expiries on its first run, emit is off in prod).Verification
159 Credly tests, DAL ones on the CI database. Staging after merge: run with emit on, then a second run on the same window must emit no state activity and count everything as
unchanged; the table must hold one row per emitted badge with the routing segment.No reviewer requested.