feat(agent-actions): add an account-age throttle for ban-evasion#2642
Conversation
|
Warning 🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨 ⏸️ Gittensory review result - manual review recommendedReview updated: 2026-07-02 23:42:54 UTC
⏸️ Suggested Action - Manual Review
Review summary Nits — 6 non-blocking
Concerns raised — review before merging
Review context
Contributor next steps
Signal definitions
🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed 💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →. Checked by Gittensory, a quiet PR intelligence layer for OSS maintainers.
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #2642 +/- ##
==========================================
- Coverage 96.09% 96.09% -0.01%
==========================================
Files 237 237
Lines 26448 26474 +26
Branches 9589 9602 +13
==========================================
+ Hits 25416 25440 +24
Misses 425 425
- Partials 607 609 +2
🚀 New features to boost your workflow:
|
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
gittensory-ui | 315f547 | Commit Preview URL Branch Preview URL |
Jul 02 2026, 11:44 PM |
The contributor blacklist matches by exact login string; the contributor
cap counts open items per repo. Neither has any signal for how old a
GitHub account is -- the classic ban-evasion gap: a banned login gets a
fresh account the same day and gets full trust until it independently
trips the cap on its own.
Adds accountAgeThresholdDays: a PR/issue from an account younger than the
threshold gets the new-account label AND a tightened effective contributor
cap (half, rounded up) -- friction/visibility, never an automatic close on
account age alone. Fetches created_at via GET /users/{login}, already
classified as a cached "metadata" GitHub response (client.ts), so this
reuses the existing response cache with no new caching infra. Off by
default. Never fires for the repo owner, admin logins, or automation bots.
Closes #2561.
The account-age throttle applied its label directly, bypassing the label-autonomy opt-in every other label mutation goes through — a repo with label autonomy still at the default "observe" would get labels written anyway. Also narrows the docs to PR-only (issue-path enforcement isn't wired yet) and hardens getGithubUserCreatedAt against a non-string created_at field. Addresses gate review findings on #2561.
main independently merged 0095_pull_request_detail_sync_pr_state.sql, colliding with this branch's own 0095_account_age_throttle.sql after rebase.
5f73109 to
315f547
Compare
Summary
accountAgeThresholdDays: a PR from an account younger than the threshold gets thenew-accountlabel AND a tightened effectivecontributorOpenPrCap(half, rounded up, minimum 1) — friction/visibility only, never an automatic close on account age alone. PR-path only for now (the issue-path cap enforcement doesn't read this setting yet).created_atviaGET /users/{login}— already classified as a cached"metadata"GitHub response (src/github/client.ts'sresolveGitHubCacheClass), so this reuses the existing response-cache infra with zero new caching mechanism.nullthreshold). Never fires for the repo owner, admin logins, automation bots, or a repo-scopedautoCloseExemptLoginsentry — same standing exemption as every other anti-abuse mechanism (blacklist, contributor cap, review-nag). The label mutation itself is additionally gated behindlabelautonomy being"auto", matching every other label write.RepositorySettingstype +db/repositories.tsresolver +.gittensory.ymlparsing + OpenAPI schema +.gittensory.yml.exampledocs).Closes #2561.
Scope
type(scope): short summaryConventional Commit format.CONTRIBUTING.mdand does not reintroduce GitHub Pages, VitePress,site/, orCNAME.Validation
git diff --checknpm run actionlint(vianpm run test:ci)npm run db:migrations:check— migration 0096 (rebased/renumbered after a main-side collision), contiguous, no new duplicatesnpm run typechecknpm run test:coveragelocally — tests covering: a below-threshold account gets the label AND the tightened cap trips a close a raw-cap check wouldn't; an above-threshold account is fully unaffected; the repo owner's own PR is never labeled even on a brand-new account;getGithubUserCreatedAtfetches/parses/fails-open on error;.gittensory.ymlparsing (set/override/clear-via-null/omitted/invalid).npm run test:workers(vianpm run test:ci)npm run build:mcp(vianpm run test:ci)npm run test:mcp-pack(vianpm run test:ci)npm run ui:openapi:check— regenerated and committedapps/gittensory-ui/public/openapi.jsonnpm run ui:lint(vianpm run test:ci)npm run ui:typecheck(vianpm run test:ci)npm run ui:build(vianpm run test:ci)npm audit --audit-level=moderateSafety
RepositorySettings's new fields added to the OpenAPI schema and regenerated.UI Evidencesection below with screenshots. — N/A, no UI change..gittensory.yml.exampledocuments the new settings.Notes