Skip to content

fix: gate off-orglist purge on governance freshness, not sync state - #1750

Merged
TheLastCicada merged 1 commit into
v2-rc2from
fix/governance-readiness-freshness
Aug 13, 2026
Merged

fix: gate off-orglist purge on governance freshness, not sync state#1750
TheLastCicada merged 1 commit into
v2-rc2from
fix/governance-readiness-freshness

Conversation

@TheLastCicada

@TheLastCicada TheLastCicada commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Summary

Governance readiness was a boolean cleared at the start of every governance sync. sync-governance-body (producer) and sync-default-organizations (consumer) are separate jobs that share a default 120s interval and fire on the same scheduler tick, so the consumer read the cleared value for the entire cycle and the ONLY_CADT_SUBSCRIPTIONS off-orglist purge was skipped every time. On an affected node this leaves organizations that governance has dropped from the orgList subscribed and syncing indefinitely.

  • Readiness is now the timestamp of the last confirmed-good sync rather than a flag, so it never dips false merely because a refresh is underway. It expires after five sync intervals, clamped to between 10 and 60 minutes.
  • The clamp keeps its own floor of two sync intervals. Without it, a GOVERNANCE_SYNC_TASK_INTERVAL longer than the ceiling would expire readiness before the next scheduled sync could renew it, disabling reconciliation outright instead of pausing it.
  • A governance download carrying no orgList cannot vouch for the cached one, so it now revokes readiness instead of leaving the purge running against stale data until the window lapses.
  • The rationale for both invariants is documented in src/utils/governance-readiness.js, since the failure mode is timing-dependent and not visible from the call sites.

Reviewer note

ONLY_CADT_SUBSCRIPTIONS defaults to true, so this moves the off-orglist purge from "almost never runs" to "runs on every consumer tick following a good sync" on default-configured deployments. That is the intended fix, but it activates the unsubscribe-and-delete path broadly on upgrade and is worth an explicit ack rather than being treated as a routine bug fix.

Related tuning question: the 10-minute staleness window spans five reconcile cycles while the purge needs only three grace cycles, so a purge can complete after governance sync has begun failing. That follows from choosing 10 minutes as the tolerance; lowering the interval multiplier or raising the grace cycles would tighten it.

Test plan

  • npm run test:v1 — 155 passing, 5 pending (unchanged from base)
  • npm run test:v2 — 1756 passing (up 5 from the new tests), 0 failing
  • npx eslint clean on all changed files; the 5 dynamic-import errors in governance-sync-subscribe-first.spec.js pre-exist on the base branch and are not added to
  • New coverage: readiness expiry, window scaling with the configured interval, the ceiling's two-interval floor, readiness surviving an in-flight sync, and revocation on an orgList-less download
  • Each new test mutation-verified — reintroducing the clear-at-sync-start, weakening the interval multiplier, removing the ceiling floor, and removing the no-orgList revocation each produce a failure

Known gaps: the V1 no-orgList revocation branch is not reachable from the test runner because Governance captures USE_SIMULATOR at module import (a limitation already documented for V1 sync paths), so it is covered by the V2 equivalent plus code reading. The task-level call sites have no direct test; the regression guard sits at the model level.


Note

High Risk
Changes when the destructive off-orglist unsubscribe-and-delete path runs on default-config nodes (ONLY_CADT_SUBSCRIPTIONS defaults true), so upgrades can activate broad reconciliation; the logic is safety-critical for local org data.

Overview
Fixes ONLY_CADT_SUBSCRIPTIONS off-orglist purge being skipped on most scheduler ticks because governance readiness was cleared at the start of every governance sync while the purge task read that flag on the same interval.

Governance readiness is now a last-confirmed-good timestamp (not a boolean cleared on sync start). It stays true during an in-flight refresh and expires after five GOVERNANCE_SYNC_TASK_INTERVAL periods, clamped between 10 and 60 minutes, with a floor so long intervals do not expire before the next sync can renew. markGovernanceNotReady is only used when a download carries no orgList; sync tasks no longer clear readiness when a refresh begins.

The default-org reconcile tasks read isGovernanceReady once per run and log that purge waits until a recent sync confirms a fresh orgList. README documents the freshness window and ties it to GOVERNANCE_SYNC_TASK_INTERVAL. Tests cover expiry, window scaling, in-flight sync, and no-orgList revocation (V1/V2).

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

Governance readiness was a boolean cleared at the start of every
governance sync. The sync-governance-body and sync-default-organizations
jobs share a default 120s interval and fire on the same scheduler tick,
so the consumer read the cleared value for the whole cycle and the
ONLY_CADT_SUBSCRIPTIONS purge was skipped every time.

Track the timestamp of the last confirmed-good sync instead. Readiness
now expires after five sync intervals, clamped to between 10 and 60
minutes, and never dips false merely because a refresh is underway. The
clamp keeps its own floor of two intervals so a long configured interval
cannot expire readiness before the next sync could renew it, which would
disable reconciliation outright rather than pause it.

A download that carries no orgList cannot vouch for the cached one, so
it now revokes readiness rather than leaving the purge running against
stale data until the window lapses.
@TheLastCicada
TheLastCicada deployed to windows-code-signing August 12, 2026 21:53 — with GitHub Actions Active
@TheLastCicada
TheLastCicada merged commit d0e4819 into v2-rc2 Aug 13, 2026
40 of 51 checks passed
@TheLastCicada
TheLastCicada deleted the fix/governance-readiness-freshness branch August 13, 2026 02:37
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