diff --git a/.gittensory.yml.example b/.gittensory.yml.example index d76e7049e1..46d183eecb 100644 --- a/.gittensory.yml.example +++ b/.gittensory.yml.example @@ -841,8 +841,11 @@ settings: # one-shot review process, not making an ordinary close. When enabled, gittensory reopens (if needed) and # re-closes the PR as the App -- a close the contributor cannot themselves reopen (#one-shot-reopen) -- # posts an explanation comment, applies the configured label, and records a `review_evasion` moderation - # strike (subject to moderationRules above including it). Off by default. - # reviewEvasionProtection: off # off | close. Default: off. + # strike (subject to moderationRules above including it). CLOSE BY DEFAULT as of #4011 -- "off" is an + # explicit opt-out, not the default. Note: "off" only suppresses the enforcement close -- the + # ready<->draft cycling counter keeps incrementing regardless, so re-enabling can immediately treat a + # historical off-period cycle as "repeated." + # reviewEvasionProtection: close # off | close. Default: close. # reviewEvasionLabel: review-evasion # Label applied alongside the enforcement close. Gated on autonomy.close # # (#label-scoping); set to explicit `null` to close without any label. # # Default: review-evasion. diff --git a/apps/gittensory-ui/public/openapi.json b/apps/gittensory-ui/public/openapi.json index a9eb9eb9dc..04719681b5 100644 --- a/apps/gittensory-ui/public/openapi.json +++ b/apps/gittensory-ui/public/openapi.json @@ -9568,7 +9568,8 @@ "enum": [ "off", "close" - ] + ], + "description": "Effective default is \"close\" as of #4011 -- \"off\" is an explicit opt-out, not the default. \"off\" only suppresses the enforcement close; the ready<->draft cycling counter keeps incrementing regardless, so re-enabling can immediately treat a historical off-period cycle as \"repeated.\"" }, "reviewEvasionLabel": { "type": "string", diff --git a/config/examples/gittensory.full.yml b/config/examples/gittensory.full.yml index f89e4d4079..87be1cde82 100644 --- a/config/examples/gittensory.full.yml +++ b/config/examples/gittensory.full.yml @@ -854,8 +854,11 @@ settings: # one-shot review process, not making an ordinary close. When enabled, gittensory reopens (if needed) and # re-closes the PR as the App -- a close the contributor cannot themselves reopen (#one-shot-reopen) -- # posts an explanation comment, applies the configured label, and records a `review_evasion` moderation - # strike (subject to moderationRules above including it). Off by default. - # reviewEvasionProtection: off # off | close. Default: off. + # strike (subject to moderationRules above including it). CLOSE BY DEFAULT as of #4011 -- "off" is an + # explicit opt-out, not the default. Note: "off" only suppresses the enforcement close -- the + # ready<->draft cycling counter keeps incrementing regardless, so re-enabling can immediately treat a + # historical off-period cycle as "repeated." + # reviewEvasionProtection: close # off | close. Default: close. # reviewEvasionLabel: review-evasion # Label applied alongside the enforcement close. Gated on autonomy.close # # (#label-scoping); set to explicit `null` to close without any label. # # Default: review-evasion. diff --git a/src/openapi/schemas.ts b/src/openapi/schemas.ts index e92af604c0..e641d3146f 100644 --- a/src/openapi/schemas.ts +++ b/src/openapi/schemas.ts @@ -833,7 +833,12 @@ export const RepositorySettingsSchema = z moderationWarningLabel: z.string().optional(), moderationBannedLabel: z.string().optional(), skipAutomationBotAuthors: z.enum(["inherit", "off", "enabled"]).optional(), - reviewEvasionProtection: z.enum(["off", "close"]).optional(), + reviewEvasionProtection: z + .enum(["off", "close"]) + .optional() + .describe( + "Effective default is \"close\" as of #4011 -- \"off\" is an explicit opt-out, not the default. \"off\" only suppresses the enforcement close; the ready<->draft cycling counter keeps incrementing regardless, so re-enabling can immediately treat a historical off-period cycle as \"repeated.\"", + ), reviewEvasionLabel: z.string().nullable().optional(), reviewEvasionComment: z.boolean().optional(), mergeTrainMode: z.enum(["off", "audit", "enforce"]).optional(), diff --git a/src/types.ts b/src/types.ts index 85dca132d0..aa6bc27575 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1131,9 +1131,14 @@ export type RepositorySettings = { skipAutomationBotAuthors?: "inherit" | "off" | "enabled" | undefined; /** Review-evasion protection (#review-evasion-protection): a contributor closing or converting their OWN * PR to draft while gittensory has an ACTIVE review pass running against it is dodging the one-shot - * review process. `"off"` (the default) disables detection entirely; `"close"` reopens (if needed) and - * re-closes as the App -- a close the contributor cannot themselves reopen (#one-shot-reopen) -- applies - * the configured label/comment, and records a `review_evasion` moderation strike. */ + * review process. The effective default is `"close"` as of #4011 (see `normalizeReviewEvasionProtection` + * in `db/repositories.ts`) -- `"off"` is now an explicit opt-out, not the default. `"close"` reopens (if + * needed) and re-closes as the App -- a close the contributor cannot themselves reopen (#one-shot-reopen) + * -- applies the configured label/comment, and records a `review_evasion` moderation strike. Note: + * `"off"` only suppresses this ENFORCEMENT -- the ready↔draft cycling COUNTER (`processors.ts`'s + * `converted_to_draft` handler, `bumpPullRequestDraftConversionCount`) keeps incrementing regardless, so a + * repo re-enabling `"close"` (or removing an `"off"` override, which now also resolves to `"close"`) can + * immediately treat a historical off-period cycle as "repeated" on the very next legitimate conversion. */ reviewEvasionProtection?: "off" | "close" | undefined; /** Merge-train FIFO gate (#selfhost-merge-train): without this, a PR merges the instant its OWN gate * clears, with zero awareness of an older sibling PR still open in the same repo -- proven live to cause