Files
cgalo5758 a94ff08336 Add Discourse integration
Deliver forum posting entitlements through managed group membership with
identity linkage, periodic reconciliation, webhook handling, and an
operator mapping surface.

Include fake and live test environments, setup documentation,
migrations,
and end-to-end coverage.
2026-07-20 19:49:34 -07:00

4.3 KiB

discourse-group-sync Specification

Purpose

TBD - created by archiving change discourse-integration. Update Purpose after archive.

Requirements

Requirement: Desired state derives from provisions and org-membership union

Desired membership of a managed group SHALL be the set of linked persons holding an active membership in at least one organization currently conferred discourse_posting — computed as the OR-union across each person's organizations (both owned and member-of). Conferral SHALL be read from active pool provisions and the materialized boolean entitlement state; grants.status SHALL NOT be consulted for delivery.

Scenario: Person covered by two orgs loses one

  • WHEN a person belongs to two entitled organizations and one org's entitlement ends
  • THEN the person remains in desired membership because the other org still covers them

Scenario: Last covering org lapses

  • WHEN the only organization conferring discourse_posting for a person ceases to confer it
  • THEN the person leaves desired membership and is removed from the managed group at next convergence

Scenario: Grant superseded but provision active

  • WHEN an org's grant ledger contains superseded rows but an active provision confers the entitlement
  • THEN the org counts as conferring and its members stay in desired membership

Requirement: Periodic full-sweep convergence

A singleton Temporal-scheduled sweep SHALL periodically compute desired membership for every managed group, diff it against observed membership, and converge Discourse via group add/remove calls. The sweep alone SHALL be sufficient for eventual correctness: any missed webhook or event costs at most one sweep interval of staleness.

Scenario: Drift introduced while webhooks are disabled

  • WHEN managed-group membership is changed forum-side and no webhook is configured
  • THEN the next sweep detects the difference and restores desired membership

Scenario: Sweep after downtime

  • WHEN the console was down while entitlements and org memberships changed
  • THEN the first sweep after restart converges all managed groups to current desired state

Requirement: Idempotent convergence operations

Convergence SHALL treat Discourse's already-converged responses as success — in particular a 422 response to add_members when all requested users are already members — and SHALL be safe to repeat.

Scenario: Add of an existing member

  • WHEN convergence adds users to a group and Discourse responds 422 because all are already members
  • THEN the operation is recorded as success and the sweep continues

Requirement: Managed-group ownership boundary

The reconciler SHALL modify membership only of groups present in the operator-configured mapping. Forum-side membership changes to managed groups SHALL be corrected to desired state and logged with the observed discrepancy. Groups not in the mapping SHALL never be touched.

Scenario: Forum admin removes an entitled member from a managed group

  • WHEN a user_removed_from_group event (or sweep diff) shows an entitled linked person missing from a managed group
  • THEN the person is re-added and the correction is logged

Scenario: Unmanaged group untouched

  • WHEN convergence runs while unmanaged groups contain arbitrary membership
  • THEN no API call modifies any unmanaged group

Requirement: Targeted reconcile with per-person serialization

Webhook events on managed groups and link establishment SHALL trigger a targeted reconcile scoped to the affected person, executed under a deterministic per-person Temporal workflow identity so concurrent triggers for the same person serialize.

Scenario: Concurrent triggers for one person

  • WHEN a webhook event and a link establishment fire for the same person at nearly the same time
  • THEN their reconciles execute serially and the final group state matches desired state

Requirement: Observed-state projection

The integration SHALL cache last-observed membership of managed groups in its own schema as an observed projection, refreshed by sweeps and webhook events, with Discourse remaining canonical.

Scenario: Sweep refreshes projection

  • WHEN a sweep completes
  • THEN the stored observed membership for each managed group reflects what Discourse reported during that sweep