Skip to content

Add a reusable cross-SDK parity check - #3

Open
brionmario wants to merge 1 commit into
thunder-id:mainfrom
brionmario:sdk-parity-check
Open

brionmario wants to merge 1 commit into
thunder-id:mainfrom
brionmario:sdk-parity-check

Conversation

@brionmario

@brionmario brionmario commented Sep 15, 2026

Copy link
Copy Markdown
Member

Purpose

A ThunderID capability has to exist in javascript-sdks, ios-sdks, android-sdks and flutter-sdks before a developer can rely on it, but nothing at review time asked whether a change landing in one of them needed to land in the others. Since the SDKs moved into separate repositories, a reviewer of a change in one has no visibility into whether the equivalent work in the siblings exists, is planned, or was consciously skipped.

The SDK development specification states that the parity decision is made on every pull request. This is the check that enforces it, the second half of the proposal in thunder-id/thunderid#5354.

It lives here rather than four times over, so the SDK repositories cannot drift. Each of them gets a thin caller that owns only the triggers, which a reusable workflow cannot declare for its caller.

Approach

A label is the gate, and the only thing that clears it. Every pull request must carry exactly one of parity/prs-raised or parity/prs-not-needed. There is no path based exemption: "it only touched docs" is a judgement a person makes, not one a file path can be trusted to make for them. Applying a label re-runs the check, so it goes green without a push.

The checklist maintains itself. Alongside the gate the check keeps a single comment listing the sibling repositories, and ticks the boxes as port links appear in the pull request body or in replies on the thread. Both link styles are recognised, and a linked issue counts as well as a pull request, since a recorded deferral is a recorded deferral. Contributors cannot edit that comment, external ones especially, so nobody is asked to maintain it by hand.

No input to keep in sync. The sibling list is derived from the repository the check runs in, matched on repository name so it still excludes itself when it runs in a fork. A siblings input exists for overrides but the callers pass nothing.

pull_request_target, not pull_request, because the check has to comment on pull requests opened from forks, where the pull_request token is read only. Nothing from the contributor's branch is checked out or executed, so the elevated token is never handed to untrusted code.

Comment events never fail the run. An issue_comment run is not part of the pull request's check suite, so failing it there would surface a red run detached from the pull request. Replies refresh the checklist; the gate is enforced on pull request events.

Testing

The workflow script was exercised against a stubbed github-script environment, 17 cases covering each label state, the both-labels conflict, link parsing in the body and in replies, the self-comment loop guard, comment upsert and the no-op path, look-alike repository names, and the sibling exclusion rule including the fork case.

It was then dry run end to end on a throwaway pull request in a fork, which turned up two things now fixed:

  • The self-exclusion compared the full owner/repo, so in a fork the check listed its own upstream as a sibling. It now matches on repository name.
  • A comment from an unrelated bot cancelled the in-flight gating run, because the issue_comment run shared its concurrency group. The callers now include the event name in the group.

The dry run confirmed the rest: the check blocked the pull request red with the checklist comment, went green the moment the label was applied without a push, and updated its comment in place rather than posting again.

Related Issues

Related PRs

Notes for merging

  • This should merge first. The callers reference @main here and cannot resolve until it does.
  • The two labels have to exist in each SDK repository, or the gate cannot be cleared.
  • The required check to add to branch protection is 🔀 Cross-SDK Parity / 🏷️ Parity Decision. Renaming either job later breaks the protection rule.

A ThunderID capability has to exist in javascript-sdks, ios-sdks, android-sdks
and flutter-sdks before a developer can rely on it, but nothing at review time
asked whether a change landing in one of them needed to land in the others. The
SDK development specification now states that the decision has to be made on
every pull request; this is the check that enforces it.

The gate is a label, and a label is the only thing that clears it. There is no
path based exemption: "it only touched docs" is a judgement a person makes, not
one a file path can be trusted to make for them. Alongside the gate the check
keeps a single comment carrying a checklist of the sibling repositories, and
ticks the boxes itself as port links appear in the pull request body or in
replies on the thread, so nobody maintains that list by hand and a contributor
who cannot edit the comment is not asked to.

It lives here rather than four times over so the repositories cannot drift, and
it derives the sibling list from the repository it runs in, so the caller in
each SDK repository passes nothing and owns only the triggers.

Signed-off-by: Brion <info@brionmario.com>
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