Skip to content

Conversation

@Akshat8510
Copy link
Contributor

Description

Adds Phase 2 of the inactivity-unassign bot.
This phase handles contributors who do have an open PR, but the PR has had no commit activity for 21+ days.

What this PR adds

  • New script: inactivity_unassign_phase2.sh

    • Detects stale PRs linked to issues (via timeline cross-references)
    • Comments with an InactivityBot message
    • Closes the stale PR
    • Unassigns the contributor
  • New dry-run script for safe local testing:
    dry_run_inactivity_unassign_phase2.sh

  • Updates to Phase 1 workflow:

    • Adds pull-requests: write
    • Adds a new step that runs Phase 2 after Phase 1
  • New standalone workflow:
    .github/workflows/bot-inactivity-unassign-phase2.yml

  • CHANGELOG entry updated.

Related issue
Fixes #969

Signed-off-by: Akshat Kumar <akshat230405@gmail.com>
Signed-off-by: Akshat8510 <akshat230405@gmail.com>
Signed-off-by: Akshat8510 <akshat230405@gmail.com>
Signed-off-by: Akshat Kumar <akshat230405@gmail.com>
@github-actions
Copy link

github-actions bot commented Dec 7, 2025

Hi, this is MergeConflictBot.
Your pull request cannot be merged because it contains merge conflicts.

Please resolve these conflicts locally and push the changes.

To assist you, please read:

Thank you for contributing!

From the Hiero Python SDK Team

Signed-off-by: Akshat8510 <akshat230405@gmail.com>
Signed-off-by: Akshat8510 <akshat230405@gmail.com>
@Akshat8510
Copy link
Contributor Author

Hi @exploreriii ,

I verified the entire workflow on my fork, including stale-PR detection, commenting and closing
Test run link (working end-to-end):
https://github.com/Akshat8510/hiero-sdk-python/pull/3

Please take your time reviewing — happy to adjust anything if needed!

@exploreriii
Copy link
Contributor

I am reviewing this currently but we have 4 concurrent bot PRs to review.
Request help to review @MonaaEid @tech0priyanshu @AntonioCeppellini @Adityarya11 if available

@MonaaEid
Copy link
Contributor

MonaaEid commented Dec 7, 2025

Do the bot have the privilege to close a pull request?? @exploreriii @Akshat8510 ? I mean we can't.
In our forked repo it works, but in the main repo? idk

@Akshat8510
Copy link
Contributor Author

Hi @MonaaEid! Great question , and yes, the bot does have the required permissions to close pull requests in the main repository. The workflow explicitly grants pull-requests: write, which is the permission level GitHub Actions needs to comment on and close PRs. This is the same permission model used by the other automation bots in this repo, so it stays fully consistent. I also verified the entire Phase 2 flow on my fork and everything worked exactly as intended: https://github.com/Akshat8510/hiero-sdk-python/pull/3
Still, if there's anything you'd like adjusted, I'm happy to refine it!

@Adityarya11
Copy link
Contributor

Hi @MonaaEid! Great question , and yes, the bot does have the required permissions to close pull requests in the main repository. The workflow explicitly grants pull-requests: write, which is the permission level GitHub Actions needs to comment on and close PRs. This is the same permission model used by the other automation bots in this repo, so it stays fully consistent. I also verified the entire Phase 2 flow on my fork and everything worked exactly as intended: Akshat8510#3 Still, if there's anything you'd like adjusted, I'm happy to refine it!

just a small doubt like what if this gets merged, then will the bot unassign the people who were inactive earlier?

@MonaaEid
Copy link
Contributor

MonaaEid commented Dec 7, 2025

Hi @MonaaEid! Great question , and yes, the bot does have the required permissions to close pull requests in the main repository. The workflow explicitly grants pull-requests: write, which is the permission level GitHub Actions needs to comment on and close PRs. This is the same permission model used by the other automation bots in this repo, so it stays fully consistent. I also verified the entire Phase 2 flow on my fork and everything worked exactly as intended: Akshat8510#3 Still, if there's anything you'd like adjusted, I'm happy to refine it!

It will work in your forked repo for sure, but for example I can comment on other's pull requests, but I can't close it
I'm also creating a bot, and I thought about this

@Akshat8510
Copy link
Contributor Author

Based on how the workflow is currently designed , and to be fully transparent, I’m not completely sure, but this is how it should behave. The bot only checks PRs that are currently open. If an open PR hasn’t received any new commits for more than 21 days, the bot will post the inactivity message, close the PR, and unassign the contributor from the linked issue. Closed PRs are completely ignored and won’t be affected. So, if there are already stale open PRs in the main repository, the bot should automatically detect and handle them during its next scheduled run.

@Akshat8510
Copy link
Contributor Author

Hi @MonaaEid! Thanks for raising this , and that’s a very valid point. You’re right that as contributors we can comment on others’ PRs but can’t close them manually. The key difference here is that GitHub Actions doesn’t operate using our personal contributor permissions; instead, it uses the permissions defined directly in the workflow. Since the workflow grants pull-requests: write, it effectively gives the bot elevated access beyond what a regular contributor has, which is why it can close PRs even though we personally cannot. And just to be transparent, I’m not entirely certain how GitHub handles every edge case, but based on testing and GitHub’s documentation, the bot should behave in the main repository exactly as it did in the fork.

Copy link
Contributor

@exploreriii exploreriii left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if a user has multiple pull requests tied to an issue they are assigned to?
For example, try 1 failed, open up try 2, but you leave try 1 open.

This is not relevant right now, so not that important, but it could be.
In this case, it will only close one PR, keep the other open, but unassign the user.
Shouldn't it also close the second PR?

@MonaaEid
Copy link
Contributor

MonaaEid commented Dec 7, 2025

Hi @MonaaEid! Thanks for raising this , and that’s a very valid point. You’re right that as contributors we can comment on others’ PRs but can’t close them manually. The key difference here is that GitHub Actions doesn’t operate using our personal contributor permissions; instead, it uses the permissions defined directly in the workflow. Since the workflow grants pull-requests: write, it effectively gives the bot elevated access beyond what a regular contributor has, which is why it can close PRs even though we personally cannot. And just to be transparent, I’m not entirely certain how GitHub handles every edge case, but based on testing and GitHub’s documentation, the bot should behave in the main repository exactly as it did in the fork.

That makes sense, I didn't think of this. Thank you for this explanation.

@exploreriii

This comment was marked as spam.

@Akshat8510
Copy link
Contributor Author

You’re right , in the current setup, the bot would only close one stale PR and still unassign the user even if another active PR exists. It’s not ideal, and the logic could definitely be improved later to either close all stale PRs for the issue or only unassign once all related PRs are handled. For now, the workflow keeps things simple, but this is a good edge case to refine in a future update.

@exploreriii
Copy link
Contributor

Why is this PR being judged as inactive for 39 days? #362

@Akshat8510
Copy link
Contributor Author

Hi @exploreriii , great question!

The reason this PR is currently being flagged as “inactive for 39 days” is based purely on commit activity, not comments, reviews, merges from main, or branch syncs.

How the inactivity counter works

Our Phase 2 bot (and GitHub’s API) looks only at:

→ The timestamp of the most recent commit authored on the PR’s branch itself.

So even if the PR is actively discussed, reviewed, or repeatedly updated by merging main, the bot still sees:

  • No new commits by the PR author, and
  • No changes to the PR branch’s actual code,
    → for 39 days.

Merges like “Merge branch 'main' into AddSetNodeAccountIdMethod” do not count as development work , they only pull upstream updates and don’t modify the contributor’s changes.

Why this metric was chosen

I’m not fully sure if GitHub provides a more detailed or reliable activity metric (like tracking “meaningful pushes”), but the last commit timestamp is:

  • stable
  • easy to audit
  • avoids false positives from comments or reviews
  • aligns with “has there been progress on the code?”

If a better activity signal exists, I’m happy to explore it but for now, this is the most consistent measure available.

@exploreriii
Copy link
Contributor

Could you try to run a debug script on that PR, as some of the recent commits are not merge commits, I think:

eg

#!/usr/bin/env bash
set -euo pipefail

REPO="${REPO:-}"
PR="${PR:-}"

if [[ -z "$REPO" || -z "$PR" ]]; then
  echo "USAGE:"
  echo "  REPO=owner/repo PR=362 ./debug-last-commit.sh"
  exit 1
fi

echo "============================================================"
echo " DEBUG: Last Commit Detection"
echo " Repo: $REPO"
echo " PR:   #$PR"
echo "============================================================"

echo
echo "[INFO] Fetching PR commits..."
COMMITS=$(gh api "repos/$REPO/pulls/$PR/commits" --paginate)

COUNT=$(echo "$COMMITS" | jq length)
echo "[INFO] Number of commits returned: $COUNT"
echo

NOW_TS=$(date +%s)

parse_ts() {
  if date --version >/dev/null 2>&1; then
    date -d "$1" +%s
  else
    date -j -f "%Y-%m-%dT%H:%M:%SZ" "$1" +"%s"
  fi
}

echo "------------------------------------------------------------"
echo " COMMITS (in the order GitHub API returned them)"
echo "------------------------------------------------------------"

INDEX=0
echo "$COMMITS" | jq -c '.[] | {sha: .sha, author_date: .commit.author.date, committer_date: .commit.committer.date}' \
| while read -r line; do
    SHA=$(echo "$line" | jq -r '.sha')
    ADATE=$(echo "$line" | jq -r '.author_date')
    CDATE=$(echo "$line" | jq -r '.committer_date')

    echo "[$INDEX]"
    echo "  sha:            $SHA"
    echo "  author.date:    $ADATE"
    echo "  committer.date: $CDATE"
    echo

    INDEX=$((INDEX+1))
done

echo
echo "============================================================"
echo " DEBUG COMPLETE"
echo "============================================================"

Copy link
Contributor

@exploreriii exploreriii left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you improve the precision of the lastest commit identification, I think you can sort the commits by timestamp to be sure

This is because you do a fetch the last commit approach - but i think this is not always accurate as the last in time commit

I don't want to unassign users that have been active in the last 21 days as that can be demotivating

@Akshat8510
Copy link
Contributor Author

Hi @exploreriii — I ran the debug script on PR #362 exactly as you suggested:

REPO=hiero-ledger/hiero-sdk-python PR=362 ./debug-last-commit.sh

Here’s what the script reports:

  • The GitHub API returns 55 commits for this PR.
  • The most recent commit, according to /pulls/362/commits, is:
sha:            a0f96ad831ab21f5af60d9786fe30c1ed49cdc8e
author.date:    2025-12-03T23:43:54Z
committer.date: 2025-12-03T23:43:54Z

From the API’s perspective, the latest commit on this PR is only a few days old , not 39 days.
This indicates that the current Phase 2 detection logic:

.[-1].commit.committer.date
// or
.[-1].commit.author.date

is correctly identifying the newest commit for #362.

If a stale-age value showed “39 days,” it likely came from either:

  • an earlier bot run before the recent commits were pushed, or
  • a log referencing Phase 1 assignment age instead of commit age.

I can review the workflow run if needed. I can also extend the debug script to explicitly sort commits by date to make its output clearer.

@Akshat8510
Copy link
Contributor Author

Akshat8510 commented Dec 7, 2025

Hi @exploreriii , absolutely, that makes sense and I agree with your concern.
Right now, Phase 2 identifies the “latest commit” by taking the last element returned by:

gh api /pulls//commits

But as you said, the API's array order is not guaranteed to represent true chronological order, especially when PRs involve merges, rebases, or rewritten history.
So relying on .[-1] can lead to rare but important edge cases where we mis-detect inactivity , which is exactly what we want to avoid since unassigning an active contributor would be discouraging.

I can improve the precision

I’ll update the logic so the bot:

  1. Fetches all commit timestamps for the PR
  2. Sorts them by actual commit/committer date
  3. Uses the maximum (latest-in-time) timestamp when calculating inactivity

This ensures that even if the API returns commits out of order, the bot still evaluates the correct most recent activity.

Benefit

This makes inactivity detection much more reliable and prevents accidental unassignments for contributors who have committed within the 21-day window.

If you prefer sorting only by committer.date, only by author.date, or using the more conservative max(author, committer) per commit, I can implement whichever approach aligns best with the repo’s expectations.

Happy to refine this further!

@exploreriii
Copy link
Contributor

Hi @Akshat8510
I did not understand what you meant in the last benefit section but I agree with this part -

I’ll update the logic so the bot:

Fetches all commit timestamps for the PR
Sorts them by actual commit/committer date
Uses the maximum (latest-in-time) timestamp when calculating inactivity

thanks!

@exploreriii exploreriii marked this pull request as draft December 7, 2025 18:38
… bot

Signed-off-by: Akshat Kumar <akshat230405@gmail.com>
@Akshat8510
Copy link
Contributor Author

Hi @exploreriii , thank you for the clarification! That helps me understand exactly what part was confusing in my previous explanation.

To put it simply, the core issue you were highlighting is:

The last commit in the GitHub API array is not guaranteed to be the actual latest commit in time.

So if we rely on .[-1], the bot might:

  • Think a PR is “inactive”
  • Even though the contributor actually made a recent commit
  • → leading to an incorrect and discouraging unassignment

I completely understand why that’s a risk we shouldn’t take.

Update implemented

I’ve updated Phase 2 so it now:

  1. Fetches all commits for the PR
  2. Extracts commit timestamps (author + committer)
  3. Sorts them chronologically
  4. Uses the true latest timestamp to evaluate inactivity

This guarantees the bot always uses the correct most recent activity — even in PRs with merges, rebases, or rewritten history.

The ambiguity you mentioned in my earlier message ("benefit section") makes sense, and thanks for pointing it out. The important thing is: the logic is now fully deterministic and safe.

If there’s any specific edge case you’d like me to test or validate, I’m happy to run more checks!

@exploreriii
Copy link
Contributor

exploreriii commented Dec 7, 2025

@nadineloepfe @manishdait FYI

SUMMARY: Actions that WOULD be taken (no changes made) if the bot is merged

both the PR would be closed and they would be unassigned from the issues

eg
ISSUE #744

[INFO] Assignees: Raja-89

→ Checking assignee: Raja-89
[INFO] Linked PRs by Raja-89: 749
763
[SKIP] PR #749 is not open (CLOSED).
[INFO] PR #763 last commit: 2025-11-12T10:57:31Z (~25 days ago)
[DRY RUN] Would CLOSE PR #763 (no commits for 25 days)
[DRY RUN] Would UNASSIGN @Raja-89 from issue #744

Signed-off-by: Akshat Kumar <akshat230405@gmail.com>
Signed-off-by: Akshat8510 <akshat230405@gmail.com>
Signed-off-by: Akshat8510 <akshat230405@gmail.com>
Updated the CHANGELOG to reflect recent additions and changes, including improvements to the inactivity-unassign bot and updates to the CustomFixedFee class.

Signed-off-by: Akshat8510 <akshat230405@gmail.com>
@Akshat8510
Copy link
Contributor Author

Hi @exploreriii

I ran the updated Phase 2 dry-run script directly against the main repo with:

export REPO=hiero-ledger/hiero-sdk-python
export DAYS=21
.github/scripts/dry_run_inactivity_unassign_phase2.sh

The output matches exactly what you described earlier. In the final summary, the bot reports:

  • Issue #760 → user @Raja-89 → stale PR #763 (no commits for 25 days)
  • Issue #744 → user @Raja-89 → stale PR #763 (no commits for 25 days)
  • Issue #679 → user @prakhar14-op → stale PR #694 (no commits for 37 days)
  • Issue #677 → user @Pranay22077 → stale PR #733 (no commits for 33 days)
  • Issue #591 → user @Pranay22077 → stale PR #724 (no commits for 34 days)

And for #86 / PR #362, it correctly detects:

[INFO] PR #362 last commit: 2025-12-03T23:43:54Z (~4 days ago)
[KEEP] No OPEN PR for aceppaluni is stale (>= 21 days).

So Phase 2 is now:

  • closing only PRs that have no commits for ≥ 21 days, and
  • leaving recently active PRs (like #362) untouched.

This gives me confidence that the current logic behaves as intended, but I’m happy to adjust anything further if you’d like. 🙂

Copy link
Contributor

@exploreriii exploreriii left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great!! Nearly there, you have two workflows submtited
https://github.com/hiero-ledger/hiero-sdk-python/pull/989/files#r2597621938

Signed-off-by: Akshat Kumar <akshat230405@gmail.com>
@exploreriii exploreriii marked this pull request as ready for review December 8, 2025 12:53
@exploreriii
Copy link
Contributor

Request second review @nadineloepfe @manishdait as this bot will unassign users and close PRs that are stale

@nadineloepfe
Copy link
Contributor

Absolutely LOVE this! Brilliant work, let's merge it!

@exploreriii exploreriii merged commit ee17b82 into hiero-ledger:main Dec 9, 2025
17 of 18 checks passed
@exploreriii
Copy link
Contributor

Thank you! Merged
Will run automatically in 2.5 hours

adityashirsatrao007 pushed a commit to adityashirsatrao007/hiero-sdk-python that referenced this pull request Dec 10, 2025
…hiero-ledger#989)

Signed-off-by: Akshat Kumar <akshat230405@gmail.com>
Signed-off-by: Akshat8510 <akshat230405@gmail.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.

Expand bot-inactivity-unassign bot - Phase 2: Extend the logic to handle users who do have a PR, but with ≥21 days of inactivity

5 participants