chore(memory): BDR-091 BDR-092 LRN-155..157, journal 2026-09-16

This commit is contained in:
Bastien Chanot
2026-09-17 11:43:39 +02:00
parent 56bd035281
commit b96fab7719
4 changed files with 49 additions and 2 deletions
+21
View File
@@ -100,6 +100,8 @@ rules:
| BDR-088 | 2026-09-15 | gstack Playwright bump shared via lib, re-applied after submodule update; update helper never touches the submodule tree | accepted |
| BDR-089 | 2026-09-15 | No Playwright browser-cache pruner; read-only doctor report — .links proved 0 bytes reclaimable | accepted |
| BDR-090 | 2026-09-15 | Destructive shell work → autoMode soft_deny/hard_deny; `ask` tier abandoned (inert under auto) | accepted |
| BDR-091 | 2026-09-16 | Ask, don't guess: open-choice sweep (3 classes) at plan step + mid-run CLASS channel supersede "one question upfront" | accepted |
| BDR-092 | 2026-09-16 | docker + node framed by the classifier via autoMode.allow + soft_deny; ask entries retired | accepted |
---
@@ -1157,3 +1159,22 @@ Branch feature/user-writing-web-rules, UNMERGED (human gate).
- **Caveat**: the guardrail `hard_deny` bars REMOVING a `deny`/`soft_deny`/`hard_deny` entry, not adding one. Future loosening goes through `/permissions` or the user's own edit — deliberate, confirmed with the user.
- **Status**: accepted.
- **Reference**: `settings.json`, `doctor.sh` `check_automode`, `templates/settings/SETTINGS.md`. Links [[LRN-153]], [[LRN-146]], [[BDR-004]].
## BDR-091 — Ask, don't guess: open-choice sweep + mid-run channel supersede "one question upfront"
- **Date**: 2026-09-16
- **Decision**: `CLAUDE.global.md` rule → ask on a VISIBLE (placement, wording, order, behavior), PUBLIC NAME (command, flag, endpoint, file) or SCOPE ("X too?") choice the request leaves open, even mid-task; class 4 (internal technical, no observable effect) never. `lib/contract-interview.md` STEP 2 = CLARIFY: pass A (gaps: outcome / scope / constraints) at contract time; pass B (open-choice sweep, 3 classes) ONCE at each flow's PLAN step, no question cap, >5 open → under-specified, list + stop; "you decide" recorded `A: delegated — <default>`, never re-asked. New MID-RUN CLARIFICATION: executor halts `NEED-DECISION` + `CLASS:` tag; visible / public-name / scope → human verbatim; internal → loop decides, max 2 round-trips. New HOW TO ASK (LRN-102: ≤4 → one AskUserQuestion, context in option descriptions; else plain text ending the turn). Wiring: feat STEP 1, bugfix STEP 3, hotfix LOCATE (pass A stays silent autofill; one re-dispatch on class-tagged BLOCKED = the sole hotfix re-dispatch), ship-feature STEP 2, init-project STEP 3; interviewer: class 1-3 item never `(assumed)`, one extra targeted question. Executors (feater, bugfixer, hotfixer) report the class. Locks: contract-verifier (9), loops-light (hotfix), gates (3).
- **Why**: gap-only trigger structurally blind to taste — "add a share icon" passes outcome / scope / constraints and the icon lands wherever the executor put it; raising the 3-question cap changes nothing. feat:153 / bugfix:165 told the orchestrator "make the decision HERE", twice, before escalating = institutional guessing. Fresh re-dispatch keeps the tree, loses the executor's reasoning → a plan-time batch costs less than the same question mid-run; the mid-run channel stays for leftovers.
- **Alternatives rejected**: bigger budget (quota was never the limiter); new `lib/clarify.md` (extra hop, STEP 2 already the mandatory passage every orchestrator runs); global rule only (skills carried explicit counter-instructions — `zero questions ever`, `make the decision HERE`, `max 3 questions` — the specific beats the general).
- **Risk watched**: chattiness. Brakes = class 4 exclusion + over-5 guard. hotfix identity (speed, silence) = the flow to watch; if pass B fires on most hotfixes the class definitions are too wide, not the flow.
- **Status**: accepted. Behavioral check OPEN: `/feat "add a share icon to the header"` must ask placement before dispatch; the fully specified variant must ask nothing → record in `evals.md`.
- **Reference**: spec + plan `docs/superpowers/{specs,plans}/2026-09-16-ask-dont-guess*` (purged at finish, in history at `22ce57f`), commits `9eb6934..22ce57f`, merge `56bd035`. Supersedes the `CLAUDE.global.md:51` rule line. Refines [[BDR-049]] (contract), applies [[LRN-102]]. Links [[LRN-157]].
## BDR-092 — docker + node framed by the classifier (`autoMode.allow`), `ask` rules retired
- **Date**: 2026-09-16
- **Decision**: `Bash(docker run|exec *)`, `Bash(docker[-| ]compose up*)`, `Bash(node -e *)` out of `permissions.ask`. New `autoMode.allow` (`$defaults` first): (1) local dev containers — `docker exec/run/compose` against a workstation container whose name lacks `prod`/`production`, running a repo SQL file or script inside, output piped; Remote Shell Writes / Production Reads / Sensitive Remote Exec scoped to sensitive-named hosts; a literal `DROP/TRUNCATE/DELETE` on the command line stays under Mass Delete. (2) project-local node — `node <file>`, `npm run`/`pnpm`/`yarn` scripts, `npx`/`pnpm exec` of a lockfile-declared package, effects in cwd. +2 `soft_deny`: docker data destruction (`rm -f`, `volume rm/prune`, `system prune`, `compose down -v`, `--privileged`, bind mount outside cwd); undeclared node packages (`npx`/`dlx` absent from lockfile, `npm install <name>`). `model` bump to fable 5.1 committed alongside.
- **Why**: real gate = built-in `Remote Shell Writes` / `Production Reads` soft_deny catching `docker exec` into `supabase_db_game`; inside the classifier `allow` = exception tier (hard_deny > soft_deny > allow > explicit intent). Static `Bash(node *)` allow is suspended under auto (wildcarded interpreter) → prose is the only lever for a conditional node permission; `awk`/`echo` statics short-circuit, `node` cannot. `ask` inert on 2.1.273 (probe, [[LRN-155]]) — retiring it is forward-safe: if the documented prompt behavior lands, those entries would prompt for exactly what should run free.
- **Alternatives rejected**: static `permissions.allow` for docker (short-circuits the classifier, framing impossible); keep the `ask` entries (inert today, wrong tomorrow); strict on every `.sql` (blocks the repo's verify scripts).
- **Trade-off accepted**: a repo SQL file runs even when its content is opaque to the classifier — local dev DB only, resettable.
- **Guardrail**: S6 (loosening = user's own edit) overridden explicitly by the user for this change; diff reviewed on the branch before merge.
- **Status**: accepted. Verified: `jq` valid; `claude auto-mode config` shows the 4 entries with `$defaults` expanded; `doctor.sh` autoMode PASS; live `docker exec -i supabase_db_game psql … -f - < verify/0043 … | tail` → `ROLLBACK`, exit 0, no prompt. `claude auto-mode critique` printed nothing (2.1.273).
- **Reference**: `settings.json`, `templates/settings/SETTINGS.md` (`autoMode.allow` row + interpreter note), commit `5eccc3f`, merge `ddadca6`. Links [[BDR-090]], [[LRN-153]], [[LRN-155]], [[LRN-156]].
+5
View File
@@ -471,3 +471,8 @@ rules:
- `make test` 0 RED, `doctor.sh` 0 errors, `shellcheck` clean.
- graphify skill untracked + gitignored (written by `graphify install --platform claude` since `~/.claude/skills` symlinks to `skills/`). Cost one self-inflicted incident: `git rm --cached` kept the files, `gitflow finish` deleted them at the merge ([[LRN-154]]). Restored at 0.9.61, guarded configs snapshotted and verified untouched.
- `.claude/settings.local.json` 14.6 KB -> 6.2 KB. It was not just duplication: its local `deny` still carried the 4 rules moved out of global deny, making [[BDR-090]]'s soft_deny a dead letter in this repo, and its `allow` carried `sed *` / `cp *` / `python3 -`, which short-circuit the classifier on the same rules.
## 2026-09-16
- Ask, don't guess ([[BDR-091]]): spec + plan, 9 lock-first tasks (contract-interview CLARIFY two passes, MID-RUN CLARIFICATION with `CLASS:` tag, HOW TO ASK; global rule; feat / bugfix / hotfix / ship-feature / init-project wired; interviewer; 3 executors), suite green. Behavioral fixture check still open ([[LRN-157]]).
- docker + node under auto mode ([[BDR-092]]): `ask` entries retired (inert on 2.1.273, probe — [[LRN-155]]), `autoMode.allow` + 2 soft_deny, live `docker exec … psql` OK. Static interpreter allow is suspended under auto → prose only ([[LRN-156]]).
- Both merged into develop 2026-09-17 via gitflow (`ddadca6`, `56bd035`), two stack conflicts (TODO, CHANGELOG) resolved keeping both blocks. Symlinked `settings.json` follows the checkout: live config = whatever branch is out.
+21
View File
@@ -144,6 +144,9 @@ rules:
| LRN-152 | 2026-09-15 | git `protocol.file=user` blocks submodule fixtures; `-c` misses the code under test, `GIT_CONFIG_*` env does not | tests building git fixtures |
| LRN-153 | 2026-09-15 | `autoMode` lists replace built-ins without `"$defaults"`; a user-scope block reaches every project | any `autoMode` edit |
| LRN-154 | 2026-09-15 | `git rm --cached` + merge into a branch that still tracks the file DELETES it from disk | untracking a generated file |
| LRN-155 | 2026-09-16 | ask under auto: doc says prompt, probe on 2.1.273 says no; re-probe after upgrades | any permission-tier reasoning |
| LRN-156 | 2026-09-16 | autoMode.allow = exception tier; static interpreter allow suspended under auto → conditions live in prose | conditional permissions |
| LRN-157 | 2026-09-16 | gap-only trigger blind to taste → add a trigger class, not budget; ask at plan, mid-run for leftovers | any "ask more" request |
---
@@ -1469,3 +1472,21 @@ Rule: when editing a doctrine file under structure locks, grep the test's lock s
- **Future application**: untracking any generated file — know the regeneration command BEFORE merging, and `ls` the path right after `finish`. If nothing regenerates it, keep it tracked.
- **graphify specifics**: `graphify install --platform claude` copies the skill and touches nothing else. `graphify claude install` is a different command — it writes the CLAUDE.md section and the `.claude/settings.json` hooks, rewrites both guarded configs, and does NOT copy the skill. Confusing the two wastes a recovery attempt.
- **Reference**: `CLAUDE.md` machine-owned section, commit 80ccdaf. Links [[BDR-090]].
## LRN-155 — `permissions.ask` under auto mode: the probe beats the doc
- **Date**: 2026-09-16
- **Pattern**: `auto-mode-config` + `permissions` docs say a content-scoped `ask` rule (`Bash(git push *)`) is evaluated BEFORE the classifier and always prompts, even in auto mode. Probe on 2.1.273: `node -e 'console.log(...)'` matching `Bash(node -e *)` in `ask` ran, no prompt, exit 0. [[LRN-146]] holds. Either the doc describes a later build or "content-scoped" means something narrower; observed wins.
- **Future application**: before reasoning about a permission tier, probe it with a benign command matching the rule; re-probe after every Claude Code upgrade — the day `ask` starts prompting, every leftover `ask` entry becomes a nag for things meant to run free.
- **Reference**: [[BDR-092]], `templates/settings/SETTINGS.md` "ask is not a prompt" §.
## LRN-156 — Conditional permissions live in classifier prose, not static rules
- **Date**: 2026-09-16
- **Pattern**: `autoMode.allow` = exception tier: an entry overrides a matching `soft_deny`, built-in or own (precedence hard_deny > soft_deny > allow > explicit intent). Under auto, static allow rules granting arbitrary execution (`Bash(*)`, wildcarded interpreters like `Bash(node *)`) are suspended → classifier anyway; non-interpreter statics (`awk`, `echo`) resolve before it. A condition ("package declared in the lockfile", "container is local dev") is therefore expressible ONLY as `autoMode.allow` prose. Word it narrowly: it punches through built-in rules too.
- **Tooling**: `claude auto-mode defaults` prints the built-in lists (grep it for the rule that bit); `claude auto-mode config` = effective lists with `$defaults` expanded; `claude auto-mode critique` printed nothing on 2.1.273. Shell-snapshot `claude` wrapper is broken (`exec command claude` → "command: not found") → call `~/.local/bin/claude` directly.
- **Reference**: [[BDR-092]], [[LRN-153]].
## LRN-157 — Taste is invisible to a gap-only trigger; ask at plan time
- **Date**: 2026-09-16
- **Pattern**: a trigger that fires only on missing outcome / scope / constraints lets every taste choice through — "add a share icon" is complete by those criteria and the icon's side is decided downstream. More budget changes nothing; the fix is a new trigger class (VISIBLE / PUBLIC NAME / SCOPE). Cost geometry: a fresh re-dispatch keeps the working tree and loses the executor's reasoning → the same question costs about one executor run more mid-run than at PLAN. So: sweep once at the plan step, keep the mid-run channel for leftovers. Executor tags the class; orchestrator re-reads it (tag = hint, a mis-tag would offload class 4 onto the human). Relayed questions obey [[LRN-102]]: context inside `AskUserQuestion`, nothing the user needs printed before it.
- **Future application**: any "ask more" request → check WHICH trigger is blind before touching a quota. Any orchestrator with a "decide it yourself" fallback on an executor halt → route by class first.
- **Reference**: [[BDR-091]], `lib/contract-interview.md` STEP 2 + MID-RUN CLARIFICATION.
+2 -2
View File
@@ -20,7 +20,7 @@ for this change, diff reviewed on the branch).
- [x] A3 CHANGELOG [Unreleased] Changed
- [x] A4 verify (2026-09-16, all green; `critique` printed nothing): `jq`, `claude auto-mode config`,
`doctor.sh`, live `docker exec` in game
- [ ] A5 registries at capitalize: LRN (doc vs observed `ask` under auto,
- [x] A5 registries written 2026-09-17: LRN (doc vs observed `ask` under auto,
2.1.273; `autoMode.allow` = exception tier; wildcarded-interpreter
allow suspended), BDR-090 addendum
## 2026-09-16 — ask, don't guess: orchestrators ask about open choices (feature/ask-dont-guess)
@@ -47,7 +47,7 @@ SCOPE ask, internal technical choices never. Spec:
- [x] P7 `agents/interviewer.md` — visible/public/scope item never `(assumed)`
- [x] P8 `agents/{feater,bugfixer,hotfixer}.md` — CLASS tag; 3 locks in `gates.test.sh`
- [x] P9 `make test` green (2026-09-16), CHANGELOG, TODO tick; manual behavioral check still OPEN before merge
- [ ] P10 registries at capitalize: BDR (supersedes the one-question rule),
- [x] P10 registries written 2026-09-17: BDR (supersedes the one-question rule),
LRN (taste is invisible to a gap-only trigger; fresh re-dispatch cost
favors plan-time questions)