Menu

#199 engine: decide and fix force-push risk classification beyond the default protected-branch list

open
nobody
2026-08-20
2026-07-30
Anonymous
No

Originally created by: fu351

What

_git_force_push_to_protected() (src/doberman/engine/rules/commands.py:417) only escalates a force-push to BLOCK when the target ref is in the hardcoded DEFAULT_PROTECTED_BRANCHES list (("main", "master", "release", "develop"), line 87) — used unless a caller supplies its own protected_branches to DestructiveCommandRule.__init__. A force-push to any other branch or remote — a teammate's feature branch, a shared long-lived staging/prod branch not named one of those four, or any branch on a fork remote — is not classified as risky at all by this rule today (verified: _segment_verdict's only force-push check is line 605, gated entirely on protected_branches membership). This under-classifies real destructive-history risk for any team whose branch-naming convention differs from the four defaults. This issue is a design question first: should Doberman (a) widen the default list, (b) escalate any force-push that isn't to the current branch's own remote-tracking branch to AUTH regardless of name, or (c) leave it name-list-based by design (simpler, fewer false positives) and instead make it easier to configure per-repo? Open the issue, get maintainer agreement on the direction in the issue thread, then implement.

Difficulty: level-8

Changes how force-pushes are risk-classified (what counts as "protected" for force-push purposes) — a wrong call here either produces false BLOCKs across common workflows or leaves a real destructive-history gap, so it needs a maintainer decision on the intended classification before code lands.

Safety constraints (do not weaken these)

  • Whatever direction is agreed, the change must be raise-only relative to today's behavior for the existing four default branches — it must never make main/master/release/develop force-pushes less protected.
  • Do not implement anything until a maintainer has confirmed the classification approach in the issue thread — this is the one item in this ladder where code before sign-off is explicitly out of process, not just discouraged.
  • If the resolution widens escalation, DestructiveCommandRule.__init__'s existing protected_branches override parameter (used by callers/tests to pass a custom list) must keep working exactly as it does today — this is an additive/behavioral change, not an interface break.

Starting files

  • src/doberman/engine/rules/commands.py_git_force_push_to_protected (line 417), DEFAULT_PROTECTED_BRANCHES (line 87), the force-push branch in _segment_verdict (line 605), DestructiveCommandRule.__init__ (line 759).
  • tests/unit/test_rule_commands.py — existing force-push tests, to extend once a direction is agreed.

Acceptance criteria

  • [ ] The issue thread records the maintainer-agreed classification direction before any PR is opened against it.
  • [ ] Once implemented: force-pushes to the four existing default-protected branches are still BLOCKed exactly as today (regression test).
  • [ ] The agreed new behavior for non-default-list branches is covered by an explicit new test.
  • [ ] DestructiveCommandRule(protected_branches=...)'s existing override behavior is unchanged.
  • [ ] Existing behaviour unchanged for every case not touched here (no test weakened, no output format broken)
  • [ ] ruff check . && ruff format --check . and lint-imports pass
  • [ ] pytest passes

How to validate

pytest tests/unit/test_rule_commands.py -v -k force

Out of scope

  • Do not touch the recoverable/catastrophic classification of anything other than git push --force (no scope creep into rm/bulk-delete/git reset --hard).
  • Do not add network calls (e.g. querying a hosting provider's branch-protection API) — any resolution here must stay local/offline, consistent with Doberman's local-first design.

Notes for contributors

New here? Start with CONTRIBUTING.md. Issues are labelled level-1 (docs only) through level-10 (new subsystem) — pick one at your level and climb. Comment to claim an issue before starting.

Related

Tickets: #164

Discussion

  • Anonymous

    Anonymous - 2026-08-17

    Ticket changed by: fu351

    • status: open --> closed
     
  • Anonymous

    Anonymous - 2026-08-17

    Ticket changed by: fu351

    • status: closed --> open
     

Log in to post a comment.