Repository navigation
fix(ops): guard against duplicate same-fix pull requests #80
Changes from 8 commits
2091c7a
3f45ab2
57f654a
2db89fd
4fbdc34
8120c4d
e3ea807
1a2e190
eb77414
25b426f
95228e1
d8c186d
99030e8
f22562d
384b343
c1f34db
8da2390
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| name: PR Duplicate Guard | ||
|
|
||
| # Stops duplicate same-fix pull requests from silently piling up (the fleet | ||
| # kept dispatching the same finding to multiple lanes: #36/#44/#55/#56, | ||
| # #39/#49, #40/#52, #38/#48/#51, ...). On every PR event this job compares | ||
| # the PR's diff against every other OPEN pull request. When another open PR | ||
| # covers the same fix (>= 80% shared changed-file coverage and >= 50% patch | ||
| # similarity on the shared files), the check fails loudly and the job posts | ||
| # one marker comment naming the duplicate(s) and the canonical PR. The check | ||
| # is deliberately not a required status, so legitimate work never blocks on | ||
| # it; it exists to make the duplication visible the moment it happens. | ||
| # | ||
| # Run locally before opening a PR: | ||
| # node scripts/check-pr-duplicates.mjs --pr 0 --no-fail --repo OWNER/REPO | ||
| # (use the real PR number once the PR exists). | ||
|
|
||
| on: | ||
| pull_request: | ||
| types: [opened, synchronize, reopened, ready_for_review] | ||
| workflow_dispatch: | ||
| inputs: | ||
| pr-number: | ||
| description: "PR number to check (defaults to the PR that triggered the run)" | ||
| required: false | ||
| type: string | ||
|
Comment on lines
+22
to
+25
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
A Useful? React with 👍 / 👎. |
||
|
|
||
| permissions: | ||
| contents: read | ||
| pull-requests: write | ||
|
|
||
| concurrency: | ||
| group: pr-duplicate-guard-${{ github.workflow }}-${{ github.ref }} | ||
| cancel-in-progress: true | ||
|
|
||
| jobs: | ||
| duplicate-guard: | ||
| runs-on: [self-hosted, linux, x64, vps-verify] | ||
| steps: | ||
| - uses: actions/checkout@v7 | ||
| - uses: actions/setup-node@v7 | ||
| with: | ||
|
Comment on lines
+40
to
+41
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Unlike the existing repo-check workflow, these steps reference mutable major-version tags. If either tag is retargeted or its upstream release is compromised, replacement code runs on the self-hosted runner; Useful? React with 👍 / 👎. |
||
| node-version: 20 | ||
| - name: Detect same-fix duplicate open PRs | ||
| run: node scripts/check-pr-duplicates.mjs --pr "$PR_NUMBER" --comment | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When a same-repository PR modifies Useful? React with 👍 / 👎. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
In this Useful? React with 👍 / 👎. |
||
| env: | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| GITHUB_REPOSITORY: ${{ github.repository }} | ||
| PR_NUMBER: ${{ github.event.inputs.pr-number || github.event.pull_request.number }} | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -73,6 +73,23 @@ node scripts/test-cross-repo-service.mjs --public-repo "/absolute/path/to/TinySt | |
| git diff --check | ||
| ``` | ||
|
|
||
| ## PR duplicate guard | ||
|
|
||
| Same-fix PR pairs kept appearing because the same finding gets dispatched to | ||
| multiple lanes (`fix/operator-export-cli-help` #36 and `fix/operator-export-cli-help-lane1` | ||
| #44 were byte-identical patches; #39/#49 and #40/#52 followed the same pattern). | ||
| The `PR Duplicate Guard` workflow now compares every PR's diff against all | ||
| other open PRs and fails loudly (with a comment naming the canonical PR) when | ||
| another open PR covers the same fix with the same changed-file set. Run the | ||
| same check locally before opening a PR: | ||
|
|
||
| ```bash | ||
| node scripts/check-pr-duplicates.mjs --pr 0 --repo nish3451/tinystudio-in --no-fail | ||
| ``` | ||
|
Comment on lines
+86
to
+88
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This documented command always exits with Useful? React with 👍 / 👎. |
||
|
|
||
| The check is informational, not a required status, so it never blocks | ||
| legitimate work; it exists to make duplication visible the moment it happens. | ||
|
|
||
| ## SaaS graduation evidence gate | ||
|
|
||
| TinyStudio does not become SaaS by assumption. Graduation requires **at least 10 paid sprints**, the **same problem in at least 7**, **at least 70% workflow repeatability**, **usefulness at least 8/10**, **approval at least 70%**, a **recurring need**, and **at least 3 deposits or preorders**. Until every threshold is evidenced, this remains a managed service. | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the inspected
pr-duplicate-guard.ymlworkflow, closing or merging a matched PR triggers none of these event types, so the remaining PR is never reevaluated. If the recommended canonical PR is closed without merging, the survivor retains both a failed check and a marker comment instructing maintainers to close it in favor of a PR that is no longer open; cleaning up only during later synchronizations does not help when its head remains unchanged. Add handling that reevaluates affected open peers when a PR closes, or periodically reconcile outstanding reports.Useful? React with 👍 / 👎.