chore(memory): BDR-034 + LRN-051/052 + EVAL-007 — coupled-capitalize v1

This commit is contained in:
Bastien Chanot 2026-06-26 13:27:57 +02:00
parent 037e14dacc
commit 07e846f0a6
5 changed files with 61 additions and 0 deletions

View File

@ -44,6 +44,7 @@ rules:
| BDR-020 | 2026-06-11 | `/audit-delta`: per-axis SHA markers + always-on fix gate + unreachable-first-run = full report-only | accepted |
| BDR-022 | 2026-06-18 | doc-syncer scoped to public docs; `.claude/` + `CLAUDE.md` read-only context, never targets; conventions + clean mode | accepted |
| BDR-023 | 2026-06-19 | Merge /close into /capitalize — 2 modes + TODO reconcile; /close alias | accepted |
| BDR-034 | 2026-06-26 | Coupled-capitalize invariant v1 — memory commit auto per dev flow (Frame 2) | accepted |
---
@ -538,3 +539,16 @@ rules:
- Blocking yes/skip prompt à la `/onboard` STEP 2.5 — a 2nd STOP mid-build on an optional dep.
- Prose "agent remembers not to re-suggest" — fragile behavioral guard, contradicts [[LRN-046]]/[[LRN-047]].
- **Reference**: commit `11792cc`, `lib/design-gate.md` §4 + §DETECTION (`+motion`/`+animate`). Helper `lib/animation-lib-check.sh` unchanged. Live via symlink (`~/.claude/lib/`→repo). Builds on [[BDR-005]]. See [[LRN-049]].
## BDR-034 — Coupled-capitalize invariant v1 — memory commit auto per dev flow (Frame 2)
- **Date**: 2026-06-26
- **Status**: accepted
- **Decision**: Dev flows committing code now auto-commit memory same breath, via include `lib/capitalize-commit.md` + helper `lib/memory-commit.sh` (surgical: stages+commits `.claude/memory`+`.claude/tasks` only, pathspec, never `git add -A`). 4 inline flows (feat/hotfix/bugfix/commit-change) ref the include at their capitalize step; ship-feature reordered (CAPITALIZE STEP 7 before FINISH STEP 8 — fixes memory committed after push/PR + stranded outside it); init-project gains STEP 10b founding-decisions capitalize. 1 memory commit/flow (F3). Capitalize CONTENT keeps its approval gate — only the COMMIT of approved entries is automated.
- **Why**: Real pain = the 2nd (memory) commit forgotten/manual — ~42% of recent history (17/40 commits) was emergent `chore(memory)`. Frame chosen = "couplé après-code" not "avant commit": keeps hash-anchoring (>50% entries carry `Reference: commit`) + code/memory concern separation; attacks the forgetting, not the ordering. "Capitalize before commit" rejected — inverts a deliberate property AND can't anchor the code hash (hash exists only post-commit).
- **Alternatives rejected**:
- (a) each orchestrator calls capitalize-before-commit — duplicated across 5+ flows (each has bespoke inline capitalize), breaks hash-anchoring, forgettable on next skill added.
- (b) commit-change as the single gate — not on the path of feat/hotfix/bugfix/ship-feature/init-project (they commit inline or via external superpowers); can't detect "pending capitalize".
- (c) single commit chokepoint — doesn't exist; 3 distinct commit mechanisms, one external/unmodifiable (`superpowers:finishing-a-development-branch`).
- Frame 3 (single unified commit, drop hash) — sacrifices >50% entries' anchoring for history aesthetics.
- **Reference**: commits `58cb91d` (helper+tests) · `bbef41c` (hash/stdout + T6/T7) · `b44791b` (include) · `2763678` (4 flows) · `e8eff7e` (ship-feature reorder) · `df60df6` (init-project). Hook (v2, Stop-hook non-blocking BDR-033-style) + doc-sync twin chantier (same PR bug, reorder before FINISH) deferred. See [[LRN-051]], [[LRN-052]], [[EVAL-007]].

View File

@ -27,6 +27,7 @@ rules:
| EVAL-004 | 2026-06-11 | darwin eval 26 perso skills + 4-bug fix round | keep |
| EVAL-005 | 2026-06-23 | Obsolete `claude --effort max` alias missed across Step 9 edits | correct |
| EVAL-006 | 2026-06-25 | prune-memory v1.1 TDD — 6 guards (0a3e766), validated on real data | keep |
| EVAL-007 | 2026-06-26 | Coupled-capitalize machinery — TDD 13 + e2e, surgical scope proven | keep |
---
@ -86,3 +87,12 @@ rules:
- **Method**: run-deterministic all-green (RED-1/2/5/6); RED-3/4 by single faithful subagent runs on throwaway fixtures (deterministic oracles — byte-identical + layer-(a) substring; N=6 tolerance-zero fleet documented in run-behavioral.md, NOT exhausted — 1 run sufficed to prove presence then closure); REAL-data re-test on live learnings.md (602 l): fidelity 0 false-positive vs old line-grep 13, census PROVEN counting both sides (HEAD/WORK not=107/114, no=64/71, never=34/34 — no category dropped). Scope held (only learnings.md), reverted after (measurement, not a kept prune). Clean tree verified first; git + cp backup.
- **Anomalies**: (1) SAFE ≠ USEFUL — compression (pass C) marginal on already-caveman dense content (~3.6% trim, registry GREW); real value = index-drift (D found 19 missing Index rows on the real learnings.md, measured then reverted) + merge (B), not C on dense. (2) RED-8 OPEN — fidelity proves "no negation DELETED", not "none ADDED wrongly"; visible empirically (not/no +7 in the measurement, passed under the drop-radar); remote (compression subtracts) but real. (3) RED-7 OPEN — merge LRN-014+016 maybe PRIMED by the SKILL.md example, not real overlap; verify. (4) two guard bugs caught by VALIDATION not logic: awk `\<` unsupported (mawk) → not/no counted 0; `NR==FNR` blind when working census empty = the deletion case → both fixed + re-validated. (5) REAL ANCHOR FOR PASS D — this very evals.md had EVAL-005's Index row MISSING (pre-existing drift), exactly what the skill's D pass auto-corrects; hand-backfilled in a separate `fix(memory)` commit. learnings.md likewise carries 19 missing Index rows (deferred to an intentional prune). D is NOT theoretical.
- **Action**: keep — safe, useful for B/D, compression marginal on dense (documented limit). `Fixed in v1.1 (TDD found it)` WAS the RED-1 defect (claim of a verify never run); TDD note now TRUE (real suite passes). Patterns → LRN-046/047/048; open items → tests/BACKLOG.md (RED-7/RED-8).
## EVAL-007 — Coupled-capitalize machinery (helper + include + 6 flows)
- **Date**: 2026-06-26
- **Output**: `lib/memory-commit.sh` + `lib/capitalize-commit.md` + wiring of 6 dev flows for the coupled-capitalize invariant (BDR-034).
- **Method**: TDD — RED harness first (helper absent → fail), then 13 deterministic tests (`lib/tests/run-deterministic.sh`): T1/T2 dangling code (untracked + pre-staged) not embarked, T2-bis stale-staged memory → working-tree committed, T3 idempotent no-op, T4 fail-closed on broken git state (exit 3), T5 TODO.md in scope, T6 stdout contract 3-case (hash/empty/empty), T7 double-run = at most one commit. Plus in-vivo e2e (code commit → capitalize writes memory → include commits it: 3 commits, memory commit `.claude/` only, dangling untouched, mem_hash ≠ code_hash). `shellcheck lib/*.sh` clean.
- **Anomalies**: (1) `git commit -- pathspec` strict-on-no-match — caught by real-exec, would have silently aborted the commit on the majority of flows (any run where one scoped path is clean) → fixed by `_changed_paths` BEFORE integration ([[LRN-051]]). (2) v1 helper emitted no clean hash → caught at include design (the reported `<hash>` would have been aspirational) → added `bbef41c` (hash→stdout, diag→stderr), proven by T6. Both caught by exec/review, not assumed.
- **Action**: keep.
- **Reference**: commits `58cb91d`..`df60df6`.

View File

@ -201,3 +201,8 @@ rules:
- TDD'd `/prune-memory` (only destructive skill, untested + carried a false `Fixed in v1.1 (TDD found it)` claim): 6 dangers (RED-1..6) closed by deterministic guards, skill `0a3e766`. Real-data run on learnings.md exposed SAFE≠USEFUL (compression marginal on dense; value = index/merge, not C) + a 13/13-false-positive line-grep fidelity guard → replaced by a per-entry count census (0 FP, proven counting both sides). RED-7 (example-priming) + RED-8 (added-negation) filed in BACKLOG. EVAL-006, LRN-046/047/048.
- Wired `design-gate.md` §4: anim-lib suggestion when a design task hits a motion signal — suggest-only, non-blocking, stateless 1-line (no marker). `motion`/`animate` added to §DETECTION (source). Chose stateless-minimal over a state marker, conditional on stakes: a 1-line cosmetic note's re-fire is annoyance not risk → no marker-grade infra (unlike LRN-046/047's destructive context). Helper unchanged, no 3rd copy of the lib list. Live via symlink. BDR-033, LRN-049.
- Process: caught "write-before-show" twice this session on a live (symlinked) file → on edit=deploy targets the pre-write diff is the only control gate → inverted to show→validate→write. LRN-050.
## 2026-06-26
- Coupled-capitalize invariant v1: dev flows auto-commit memory via include `lib/capitalize-commit.md` + helper `lib/memory-commit.sh` (surgical pathspec, never `-A`; hash→stdout). Frame 2 (après-code-couplé, hash-anchoring kept, 2 commits, memory commit automatic per flow). 6 commits `58cb91d..df60df6`. BDR-034, LRN-051/052, EVAL-007.
- Caught `git commit -- pathspec` strict-on-no-match by real-exec test (would silent-abort on majority of flows) → `_changed_paths` filter (LRN-051). ship-feature reordered CAPITALIZE→before FINISH (fixes memory stranded outside PR). init-project STEP 10b founding decisions (no hash by nature, LRN-052). Hook v2 + doc-sync twin chantier deferred.
- TDD: 13 deterministic + in-vivo e2e, shellcheck clean (EVAL-007). Pre-existing Index drift (decisions 11, learnings 21 rows missing) noted for /prune-memory — not backfilled here.

View File

@ -49,6 +49,8 @@ rules:
| LRN-046 | 2026-06-25 | Destructive skill: deterministic oracle (byte-identical / count census) > semantic judge | any destructive/irreversible skill; behavioral-oracle TDD |
| LRN-047 | 2026-06-25 | A noisy safety guard (13/13 FP) = a guard you learn to ignore = risk → refine, don't tolerate | any guard/alert/lint that can false-positive |
| LRN-048 | 2026-06-25 | A "0/OK/pass" must prove it LOOKED (counted both sides), else verify hard-wired to pass | any verify/test/lint reporting success |
| LRN-051 | 2026-06-26 | `git commit -- pathspec` strict on no-match → filter scoped commits to changed paths | any scoped-commit automation |
| LRN-052 | 2026-06-26 | Hash-anchoring: 2 cases it does NOT apply (pre-code founding, squash-merge) | capitalizing founding/arch decisions; squash repos |
---
@ -643,3 +645,19 @@ rules:
- **Context**: this session twice wrote-then-showed on `lib/design-gate.md` (live via symlink). Both harmless (non-destructive), but the pattern would bite on a destructive live edit. User flagged it → inverted to show→validate→write.
- **Future application**: before editing any file, check if it is live (`readlink -f`, compare to `~/.claude/`); if live, treat the pre-write diff as a mandatory approval gate, not an optional preview. Generalizes to any "edit = deploy" target (dotfiles, served config, hot-reloaded sources).
- **Reference**: `lib/design-gate.md` (symlink → `~/.claude/lib/`). Sibling to [[LRN-044]] (write-through-symlink → resolve real path). Linked to [[BDR-033]].
## LRN-051 — `git commit -- <pathspec>` strict on no-match → filter scoped commits to changed paths
- **Date**: 2026-06-26
- **Pattern**: Automating a scoped commit (commit only subtree X), pass to `git add`/`git commit` ONLY paths with real pending changes. `git add -- <pathspec>` TOLERATES a no-match pathspec (rc 0, stages the matching ones); `git commit -- <pathspec>` is STRICT — one no-match pathspec ABORTS the whole commit (`error: pathspec '<x>' did not match any file(s) known to git`). So a clean scoped path (e.g. empty `.claude/tasks`) silently aborts the commit on most runs. Filter via `git status --porcelain -- <path>` to changed paths only. Bonus: `git commit -- pathspec` = PARTIAL commit (working-tree of those paths, ignores rest of index) → surgical-scope safety: dangling code (untracked OR pre-staged) never embarked.
- **Context**: building `lib/memory-commit.sh`. Naive `git commit -- .claude/memory .claude/tasks` aborted whenever `.claude/tasks` was clean. Caught by real-exec test (T1/T2/T2-bis), NOT by assuming git's behavior — `add` and `commit` are NOT symmetric on pathspecs.
- **Future application**: any "commit only subtree X" automation — filter to changed paths; rely on partial-commit for surgical scope; never assume tool behavior symmetric across sibling subcommands — exec-test it.
- **Reference**: commit `58cb91d` (`_changed_paths` filter + T1/T2/T2-bis), `bbef41c` (stdout hash contract). See [[BDR-034]].
## LRN-052 — Hash-anchoring applicability — 2 cases where `Reference: commit <hash>` does NOT apply
- **Date**: 2026-06-26
- **Pattern**: The anchoring convention (`Reference: commit <hash>`) means "the commit that IMPLEMENTS this decision" (BDR-033 → 11792cc). It does NOT apply in 2 cases: (1) a FOUNDING decision made pre-code (at design time) — attested by no implementing commit; anchoring it to the unrelated scaffold commit is a FALSE anchor. (2) a SQUASH-MERGED PR — the anchored commit ceases to exist post-squash. Forcing a hash in either case dilutes what "anchored" means everywhere else. Rule: pre-code founding decisions carry NO hash (path+date suffice); squash-merge workflows can't anchor.
- **Context**: building init-project STEP 10b (capitalize founding architecture decisions). A founding "Astro not Next" has no implementing commit. Surfaced the BOUNDARY of the anchoring convention — completes it, not contradicts it.
- **Future application**: capitalizing founding/architecture decisions, or working in squash-merge repos — do NOT fabricate a hash; the anchor only means something when a real implementing commit exists.
- **Reference**: commit `df60df6` (init-project STEP 10b hash rule), `lib/capitalize-commit.md` (2-hash non-confusion). See [[BDR-034]], [[BDR-033]].

View File

@ -233,3 +233,17 @@ Version 3.4.0 → 3.5.0.
- [x] PHASE 3: install-plugins.sh STEP 5.5; update-all.sh block; plugins.lock.json; doctor.sh; lib/detect-plugins.sh; lib/profile.sh; plugin-advisor.md; skills/profile/SKILL.md
- [x] PHASE 4: README row; USAGE always-on line; CHANGELOG; CLAUDE.md cmd ref; skills/capitalize+prune-memory cmd refs; version.txt
- [x] PHASE 5: shellcheck clean (SC1091 info only); full diff reviewed → committed + merged to master
## 2026-06-26 — coupled-capitalize invariant v1 (Frame 2)
Plan: [.claude/tasks/2026-06-26-coupled-capitalize-invariant.md](2026-06-26-coupled-capitalize-invariant.md)
Goal: every dev flow commits its memory automatically (1 commit/flow) via shared
include; ship-feature reordered (capitalize before FINISH = PR-bug fix). Hook v2,
doc-sync twin chantier deferred. Safety in the pathspec, never `git add -A`.
- [x] Task 1 — `lib/memory-commit.sh` + tests T1/T2/T2-bis/T3/T4/T5/T6/T7 (real exec, outputs reported) — 58cb91d + bbef41c
- [x] Task 2 — `lib/capitalize-commit.md` include — b44791b
- [x] Task 3 — wire feater/hotfixer/bugfixer/commit-changer — 2763678
- [x] Task 4 — ship-feature reorder (capitalize before FINISH) — e8eff7e
- [x] Task 5 — init-project founding-decisions capitalize (F5) — df60df6
- [x] Task 6 — behavioral verify + shellcheck + CHANGELOG + BDR/LRN — this commit
- [ ] v2 (deferred) — Stop hook (non-blocking, BDR-033 style) reusing the detector
- [ ] twin chantier (deferred) — doc-sync reorder before FINISH (same PR bug)