SIGN IN SIGN UP

Announce a public API change in the SDK API feed once per PR (#3991)

- The feed announced the same summary on every CI run of a PR touching a
signature file. Now it announces once per distinct summary.
- Dedup compares against the channel's newest message about this PR, so
a PR that reverts to a surface it announced earlier is announced again.
- When the channel says nothing , a `<!-- api-diff:<hash> -->` marker on
the PR comment decides. It is written only after the post succeeds, so a
Slack outage cannot silence the next run.
- Needs `channels:history` on the bot token and the channel ID, not
`#name`, in `SLACK_CHANNEL_SDK_NEW_API`. Without either, dedup still
works across pushes through the marker and the PR gets a warning naming
the reason.

- Companion change on `purchases-ios`:
https://github.com/RevenueCat/purchases-ios/pull/7431

### Checklist
- [x] If applicable, unit tests
- [ ] If applicable, create follow-up issues for `purchases-ios` and
hybrids

<details><summary>Agent description</summary>

### Motivation

`#3976` shipped the announcement without the dedup: `run` posted
whenever the diff against the PR base was non-empty, which is every run
of a PR that already changed the API surface. `#3884` was announced
three times with byte-identical content, twice within seven seconds.

Those seven seconds are a second cause. Each push creates two pipelines
(26535 and 26537, 26496 and 26498, and so on): `build-test-deploy` on
the older one is auto-canceled, but `danger` finishes in ~25s and posts
first. That rules out the PR comment as the only store, since Danger
writes it at the end of the run and two concurrent runs would both read
the previous push's state.

### Description

- `announcement_state` returns `:same` / `:different` / `:unknown`.
Identity is the PR link plus the platform label, both already in the
message; modules are excluded because they change with what the PR
touches.
- `:unknown` is the only state that consults the comment marker, so both
stores answer one question: what was announced last.
- `announce` returns `[:posted | :duplicate | :failed, reason]`, and the
marker is recorded for the first two only.
- The comment lookup is injected from the `Dangerfile`, since Danger's
Octokit client is the only thing that can list comments, and it receives
the marker text rather than the bare hash so the helper owns the marker
shape on both sides.

Not visible in the diff: the marker sits in the `<details>` block Danger
rewrites every run, so it always reflects the last announcement rather
than accumulating.

</details>

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Changes CI Danger behavior and Slack integration for API
announcements; misconfiguration (channel name vs ID or missing scopes)
can cause duplicate posts or warnings, but no runtime SDK or auth
impact.
> 
> **Overview**
> Stops **duplicate Slack posts** to the SDK API feed when Danger reruns
on the same public API diff. Announcements now go out **once per
distinct summary** for a PR, while still **re-announcing** if the API
surface changes again (including reverting to an earlier announced
state).
> 
> Dedup first checks Slack **`conversations.history`** for this PR’s
latest message (matched by PR link and Android platform label) and skips
posting when the text matches. When history is unavailable—wrong channel
format, missing `channels:history`, errors, or concurrent CI siblings—it
falls back to a **`<!-- api-diff:<hash> -->`** marker on the PR comment
(lookup injected from the `Dangerfile`). The hash fingerprints the
**full Slack message**, not raw declaration lists, so removals and
additions don’t collide. The marker is recorded only after a
**successful** post so a Slack outage doesn’t block a later
announcement.
> 
> Operational notes: **`SLACK_CHANNEL_SDK_NEW_API` must be a channel
ID** (not `#name`) for history. Warnings replace the old `slack_error`
field when Slack fails or when a post may duplicate because neither
Slack nor the comment marker could confirm prior announcement.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
4c4c48909a304a8be82c1becc170f20622b0f605. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
Á
Álvaro Brey committed
97a135600c1139ae1d9de85486734fa94ab00811
Parent: 8659769
Committed by GitHub <noreply@github.com> on 8/19/2026, 7:18:24 AM