forked from bchanot/claude
Merge chore/review-remediation into develop
This commit is contained in:
@@ -35,6 +35,7 @@ rules:
|
|||||||
| 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-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-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 `<type> <name>` args → merged the CHECKED-OUT branch not the one named → wrong-branch merge (audit LOT3) | resolved |
|
| BLK-015 | 2026-07-03 | `gitflow_finish` ignored its `<type> <name>` args → merged the CHECKED-OUT branch not the one named → wrong-branch merge (audit LOT3) | resolved |
|
||||||
|
| BLK-016 | 2026-07-04 | rtk compression PATH-dead 30 days — 6/5070 Bash commands compressed (~460K tokens missed); installer sources cargo env so its own check passes, Claude tool shell never gets ~/.cargo/bin | resolved |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -190,3 +191,13 @@ rules:
|
|||||||
- **Solution**: `gitflow_finish [<type> <name>]` — 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).
|
- **Solution**: `gitflow_finish [<type> <name>]` — 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`.
|
- **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).
|
- **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).
|
||||||
|
|
||||||
|
## BLK-016 — rtk compression PATH-dead for 30 days: installer's own check can't see the tool shell
|
||||||
|
|
||||||
|
- **Date**: 2026-07-04
|
||||||
|
- **Friction**: user asked "is rtk installed + used right?". Measured (`rtk discover`): 6 of 5070 Bash commands compressed over 30 days, ~460K tokens missed (grep ~144K, git status ~112K, ls ~92K…). Hook registered, integrity pin OK, registry broad — yet near-zero real usage. Nobody noticed: degradation was silent (LRN-047 class).
|
||||||
|
- **Real cause**: two-layer. (1) cargo installs rtk into `~/.cargo/bin`; hand-managed profile lost the PATH line (LRN-036 class) → Claude's TOOL shell can't resolve `rtk`. (2) install-plugins.sh sources `~/.cargo/env` for itself, so its `command -v rtk` check PASSES in the installer shell — validating an env the runtime never has. Hook survived via absolute-path substitution, but ONLY at string head (f0b7e89 guard): every COMPOUND rewrite (dominant Claude style — echo separators, `&&`) was dropped by design.
|
||||||
|
- **Solution**: bridge symlink `~/.cargo/bin/rtk` → `~/.local/bin/rtk` (standard PATH). Immediate: created live, compound rewrites revived, proven in-session (bare grep → `rtk grep` output). Durable: install-plugins.sh STEP 3 idempotent self-repairing bridge, flip-tested 4/4 sandboxed HOME (LRN-096). Commit `e58037c` (RC fix on release/1.0.0).
|
||||||
|
- **Status**: resolved.
|
||||||
|
- **Reference**: lesson: a PATH-dependent hook must be verified in the TARGET shell, not the installer's (installer sourcing envs lies to its own checks); usage is MEASURED (`rtk discover`), never assumed. Corroborates [[LRN-047]] (silent degradation → measure) + [[LRN-036]] (hand-managed profile drift); guard interplay [[LRN-089]]-adjacent (ambient-state assumptions).
|
||||||
|
- **backmerge**: entry from release/1.0.0 (2b4e7401); the fix `e58037c` was ALSO missing from develop (rtk was live-broken on develop) — ported to develop 2026-07-08 (review remediation A3, commit follows) so this "resolved" is now true on develop too.
|
||||||
|
|||||||
@@ -82,6 +82,7 @@ rules:
|
|||||||
| BDR-059 | 2026-07-07 | job8: explicit ask-gate for all 4 magic MCP tools, empty allow stays empty | accepted |
|
| BDR-059 | 2026-07-07 | job8: explicit ask-gate for all 4 magic MCP tools, empty allow stays empty | accepted |
|
||||||
| BDR-060 | 2026-07-08 | job9: CC orchestration floor = v2.1.172 (nested dispatch), supersedes implicit v2.1.83 whole-system floor | accepted |
|
| BDR-060 | 2026-07-08 | job9: CC orchestration floor = v2.1.172 (nested dispatch), supersedes implicit v2.1.83 whole-system floor | accepted |
|
||||||
| BDR-061 | 2026-07-08 | job9: seo/geo analyzers → fix-bundle→L1 by doctrine (validator-analyzer pattern), not by version constraint | accepted |
|
| BDR-061 | 2026-07-08 | job9: seo/geo analyzers → fix-bundle→L1 by doctrine (validator-analyzer pattern), not by version constraint | accepted |
|
||||||
|
| BDR-062 | 2026-07-08 | supersede BDR-031's 275 CLAUDE.md target — 305 assumed reality (extraction done at job1; more compression costs clarity > tokens); guard threshold realigned 280→320 | accepted |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -931,3 +932,12 @@ rules:
|
|||||||
- **Alternatives rejected**: only raise the version floor (BDR-060 alone) — leaves the analyzers version-contingent, and the `/seo` nested-fix design fragile; keep analyzers self-applying but require CC≥2.1.172 — works on current env but not robust and keeps the parallel-edit race; make the dispatcher apply via direct Edit everywhere (like /harden) instead of hotfixer/feater — loses the fresh-context specialist fix; kept direct-Edit only for /harden's tiny scope.
|
- **Alternatives rejected**: only raise the version floor (BDR-060 alone) — leaves the analyzers version-contingent, and the `/seo` nested-fix design fragile; keep analyzers self-applying but require CC≥2.1.172 — works on current env but not robust and keeps the parallel-edit race; make the dispatcher apply via direct Edit everywhere (like /harden) instead of hotfixer/feater — loses the fresh-context specialist fix; kept direct-Edit only for /harden's tiny scope.
|
||||||
- **Verification**: `make test` green + 4 real smokes — analyzer emits bundle + edits nothing (md5 unchanged); AUTO fix lands on disk via L1 hotfixer with no confirmation (the exact previously-broken path); GATED withheld pre-approval then applied post-accord; /onboard writes only the report, zero source files.
|
- **Verification**: `make test` green + 4 real smokes — analyzer emits bundle + edits nothing (md5 unchanged); AUTO fix lands on disk via L1 hotfixer with no confirmation (the exact previously-broken path); GATED withheld pre-approval then applied post-accord; /onboard writes only the report, zero source files.
|
||||||
- **Reference**: `agents/seo-analyzer.md` STEP 12, `agents/geo-analyzer.md` STEP 13, `skills/seo/SKILL.md` STEP 1.5, `skills/geo/SKILL.md`, `agents/validator-analyzer.md` (reference contract), `.audit/job9-report.md` §6 option (b); commits `a5a7b54`/`6df42e4`/`c498b93`/`70fb3b4`. Linked to [[BDR-060]] (nesting floor), [[LRN-112]] (nesting mechanics).
|
- **Reference**: `agents/seo-analyzer.md` STEP 12, `agents/geo-analyzer.md` STEP 13, `skills/seo/SKILL.md` STEP 1.5, `skills/geo/SKILL.md`, `agents/validator-analyzer.md` (reference contract), `.audit/job9-report.md` §6 option (b); commits `a5a7b54`/`6df42e4`/`c498b93`/`70fb3b4`. Linked to [[BDR-060]] (nesting floor), [[LRN-112]] (nesting mechanics).
|
||||||
|
|
||||||
|
## BDR-062 — supersede BDR-031's 275-line CLAUDE.md target: 305 is the assumed reality
|
||||||
|
|
||||||
|
- **Date**: 2026-07-08
|
||||||
|
- **Status**: accepted (supersedes the 275-line density TARGET of [[BDR-031]] only; BDR-031's core principle — lightening = compression, not path-scope/externalization — stands unchanged)
|
||||||
|
- **Decision**: The global CLAUDE.md sits at 305 lines and stays there. job1's density pass took it 319→305 and no later job re-inflated it; the extraction BDR-031 called for is done. Reaching the old 275 target (or even the 280 guard threshold) now costs clarity more than it saves tokens. The `hooks/session-start.sh` guard threshold is realigned 280→320: still catches genuine regression (real bloat past 320) but stops firing a permanent "density pass requis" warning on an assumed-final 305.
|
||||||
|
- **Why**: the review (`.audit/review-release-1.0.0.md` A6) found the guard had warned every session since job1 without the target ever being met — a self-inflicted permanent warning, not an actionable signal. A gate that never goes green trains you to ignore it. Realign to reality; keep a 15-line margin so real regressions still surface.
|
||||||
|
- **Alternatives rejected**: (a) finish the compression 305→≤275 — the remaining lines are load-bearing constraints, not filler; further squeeze loses clarity for a marginal token gain on a solo repo. (b) leave the guard at 280 and accept the permanent warning — a permanently-red non-blocking gate is noise. (c) rewrite BDR-031 — registries are append-only; supersede the target, keep the principle.
|
||||||
|
- **Reference**: `hooks/session-start.sh:202-211`; supersedes the 275 target in [[BDR-031]] (principle kept). Review remediation A6, 2026-07-08.
|
||||||
|
|||||||
@@ -155,6 +155,15 @@ rules:
|
|||||||
- **anomalies**: (1) scratch semgrep files untracked → tree dirty at end, would self-block next run — patched STEP 3.2 [[LRN-100]]; (2) SEC-2 API-BREAKING fix (new required header) unflagged — patched template BREAKING tag; (3) positive: it2 re-verify caught regression of agent's OWN fix (`compare_digest(str)` raises on non-ASCII → 500 not 403), fixed + functionally proven it3 — re-verify loop has real teeth.
|
- **anomalies**: (1) scratch semgrep files untracked → tree dirty at end, would self-block next run — patched STEP 3.2 [[LRN-100]]; (2) SEC-2 API-BREAKING fix (new required header) unflagged — patched template BREAKING tag; (3) positive: it2 re-verify caught regression of agent's OWN fix (`compare_digest(str)` raises on non-ASCII → 500 not 403), fixed + functionally proven it3 — re-verify loop has real teeth.
|
||||||
- **action**: keep (skill shipped). REFACTOR additions not re-run through 3rd full pass — re-test at first real use ([[LRN-100]]).
|
- **action**: keep (skill shipped). REFACTOR additions not re-run through 3rd full pass — re-test at first real use ([[LRN-100]]).
|
||||||
|
|
||||||
|
## EVAL-015 — /tour first REAL run (report-only, bchanot-cv): REFACTOR additions validated; premise corrected by user
|
||||||
|
|
||||||
|
- **Date**: 2026-07-05
|
||||||
|
- **output**: report-only tour on live repo bchanot-cv: 4 parallel read-only audits (security-auditor semgrep BLOCK(1), cso posture 3 med/2 low/5 info, clean 10 findings, doc 2 drifts) + inline reconcile (ZERO drift — BLK-001 even live-confirmed via prod favicon 200). 14 findings folded into committed TOUR.md (5a813df, `.claude/**` on develop), scratch reports deleted, tree clean at end.
|
||||||
|
- **method**: real repo, no fixture. Deferred re-test executed: STEP 3.2 cleanup HELD (no self-block for next run), BREAKING tag correctly N/A (zero fixes in report-only). Cross-checks: cso live-confirmed SEC-2 (zero security headers served) — config-only review would have missed it ([[LRN-101]]).
|
||||||
|
- **anomalies**: (1) skill gap — report-only + clean tree has no branch, so the report commit lands on develop via the `.claude/**` exemption; works, but the placement is a judgment call the SKILL.md doesn't specify → candidate patch (needs its own failing test per Iron Law). (2) premise corrected by USER after the run: prod = native nginx, NOT the repo's Docker stack → container findings (SEC-1/4) latent, live header fix (SEC-2/3) belongs to VPS config outside the repo; audit scoping must confirm the serving stack first ([[LRN-101]] corollary). (3) parallel-phases deviation from the skill's sequential A→D held safely (report-only ⇒ no mutations between phases).
|
||||||
|
- **action**: keep. Skill validated on real drift; two refinement candidates noted (report-commit placement, serving-stack precheck), neither blocking.
|
||||||
|
- **backmerge**: from release/1.0.0 (74d3804) — 2026-07-08 review remediation A3.
|
||||||
|
|
||||||
## EVAL-016 — /deploy first REAL run (bchanot-cv): bootstrap→instantiate→hand-back→mark, full cycle OK
|
## EVAL-016 — /deploy first REAL run (bchanot-cv): bootstrap→instantiate→hand-back→mark, full cycle OK
|
||||||
|
|
||||||
- **Date**: 2026-07-05
|
- **Date**: 2026-07-05
|
||||||
@@ -198,3 +207,16 @@ rules:
|
|||||||
- **result**: 2 real STOP conditions fired and were resolved live, not hypothetically: (1) graphifyy 0.9.8's `graphify install` traced to source (`_install_claude_hook`, pipx venv `__main__.py:2033`) confirmed as a REWRITE of the config-protected `.claude/settings.json` — diff shown, user declined, binary upgraded without hook adoption; (2) gsd-pi 3.0.0 confirmed format-INCOMPATIBLE with `status-reporter.md`'s ROADMAP.md parser by generating a real test milestone in a scratch dir (ADR-013 cutover: no ROADMAP.md at all, DB-authoritative) — user chose "patch now" over rollback, parser rewired to `gsd headless query` JSON, smoke-tested both the absent-`.gsd/` and real-`.gsd/` cases before commit. gstack's local playwright patch (BDR-029) correctly identified as disposable-by-design, backed up before discard anyway (belt-and-suspenders after an auto-mode classifier denial), reapplied via the documented `gstack_bump_playwright_if_unsupported` steps — landed one minor ahead (1.61.1 vs the pre-bump 1.61.0) since upstream had moved between backup and reapply. `make test` green after every commit (90/90 gitflow + suites); `doctor.sh` 0 errors throughout.
|
- **result**: 2 real STOP conditions fired and were resolved live, not hypothetically: (1) graphifyy 0.9.8's `graphify install` traced to source (`_install_claude_hook`, pipx venv `__main__.py:2033`) confirmed as a REWRITE of the config-protected `.claude/settings.json` — diff shown, user declined, binary upgraded without hook adoption; (2) gsd-pi 3.0.0 confirmed format-INCOMPATIBLE with `status-reporter.md`'s ROADMAP.md parser by generating a real test milestone in a scratch dir (ADR-013 cutover: no ROADMAP.md at all, DB-authoritative) — user chose "patch now" over rollback, parser rewired to `gsd headless query` JSON, smoke-tested both the absent-`.gsd/` and real-`.gsd/` cases before commit. gstack's local playwright patch (BDR-029) correctly identified as disposable-by-design, backed up before discard anyway (belt-and-suspenders after an auto-mode classifier denial), reapplied via the documented `gstack_bump_playwright_if_unsupported` steps — landed one minor ahead (1.61.1 vs the pre-bump 1.61.0) since upstream had moved between backup and reapply. `make test` green after every commit (90/90 gitflow + suites); `doctor.sh` 0 errors throughout.
|
||||||
- **anomalies**: (1) mid-session the Bash tool went universally unresponsive (`true`/`echo hello` returning non-zero, no output) right after a large heredoc `git commit` — same `/tmp` exhaustion class as [[EVAL-019]]'s anomaly (1), user confirmed and cleared it; work resumed from the last confirmed git state rather than blindly retrying. (2) MCP magic's requested "reference not plaintext" (BDR-026 pattern) turned out NOT achievable as literally asked — `${VAR}` env expansion is documented for project-scope `.mcp.json` only, not the global `~/.claude.json` where magic is registered `--scope user` (verified via 2 rounds of sourced doc lookup, not assumed); user accepted the practical ceiling (regenerate via `toggle-external.sh disable/enable` to refresh the rotated key, decline the version pin).
|
- **anomalies**: (1) mid-session the Bash tool went universally unresponsive (`true`/`echo hello` returning non-zero, no output) right after a large heredoc `git commit` — same `/tmp` exhaustion class as [[EVAL-019]]'s anomaly (1), user confirmed and cleared it; work resumed from the last confirmed git state rather than blindly retrying. (2) MCP magic's requested "reference not plaintext" (BDR-026 pattern) turned out NOT achievable as literally asked — `${VAR}` env expansion is documented for project-scope `.mcp.json` only, not the global `~/.claude.json` where magic is registered `--scope user` (verified via 2 rounds of sourced doc lookup, not assumed); user accepted the practical ceiling (regenerate via `toggle-external.sh disable/enable` to refresh the rotated key, decline the version pin).
|
||||||
- **action**: keep. Branch unmerged (`chore/job6-deps-upgrade`, gitflow finish = separate human signal per CLAUDE.md). [[BDR-056]] captures the policy reversal this run demonstrated; [[LRN-107]] captures the secrets-copy mandate gap the report's own incident surfaced.
|
- **action**: keep. Branch unmerged (`chore/job6-deps-upgrade`, gitflow finish = separate human signal per CLAUDE.md). [[BDR-056]] captures the policy reversal this run demonstrated; [[LRN-107]] captures the secrets-copy mandate gap the report's own incident surfaced.
|
||||||
|
|
||||||
|
## EVAL-021 — adversarial review of the 9-job series (release/1.0.0..develop) + remediation
|
||||||
|
- **Date**: 2026-07-08
|
||||||
|
- **output**: read-only adversarial review — 11 analyzers (1/job + validator-analyzer contract) + fresh-context verifier on 6 top findings + make test. Report `.audit/review-release-1.0.0.md`: 1 BLOQUANT (A1 trailer), 5 à corriger (A2 gitleaks hook inert, A3 back-merge gap, A4 YAML, A5 geo attribution, A8 smoke-A), 5 mineurs, 10 verified false-positives; jobs 4/5/6/8 CLEAN, validator-analyzer contract SOUND. Remediation (chore/review-remediation): A1/A2/A4/A5 fixed, A8 PROVEN (both /seo+/geo AUTO items land on disk via L1 — no silent no-op), fil-rouge guard added, A3 backfilled + rtk fix ported, A6 threshold realigned.
|
||||||
|
- **method**: analyzers write findings to scratch; main loop does the inter-jobs cross-pass + memory-sequence + trailer sweep + cost check; verifier re-derives 6 findings from scratch. Sandbox gotcha logged: `git log | grep` truncates silently → used `git rev-list`.
|
||||||
|
- **anomalies**: (1) 2 sub-agent verdicts overturned — job7 CLEAN was wrong (gitleaks hook not wired, [[LRN-114]]) and the contract-agent's tool-grant "defect" was a false-positive ([[LRN-115]]). (2) A8 smoke-A root cause was undocumented in 212f9aa; reconstructed live — dispatcher classifies by batch-id (seo A/B/C, geo G1-G7), tolerant of header wording so items aren't dropped; path-b proven to land AUTO fixes on disk. (3) A7: job1/3f639b3 broke the design-hook oracle ~10h until job2/860b803 — historical; lesson = run make test before merging a branch, not only at finish.
|
||||||
|
- **action**: keep. Remediation branch unmerged (human gate). Fil-rouge guard now prevents the partial-fix class ([[LRN-113]]).
|
||||||
|
|
||||||
|
## EVAL-022 — job9 model pins (BDR-060) were smoke-tested but never recorded as an EVAL (M5 trace)
|
||||||
|
- **Date**: 2026-07-08
|
||||||
|
- **output**: review M5 flagged "no EVAL trace of the BDR-060 pin smoke-test." Traced: `.claude/tasks/TODO.md` job9 PART 1 GATE P1 DID record it — verifier `CONFORME`, security-auditor `BLOCK(2)`, plugin-advisor `ACTION REQUIRED`, verdict grammar intact, mode honored, no revert. The pins (verifier/security-auditor/plugin-advisor → sonnet, ea6c126/1c270e6/5ab6c21) WERE dispatch-smoked; the only gap was that the record lived in TODO, not evals.md.
|
||||||
|
- **method**: cross-read TODO PART 1 against the M5 finding; no re-run (recorded verdicts conclusive, pins unchanged since).
|
||||||
|
- **action**: keep — record backfilled here, no re-smoke required.
|
||||||
|
|||||||
@@ -365,3 +365,6 @@ rules:
|
|||||||
- **Part 2** (`a5a7b54`/`6df42e4`/`c498b93`/`70fb3b4` + hardening `212f9aa`): seo/geo analyzers re-architected to fix-bundle→L1 (validator-analyzer contract), `Agent` dropped from both `tools:`; `/seo` new STEP 1.5 applies at L1 (serial by ownership, dissolves the parallel-edit race), `/geo` → dispatch+apply orchestrator, `/harden` already end-to-end path-b (untouched), `/onboard` audit-only (untouched). [[BDR-060]] version floor + [[BDR-061]] path-b doctrine. 4 real smokes green: analyzer emits bundle + edits nothing (md5 unchanged, no files created); AUTO fix LANDS on disk via L1 hotfixer with no confirmation (the exact previously-broken path — *report but zero fix* → resolved); GATED withheld pre-accord then applied post-accord (new tier, first test); /onboard writes only the report, zero source files.
|
- **Part 2** (`a5a7b54`/`6df42e4`/`c498b93`/`70fb3b4` + hardening `212f9aa`): seo/geo analyzers re-architected to fix-bundle→L1 (validator-analyzer contract), `Agent` dropped from both `tools:`; `/seo` new STEP 1.5 applies at L1 (serial by ownership, dissolves the parallel-edit race), `/geo` → dispatch+apply orchestrator, `/harden` already end-to-end path-b (untouched), `/onboard` audit-only (untouched). [[BDR-060]] version floor + [[BDR-061]] path-b doctrine. 4 real smokes green: analyzer emits bundle + edits nothing (md5 unchanged, no files created); AUTO fix LANDS on disk via L1 hotfixer with no confirmation (the exact previously-broken path — *report but zero fix* → resolved); GATED withheld pre-accord then applied post-accord (new tier, first test); /onboard writes only the report, zero source files.
|
||||||
- **Part 3** (`87d63bf`/`af9656f`): H2 "Load and follow" idiom → **INLINE-LOAD** verb at code-cleaner + scaffolder (main-loop-BECOMES-agent, `Agent` not involved), drop unused `Agent` from code-cleaner; H1 code-cleaner→refactorer handoff now a named artifact `.claude/audits/CODE-CLEAN-SCOPE.md`. Tight scope per user (2 cited sites, no 40-site rewrite).
|
- **Part 3** (`87d63bf`/`af9656f`): H2 "Load and follow" idiom → **INLINE-LOAD** verb at code-cleaner + scaffolder (main-loop-BECOMES-agent, `Agent` not involved), drop unused `Agent` from code-cleaner; H1 code-cleaner→refactorer handoff now a named artifact `.claude/audits/CODE-CLEAN-SCOPE.md`. Tight scope per user (2 cited sites, no 40-site rewrite).
|
||||||
- Branch unmerged, human gate. **Fixed** (`5a3de92`, isolated): stripped `Co-Authored-By: Claude` from `commit-changer.md` message template — it contradicted [[no-commit-attribution]] since the template's creation (the settings.json backstop caught real commits, but the template itself would keep re-seeding the trailer). Only banned trailer in the file (no Claude-Session/--trailer). FOLLOW-UP next cycle: cross with J4-16 (lib-layer lock) to verify no other agent template carries the same trailer.
|
- Branch unmerged, human gate. **Fixed** (`5a3de92`, isolated): stripped `Co-Authored-By: Claude` from `commit-changer.md` message template — it contradicted [[no-commit-attribution]] since the template's creation (the settings.json backstop caught real commits, but the template itself would keep re-seeding the trailer). Only banned trailer in the file (no Claude-Session/--trailer). FOLLOW-UP next cycle: cross with J4-16 (lib-layer lock) to verify no other agent template carries the same trailer.
|
||||||
|
- Adversarial review of the whole 9-job series (release/1.0.0..develop) → `.audit/review-release-1.0.0.md`: 1 BLOQUANT + 5 à corriger + 5 mineurs, 10 verified false-positives. 2 sub-agent verdicts overturned (job7 gitleaks hook inert [[LRN-114]], contract tool-grant FP [[LRN-115]]). Jobs 4/5/6/8 CLEAN, validator-analyzer contract SOUND. J4-16 follow-up above CLOSED: trailer twins found in bugfixer/feater/hotfixer.
|
||||||
|
- Remediation `chore/review-remediation` (unmerged, human gate): A1 trailer purge (3 templates) + whole-surface sweep; A2 gitleaks hook re-installed (`install-hook`) + negative-secret gate proven; A4 strict-YAML quote (seo/security-auditor); A5 geo own-policy (user-approved, PERMISSIVE default kept, false CLAUDE.md attribution dropped); A8 path-b PROVEN — /seo+/geo AUTO items land on disk via L1 (no silent no-op); fil-rouge `lib/tests/run-review-guards.sh` (5 guards, teeth-verified); A3 backfill LRN-098/101 + EVAL-015 + BLK-016 + PORTED rtk fix e58037c (was live-broken on develop, ~460K tokens/30d); A6 guard 280→320 + [[BDR-062]] (supersede BDR-031's 275 target). make test GREEN throughout.
|
||||||
|
- Capitalized: [[LRN-113]] partial-fix+guard (structural), [[LRN-114]] hook-drift, [[LRN-115]] analyzer report-grants (FP1), [[LRN-116]] release fix missing from develop, [[BDR-062]] density realign, [[EVAL-021]] the review, [[EVAL-022]] M5 pins trace. Noted un-back-merged release chores beyond A3: e65796f (SC1091 lint silence) — left for a future reconcile.
|
||||||
|
|||||||
@@ -117,8 +117,10 @@ rules:
|
|||||||
| LRN-095 | 2026-07-03 | orthogonal gates don't contaminate — a conformity verifier must PASS correct-but-insecure code (security is a separate gate's job); proven live (CONFORME on a feature carrying a SQLi); fusing the two degrades each | designing multi-dimension review/verify/audit gates |
|
| LRN-095 | 2026-07-03 | orthogonal gates don't contaminate — a conformity verifier must PASS correct-but-insecure code (security is a separate gate's job); proven live (CONFORME on a feature carrying a SQLi); fusing the two degrades each | designing multi-dimension review/verify/audit gates |
|
||||||
| LRN-096 | 2026-07-04 | a backstop/guard is code — reliable ONLY after a flip-test proves it CAN fail; an unproven guard replacing an advisory = a vacuous guard (LRN-048 applied to guards); flip-test mandatory at guard creation | building any deterministic guard/lint/backstop |
|
| LRN-096 | 2026-07-04 | a backstop/guard is code — reliable ONLY after a flip-test proves it CAN fail; an unproven guard replacing an advisory = a vacuous guard (LRN-048 applied to guards); flip-test mandatory at guard creation | building any deterministic guard/lint/backstop |
|
||||||
| LRN-097 | 2026-07-04 | community blog pattern ≠ official feature — "contexts dir" doesn't exist in Claude Code; verify feature against official docs (claude-code-guide) BEFORE building infra; the intent was already covered by real mechanisms (agents/skills/rules) | any "add support for X" request naming a Claude Code feature |
|
| LRN-097 | 2026-07-04 | community blog pattern ≠ official feature — "contexts dir" doesn't exist in Claude Code; verify feature against official docs (claude-code-guide) BEFORE building infra; the intent was already covered by real mechanisms (agents/skills/rules) | any "add support for X" request naming a Claude Code feature |
|
||||||
|
| LRN-098 | 2026-07-04 | `/model` rewrites settings.json (model line + key reorder) — pending diff after model switch = side-effect, not intent; 2 occurrences | any settings.json commit; any "commit file X" — read diff, verify content matches intent |
|
||||||
| LRN-099 | 2026-07-05 | auto-orchestrator autonomy boundary: git discipline transfers naturally (branch, no-merge), declared-state discipline does NOT — baseline silently rewrote target TODO + authored registries + scope-crept | designing any auto/headless flow — enumerate declared surfaces, mark each read-only or gated |
|
| LRN-099 | 2026-07-05 | auto-orchestrator autonomy boundary: git discipline transfers naturally (branch, no-merge), declared-state discipline does NOT — baseline silently rewrote target TODO + authored registries + scope-crept | designing any auto/headless flow — enumerate declared surfaces, mark each read-only or gated |
|
||||||
| LRN-100 | 2026-07-05 | tool gated on clean tree must clean its OWN scratch (else self-DoS next run); contract-changing auto-fix needs structural BREAKING flag in the reviewed artifact | any recurring tool w/ cleanliness precondition; any auto-fix touching an API contract |
|
| LRN-100 | 2026-07-05 | tool gated on clean tree must clean its OWN scratch (else self-DoS next run); contract-changing auto-fix needs structural BREAKING flag in the reviewed artifact | any recurring tool w/ cleanliness precondition; any auto-fix touching an API contract |
|
||||||
|
| LRN-101 | 2026-07-05 | nginx `add_header` inheritance trap: ANY add_header in a location block drops ALL inherited server-level headers on those responses — audit headers on LIVE responses (`curl -I`), never by reading the config; declared infra can be stale (prod ≠ repo stack) | any nginx project audit (zenquality, faunosteo…); any security-header claim |
|
||||||
| LRN-102 | 2026-07-05 | deliverable text placed BEFORE a tool call may never render — only the turn's FINAL text is guaranteed displayed; a checklist printed above AskUserQuestion was invisible to the user | any flow whose deliverable is conversational text (checklist, commands, report): end the turn with it, blocking questions come before, never after |
|
| LRN-102 | 2026-07-05 | deliverable text placed BEFORE a tool call may never render — only the turn's FINAL text is guaranteed displayed; a checklist printed above AskUserQuestion was invisible to the user | any flow whose deliverable is conversational text (checklist, commands, report): end the turn with it, blocking questions come before, never after |
|
||||||
| LRN-105 | 2026-07-06 | explorer subagent ran a build tool (`graphify .`) mid read-only audit despite prose instructions to only Read/Grep/Bash-read — the runtime observed a config-protection sentinel deny message and self-corrected only after an explicit main-session correction, not from the original prompt | dispatching any "read-only audit" subagent whose toolset includes Bash: state "do not execute build/generator/mutating commands" explicitly, don't rely on "read-only" framing alone to constrain tool CHOICE |
|
| LRN-105 | 2026-07-06 | explorer subagent ran a build tool (`graphify .`) mid read-only audit despite prose instructions to only Read/Grep/Bash-read — the runtime observed a config-protection sentinel deny message and self-corrected only after an explicit main-session correction, not from the original prompt | dispatching any "read-only audit" subagent whose toolset includes Bash: state "do not execute build/generator/mutating commands" explicitly, don't rely on "read-only" framing alone to constrain tool CHOICE |
|
||||||
| LRN-106 | 2026-07-06 | job3-B1 froze a fixture + repointed run-reconcile.sh's T2 off the live registry, declared "unblocked", 20/20 green — job4 (next audit, same file, same day) found T3+T5 in the SAME FILE still read the live registry, same fragility, untouched | fixing one instance of a "reads live state it shouldn't" finding: grep the WHOLE file (not just the cited line) for the same pattern before declaring the class closed |
|
| LRN-106 | 2026-07-06 | job3-B1 froze a fixture + repointed run-reconcile.sh's T2 off the live registry, declared "unblocked", 20/20 green — job4 (next audit, same file, same day) found T3+T5 in the SAME FILE still read the live registry, same fragility, untouched | fixing one instance of a "reads live state it shouldn't" finding: grep the WHOLE file (not just the cited line) for the same pattern before declaring the class closed |
|
||||||
@@ -126,6 +128,10 @@ rules:
|
|||||||
| LRN-110 | 2026-07-07 | job8: `21st_magic_component_builder` (magic MCP) opens unauth'd 127.0.0.1 callback server, CORS `*`, no token check, 10min window — any local POST lands verbatim in the tool result the model consumes = local prompt-injection channel | any MCP tool that opens a local callback/listener server to receive async results — check auth + origin scoping on the listener, not just the outbound call |
|
| LRN-110 | 2026-07-07 | job8: `21st_magic_component_builder` (magic MCP) opens unauth'd 127.0.0.1 callback server, CORS `*`, no token check, 10min window — any local POST lands verbatim in the tool result the model consumes = local prompt-injection channel | any MCP tool that opens a local callback/listener server to receive async results — check auth + origin scoping on the listener, not just the outbound call |
|
||||||
| LRN-111 | 2026-07-07 | job8: empty permissions.allow for a risky MCP tool is a VALID posture (not a gap) when transcript census shows zero real invocations — pre-authorizing unused surface buys nothing, ask-gate costs nothing | deciding whether to allowlist any tool/command — check real usage before assuming "no entry = todo" |
|
| LRN-111 | 2026-07-07 | job8: empty permissions.allow for a risky MCP tool is a VALID posture (not a gap) when transcript census shows zero real invocations — pre-authorizing unused surface buys nothing, ask-gate costs nothing | deciding whether to allowlist any tool/command — check real usage before assuming "no entry = todo" |
|
||||||
| LRN-112 | 2026-07-08 | job9: CC nested subagent dispatch SUPPORTED since v2.1.172 (cap 5 levels, `Agent` must be in subagent `tools:`) — "flattens to 1 level" is the pre-2.1.172 regime; live env v2.1.203. Contradicts the operating premise of the whole job1-9 series | a subagent-dispatches-subagent design is VERSION-CONTINGENT, not "broken" — check CC version before flagging; fix = raise floor or re-architect to bundle→L1 |
|
| LRN-112 | 2026-07-08 | job9: CC nested subagent dispatch SUPPORTED since v2.1.172 (cap 5 levels, `Agent` must be in subagent `tools:`) — "flattens to 1 level" is the pre-2.1.172 regime; live env v2.1.203. Contradicts the operating premise of the whole job1-9 series | a subagent-dispatches-subagent design is VERSION-CONTINGENT, not "broken" — check CC version before flagging; fix = raise floor or re-architect to bundle→L1 |
|
||||||
|
| LRN-113 | 2026-07-08 | partial-pattern-fix = recurring defect of the job1-9 series: fix the cited instance, leave the twins (trailer A1, YAML A4, attribution A5, hook A2). An adversarial review catches twins later; nothing catches them at commit time | any fix of a banned pattern: grep the ENTIRE surface + add a make-test guard (run-review-guards.sh) that REDs if one occurrence subsists |
|
||||||
|
| LRN-114 | 2026-07-08 | editing a hook GENERATOR (_gitflow_emit_pre_commit) does NOT update the INSTALLED hook (.githooks/pre-commit) — silent drift; T10 diffs the allow/block verdict not content, T16 emits fresh in a throwaway repo → job7 gitleaks backstop inert on the repo 8 days | after editing a template-generated artifact: reinstall (install-hook) + a gate that diffs installed==emit |
|
||||||
|
| LRN-115 | 2026-07-08 | analyzer Edit/Write grants (seo/geo/validator) are NOT dead: needed to write the REPORT (VALIDATE/SEO/GEO.md); the "never edit" rule targets CODE, instruction-level (same as the patron) — verified false-positive | do NOT re-flag as a tool-grant defect; a report-only agent keeps Write for its own report |
|
||||||
|
| LRN-116 | 2026-07-08 | memory backfill release→develop: a BLK marked "resolved" can have its RESOLUTION (code) missing from develop — BLK-016 resolved on release but rtk fix e58037c never back-merged → bug LIVE on develop | before backfilling a resolved blocker: verify the fix CODE is on the target branch, not just the registry entry |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -1033,6 +1039,14 @@ rules:
|
|||||||
- **future application**: "add support for X" where X is a Claude Code/tool feature — claude-code-guide first, build second. Same discipline for any tool: feature existence is a fact to verify, not assume.
|
- **future application**: "add support for X" where X is a Claude Code/tool feature — claude-code-guide first, build second. Same discipline for any tool: feature existence is a fact to verify, not assume.
|
||||||
- **cousin**: [[LRN-086]] provenance discipline; [[LRN-046]] verify before trust; CLAUDE.md "Never assume — verify".
|
- **cousin**: [[LRN-086]] provenance discipline; [[LRN-046]] verify before trust; CLAUDE.md "Never assume — verify".
|
||||||
|
|
||||||
|
## LRN-098 — `/model` silently rewrites settings.json: read the diff before any settings commit
|
||||||
|
- **pattern**: `/model` persists the switch by REWRITING settings.json — changes `model` line AND reorders keys (attribution block moved to top). Pending settings.json diff after a model switch = side-effect, not intent. 2nd occurrence: ae8ad86 undid the first (opus-4-8 restored); today "commit settings.json" nearly re-committed fable-5 as default right after that undo. Catch came from reading DIFF CONTENT, not filename: request said commit, diff contradicted prior intentional commit → surfaced, user chose `git restore`.
|
||||||
|
- **why it matters**: "dirty settings.json" reads as innocent drift; blind commit flips default model for ALL sessions + silently reverses an explicit prior decision. A request "commit file X" is about the file — content must still match user intent.
|
||||||
|
- **context**: 2026-07-04 RC 1.0.0 cleanup. Diff = `claude-opus-4-8[1m]` → `claude-fable-5[1m]` + attribution reorder (no semantic change). AskUserQuestion → restore.
|
||||||
|
- **future application**: settings.json modified → read diff, check `model` line before commit. Generalize: any hand-curated config a tool co-writes ([[LRN-039]]) — diff before commit, surface contradiction with prior commits.
|
||||||
|
- **cousin**: [[LRN-039]] installers drift hand-curated config; [[LRN-050]] show-before-write gate; [[LRN-034]] narrated state ≠ ground truth.
|
||||||
|
- **backmerge**: from release/1.0.0 (a623514) — 2026-07-08 review remediation A3.
|
||||||
|
|
||||||
## LRN-099 — Auto-orchestrator autonomy boundary: working branch YES, declared/shared state NO
|
## LRN-099 — Auto-orchestrator autonomy boundary: working branch YES, declared/shared state NO
|
||||||
|
|
||||||
- **pattern**: /tour RED baseline (no skill, pressure "injoignable, reboucle jusqu'à propre"): git discipline held NATURALLY (gitflow lib branch, no merge w/o signal, atomic commits — doctrine survived into subagent) BUT state-write discipline failed across the board: target TODO silently rewritten (boxes checked, restructured), BDR/journal entries authored autonomously, unrequested bootstrap (.gitignore + registries "bonus hygiene"). Plus: security = ad-hoc grep+ruff (no semgrep floor), findings only in final chat msg (no reviewable artifact), loop unbounded (converged pass 2 by luck).
|
- **pattern**: /tour RED baseline (no skill, pressure "injoignable, reboucle jusqu'à propre"): git discipline held NATURALLY (gitflow lib branch, no merge w/o signal, atomic commits — doctrine survived into subagent) BUT state-write discipline failed across the board: target TODO silently rewritten (boxes checked, restructured), BDR/journal entries authored autonomously, unrequested bootstrap (.gitignore + registries "bonus hygiene"). Plus: security = ad-hoc grep+ruff (no semgrep floor), findings only in final chat msg (no reviewable artifact), loop unbounded (converged pass 2 by luck).
|
||||||
@@ -1049,6 +1063,15 @@ rules:
|
|||||||
- **future application**: any recurring tool gated on repo cleanliness → audit what IT leaves behind; any auto-applied fix changing a contract → structural BREAKING flag in the human-reviewed artifact.
|
- **future application**: any recurring tool gated on repo cleanliness → audit what IT leaves behind; any auto-applied fix changing a contract → structural BREAKING flag in the human-reviewed artifact.
|
||||||
- **cousin**: [[LRN-099]] same chantier; [[LRN-071]] swallowed-failure class (silent residue ≈ masked state).
|
- **cousin**: [[LRN-099]] same chantier; [[LRN-071]] swallowed-failure class (silent residue ≈ masked state).
|
||||||
|
|
||||||
|
## LRN-101 — nginx add_header inheritance: one child header wipes ALL parent headers — verify LIVE, not in config
|
||||||
|
|
||||||
|
- **pattern**: nginx `add_header` inherits from server level ONLY if a location block declares NONE of its own. One `add_header Cache-Control ...` in a location → ALL 5 server-level security headers (CSP, X-Content-Type-Options, X-Frame-Options, Referrer-Policy, Permissions-Policy) silently dropped on every response matching that location. bchanot-cv live: pages served ZERO security headers while the config declared all 5; only the 404 path (no location-level add_header) carried them. Corollary, same audit: declared infra was STALE — prod turned out native nginx, repo's Docker stack latent (user correction post-audit) → container findings latent, live fix belongs to the VPS config outside the repo.
|
||||||
|
- **why**: config review says "headers present" — a lie by inheritance. Only oracle = live responses (`curl -sI` per content type: html, pdf, image). Fix = repeat the headers in every location that uses add_header (or `include security-headers.conf`).
|
||||||
|
- **context**: 2026-07-05 first real /tour run (report-only, bchanot-cv), cso posture finding SEC-2, live-confirmed.
|
||||||
|
- **future application**: ANY nginx repo audit — curl live per location class before trusting config; ANY audit — confirm which stack actually serves prod before scoping fixes.
|
||||||
|
- **cousin**: [[LRN-034]] narrated ≠ ground truth; [[LRN-046]] verify before trust.
|
||||||
|
- **backmerge**: from release/1.0.0 (74d3804) — 2026-07-08 review remediation A3.
|
||||||
|
|
||||||
## LRN-102 — Deliverable text before a tool call may never render: the turn's FINAL text is the only guaranteed display
|
## LRN-102 — Deliverable text before a tool call may never render: the turn's FINAL text is the only guaranteed display
|
||||||
|
|
||||||
- **pattern**: /deploy hand-back printed the full checklist in the assistant message, then called AskUserQuestion. The user saw ONLY the question UI — the checklist never reached them ("là on a rien, je dois ouvrir le fichier"). The harness renders reliably only the LAST text of a turn; text between/before tool calls can be swallowed by the tool UI.
|
- **pattern**: /deploy hand-back printed the full checklist in the assistant message, then called AskUserQuestion. The user saw ONLY the question UI — the checklist never reached them ("là on a rien, je dois ouvrir le fichier"). The harness renders reliably only the LAST text of a turn; text between/before tool calls can be swallowed by the tool UI.
|
||||||
@@ -1130,3 +1153,30 @@ rules:
|
|||||||
- **context**: the whole job1-9 audit series ran on the premise *"Claude Code aplatit à 1 niveau → un design supposant 2 niveaux de sous-agents est cassé silencieusement."* job9 corrected it via `claude-code-guide` (official docs `code.claude.com/docs/en/agent-sdk/subagents.md`): a running subagent CAN spawn a further subagent IF `Agent` is in its `tools:` (omit it / add to `disallowedTools` to prevent nesting); hard cap **5 levels** ("a subagent 5 levels below main can't spawn further"); nesting **stabilized in v2.1.172** ("let subagents spawn their own subagents") — earlier versions did not support it at all. Live env confirmed **v2.1.203** (user). `claude --version` was unavailable in-sandbox so the report bracketed but could not pin it; the user pinned it.
|
- **context**: the whole job1-9 audit series ran on the premise *"Claude Code aplatit à 1 niveau → un design supposant 2 niveaux de sous-agents est cassé silencieusement."* job9 corrected it via `claude-code-guide` (official docs `code.claude.com/docs/en/agent-sdk/subagents.md`): a running subagent CAN spawn a further subagent IF `Agent` is in its `tools:` (omit it / add to `disallowedTools` to prevent nesting); hard cap **5 levels** ("a subagent 5 levels below main can't spawn further"); nesting **stabilized in v2.1.172** ("let subagents spawn their own subagents") — earlier versions did not support it at all. Live env confirmed **v2.1.203** (user). `claude --version` was unavailable in-sandbox so the report bracketed but could not pin it; the user pinned it.
|
||||||
- **future application**: NEVER classify a subagent-dispatches-subagent design as "BROKEN" without checking the CC version. On ≥2.1.172 it works within the 5-level cap; on <2.1.172 it silently no-ops. The actionable finding is a VERSION-FLOOR ([[BDR-060]]) or a version-robust re-architecture (bundle→L1, [[BDR-061]]) — not "it's broken." When an agent must NOT nest, enforce it structurally: drop `Agent` from its `tools:` (done for seo/geo analyzers). Re-audit any prior job1-9 "nested = broken" finding through this lens.
|
- **future application**: NEVER classify a subagent-dispatches-subagent design as "BROKEN" without checking the CC version. On ≥2.1.172 it works within the 5-level cap; on <2.1.172 it silently no-ops. The actionable finding is a VERSION-FLOOR ([[BDR-060]]) or a version-robust re-architecture (bundle→L1, [[BDR-061]]) — not "it's broken." When an agent must NOT nest, enforce it structurally: drop `Agent` from its `tools:` (done for seo/geo analyzers). Re-audit any prior job1-9 "nested = broken" finding through this lens.
|
||||||
- **cousin**: [[BDR-060]] (version floor), [[BDR-061]] (path-b bundle pattern), [[LRN-057]] (subagent invocation idioms).
|
- **cousin**: [[BDR-060]] (version floor), [[BDR-061]] (path-b bundle pattern), [[LRN-057]] (subagent invocation idioms).
|
||||||
|
|
||||||
|
## LRN-113 — Partial-pattern-fix is the job1-9 series' recurring defect: grep the whole surface + guard it
|
||||||
|
- **pattern**: fix one cited instance of a banned pattern, leave the twins. Review found 4: trailer stripped from commit-changer only (A1, twins in bugfixer/feater/hotfixer); YAML quoted elsewhere but seo/security-auditor left broken (A4); attribution scrubbed on 3 skills but geo-analyzer missed (A5); gitleaks added to the hook generator but the installed hook not regenerated (A2).
|
||||||
|
- **why it recurs**: the fixer greps for the reported line, fixes it, stops — never enumerates the pattern across the full surface. An adversarial review catches the twins later; nothing catches them at commit time.
|
||||||
|
- **fix**: every pattern-fix ends with (1) a whole-surface grep proving zero residue, (2) a deterministic make-test guard that REDs if any occurrence returns. Shipped `lib/tests/run-review-guards.sh` — G1 trailer, G2 false attribution, G3 strict-YAML, G4 reconcile hermeticity, G5 hook-drift; teeth-verified (planted violation REDs). This is the check that would have caught A1/A4/A5/A2 at make-test time instead of a review.
|
||||||
|
- **future application**: any "fix pattern X" task → grep agents/ lib/ hooks/ templates/ skills/, add/extend a review-guard with teeth.
|
||||||
|
- **cousin**: [[LRN-114]] (hook-drift class), [[LRN-047]] (silent degradation → measure/guard).
|
||||||
|
|
||||||
|
## LRN-114 — Editing a hook generator does not touch the installed hook: reinstall + drift-guard
|
||||||
|
- **pattern**: job7 added the gitleaks scan to `_gitflow_emit_pre_commit` (the GENERATOR), but the installed `.githooks/pre-commit` is only (re)written by `gitflow init`/`install-hook`. job7 never re-installed → the repo's active hook stayed the pre-job7 version (620071b) for 8 days; `git commit` ran no secret scan while the team believed it did.
|
||||||
|
- **why undetected**: T10 (drift test) compares only the hook's allow/block VERDICT, not content; T16 emits a FRESH hook in a throwaway repo, validating the generator, never the installed file. Both green while the installed hook was stale.
|
||||||
|
- **fix**: after editing any template-generated artifact, regenerate the installed copy (`gitflow.sh install-hook`) AND add a content-drift gate — `run-review-guards.sh` G5 diffs installed `.githooks/pre-commit` against `emit-hook`.
|
||||||
|
- **future application**: any generator/template emitting an on-disk artifact needs an "installed == freshly-emitted" test, not just a behavioral one.
|
||||||
|
- **cousin**: [[LRN-113]] (partial-fix + guard), [[LRN-039]] (installers drift hand-curated config).
|
||||||
|
|
||||||
|
## LRN-115 — Analyzer Edit/Write grants are not dead capability: they write the report (false-positive)
|
||||||
|
- **pattern**: a contract audit flagged seo/geo/validator-analyzer holding `Edit`/`Write` while instructed "do NOT apply any Edit/Write" as a defense-in-depth defect. Verified FALSE: those grants write the agent's own REPORT (`.claude/audits/VALIDATE.md`/`SEO.md`/`GEO.md`). The "never edit" rule targets CODE files (the fix-bundle is applied by the dispatcher) and is instruction-level — identical in the patron. Removing Write would break report generation.
|
||||||
|
- **why it matters**: don't "harden" a report-only agent by stripping Write — it needs it for its report. The code/report distinction is instruction-enforced, not tool-enforced, by design.
|
||||||
|
- **future application**: before flagging a tool-grant as dead, check whether the agent uses it for its own output artifact (report), not the forbidden target (code).
|
||||||
|
- **cousin**: [[BDR-061]] (analyzer bundle→L1 contract), [[LRN-113]].
|
||||||
|
|
||||||
|
## LRN-116 — A resolved blocker's FIX can be missing from develop even when the entry backfills cleanly
|
||||||
|
- **pattern**: backfilling release/1.0.0 memory into develop, BLK-016 (rtk PATH-dead) was marked "resolved" via fix e58037c. Checked before backfilling: e58037c (the `~/.cargo/bin`→`~/.local/bin` bridge in install-plugins.sh) was NOT on develop — develop still installed rtk to a cargo bin dir the tool shell can't see → rtk compression was LIVE-broken on develop (~460K tokens/30d). The registry entry looked safe to copy; the underlying fix wasn't there.
|
||||||
|
- **why it matters**: append-only registry backfill is "safe" only for the TEXT; a "resolved" status is a claim about CODE state that must be verified on the target branch, else you assert a resolution that isn't true.
|
||||||
|
- **fix**: ported e58037c to develop (13-line idempotent bridge), THEN backfilled BLK-016 resolved. General: before backmerging a resolved blocker, grep the target for the fix's code signature.
|
||||||
|
- **future application**: gitflow divergence review — enumerate release-only COMMITS that touch code, not just memory; a feature can be parallel-merged while its RC-branch fix is orphaned.
|
||||||
|
- **cousin**: [[LRN-036]] (PATH profile drift), [[LRN-047]] (silent degradation).
|
||||||
|
|||||||
@@ -1,5 +1,23 @@
|
|||||||
# TODO
|
# TODO
|
||||||
|
|
||||||
|
## 2026-07-08 — review remediation (chore/review-remediation)
|
||||||
|
Genèse : `.audit/review-release-1.0.0.md` (revue adversariale des 9 jobs). GO user,
|
||||||
|
ordre imposé. Déviation justifiée : 1 branche (pas 1/EP) car le gate fil-rouge (step 6)
|
||||||
|
grep toute la surface et n'est vert qu'avec A1/A4/A5 déjà appliqués. Commits atomiques,
|
||||||
|
branche non mergée (gate humain). EP-A3/A6 = décisions user tranchées (combler / option b).
|
||||||
|
- [x] EP-A1 (BLOQUANT) trailer bugfixer/feater/hotfixer (56018df) + grep étendu = 0 autre
|
||||||
|
- [x] EP-A2 (P0) hook réinstallé gitleaks (d4526e6) + 3 gates verts + root-cause (générateur édité, jamais réinstallé)
|
||||||
|
- [x] EP-A4 quote YAML seo-analyzer:3 + security-auditor:3 (5a0fc16) + gate yaml.safe_load tous agents
|
||||||
|
- [x] EP-A5 geo own-policy PERMISSIVE (f0111e1), user-approved, grep==0
|
||||||
|
- [x] EP-A8 smoke /seo+/geo réel PROUVÉ — AUTO llms.txt + sitemap.xml atterrissent sur disque (no-op infirmé)
|
||||||
|
- [x] FIL-ROUGE run-review-guards.sh 5 gardes (4e83f39), user-approved, à dents
|
||||||
|
- [x] EP-A3 backfill LRN-098/101 (7cd82cf/a01250b) + EVAL-015 (38cc821) + BLK-016 (8e9ff33) + PORT rtk e58037c (416b68f) car fix absent+bug live sur develop
|
||||||
|
- [x] EP-A6 (option b) seuil 280→320 + BDR-062 (1be9036)
|
||||||
|
- [x] EP-A7 documentaire + M5 → EVAL-022 (capitalize cc4f161)
|
||||||
|
- [x] Capitalize LRN-113/114/115/116 + BDR-062 + EVAL-021/022 + journal (cc4f161)
|
||||||
|
- [x] GATE FINAL : make test GREEN (exit 0) + A2 secret BLOCKED (gitleaks) + A8 AUTO landed + review-guards 5/0
|
||||||
|
- Branche chore/review-remediation NON mergée (gate humain). Résidu noté : e65796f (SC1091 lint) non back-mergé, hors scope.
|
||||||
|
|
||||||
## 2026-07-08 — job9 sub-agent architecture corrections (chore/job9-agents)
|
## 2026-07-08 — job9 sub-agent architecture corrections (chore/job9-agents)
|
||||||
Genèse : `.audit/job9-report.md` (agents/*.md frontmatter+body, verify-loop,
|
Genèse : `.audit/job9-report.md` (agents/*.md frontmatter+body, verify-loop,
|
||||||
dispatch graph, read-only). Premise correction confirmed CC v2.1.203 : nesting
|
dispatch graph, read-only). Premise correction confirmed CC v2.1.203 : nesting
|
||||||
|
|||||||
@@ -7,6 +7,19 @@ br=$(git symbolic-ref --short -q HEAD 2>/dev/null)
|
|||||||
git rev-parse --verify -q HEAD >/dev/null 2>&1 || exit 0 # root commit — allow
|
git rev-parse --verify -q HEAD >/dev/null 2>&1 || exit 0 # root commit — allow
|
||||||
[ -f "$gd/MERGE_HEAD" ] && exit 0 # merge in progress — allow
|
[ -f "$gd/MERGE_HEAD" ] && exit 0 # merge in progress — allow
|
||||||
|
|
||||||
|
# Secret backstop (job7) — any branch, not just protected ones. Non-blocking
|
||||||
|
# if gitleaks isn't installed; auto-discovers ./.gitleaks.toml (repo root).
|
||||||
|
if command -v gitleaks >/dev/null 2>&1; then
|
||||||
|
if ! gitleaks git --staged --no-banner >/dev/null 2>&1; then
|
||||||
|
echo "gitflow pre-commit: BLOCKED — gitleaks found a secret in staged changes." >&2
|
||||||
|
echo " Details: gitleaks git --staged --no-banner" >&2
|
||||||
|
echo " Genuine false-positive? add an allowlist rule to .gitleaks.toml — never bypass with --no-verify." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "gitflow pre-commit: gitleaks not installed — secret scan skipped (https://github.com/gitleaks/gitleaks)." >&2
|
||||||
|
fi
|
||||||
|
|
||||||
case "$br" in
|
case "$br" in
|
||||||
main|develop) ;; # protected — keep checking
|
main|develop) ;; # protected — keep checking
|
||||||
*) exit 0 ;; # working branch — allow
|
*) exit 0 ;; # working branch — allow
|
||||||
|
|||||||
@@ -180,8 +180,6 @@ Apply the fix following the plan:
|
|||||||
|
|
||||||
<what was wrong and why>
|
<what was wrong and why>
|
||||||
<what the fix does>
|
<what the fix does>
|
||||||
|
|
||||||
Co-Authored-By: Claude <noreply@anthropic.com>
|
|
||||||
```
|
```
|
||||||
7. Print summary:
|
7. Print summary:
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -138,8 +138,6 @@ Commit using conventional format:
|
|||||||
feat(<scope>): <what was added>
|
feat(<scope>): <what was added>
|
||||||
|
|
||||||
<brief description of the feature>
|
<brief description of the feature>
|
||||||
|
|
||||||
Co-Authored-By: Claude <noreply@anthropic.com>
|
|
||||||
```
|
```
|
||||||
|
|
||||||
If the feature touched multiple concerns (e.g., feature + config +
|
If the feature touched multiple concerns (e.g., feature + config +
|
||||||
|
|||||||
@@ -221,7 +221,9 @@ For each of the 25+ AI bots in the reference:
|
|||||||
|
|
||||||
### Default policy decision
|
### Default policy decision
|
||||||
|
|
||||||
User CLAUDE.md default preference: **PERMISSIVE** (maximize citations).
|
geo-analyzer default: **PERMISSIVE** (maximize citations) — a GEO audit
|
||||||
|
optimizes for AI-search visibility, so allowing AI crawlers is the coherent
|
||||||
|
default for this agent.
|
||||||
|
|
||||||
Unless the client explicitly declared premium/paywalled content or
|
Unless the client explicitly declared premium/paywalled content or
|
||||||
regulated vertical (medical records, legal filings, banking), propose
|
regulated vertical (medical records, legal filings, banking), propose
|
||||||
@@ -864,9 +866,9 @@ PROCHAINE ETAPE : <highest-priority>
|
|||||||
NEVER `Write` on shared templates. `Write` is reserved for files
|
NEVER `Write` on shared templates. `Write` is reserved for files
|
||||||
you solely own: robots.txt, llms.txt, llms-full.txt. Full-template
|
you solely own: robots.txt, llms.txt, llms-full.txt. Full-template
|
||||||
refactor → escalate as user action in §11.
|
refactor → escalate as user action in §11.
|
||||||
- **Respect PERMISSIVE/RESTRICTIVE choice.** Per user CLAUDE.md,
|
- **Respect PERMISSIVE/RESTRICTIVE choice.** geo-analyzer defaults to
|
||||||
default is PERMISSIVE. Only switch if client explicitly flags
|
PERMISSIVE (GEO's goal is AI visibility). Only switch if the client
|
||||||
premium/regulated content.
|
explicitly flags premium/regulated content.
|
||||||
- **Honest llms.txt framing.** Don't promise ranking wins. Frame as
|
- **Honest llms.txt framing.** Don't promise ranking wins. Frame as
|
||||||
low-cost hedge with real value for dev-focused content.
|
low-cost hedge with real value for dev-focused content.
|
||||||
|
|
||||||
|
|||||||
@@ -132,8 +132,6 @@ Apply the minimal change that fixes the bug:
|
|||||||
4. Commit using conventional format (only after verify AND security pass):
|
4. Commit using conventional format (only after verify AND security pass):
|
||||||
```
|
```
|
||||||
fix(<scope>): <what was wrong>
|
fix(<scope>): <what was wrong>
|
||||||
|
|
||||||
Co-Authored-By: Claude <noreply@anthropic.com>
|
|
||||||
```
|
```
|
||||||
5. Print summary:
|
5. Print summary:
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: security-auditor
|
name: security-auditor
|
||||||
description: SAST security gate — runs the pinned semgrep rulesets + the CLAUDE.md security checklist on a diff or project scope, maps severities, renders SECURITY — VERDICT: PASS | BLOCK(n). Blocks HIGH/CRITICAL only, reports the rest. Never fixes code. Fresh dispatch, no iteration history.
|
description: 'SAST security gate — runs the pinned semgrep rulesets + the CLAUDE.md security checklist on a diff or project scope, maps severities, renders SECURITY — VERDICT: PASS | BLOCK(n). Blocks HIGH/CRITICAL only, reports the rest. Never fixes code. Fresh dispatch, no iteration history.'
|
||||||
tools: Read, Grep, Glob, Bash, Write
|
tools: Read, Grep, Glob, Bash, Write
|
||||||
model: sonnet
|
model: sonnet
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: seo-analyzer
|
name: seo-analyzer
|
||||||
description: Classical SEO audit agent (Google, Bing) — dispatched from /seo. Live audit: Core Web Vitals, on-page, technical, local SEO, legal (FR). Emits a fix bundle (dispatcher applies) + scored report. AI/GEO → geo-analyzer agent.
|
description: 'Classical SEO audit agent (Google, Bing) — dispatched from /seo. Live audit: Core Web Vitals, on-page, technical, local SEO, legal (FR). Emits a fix bundle (dispatcher applies) + scored report. AI/GEO → geo-analyzer agent.'
|
||||||
tools: Read, Edit, Write, Bash, Grep, Glob, WebFetch, WebSearch
|
tools: Read, Edit, Write, Bash, Grep, Glob, WebFetch, WebSearch
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -199,11 +199,13 @@ unset _active_count _inactive_count
|
|||||||
printf "│ 🖥️ CLI : %-40s│\n" "$GSD_STATUS"
|
printf "│ 🖥️ CLI : %-40s│\n" "$GSD_STATUS"
|
||||||
[ -n "$TOKEN_WARN" ] && printf "│ 💰 %-44s│\n" "${TOKEN_WARN:0:44}"
|
[ -n "$TOKEN_WARN" ] && printf "│ 💰 %-44s│\n" "${TOKEN_WARN:0:44}"
|
||||||
printf "│ 📦 v%-45s│\n" "$CONFIG_VERSION"
|
printf "│ 📦 v%-45s│\n" "$CONFIG_VERSION"
|
||||||
# CLAUDE.md line-count guard (job1 anti-regression, BDR-031 density target: 275)
|
# CLAUDE.md line-count guard (anti-regression). BDR-062 supersedes BDR-031's
|
||||||
|
# 275 target: 305 is the assumed reality (extraction already done at job1;
|
||||||
|
# further compression costs clarity > token gain) — warn only past a 320 margin.
|
||||||
if [ -n "$REPO_DIR" ] && [ -f "$REPO_DIR/CLAUDE.md" ]; then
|
if [ -n "$REPO_DIR" ] && [ -f "$REPO_DIR/CLAUDE.md" ]; then
|
||||||
_claude_lines=$(wc -l < "$REPO_DIR/CLAUDE.md")
|
_claude_lines=$(wc -l < "$REPO_DIR/CLAUDE.md")
|
||||||
if [ "$_claude_lines" -gt 280 ]; then
|
if [ "$_claude_lines" -gt 320 ]; then
|
||||||
_cmd_warn="CLAUDE.md ${_claude_lines}L (>280) — density pass requis"
|
_cmd_warn="CLAUDE.md ${_claude_lines}L (>320) — density pass requis"
|
||||||
printf "│ ⚠️ %-44s│\n" "${_cmd_warn:0:44}"
|
printf "│ ⚠️ %-44s│\n" "${_cmd_warn:0:44}"
|
||||||
unset _cmd_warn
|
unset _cmd_warn
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -431,6 +431,19 @@ else
|
|||||||
cargo install --git https://github.com/rtk-ai/rtk
|
cargo install --git https://github.com/rtk-ai/rtk
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
# PATH bridge: cargo installs to ~/.cargo/bin, which hand-managed shell
|
||||||
|
# profiles routinely lose (LRN-036 class). This installer sources cargo env
|
||||||
|
# so `command -v rtk` passes HERE — but Claude's tool shell never gets that
|
||||||
|
# PATH: the rewrite hook then drops every COMPOUND rewrite (it can only
|
||||||
|
# absolute-path the string head) and compression silently dies (measured:
|
||||||
|
# 6/5070 commands compressed over 30 days). ~/.local/bin is on the standard
|
||||||
|
# PATH — bridge with a symlink. Idempotent; -x on a broken link is false,
|
||||||
|
# so a stale link self-repairs.
|
||||||
|
if [ -x "$HOME/.cargo/bin/rtk" ] && [ ! -x "$HOME/.local/bin/rtk" ]; then
|
||||||
|
mkdir -p "$HOME/.local/bin"
|
||||||
|
ln -sf "$HOME/.cargo/bin/rtk" "$HOME/.local/bin/rtk"
|
||||||
|
ok "rtk bridged into ~/.local/bin (cargo bin dir is not on the tool-shell PATH)"
|
||||||
|
fi
|
||||||
# Only init if not already configured (avoids overwriting custom RTK config)
|
# Only init if not already configured (avoids overwriting custom RTK config)
|
||||||
if ! grep -q "rtk" "$HOME/.claude/settings.json" 2>/dev/null; then
|
if ! grep -q "rtk" "$HOME/.claude/settings.json" 2>/dev/null; then
|
||||||
info "Configuring RTK PreToolUse hook (global)..."
|
info "Configuring RTK PreToolUse hook (global)..."
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# run-review-guards.sh — anti-"partial-fix" regression guards.
|
||||||
|
#
|
||||||
|
# Genesis: .audit/review-release-1.0.0.md fil rouge. The 9-job series repeatedly
|
||||||
|
# fixed ONE instance of a banned pattern and left the twins (A1 trailer, A4 YAML,
|
||||||
|
# A5 false attribution, A2 hook drift). Each guard below greps the WHOLE surface
|
||||||
|
# for a pattern and REDs if any occurrence subsists — the check that would have
|
||||||
|
# caught A1/A4/A5/A2 at make-test time instead of an adversarial review.
|
||||||
|
set -uo pipefail
|
||||||
|
|
||||||
|
GREP=/usr/bin/grep # LRN-074: pin grep
|
||||||
|
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
REPO="$(cd "$HERE/../.." && pwd)"
|
||||||
|
cd "$REPO"
|
||||||
|
|
||||||
|
pass=0; fail=0; skip=0
|
||||||
|
ok() { echo "GREEN ✓ $*"; pass=$((pass+1)); }
|
||||||
|
no() { echo "RED ✗ $*"; fail=$((fail+1)); }
|
||||||
|
warn() { echo "SKIP ~ $*"; skip=$((skip+1)); }
|
||||||
|
|
||||||
|
echo "=== review-guards: anti-partial-fix surface checks ==="
|
||||||
|
|
||||||
|
# G1 — banned commit-attribution trailers must not live in our own config surface
|
||||||
|
# (the ban is [[no-commit-attribution]]; skills-external/ = gstack submodule, excluded).
|
||||||
|
# This guard file is excluded: it names the pattern literally as its own search term.
|
||||||
|
if hits=$($GREP -rInE --exclude=run-review-guards.sh 'Co-Authored-By|Claude-Session' agents/ lib/ hooks/ templates/ skills/ 2>/dev/null); then
|
||||||
|
echo "$hits"; no "G1 trailer: banned attribution trailer present in tracked config surface"
|
||||||
|
else
|
||||||
|
ok "G1 trailer: zero Co-Authored-By/Claude-Session in agents|lib|hooks|templates|skills"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# G2 — false CLAUDE.md attribution (asserting a user policy CLAUDE.md does not contain)
|
||||||
|
if hits=$($GREP -rInE 'per user.{0,5}CLAUDE\.md|User CLAUDE\.md default' agents/ skills/ 2>/dev/null); then
|
||||||
|
echo "$hits"; no "G2 attribution: false 'per user CLAUDE.md' policy reference present"
|
||||||
|
else
|
||||||
|
ok "G2 attribution: zero false CLAUDE.md policy references in agents|skills"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# G3 — every agent frontmatter must be strict-YAML valid (degrade if pyyaml absent)
|
||||||
|
if python3 -c 'import yaml' 2>/dev/null; then
|
||||||
|
if python3 - "$REPO" <<'PY'
|
||||||
|
import glob, os, sys, yaml
|
||||||
|
root=sys.argv[1]; bad=0
|
||||||
|
for f in sorted(glob.glob(os.path.join(root,'agents','*.md'))):
|
||||||
|
try: yaml.safe_load(open(f).read().split('---')[1])
|
||||||
|
except Exception as e: print(" FAIL", os.path.relpath(f,root), str(e).splitlines()[0]); bad+=1
|
||||||
|
sys.exit(1 if bad else 0)
|
||||||
|
PY
|
||||||
|
then ok "G3 strict-YAML: all agents/*.md frontmatter parse"
|
||||||
|
else no "G3 strict-YAML: an agent frontmatter fails yaml.safe_load"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
warn "G3 strict-YAML: python3+pyyaml unavailable — skipped"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# G4 — the reconcile test must stay hermetic (fixtures, never the live registry) [job3 B1]
|
||||||
|
if $GREP -q '\.claude/memory' lib/tests/run-reconcile.sh 2>/dev/null; then
|
||||||
|
no "G4 hermetic: run-reconcile.sh reads the live .claude/memory registry"
|
||||||
|
else
|
||||||
|
ok "G4 hermetic: run-reconcile.sh reads fixtures only, not the live registry"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# G5 — installed pre-commit hook must match the generator (catches the A2 silent drift:
|
||||||
|
# editing _gitflow_emit_pre_commit without re-installing). Degrade if emit-hook absent.
|
||||||
|
if emitted=$(bash lib/gitflow.sh emit-hook 2>/dev/null) && [ -n "$emitted" ]; then
|
||||||
|
if [ -f .githooks/pre-commit ] && diff -q <(printf '%s\n' "$emitted") .githooks/pre-commit >/dev/null 2>&1; then
|
||||||
|
ok "G5 hook-drift: installed .githooks/pre-commit == generator emit-hook"
|
||||||
|
else
|
||||||
|
no "G5 hook-drift: installed hook diverges from generator (run 'gitflow.sh install-hook')"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
warn "G5 hook-drift: gitflow.sh emit-hook unavailable — skipped"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "================ $pass GREEN / $fail RED / $skip SKIP (review-guards) ================"
|
||||||
|
[ "$fail" -eq 0 ]
|
||||||
Reference in New Issue
Block a user