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). 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) 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