From ff0aaea7a77cb5fd5a88019441adb5be15c40d91 Mon Sep 17 00:00:00 2001 From: Christoph Date: Fri, 24 Jul 2026 11:08:22 +0200 Subject: [PATCH] fix(intake): DCO skips merge commits The DCO check counted every commit in the PR range, so a routine update of a branch with its base (or the GitHub Update branch button) added an unsigned merge commit that failed DCO with no clean fix: a merge commit cannot be signed without rewriting history. Build the commit list with --no-merges, matching the DCO convention. Guard the flag in the intake self-test. Signed-off-by: Christoph --- .github/asdd/intake-check.test.sh | 9 +++++++++ .github/workflows/asdd-intake.yml | 6 +++++- CHANGELOG.md | 4 ++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/.github/asdd/intake-check.test.sh b/.github/asdd/intake-check.test.sh index 62d9a55..9677c72 100755 --- a/.github/asdd/intake-check.test.sh +++ b/.github/asdd/intake-check.test.sh @@ -210,4 +210,13 @@ jq -e '.problems | map(select(startswith("Convention:"))) | length > 0' "$CONVW/ conv_case "a clean change passes the conventions gate" "$CONVCFG" "# a clean added line" true true conv_case "no conventions block is inert even with the banned char present" "$TREE/asdd-default.yml" "# note ${DASH} here" true true +# DCO must skip merge commits: the intake workflow builds the commit list with --no-merges, or a routine +# branch-update merge (unsignable without rewriting history) fails DCO. Guard that the flag stays. +WF="$DIR/../workflows/asdd-intake.yml" +if grep -q -- '--no-merges' "$WF" 2>/dev/null; then + echo " ok intake commit list excludes merge commits (DCO skips merges)" +else + echo " FAIL intake commit list missing --no-merges (a branch-update merge would fail DCO)"; fail=1 +fi + [ "$fail" = "0" ] && { echo "intake-check self-test: PASS"; exit 0; } || { echo "intake-check self-test: FAIL"; exit 1; } diff --git a/.github/workflows/asdd-intake.yml b/.github/workflows/asdd-intake.yml index 31705b7..0cd2f78 100644 --- a/.github/workflows/asdd-intake.yml +++ b/.github/workflows/asdd-intake.yml @@ -64,7 +64,11 @@ jobs: # empty (and the DCO check see 0 commits). --depth covers the PR's commit range. git fetch --no-tags --depth=200 origin "+refs/pull/${PR_NUMBER}/head:refs/asdd-pr-head" "$BASE_SHA" HEAD_SHA="$(git rev-parse refs/asdd-pr-head)" - git log "$BASE_SHA".."$HEAD_SHA" --format='%B%x00' > .asdd-work/commits.txt + # --no-merges: DCO signs off authored changes, not merge commits. A merge commit carries no + # change of its own and cannot be signed without rewriting history, so counting it would make a + # routine "update this branch with main" (or the GitHub "Update branch" button) fail DCO with no + # clean fix. Excluding merges matches the DCO convention (the DCO app skips them too). + git log --no-merges "$BASE_SHA".."$HEAD_SHA" --format='%B%x00' > .asdd-work/commits.txt # Changed files (for the spec-gate: did the PR add/edit a spec?). Names only. Which paths ARE # specs comes from the base .asdd.yml's `spec_paths:`; intake-check.sh does that match. # --name-status (not --name-only): the spec gate must count an ADDED/MODIFIED spec, not a diff --git a/CHANGELOG.md b/CHANGELOG.md index 7774059..8b34667 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,10 @@ draft, so pin a conformance claim to a commit or date. extraction and a reasoning model's review could fail. It now travels with the runtime. - **`connect-check` pings with a real token budget.** A one-token ping made some reasoning models return HTTP 500, false-failing a reachable model; the ping now uses a small but sufficient budget. +- **DCO skips merge commits.** The intake DCO check counted every commit in the range, so a routine + "update this branch with main" (or the GitHub "Update branch" button) added an unsigned merge commit + that failed DCO with no clean fix, because a merge commit cannot be signed without rewriting history. + The commit list is now built with `--no-merges`, matching the DCO convention. - **Model calls fall back to `max_completion_tokens`.** A newer OpenAI reasoning model rejects `max_tokens` with a 400 asking for `max_completion_tokens`, so `connect-check` reported it dead and the developer council could not call it. Both now send `max_tokens` first and retry once with the renamed parameter on