DL-281
Board issue ingestion is WEBHOOK-DRIVEN, not polled: the GitHub App webhook ingress (DL-264’s POST /webhooks/github) fans accepted issues events to a board ingest arm that normalizes the repo, gates on forge_repo_subscriptions (DL-162, kept), hydrates each coordinate via a conditional GET, and sinks through the one StripOwner→TranslateIssue→stamp pipeline into IssueProjection.PublishIssueUpdate; reliability + cold-start are a bounded per-repo updated-order reconcile sweep (startup + 30-min ticker, per-repo updated_at watermark advanced only after sink), the DL-264 backstop pattern at repo-LIST granularity. Retires the DL-161 standing poll driver + forge_list_cursors; amends DL-053’s “conditional polling in v1” transport clause (webhooks primary, conditional reads only inside the sweep) and DL-163’s four-table set (forge_list_cursors dropped by editing 0001_init.sql in place — Compass is pre-live, the init migration is edited directly; additive watermark + forge_updated_at recency-guard columns added the same way). The GitHub App is the ONLY GitHub read credential — the static read-path PAT is retired, completing the App-only cutover. Known pre-existing limit (poll had it identically): no transport removes a board row — a forge-deleted/transferred issue persists until manually removed
Status: Active (Matt, 2026-08-27)
Record: ../../server/compass-forge-board-webhook-ingestion/design.md#approach