Skip to content

fix(server): Forgejo checks keep the final status when it shares a second with a pending one - #24871

Merged
maria-rcks merged 4 commits into
pingdotgg:mainfrom
fixfon:fix/24858-forgejo-status-tie
Oct 31, 2026
Merged

maria-rcks merged 4 commits into
pingdotgg:mainfrom
fixfon:fix/24858-forgejo-status-tie

Conversation

@fixfon

@fixfon fixfon commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

Problem

A Forgejo pull request watch never wakes when a check's final status and an earlier pending status for the same check carry the same updated_at. Forgejo timestamps have one-second resolution, so a job that is skipped or finishes within a second leaves both statuses dated alike.

dedupeChecks keeps the newest entry per check, and isAtLeastAsNew returns true on equal timestamps. Forgejo lists statuses newest first, so the older pending status comes later in the list, ties with the final one and replaces it. The check stays pending and the watch never reaches "All checks passed". The statuses in #24858 show it: id 15 success and id 14 pending both at 10:14:29.

Change

dedupeChecks entries take an optional sequence. When two entries for a check have the same instant and both carry a sequence, the higher one is kept. In every other case the choice is the same as before, including the existing "last copy wins" for equal instants without a sequence.

  • packages/source-control-core/src/server/pullRequestChecks.ts: the tie-break.
  • packages/source-control-forgejo/src/server/forgejoPullRequestJson.ts: ForgejoStatus decodes an optional id, and forgejoChecks passes it as sequence. It is optional because existing fixtures and servers may omit it.

GitHub and Bitbucket never set sequence, so their results do not change. GitCafe does not use dedupeChecks.

I considered sorting the statuses by id inside the Forgejo mapping instead. That would also reorder the checks shown for Forgejo pull requests, so I kept the tie-break inside dedupeChecks.

Scope and approval

This fixes the bug in #24858, which has no maintainer triage yet. It is a small, focused fix of an obvious bug with no new setting or behavior: it only changes which of two statuses wins when their timestamps are equal. The issue itself suggests keeping the higher Forgejo status id, and that is what this does. That is why I'm sending it under the CONTRIBUTING exception for a very small fix of an obvious bug: the statuses posted in #24858 show the wrong pick directly, and the fix touches only the tie-break.

Verification

  • Fails on the original source: with only the new tests, vp test run on the two touched test files gives 2 failed | 50 passed. Both failures are pending where success was expected: the Forgejo provider test with the two statuses from [Bug]: Forgejo PR watch never wakes when a check's final status shares a second with its pending one #24858, and the dedupeChecks tie test. The other two new dedupeChecks tests (a newer instant beats a higher sequence, and a sequence on only one side) pass either way, because they guard behavior that already exists.
  • Passes with the fix: the same two files give 52 passed. Reverting only the two source files fails the same two tests again.
  • Each new test checks both listing orders (newest first and oldest first).
  • 12 targeted test files, including the GitHub and Bitbucket provider tests and the server's PR watch test: 298 tests pass.
  • vp lint and vp fmt --check on the changed files, typecheck of source-control-core and source-control-forgejo, and vp run check:changed all pass.
  • Not checked: I did not run this against a live Forgejo server. The assumption that a higher status id means a later status rests on the status table in [Bug]: Forgejo PR watch never wakes when a check's final status shares a second with its pending one #24858 (id 15 success, 14 pending, 13 pending) and on my reading of the Forgejo API, not on a test against a server. I also did not confirm that every Forgejo version returns id on statuses. A status without an id keeps the old behavior. The full CI suites and the build were not run locally.

Closes #24858

Claude Sonnet 5.5 (xhigh) via T3 Code.

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:S 10-29 changed lines (additions + deletions). labels Oct 25, 2026
@macroscopeapp

macroscopeapp Bot commented Oct 25, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at 25786b1

Macroscope's review found this PR approvable — This is a small, well-scoped server bug fix that resolves equal-second Forgejo check statuses using their IDs while preserving existing behavior when IDs are unavailable. The accompanying tests cover ordering and backward-compatible fallback cases.

You can add or adjust custom eligibility rules. Learn more.

@coderabbitai

coderabbitai Bot commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Walkthrough

Check deduplication now uses sequence numbers to resolve equal timestamps when both entries have them. Forgejo status IDs supply those sequence numbers. Tests cover timestamp precedence, sequence ordering, missing sequences, and Forgejo response ordering.

Changes: Forgejo check status deduplication

Layer / File(s) Summary
Sequence-aware check selection
packages/source-control-core/src/server/pullRequestChecks.ts, packages/source-control-core/src/server/pullRequestChecks.test.ts
dedupeChecks accepts an optional sequence and compares it when entries have equal timestamps and both have sequences. Tests cover sequence ordering, timestamp precedence, and the case where one sequence is absent.
Forgejo status ID mapping
packages/source-control-forgejo/src/server/forgejoPullRequestJson.ts, packages/source-control-forgejo/src/server/ForgejoSourceControlProvider.test.ts
ForgejoStatus accepts an optional integer ID, and forgejoChecks passes a present ID as the check sequence. Tests cover equal-timestamp statuses in both response orders.

Priority: Normal

Estimated code review effort: 2 (Simple) | ~12 minutes

Change: Bug fix · Severity of issue fixed: Medium

Suggested reviewers: mnigos, maria-rcks

Merge Risk: Minimal · up to 64474

No merge-blocking issue was identified. Forgejo version-specific ID behavior has not been verified against a live server.

Pre-merge checks: Passed 4
Check name Status Explanation
Title check Passed The title names the main change: Forgejo checks keep the final status when it shares a timestamp second with a pending status. The changeset adds an optional sequence tie-break to dedupeChecks and pas…
Description check Passed The description follows the repository template. It has Problem, Change, Scope and approval, and Verification sections, and it states the reproduction evidence from #24858. The Scope section cites the…
Linked Issues check Passed Issue [#24858] requires the final Forgejo status to win when it shares updated_at with an earlier pending status. forgejoPullRequestJson.ts decodes optional status id values and passes them as `…
Out of Scope Changes check Passed The changes stay within [#24858]. They add the shared deduplication tie-break, optional Forgejo ID mapping, and focused regression tests. No unrelated provider or product behavior is introduced.
Full details: Title check

Explanation

The title names the main change: Forgejo checks keep the final status when it shares a timestamp second with a pending status. The changeset adds an optional sequence tie-break to dedupeChecks and passes the Forgejo status id as that sequence, which matches the title. The title is specific and follows conventional commit form.

Full details: Description check

Explanation

The description follows the repository template. It has Problem, Change, Scope and approval, and Verification sections, and it states the reproduction evidence from #24858. The Scope section cites the CONTRIBUTING exception for a small fix of an obvious bug, but it does not link a maintainer-approved triage issue or comment. The Verification section is detailed and lists what was not checked. The template also asks for the model and harness used, and the author provided that at the end. The missing maintainer approval link is the main gap.

Resolution

Optionally confirm the exception claim in the Scope and approval section. The description relies on the CONTRIBUTING exception for a small, obvious bug fix, but it does not link a maintainer-approved triage or discussion. Add a link to any maintainer comment that approves this direction, or state explicitly why the exception applies.

Full details: Linked Issues check

Explanation

Issue [#24858] requires the final Forgejo status to win when it shares updated_at with an earlier pending status. forgejoPullRequestJson.ts decodes optional status id values and passes them as sequence. dedupeChecks keeps the higher sequence when equal timestamps and both sequences exist. Regression tests cover both response orders and missing sequences.

Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Usage-based review receipt

Note

This review was completed with usage-based billing: files reviewed beyond your plan's included limits are billed at $0.25/file. View usage-based billing.

Comment @coderabbitai help to get the list of available commands.

@fixfon
fixfon force-pushed the fix/24858-forgejo-status-tie branch from 25786b1 to f86398a Compare October 29, 2026 08:41

Copy link
Copy Markdown
Collaborator

Note

Written by gpt-6.1-sol on behalf of Maria

thanks @fixfon. your optional status-id tie-break preserves timestamp precedence and leaves other providers unchanged. i kept your commit and merged current main into this branch without rebasing.

i removed the extra comparison helper and its duplicate types. the reverse timestamp comparison now runs only when both ids exist and the incoming id is lower. i also extended your provider regression to cover both check summaries and full pull request details. no behavior or original test coverage was dropped.

verification on 64474d4bda30290ba7a55aae4d83faa736a84ea4:

  • reproduced the bug with your tests on main: 2 failed, 52 passed; the failures returned pending instead of success.
  • 132 focused core, forgejo, github, and bitbucket tests passed through blacksmith.
  • vp run check:changed passed through blacksmith: formatting, lint, knip, typechecks for 18 affected packages, and 60 tests.
  • two independent reviews found no issues on this exact head.

unverified: live forgejo and browser rendering. this changes server status selection, with no client code changes; the provider regressions cover decoding and both read paths using fixture api responses.

all 29 ci checks are green and gitcafe reports this head mergeable. the automatic review found no merge-blocking issue. its optional approval-link suggestion needs no code change: maria explicitly authorized this takeover and its original scope.

maria-rcks commented Oct 30, 2026 •

Copy link
Copy Markdown
Collaborator

Note

Written by gpt-6.1-sol on behalf of Maria

Verified in a real dev environment

verified as-is at 64474d4bda30290ba7a55aae4d83faa736a84ea4. no code changes or pushes were needed.

ran main and the exact pr head sequentially with vp i and isolated vp run dev state. used linux chrome through the repo's playwright, real forgejo 15.0.9 with mariadb, tea 0.16, and real codex gpt-6.1-sol turns through the local proxy. created the project and threads through the app. statuses were submitted through forgejo's authenticated api, with no mocks or fixtures.

  • reproduced on github/main (6575ce3250): the real paginated status response returned success id 23 before pending ids 22/21, all at 2026-10-30T14:56:22Z. t3 incorrectly showed "1 of 1 running".
  • the pr head showed "all checks passed" with that same repository, commit, and statuses. both pullRequests.checks and pullRequests.detail returned success through the running server.
  • a fresh sol thread watched a pending check. pending id 35 and success id 36 shared 15:45:56Z; t3 woke the thread with "checks passed", sol reported all 3 checks passed, and unwatched.
  • neighboring behavior passed: a later same-second failure stayed failed; a newer pending status stayed pending; later success recovered it. checked through both websocket read paths and the client.
  • 54 focused core/forgejo tests passed through blacksmith. all 29 ci checks are green on this exact head.

runtime command transcript

main incorrectly keeps the completed forgejo check running

pr head correctly shows the same forgejo check passed

the recording shows the pending watch, its actual wake, and sol's response. the idle interval between them is cut.

real sol watch wakes after the forgejo same-second completion

Not verified

native desktop, ios/android, remote/relay/tunnel connections, live github/bitbucket, and forgejo responses without status ids. no forgejo actions runner was exercised; statuses came from the real status api. production forgejo deployments and other version/database combinations were not verified for this regression.

yasinuslu added a commit to yasinuslu/t3code that referenced this pull request Oct 30, 2026
…ingdotgg#24706 instead of our own Forgejo fixes' (pingdotgg#97) from fix/forgejo-upstream-prs into dev
@maria-rcks
maria-rcks merged commit f7e5565 into pingdotgg:main Oct 31, 2026
29 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:S 10-29 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Forgejo PR watch never wakes when a check's final status shares a second with its pending one

2 participants