commit: refuse on the default branch by default; allow_default_branch= / --allow-default-branch override #223

Closed
opened 2026-07-17 17:17:13 +00:00 by hexajon · 0 comments
hexajon commented 2026-07-17 17:17:13 +00:00 (Migrated from codeberg.org)

Implements the recoverable-guard tier (#222) for commits. Today madt_commit happily commits on main - a confused working directory (the incident: an agent whose cwd landed on the primary checkout) builds history on the local default branch with nothing in the way until push-time branch protection, if any. finish already refuses the default branch; commit joins it, completing branch-commit-finish as the only madtea-shaped path onto the default.

Behavior (service seam, both surfaces inherit):

  • Committing while HEAD is the repo's default branch is refused unless the per-call override is passed: allow_default_branch=true (madt_commit) / --allow-default-branch (CLI). No sticky config key exists or will exist.
  • Structural carve-out: a repo with no HEAD (empty, bootstrap/init flow) never refuses - keyed on git state, not configuration.
  • madt_finish's files= commit step inherits the same guard shape for consistency (it already refuses running from the default branch, so this is belt-and-braces at the seam).

Pinned refusal text (MCP; CLI variant swaps the next-step commands and flag spelling; branch name is dynamic):

"refusing to commit on 'main' - it is this repository's default branch, and an unplanned default-branch commit is almost always a wrong-checkout accident that then has to be untangled by hand. Create a feature branch first: madt_branch_create(branch="feat/"). If this repository genuinely commits straight to its default branch, state that intent explicitly with allow_default_branch=true. Nothing was committed."

Acceptance criteria:

  • Commit on default without override: refused with the pinned text, nothing committed, exit nonzero on CLI / tool error on MCP.
  • With override: commits exactly as today; override appears in the MCP call args (transcript-visible by construction).
  • Empty-repo initial commit: unaffected on both surfaces (existing init tests keep passing).
  • Feature-branch commits: byte-identical behavior to today.
  • Tool description, paramdocs, help topics, COMPARISON commit row, reference docs regenerated; server-instructions byte budget respected if touched.
  • Breaking for default-branch committers: called out for release notes.

Depends on #222 (the ADR pins the tier and naming family this instantiates).

Implements the recoverable-guard tier (#222) for commits. Today madt_commit happily commits on main - a confused working directory (the incident: an agent whose cwd landed on the primary checkout) builds history on the local default branch with nothing in the way until push-time branch protection, if any. finish already refuses the default branch; commit joins it, completing branch-commit-finish as the only madtea-shaped path onto the default. Behavior (service seam, both surfaces inherit): - Committing while HEAD is the repo's default branch is refused unless the per-call override is passed: allow_default_branch=true (madt_commit) / --allow-default-branch (CLI). No sticky config key exists or will exist. - Structural carve-out: a repo with no HEAD (empty, bootstrap/init flow) never refuses - keyed on git state, not configuration. - madt_finish's files= commit step inherits the same guard shape for consistency (it already refuses running from the default branch, so this is belt-and-braces at the seam). Pinned refusal text (MCP; CLI variant swaps the next-step commands and flag spelling; branch name is dynamic): "refusing to commit on 'main' - it is this repository's default branch, and an unplanned default-branch commit is almost always a wrong-checkout accident that then has to be untangled by hand. Create a feature branch first: madt_branch_create(branch=\"feat/<thing>\"). If this repository genuinely commits straight to its default branch, state that intent explicitly with allow_default_branch=true. Nothing was committed." Acceptance criteria: - Commit on default without override: refused with the pinned text, nothing committed, exit nonzero on CLI / tool error on MCP. - With override: commits exactly as today; override appears in the MCP call args (transcript-visible by construction). - Empty-repo initial commit: unaffected on both surfaces (existing init tests keep passing). - Feature-branch commits: byte-identical behavior to today. - Tool description, paramdocs, help topics, COMPARISON commit row, reference docs regenerated; server-instructions byte budget respected if touched. - Breaking for default-branch committers: called out for release notes. Depends on #222 (the ADR pins the tier and naming family this instantiates).
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
sixfold-space/madtea#223
No description provided.