Skip to content

QM-46: Drive Slack runtime reconciliation from one installation snapshot and change notifications - #1493

Merged
pcapriolo-yc merged 1 commit into
qm-29-port-factory-loopfrom
qm-46-s1477178087
Sep 21, 2026
Merged

pcapriolo-yc merged 1 commit into
qm-29-port-factory-loopfrom
qm-46-s1477178087

Conversation

@pcapriolo-yc

Copy link
Copy Markdown
Contributor

Closes QM-46.

Changes

Why this matters: Every core instance re-read the Slack installation row twice
every five seconds, even for organizations that have never connected Slack, because
the reconciler had to ask two separate questions to tell "no Slack configured" apart
from "Slack was removed". That is roughly 94 pointless SELECTs per second across the
fleet, and the two reads could also disagree with each other when an uninstall landed
between them. Polling was also the only way a second instance learned about a save, so
an admin's change was invisible elsewhere until the next tick.

What changes:

  • The Slack runtime reconciler no longer polls. It reads the installation once at
    startup and afterwards only when the installation actually changes, when its
    listener reconnects, or on a slow five-minute repair tick (five seconds while a
    reconcile is failing).
  • Saving, rotating, or removing Slack through PUT/DELETE /api/slack-installation
    now takes effect on every core instance in milliseconds instead of waiting for a
    poll. The GET/PUT/DELETE response bodies the admin console reads are unchanged.
  • One read now answers both "is this org managed" and "what is the installation", so
    unmanaged, disabled, and active can no longer disagree; an uninstall still beats
    SLACK_BOT_TOKEN/SLACK_APP_TOKEN from the environment.
  • No new setting or feature flag. With DATABASE_URL set, the change notification
    rides a Postgres slack_installation notify channel carrying only the record
    version and never token material; without it, an in-process bus keeps a
    single-process dev instance just as instant.

Acceptance stories:

  • As an idle core instance with no Slack configured, I used to re-read the
    installation row twice every five seconds; now I read it once at startup and again
    only on the five-minute repair tick.
  • As an org admin in the Connectors view, when I save, rotate, or remove Slack, the
    plugin on another core instance used to catch up on its next poll; now it picks up
    the change in milliseconds, and a rejected save still changes nothing.
  • As the core's Slack config loader, I used to combine two separate reads and could
    hand back environment tokens for an installation that had just been removed; now one
    snapshot decides, and a removed installation keeps the plugin off.
  • As the reconciler, a change arriving while I am already reconciling used to be
    dropped and covered by the next poll; now it coalesces into exactly one follow-up
    reconcile, with no two reconciles ever overlapping.
  • As a developer running the app without Postgres, I used to wait out a poll after
    saving tokens; now activation is immediate through the in-process bus.

Test Plan

  • npm run typecheck
  • npm run lint
  • npm run lint:ox
  • npm run lint:knip
  • npm run format:check
  • NODE_ENV=test ALLOW_UNSIGNED_TEST_IDENTITY=1 node --experimental-test-module-mocks --test test/slack-runtime.test.ts
  • NODE_ENV=test ALLOW_UNSIGNED_TEST_IDENTITY=1 node --experimental-test-module-mocks --test test/slack-installation-store.test.ts
  • NODE_ENV=test ALLOW_UNSIGNED_TEST_IDENTITY=1 node --experimental-test-module-mocks --test test/connector-byo-route.test.ts
  • NODE_ENV=test ALLOW_UNSIGNED_TEST_IDENTITY=1 node .io-agent-qm-46/proof/qm46-runtime-proof.ts

Manual check: none beyond the above. This is a backend-only change; no admin console
or other rendered surface was touched.

Proof it works

All five acceptance stories were exercised at runtime against the real store,
reconciler, notify buses, and /v1/admin/slack-installation handlers, with the
pre-fix modules run side by side over the same idle window as the "before" baseline.

  • qm46-runtime-proof.ts — .io-agent-qm-46/proof/
  • runtime-proof.out — .io-agent-qm-46/proof/
  • baseline-slack-installation.ts — .io-agent-qm-46/proof/
  • baseline-slack-runtime.ts — .io-agent-qm-46/proof/

@pcapriolo-yc
pcapriolo-yc merged commit d5b3c71 into qm-29-port-factory-loop Sep 21, 2026
16 checks passed
@pcapriolo-yc
pcapriolo-yc deleted the qm-46-s1477178087 branch September 21, 2026 21:46
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.

1 participant