fix(pull-base): arg-bearing /clear skips the pull; no-identity refusal blocks even a fast-forward #151
Labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Cloonar/coding-lab#151
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Two narrow gaps in the
/pull-baselab command, both found while landing PR #150 (issue #149). Neither is a regression — each degrades to the pre-#149 behaviour — but both defeat the pull in cases the design intended to cover.1. An arg-bearing clear silently skips the pull
isClearCommandmatches the provider'srole=clearentry by exact string equality:But claude-code's clear entry carries an argument hint:
So
/clear my-sessionfails the exact match, falls through to the ordinary reply path, and is forwarded to the provider without a base pull and without a notice. The operator gets a fresh context on a stale base — the precise failure #149 exists to prevent — with no indication it happened.The bare
/clear(the common case) works correctly. This matters more than it first looks because the autocomplete gesture model (#122) makes an arg-hinted command insert rather than send on click, which actively invites the operator to type a name.Codex is unaffected: its clear-role
/newcarries noArgHint.Fix sketch: match on the command word rather than the whole string — split
cmdat the first whitespace and compare the head to"/"+c.Name. The/pull-baseinterception above it already distinguishes bare from arg-bearing (exact match, then a"/pull-base "prefix → 400), so the two paths should agree on how a command word is recognised. Decide explicitly whether an arg-bearing clear pulls-then-forwards-verbatim (preserving the argument) — that is almost certainly the intent.2. The no-identity refusal fires even for a fast-forward
The refusal runs before any git does, so a repo with neither
git_author_name/git_author_emailnor the global settings pair can never/pull-base— even when the pull would trivially fast-forward, which authors no commit and needs no identity at all. The identity is only genuinely required on the diverged path, where a merge commit gets written.The check was inherited from crmerge, where every merge does author a commit, so the up-front refusal is right there. Here it over-refuses.
Fix sketch:
gitx.PullBasealready computesffablebefore merging. Either defer the identity check to the diverged branch, or keep the early check but let it pass when the pull turns out to be a fast-forward. Note the ordering constraint: the ff-ness is only known after the fetch, so the check has to move below it rather than being deleted.Acceptance
/clear <arg>pulls the base before forwarding, and the argument survives the forward./pull-basewhen the result is a fast-forward; the diverged case still refuses withErrNoAuthorIdentity.Landing audit — PR #153 → PASS
Verification signal relied on: Forgejo Actions CI,
ci / native (pull_request)— success (5m20s, run 167). Not re-run locally.Checked:
fix(pull-base): word-match the clear hook; defer no-identity refusal to diverged pullsis Conventional Commits; headafk/151carries a workingCloses #151. Single commit, no conflict withorigin/main(clean merge-tree against the post-#155 tip).commandWord(first token,unicode.IsSpace) now drives both dispatch paths, as the issue sketched./clear my-sessionmatches the clear hook, pulls, then forwardsreq.Textverbatim (the original untrimmed text, argument intact) viahandleClearWithPull— the "pull-then-forward-preserving-the-argument" intent the issue asked to decide explicitly./pull-basebare executes; any argument, space- or tab-separated, 400s.gitx.PullBase, gated on!ffable. Verified the predicate is sound: theupToDateshort-circuit (isAncestor(base, HEAD)) returns beforeffableis computed, so a worktree merely ahead of an unchanged base — also not ff-able, also needing no commit — exits early and is never caught by the new refusal.!ffableat that point genuinely means diverged. The refusal lands beforerunPullMergetouches the worktree, andinternal/pullre-flagsgitx.ErrAuthorIdentityRequiredas its ownErrNoAuthorIdentity, so the 409 classification is unchanged.TestAPI_ClearHook_argBearingClearPulls,TestAPI_ClearHook_prefixIsNotClear(/clearxis not/clear+arg),TestAPI_PullBase_tabArgRejected, plus gitx/pull-service pairs for ff-empty-identity-succeeds / diverged-empty-identity-refused.Findings: none blocking. Scope matches the issue exactly — no divergence, no scope creep.