From 4e7f6b0951a293accfc8c0745af3dde54e9e45ba Mon Sep 17 00:00:00 2001 From: Bastien Chanot Date: Fri, 3 Jul 2026 14:03:12 +0200 Subject: [PATCH] chore(memory): BLK-015 + LRN-089 + LRN-047 corrob + journal 2026-07-03 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gitflow_finish arg-guard bugfix + 3 doctor false-warns. BLK-015 (finish ignored args → merged current branch), LRN-089 (pass-through wrapper deriving target from ambient state = silent contract violation), LRN-047 corroborated (doctor false-warns), TODO items closed. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01XpphkdTosUzokBDNG7PToS --- .claude/memory/blockers.md | 10 ++++++++++ .claude/memory/journal.md | 6 ++++++ .claude/memory/learnings.md | 9 +++++++++ .claude/tasks/TODO.md | 17 +++++++++++++++++ 4 files changed, 42 insertions(+) diff --git a/.claude/memory/blockers.md b/.claude/memory/blockers.md index 3d04ef0..761c3e9 100644 --- a/.claude/memory/blockers.md +++ b/.claude/memory/blockers.md @@ -34,6 +34,7 @@ rules: | BLK-012 | 2026-06-29 | gitflow_init half-applied: socle-commit failure swallowed → hook activated on partial run → re-run self-blocks | resolved | | BLK-013 | 2026-06-30 | `make plugin` Error 127 — npm absent on apt-`nodejs` host (Step 4 gsd-pi aborts, Steps 5-10 + residual cleanup never run) | resolved (env) | | BLK-014 | 2026-07-01 | `make install` aborts npm EEXIST on `~/.local/bin/claude` when claude already installed via native installer — no presence guard | resolved | +| BLK-015 | 2026-07-03 | `gitflow_finish` ignored its ` ` args → merged the CHECKED-OUT branch not the one named → wrong-branch merge (audit LOT3) | resolved | --- @@ -179,3 +180,12 @@ rules: - **Status**: resolved. Fix `8dc4027`, branch `bugfix/install-claude-idempotent`, pending merge validation. - **Reference**: [[BLK-013]] npm prefix `~/.local` = contributing factor (npm bin over native bin). install-plugins.sh already pointed to code.claude.com (native) — install.sh was the npm outlier. Fresh-machine `elif npm` branch channel-consistency = open design question (potential BDR). Pattern → [[LRN-085]]. - **Update 2026-07-01**: MERGED `2393ca5` (bugfix/install-claude-idempotent → develop), pushed — supersedes "pending merge validation". The open channel-consistency question is RESOLVED by [[BDR-046]] (fresh install → native installer, npm dropped for claude); install.sh has no `elif npm` branch → nothing left to trancher. + +## BLK-015 — `gitflow_finish` ignored its args, merged the CURRENT branch not the one asked + +- **Date**: 2026-07-03 +- **Friction**: audit 2026-07-02 — `gitflow.sh finish bugfix audit-bugs` run while checked out on `feature/audit-tokens` merged audit-tokens (LOT3), NOT audit-bugs. Final develop state identical (disjoint hunks) so no data damage, but the merge order was silently wrong. UX trap: the command LOOKS like it targets `bugfix/audit-bugs`. +- **Real cause**: CLI dispatch (`lib/gitflow.sh:257` `finish) gitflow_finish "$@"`) forwards args, but the function derived its source from `HEAD` (`git symbolic-ref`) and NEVER read `$1/$2` → the ` ` were silently dropped. Merge source = ambient state (checked-out branch), not the named target. Design intended finish to always operate on HEAD (human gate = "be on the branch"), but nothing enforced that passed args, if any, MATCH the branch you're on. +- **Solution**: `gitflow_finish [ ]` — args now an optional safety ASSERTION: present AND `"$req_type/$req_name" != "$br"` → error `operates on the current branch 'X', but you asked 'Y' — checkout 'Y' first`, rc 2. No args = behavior unchanged (only real caller `skills/gitflow/SKILL.md:36` + every test pass none → zero regression). +7 regression assertions (`gitflow-test.sh` T12, numbered to dodge collision with reconcile's own T6c). +- **Status**: resolved. Commit `d9fdd4c`, branch `bugfix/gitflow-finish-args`. +- **Reference**: journal 2026-07-02 (trap noted, not fixed) → fixed 2026-07-03. Pattern → [[LRN-089]] (pass-through wrapper deriving target from ambient state = silent contract violation). diff --git a/.claude/memory/journal.md b/.claude/memory/journal.md index 49abc38..895c878 100644 --- a/.claude/memory/journal.md +++ b/.claude/memory/journal.md @@ -302,3 +302,9 @@ rules: - #11 rtk auto-allow DROPPED — permission control back in settings.json (rtk registry was a parallel authority bypassing deny/ask). #10 rules/context7.md deleted (−493 tok; find-docs survives, stable — regen keyed on its absence); faulty examples → upstream issue draft (upstash/context7, gh unauthenticated). plugin-dev uninstalled + dropped from installer. - Incidents: magic API key printed into transcript from ~/.claude.json → rotated, [[BDR-026]] update (copies of secrets); gitflow_finish ignores its args (operates on CURRENT branch, lib/gitflow.sh:104) → LOT 3 merged first by mistake, final develop state identical (disjoint hunks) — UX trap noted, not fixed. - Residuals (flagged, not built): doctor "Cargo not found (RTK unavailable)" parenthesis now misleading; doctor symlink-check false-warns on dir-level symlinks; doctor token constants stale; find-docs faulty examples ctx7-owned. + +## 2026-07-03 +- bugfix/gitflow-finish-args: `gitflow_finish` contract fix — args now optional safety ASSERTION (present + ≠ current branch → refuse rc2 "operates on current branch X, you asked Y — checkout Y first"); no-args unchanged (only real caller SKILL.md:36 + all tests pass none → zero regression). +7 T12 assertions. [[BLK-015]], [[LRN-089]]. Off-by-one caught at capitalize: next free BLK = 015 not 016 (gate proposal said 016) → gitflow.sh comment corrected pre-finish via soft-reset+redo of the 3 commits. +- Same branch, 3 doctor false-warns fixed ([[LRN-047]] corrob — a doctor that cries false is ignored): cargo "(RTK unavailable)" → optional info (RTK prebuilt, detect_rtk); check_symlink passes children of dir-level symlinks (hooks/session-start.sh); gstack counts 34 per-skill symlinks not a mythical skills/gstack link (link.sh removes it); token budget vs 200k context window not bogus 11k "session budget" → killed false "92% CRITICAL" (measured ~11.4k [[LRN-088]]; 200k confirmed by user — 1M pin revoked at audit #7, calibrate on default not the exceptional session). +- Suites green: gitflow 71/71 (+7), deterministic 13, doc-commit 32, doc-shape 19, reconcile 20, deploy-commit 13, release-candidate 5/5 tag-mode. doctor: 0 false-warn (1 legit survivor = gstack tracks branch=main advisory). shellcheck clean. T12 named to dodge collision with reconcile's own T6c (darwin path, audit #3). +- 3 atomic commits (fix gitflow / fix doctor / docs changelog Unreleased) + memory. finish bugfix→develop on GO; user pushes develop. diff --git a/.claude/memory/learnings.md b/.claude/memory/learnings.md index fe97b0d..16e7585 100644 --- a/.claude/memory/learnings.md +++ b/.claude/memory/learnings.md @@ -108,6 +108,7 @@ rules: | LRN-086 | 2026-07-02 | External-tool-generated skill: prove provenance by mtime (not repo grep), gitignore + regen via install-step; guard regen on ABSENCE when the tool co-writes a user-editable config | any untracked skill/dir a tool (ctx7, etc.) drops into the repo | | LRN-087 | 2026-07-02 | presence-flag ≠ capability — rtk silently dead after .bashrc wipe; emitted commands need ABSOLUTE bin paths (they run in another shell); integrity pin = live machinery, re-pin on hook edit | any PATH-dependent capability + hand-managed shell profile; hooks emitting commands for another shell | | LRN-088 | 2026-07-02 | token-cutting intuition inverts under measurement — verbosity beats cardinality (gstack 34 skills ≈ 592 tok vs pr-review 6 agents ≈ 2,183) | any "disable X to save tokens" — measure per-item bytes first; profiles toggle skills, not plugin payloads | +| LRN-089 | 2026-07-03 | pass-through wrapper (CLI `"$@"` → fn deriving target from ambient state: HEAD/cwd/env) silently ignores its args = silent contract violation; guard = args are an ASSERTION, refuse when they disagree with state | any dispatcher forwarding args to a callee that reads ambient state instead of the args | --- @@ -956,3 +957,11 @@ rules: - **actions taken**: pr-review-toolkit OFF by default (−2,183; audit.profile keeps it = reactivation channel), 10 fattest personal descriptions compressed 6,416→4,243 chars (−~540), context7 rule dropped for the find-docs skill (−493; skill body loads on-demand, stable — regen keyed on find-docs absence). Total ≈ −3.2k/session ≈ −22%. - **future application**: before any "disable X to save tokens" → measure per-item bytes FIRST (frontmatter extraction, plugin cache); expect the fat where descriptions are hand-written rich, not where items are many. Profiles toggle SKILLS only — plugin payloads (agents/skills in cache) need `enabledPlugins`. [[LRN-080]] measure-first corroborated on a new axis (cost, not behavior). - **Reference**: audit 2026-07-02 measurement + branch feature/audit-tokens. See [[BDR-014]], [[LRN-043]]. + +## LRN-089 — a pass-through wrapper whose callee reads ambient state silently ignores its args + +- **Date**: 2026-07-03 +- **pattern**: a CLI/dispatcher that forwards `"$@"` to a function which derives its TARGET from ambient state (HEAD, cwd, env, "current X") rather than from those args → the args are silently dropped. The call SITE looks parameterized (`finish bugfix audit-bugs`) but the callee acts on whatever state it's standing in → wrong-target action, NO error. `gitflow_finish` read `HEAD`, never `$1/$2`; `finish bugfix X` from another branch merged that other branch. +- **context**: audit 2026-07-02, `lib/gitflow.sh:257` `finish) gitflow_finish "$@"` passed args the function never consulted. Surfaced when a finish "for" one branch merged another (LOT3). [[BLK-015]]. +- **future application**: any wrapper/dispatcher forwarding args to a callee that resolves its target from ambient state — either (a) make the callee USE the args as the target, or (b) if the ambient-state contract is deliberate, treat passed args as an ASSERTION and refuse loudly when they disagree with the state. Never let forwarded args be silently dropped: silent-drop = the caller believes they steered, the callee ignored them. Sibling of "presence-flag ≠ capability" [[LRN-087]] — both = a visible signal lying about the real behavior. +- **Reference**: `lib/gitflow.sh` gitflow_finish arg-guard, `lib/gitflow-test.sh` T12. [[BLK-015]]. diff --git a/.claude/tasks/TODO.md b/.claude/tasks/TODO.md index 9a7d040..867f37d 100644 --- a/.claude/tasks/TODO.md +++ b/.claude/tasks/TODO.md @@ -393,3 +393,20 @@ Tension réelle proactif vs intrusif. Auto-déclencher feat/bugfix sur intention [done 2026-07-01 : unconditional npm guard after Node block (corepack enable npm → distro `install npm` fallback → fatal exit 1 w/ clear msg). Catches node>=22-present-but-npm-absent (NODE_OK short-circuit). shellcheck clean, bash -n OK. Fresh-apt live validation pending (no npm-less host to hand). branch bugfix/install-plugins-npm-guard.] - [x] (b) Re-baseline darwin on the 5 ex-broken gstack skills (`benchmark-models`, `context-restore`, `context-save`, `make-pdf`, `plan-tune`) — now repaired and back in scope ([[BDR-043]], trigger cleared). Verify `results.tsv` still marks them `status=error` first. (Promoted from BDR-043's action-field — not an item the user authored.) [resolved-MOOT 2026-06-30 : won't-run. BDR-043 cleared only motif (a) of BDR-015's TWO exclusion grounds (symlinks repaired ✅); motif (b) external-ownership INTACT — the 5 resolve to skills-external/gstack/ (submodule), darwin optimizes by EDITING SKILL.md → would dirty the submodule (forbidden [[LRN-070]]). Re-baseline = unactionable score. + results.tsv gone (wiped by 23/06 make-plugin reinstall) → not even a re-baseline, a fresh-from-zero one. Geometric trigger lifted, value trigger intact — twin of --help [[LRN-080]]. See [[LRN-082]]. Not "done", not "open": MOOT.] + +## 2026-07-03 — bugfix/gitflow-finish-args (contract fix + doctor false-warns) +Root: audit 2026-07-02 residuals. `gitflow_finish` ignores its args (merges CHECKED-OUT +branch) → LOT3 mis-merge trap; + 3 doctor false-warns (LRN-047 class). +- [x] (1) lib/gitflow.sh gitflow_finish — optional ; error rc2 if != current + branch ("operates on current branch X, you asked Y — checkout Y first"). No-args unchanged. + Commit d9fdd4c. [[BLK-015]] [[LRN-089]]. +- [x] (2) lib/gitflow-test.sh — T12 arg-guard: arg-mismatch → nonzero + message names both; + arg-match → merges as before. +7 assertions (71/71). T12 (not T6c — reconcile collision). +- [x] (3) doctor.sh cargo line — false "(RTK unavailable)" → optional info (RTK prebuilt). +- [x] (4) doctor.sh check_symlink — PASS iff canonical path under $REPO (direct OR via + symlinked ancestor dir); hooks/session-start.sh false-warn gone. Commit 6778b9f. +- [x] (5) doctor.sh §2 gstack — counts 34 per-skill symlinks; mythical [ -L skills/gstack ] dropped. +- [x] (6) doctor.sh token § — denominator 11000→CONTEXT_WINDOW=200000, thresholds 15/25, + comment anchored to measured ~11.4k (LRN-088). False "92% CRITICAL" → ~5% comfortable. +- [x] Verify — suites green (71/13/32/19/20/13 + RC 5/5); doctor 0 false-warn; shellcheck clean. + +docs(changelog) Unreleased entry (706abff). Gate passed on GO 2026-07-03. Finish pending.