Skip to content

feat: re-read the history of a credly template released from hold - #5167

Merged
ulemons merged 4 commits into
mainfrom
feat/issue-940-credly-release-walk
Nov 2, 2026
Merged

ulemons merged 4 commits into
mainfrom
feat/issue-940-credly-release-walk

Conversation

@ulemons

@ulemons ulemons commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Why

A template released from hold (or from excluded) has a history of badges that the live poll never saw: nothing emitted while it was held. Without this, LFC131 and the event badges would only ever get their new badges once mapped.

Refs linuxfoundation/lfx-cdp-insights-ops#940. Stacked on #5166 (queue table, DAL, template filter).

What

Resolve script

  • applyDecisions queues a release for every template whose decision reaches mapped:* without being mapped before (held:*, excluded, or a template new to the mapping table), inside the same transaction as the decision row. A run that dies in between leaves the template held, and the next run decides it again. A template Credly creates after go-live has badges held between its birth and the resolve that maps it: its release covers that gap from created_at.
  • Release floor = the template's created_at from Credly, never earlier than CREDLY_HISTORY_START (2019-03-01) and never later than the top.
  • --release <badge template id> queues one by hand (full history, no Credly/Snowflake round trip). It refuses a template that is not mapped to a live integration, since the poll would complete such a release without reading anything.
  • The apply log carries releasesQueued.

badgePoll

  • After the live window is caught up, and before the global backfill, the poll takes the next pending release and walks that template alone in 7-day state_updated_at windows with filter[badge_template_id], newest first, cursor saved on the release row after every page.
  • Same page cap as the rest of the run; complete: false while a release is pending.
  • A cursor save that touches 0 rows means the release was re-queued under our feet: the walker drops the stale bounds and reads the queue again.
  • A release queued while a run is in progress is newer than the routing loaded at the run start: an unknown template triggers one fresh routing read from the database before the release is skipped. Unmapped or unreadable releases are completed with a warning instead of blocking the queue and the backfill.
  • A window that Credly keeps failing is halved and both halves are walked, as in the global backfill.
  • A shadow run (emitEnabled: false) never touches the queue.

Listing carries created_at for the floor.

Tests

  • releasesToQueue: held→mapped, excluded→mapped with clamped floor, new→mapped from creation date, fallback to history start.
  • runBadgePoll releases: template filter walk, halved window, routing reloaded for a release queued mid-run, unmapped completed, page cap mid-release, release before global backfill, stale walk dropped, unreadable bounds, shadow run untouched.
  • createCredlyDeps: routing memoised per instance, re-read on request.
  • 452 tests green, pnpm tsc-check and pnpm lint --deny-warnings clean.

Rollout

  1. Merge feat: add the credly template release queue and the badge template filter #5166 and run the migration in staging/prod.
  2. Deploy this.
  3. Staging: pnpm script:resolve-credly-templates --release 067f5afd-160d-42df-961e-31d19e117173 (CKAD on umbertoTest5.1), watch credly_badge_poll_run for releasePages / releases.
  4. Prod: nothing to run; the next resolve apply queues the releases of the templates Joana releases.

🤖 Generated with Claude Code

@ulemons ulemons self-assigned this Nov 2, 2026
Copilot AI balanced review requested due to automatic review settings November 2, 2026 13:23
@cursor

cursor Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

PR Summary

Medium Risk
Changes Credly sync ordering and emits historical badge activities for newly mapped templates; transactional queueing limits partial-state risk, but incorrect release bounds or routing could emit or skip large badge volumes.

Overview
When a Credly badge template is newly mapped (from hold, excluded, or first-time mapping), the resolve flow now queues a history release in the same DB transaction as the mapping decision, with a time floor from the template's created_at (clamped to CREDLY_HISTORY_START). --release <template id> on resolve-credly-templates queues a full-history release manually for an already-mapped template.

runBadgePoll processes pending releases after the live window is caught up and before global backfill: it pages Credly with filter[badge_template_id] in 7-day windows, persists progress on the release row, completes or skips bad/unmapped entries, reloads routing when a mid-run mapping appears, and treats complete: false while a release is still pending. Shadow runs ignore the queue. CredlyDeps gains release queue helpers and optional fresh template routing reload; template listing includes created_at for release floors.

Reviewed by Cursor Bugbot for commit 968eca3. Bugbot is set up for automated code reviews on this repo. Configure here.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Critical release-handling bugs can stall release and global backfill by repeatedly processing the lower half of a window and permanently skip history when cached routing lacks a newly mapped target.

2 open issues
What changed in this PR

Adds historical badge ingestion for Credly templates released from held or excluded states, building on the release queue introduced in #5166.

Changes:

  • Queues history releases alongside mapping updates and adds a manual --release option.
  • Processes template-specific history before global backfill, with saved cursors and shadow-run protection.
  • Carries template creation dates into release bounds and adds release-planning and polling tests.
File Description
services/​libs/​connectors/​src/​connectors/​credly/​syncs/​badgePoll.ts Adds release-queue processing and progress counters.
services/​libs/​connectors/​src/​connectors/​credly/​syncs/​badgePoll.test.ts Tests release traversal, queue handling, and shadow runs.
services/​libs/​connectors/​src/​connectors/​credly/​mapping/​resolver.ts Adds optional template creation dates.
services/​libs/​connectors/​src/​connectors/​credly/​deps.ts Exposes release-queue database operations.
services/​libs/​connectors/​src/​connectors/​credly/​apiClient.ts Accepts creation timestamps in template listings.
services/​apps/​connectors_worker/​src/​credlyTemplateResolve.ts Calculates release bounds and queues releases transactionally.
services/​apps/​connectors_worker/​src/​credlyTemplateResolve.test.ts Tests release eligibility and date bounds.
services/​apps/​connectors_worker/​src/​bin/​resolve-credly-templates.ts Wires automatic queueing and manual release requests.
services/​apps/​connectors_worker/​src/​bin/​dry-run-credly-badge-poll.ts Supplies no-op release dependencies for dry runs.

Review effort: Balanced

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

Stale Bugbot comment from a previous run.

Base automatically changed from feat/issue-940-credly-release-foundations to main November 2, 2026 13:31
Refs linuxfoundation/lfx-cdp-insights-ops#940

Signed-off-by: Umberto Sgueglia <usgueglia@contractor.linuxfoundation.org>
@ulemons
ulemons force-pushed the feat/issue-940-credly-release-walk branch from ef596e6 to 4681f52 Compare November 2, 2026 13:35
…uting for a new release

Refs linuxfoundation/lfx-cdp-insights-ops#940

Signed-off-by: Umberto Sgueglia <usgueglia@contractor.linuxfoundation.org>
Copilot AI balanced review requested due to automatic review settings November 2, 2026 13:44

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ 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 eb05816. Configure here.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The routing reload reuses a cached snapshot, so newly mapped templates can be skipped and their history jobs permanently completed without fetching badges; a cache-bypassing refresh and real-deps regression coverage are needed.

2 open issues
1 resolved since last review

Review effort: Balanced

…n and release new templates too

Refs linuxfoundation/lfx-cdp-insights-ops#940

Signed-off-by: Umberto Sgueglia <usgueglia@contractor.linuxfoundation.org>
Copilot AI balanced review requested due to automatic review settings November 2, 2026 14:28

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Unresolved critical issues in release timing, status checks, reactivation handling, and routing can leave badge history unrecovered or send badges to the wrong segment.

No open issues 🎉

5 previously missed issues

In code that hasn't changed since last review

High severity Queue a release when reactivating a deactivated mapping

services/​apps/​connectors_worker/​src/​credlyTemplateResolve.ts:212

This excludes reactivated mappings because their before label still starts with mapped:, even though buildPlan marks them as changed. The live poll held their badges while deactivatedAt was set, but applying the decision clears that field without queuing the missed history. Preserve the prior activation state and queue a release when a deactivated mapping becomes active again.

High severity Determine release eligibility from the locked template status

services/​apps/​connectors_worker/​src/​credlyTemplateResolve.ts:254

Release eligibility comes from the earlier plan snapshot rather than the row locked by the upsert. If another resolve changes an unlocked template from mapped to held after that snapshot, this apply maps it again without queuing a release, leaving the held-period history unrecovered. Determine the previous status under the upsert's lock and queue the release in that same transaction.

High severity Refresh release top after upserting the template decision

services/​apps/​connectors_worker/​src/​credlyTemplateResolve.ts:254

Release tops are calculated before the sequential apply loop. If earlier decisions or database locks delay a template beyond the five-minute poll lag, a live poll can pass over badges newer than that top while the template is still held, leaving them outside both the release and future live windows. Refresh the top after upserting this template's decision, inside the same transaction.

High severity Refresh routing for known templates on each release generation

services/​libs/​connectors/​src/​connectors/​credly/​syncs/​badgePoll.ts:512

An unlocked template can be remapped and manually re-queued during the live walk, but this check retains its cached old target because the template ID is already present. The release then emits and stores previously unseen badges on the old segment and completes; a failed mapping lock only logs a warning. Refresh routing once per release generation, including for known template IDs.

Medium severity Recheck pending releases before completing the backfill

services/​libs/​connectors/​src/​connectors/​credly/​syncs/​badgePoll.ts:606

A release queued during the global backfill is absent from releasePending, so finishing that backfill can return complete: true with a release still waiting. This schedules the next poll at the 720-minute cadence instead of the short retry. Recheck the queue before returning, while preserving the shadow-run guard.

2 resolved since last review

Review effort: Balanced

The release walk's skip path (unmapped template, unreadable bounds) only
advanced counters.pagesFetched when it actually fetched a page from Credly,
so a run with several releases queued for templates that later became
unmapped or excluded could spin through completeRelease/nextRelease pairs
bounded only by the wall-clock run budget, never reaching the live or
backfill loops.

Refs linuxfoundation/lfx-cdp-insights-ops#940

Signed-off-by: Umberto Sgueglia <usgueglia@contractor.linuxfoundation.org>
Copilot AI balanced review requested due to automatic review settings November 2, 2026 16:06

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Human assessment is needed because concurrency and release-window risks could leave skipped badges unreplayed, while the transaction guarantees lack direct test coverage.

No open issues 🎉

Review effort: Balanced

@ulemons
ulemons merged commit 0bf4992 into main Nov 2, 2026
15 checks passed
@ulemons
ulemons deleted the feat/issue-940-credly-release-walk branch November 2, 2026 17:06
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.

2 participants