From 2741e8b23903f3bc6bae8576e1fd30d3297c5a19 Mon Sep 17 00:00:00 2001 From: Bastien Chanot Date: Thu, 9 Jul 2026 11:30:58 +0200 Subject: [PATCH 1/3] fix(client-handover): gate push behind explicit GO + report-only fallback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit STEP 5 previously ran `git push origin "$CURRENT_BRANCH"` autonomously after the fix loops (gitflow-conformity §2b, verified HIGH). Now: - gitflow precondition: no develop / no lib -> skip commit+push, note in summary (report-only fallback). - push gated behind an explicit-GO AskUserQuestion (A push / B defer) BEFORE the push; red-flag STOP on push without GO / finish / merge. Core untouched: SEO/GEO/HARDEN/VALIDATE loops, scoring, doc + PDF branding. Dry-run (throwaway repos) — both sides of each fallback: CASE 1 report-only (no develop): DEVELOP_OK=no -> NO commit/push. PASS CASE 2 gate answer A: -> RUN git push origin feature/handover. PASS CASE 3 gate answer B: -> SKIP, push deferred; HEAD unchanged. PASS --- agents/client-handover-writer.md | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/agents/client-handover-writer.md b/agents/client-handover-writer.md index c1a3bfc..ffe8eb5 100644 --- a/agents/client-handover-writer.md +++ b/agents/client-handover-writer.md @@ -486,6 +486,19 @@ PENDING_CHANGES=$(git status --porcelain) If both empty → skip to STEP 6. +**Gitflow precondition (report-only fallback).** Before any commit or push, +confirm this is a gitflow repo: + +```bash +git rev-parse --verify -q develop >/dev/null 2>&1 && echo DEVELOP_OK +[ -f "$HOME/.claude/lib/gitflow.sh" ] && echo LIB_OK +``` + +If `develop` is missing OR the gitflow lib is unavailable → **do NOT commit, +do NOT push.** Leave the changes in the working tree and record in the STEP 8 +summary: "Commit/push skipped — no gitflow model in this repo; publish the +listed changes manually before deploy." Continue to STEP 6. + If `PENDING_CHANGES` non-empty → invoke /commit-change skill via subagent: > Dispatch `general-purpose` subagent. Prompt: @@ -498,7 +511,19 @@ If `PENDING_CHANGES` non-empty → invoke /commit-change skill via subagent: > commit). Use Conventional Commits format. After committing, return the > SHA list." -Then push: +Then, **before pushing, STOP and ask for an explicit GO** — the push is an +outward-facing action and never fires autonomously: + +> AskUserQuestion — "Changes committed on ``. Push to origin now? +> - A) Yes — push `` to origin +> - B) No — I'll push manually before confirming deploy" + +Only on **A** run the push; on **B** skip it and note "push deferred to user" +in the STEP 8 summary, then continue. + +> **Red flag — STOP:** never `git push` without option-A GO; never +> `gitflow finish`/`merge`. This pipeline commits and (on GO) pushes a working +> branch — it never integrates into a protected branch. ```bash CURRENT_BRANCH=$(git branch --show-current) From 9d9c55e87c36d3a4db16c98714a61cab0b7f096b Mon Sep 17 00:00:00 2001 From: Bastien Chanot Date: Thu, 9 Jul 2026 11:31:59 +0200 Subject: [PATCH 2/3] fix(commit-change): add gitflow aiguillage before commit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit-changer committed code autonomously with no branch precondition (gitflow-conformity §2a, verified MEDIUM CONFIRMED) — on develop/main it attempted a direct code commit, backstopped only by the pre-commit hook. Adds Phase 0: the same `gitflow-aiguillage.md` mechanism hotfixer/bugfixer/ feater already use (TYPE=chore) — branches to chore/* on a protected base, no-op on a working branch — plus a report-only fallback (no develop / no lib -> ask human, don't auto-branch). Commit-plan gate + scoped staging untouched. SKILL.md pre-flight notes the aiguillage. Dry-run (throwaway repos, REAL lib + REAL pre-commit hook) — both paths: CASE 1 on develop: aiguillage -> chore/commit-pending, code commit SUCCEEDS, hook never blocks; contrast: same commit direct on develop is BLOCKED -> aiguillage is what avoids it. PASS CASE 2 no develop: fallback -> no auto-branch, changes uncommitted, no chore/* created, ask human. PASS --- agents/commit-changer.md | 13 +++++++++++++ skills/commit-change/SKILL.md | 3 +++ 2 files changed, 16 insertions(+) diff --git a/agents/commit-changer.md b/agents/commit-changer.md index 67f627d..e7b4e95 100644 --- a/agents/commit-changer.md +++ b/agents/commit-changer.md @@ -18,6 +18,19 @@ on the amount and variety of changes — could be 1, could be 20. ## Workflow +### Phase 0: Gitflow aiguillage (before any commit) + +**Follow `$HOME/.claude/lib/gitflow-aiguillage.md` — your type = `chore`.** +On `main`/`develop` it branches first (to `chore/` derived +from the pending work) so the commits never land directly on a protected +base; on a working branch it's a no-op (commit in place). Never `finish`, +never `merge`, never `push` — this engine only commits. + +**Report-only fallback.** If `develop` doesn't exist or +`$HOME/.claude/lib/gitflow.sh` is unavailable, do NOT auto-branch: report the +current branch state and ask the user which branch to commit on before +proceeding. + ### Phase 1: Gather context Run these commands to understand the full picture: diff --git a/skills/commit-change/SKILL.md b/skills/commit-change/SKILL.md index 39fb879..9f4ce86 100644 --- a/skills/commit-change/SKILL.md +++ b/skills/commit-change/SKILL.md @@ -23,5 +23,8 @@ If unreachable, emit `Commit-changer agent missing.` and STOP. Never auto-commit Pre-flight checks (the agent should also perform, but flag here): - Detached HEAD or unmerged conflicts → STOP, report state. - Identity unconfigured (`git config user.email` empty) → STOP, ask user. +- On a protected base (`main`/`develop`) the agent runs the gitflow + aiguillage (Phase 0) and branches to `chore/*` before committing — code + never lands directly on a protected branch. $ARGUMENTS From 2533e10ccb0803354bc079d75769de6e3754677f Mon Sep 17 00:00:00 2001 From: Bastien Chanot Date: Thu, 9 Jul 2026 11:33:51 +0200 Subject: [PATCH 3/3] =?UTF-8?q?chore(memory):=20LRN-118=20=E2=80=94=20gitf?= =?UTF-8?q?low-conformity=20audit=20(commits-code=20vs=20applies-defers=20?= =?UTF-8?q?discriminator=20+=20phantom-ref/dry-run-both-sides=20discipline?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .claude/memory/learnings.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.claude/memory/learnings.md b/.claude/memory/learnings.md index 411692f..beae9d0 100644 --- a/.claude/memory/learnings.md +++ b/.claude/memory/learnings.md @@ -1188,3 +1188,11 @@ rules: - **fix**: at release-finish / in /reconcile, list `develop..release/*` commits touching functional files (exclude merges, `.claude/**`, version.txt/CHANGELOG) and present them for back-merge review. Advisory, NOT a hard make-test gate — cherry-picks land with new SHAs so the source commit stays in the range; automatic "already-ported?" equivalence is unreliable and would false-positive. Backlogged. - **future application**: any long-lived fork (release/*, long feature) — audit CODE divergence, not just declared/registry state ([[LRN-034]] narrated ≠ ground truth, applied to branches). - **cousin**: [[LRN-116]] (a resolved blocker's fix can be missing from develop), [[BDR-054]] (supersession-trace discipline). + +## LRN-118 — Gitflow-conformity audit: "commits-code" vs "applies-but-defers-commit" is the line that sorts real findings from false positives +- **pattern**: audited 52 units (33 skills + 19 agents) for gitflow conformity. Raw git-signal grep over-flags: `git add -A`, `gitflow finish`, `--no-verify` mostly appear inside PROHIBITION tables ("never …"), not usages — reading context killed every one (harden/web-validate `--no-verify` = bans; capitalize `git add -A` = ban; tour `gitflow finish` ×3 = red-flags). The decisive discriminator was NOT "does it write code?" but "does it autonomously `git commit`/`push`?": seo/geo/harden/web-validate/code-clean/refactor/doc all EDIT code/public-doc yet defer the commit to the human (or have NO `git commit` path at all) → safe by construction, gitflow layer N/A. Only 2 units both wrote AND committed without a branch precondition: commit-change (commits code, no aiguillage) and client-handover (autonomous `git push`). 0 MERGES-ALONE, 0 BYPASSES-HOOK. +- **why it matters**: a conformity audit that classifies on "writes code" drowns in false positives; classify on "reaches an autonomous commit/push" and the surface collapses to the few units that can actually corrupt a branch. Thin-dispatcher skills (20-line SKILL.md → agent + commit lib) must be judged as skill+agent+lib triples — the discipline lives in the agent/lib (e.g. /doc's gitflow layer is in doc-syncer + doc-commit.sh, not SKILL.md). +- **the net**: empirically the per-repo pre-commit hook BLOCKS a non-`.claude/` code commit on main/develop (exit 1), exempts `.claude/**`, allows working branches; `--no-verify` bypasses it client-side → Gitea server-side branch protection is the real backstop. So the 2 findings fail LOUD (hook), never corrupt develop — remediation = make them branch cleanly first (aiguillage / GO-gated push), not incident-urgent. +- **fix applied**: commit-change got Phase 0 = the shared `gitflow-aiguillage.md` (TYPE=chore, branch on protected base, no-op on working) + report-only fallback; client-handover push gated behind explicit-GO AskUserQuestion + report-only fallback. Dry-runs proved BOTH sides of each fallback (branch-taken AND not-taken), not just the happy path. +- **future application**: any fleet/skill conformity audit — (1) triage by "autonomous commit/push reached?", not "file written?"; (2) read every git-signal in context (prohibition vs usage); (3) test the deterministic backstop empirically before trusting it; (4) verify a referenced lib exists + its contract matches BEFORE copying it (phantom-reference guard); (5) dry-run both branches of every fallback. +- **cousin**: [[LRN-117]] (orphaned CODE has no sequence to check), [[LRN-034]] (narrated ≠ ground truth), [[BDR-061]] (report-only agent tool-grants).