Merge feature/user-writing-web-rules into develop

This commit is contained in:
Bastien Chanot
2026-08-25 19:53:57 +02:00
8 changed files with 121 additions and 1 deletions
+9
View File
@@ -94,6 +94,7 @@ rules:
| BDR-080 | 2026-07-21 | Bug routing inverted: /bugfix primary, /investigate explicit-only | accepted | | BDR-080 | 2026-07-21 | Bug routing inverted: /bugfix primary, /investigate explicit-only | accepted |
| BDR-083 | 2026-08-24 | Contract gates: deterministic floor (GATE 0) under the fresh verifier | accepted | | BDR-083 | 2026-08-24 | Contract gates: deterministic floor (GATE 0) under the fresh verifier | accepted |
| BDR-084 | 2026-08-24 | /tour multi-project: parallel runners (LRN-083 derogation, bounded), runner inherits session model | accepted | | BDR-084 | 2026-08-24 | /tour multi-project: parallel runners (LRN-083 derogation, bounded), runner inherits session model | accepted |
| BDR-085 | 2026-08-25 | User permanent rules: writing-style always-on in rules/, web build+security path-scoped | accepted |
--- ---
@@ -1096,3 +1097,11 @@ ONE real sequential-but-independent candidate: /tour multi-project (independent
Decision: STEP 0 routes (1 project = inline unchanged; ≥2 = STEP 0b fan-out). One general-purpose runner per project, ALL in ONE message, dispatched with NO model override — inherits the session model (model-gate already validated big; a runner carries tour's reflection: fix decisions, convergence). Inside a runner every agent keeps its defined tier (security-auditor sonnet, Phase B opus, doc-syncer sonnet two-mode). Dead/mute runner ⇒ explicit `RUNNER FAILED` summary row (mute is never a pass). Capitalize offer stays MAIN LOOP ONLY (registries = shared state). Decision: STEP 0 routes (1 project = inline unchanged; ≥2 = STEP 0b fan-out). One general-purpose runner per project, ALL in ONE message, dispatched with NO model override — inherits the session model (model-gate already validated big; a runner carries tour's reflection: fix decisions, convergence). Inside a runner every agent keeps its defined tier (security-auditor sonnet, Phase B opus, doc-syncer sonnet two-mode). Dead/mute runner ⇒ explicit `RUNNER FAILED` summary row (mute is never a pass). Capitalize offer stays MAIN LOOP ONLY (registries = shared state).
LRN-083 derogation, bounded: per-project fix loop + convergence now run INSIDE the dispatched runner. Bounded because nothing a runner decides touches shared state — independent repos, per-repo chore branches, branches stay UNMERGED for human review exactly as inline (report-as-approval-gate design unchanged). Precedent: client-handover-writer already a dispatched orchestrator running parallel audit loops (BDR-077). LRN-083 derogation, bounded: per-project fix loop + convergence now run INSIDE the dispatched runner. Bounded because nothing a runner decides touches shared state — independent repos, per-repo chore branches, branches stay UNMERGED for human review exactly as inline (report-as-approval-gate design unchanged). Precedent: client-handover-writer already a dispatched orchestrator running parallel audit loops (BDR-077).
Alternatives rejected: report-only-only parallel (my recommendation — user overrode: full parallel wanted); one sub-orchestrator agent .md file (drift risk vs SKILL.md, the runner reads the skill from disk instead — client-handover→/seo precedent); pinning the runner (would put tour reflection on an executor tier — inverts BDR-076); global CLAUDE.md parallelism line (duplicate of harness injection). Census §12: 6 locks (fan-out present, no-pin, single-message, capitalize main-loop, RUNNER FAILED, no pinned runner), flip-tested. Branch feature/tour-parallel, UNMERGED (human gate). Alternatives rejected: report-only-only parallel (my recommendation — user overrode: full parallel wanted); one sub-orchestrator agent .md file (drift risk vs SKILL.md, the runner reads the skill from disk instead — client-handover→/seo precedent); pinning the runner (would put tour reflection on an executor tier — inverts BDR-076); global CLAUDE.md parallelism line (duplicate of harness injection). Census §12: 6 locks (fan-out present, no-pin, single-message, capitalize main-loop, RUNNER FAILED, no pinned runner), flip-tested. Branch feature/tour-parallel, UNMERGED (human gate).
### BDR-085 — user permanent rules: writing-style always-on in rules/, web rules path-scoped [accepted] (2026-08-25)
User supplied 4-block permanent rule text (writing / website / code security / self-check), asked: coverage check, conflict check, integrate. Coverage verdict: security CORE (parameterized queries, input validation, env-var secrets, AuthN/AuthZ split + default deny, no stack traces, fail closed, least privilege) ALREADY in CLAUDE.global.md §Security — NOT duplicated. NEW: entire writing-style block, design anti-default list, public-site done-checklist, web-app specifics (browser-exposed keys, service-key/client split, RLS, server-side auth, IDOR, hashed passwords + cookie flags, field minimization, rate limiting, upload restrictions).
Placement: CLAUDE.global.md at 308/320 (session-start density guard) → no room for ~30 always-on lines. Decision: rules/writing-style.md WITHOUT paths: (always-on load, same session cost, outside the 320 budget) + rules/web-building.md + rules/web-security.md WITH paths: (lazy-load = token win, fire only on web/code files). Project CLAUDE.md doctrine line amended with the budget exception. Feeds C2 self-contradiction audit.
Conflict carve-outs, stated INSIDE the rules: registries keep caveman format (fragments, em-dashes, bullets); code comments keep code style; structured skill/report templates keep their formats; robuste/transformer banned in buzzword sense only (robustness lens, math transform allowed); no-Inter default rule carries "existing brand identities keep their fonts" (ZenQuality deliverables use Inter+Playfair by brand decision — client-handover BDR).
Self-check rule scoped to DELIVERABLES (text, site, feature), not every conversational reply — literal "avant de me rendre quoi que ce soit" would append a compliance note to every chat answer, pure noise. User can re-widen.
Alternatives rejected: compress into CLAUDE.global.md (~11 lines to fit → loses the carve-outs, zero headroom left); path-scope writing-style (applies to conversation, not file reads → would never fire in chat-only sessions); one merged web file (two concerns, one-rule-one-file).
Branch feature/user-writing-web-rules, UNMERGED (human gate).
+3
View File
@@ -440,3 +440,6 @@ rules:
- `make test` rc 0, shellcheck clean, 64 new assertions, e2e on a real contract. Branch feature/contract-gates UNMERGED (human gate). - `make test` rc 0, shellcheck clean, 64 new assertions, e2e on a real contract. Branch feature/contract-gates UNMERGED (human gate).
- Locks caught a reflow regression (5 red on rewrapped phrases, zero doctrine lost) → [[LRN-142]]. Skill-adoption pattern → [[LRN-141]]. - Locks caught a reflow regression (5 red on rewrapped phrases, zero doctrine lost) → [[LRN-142]]. Skill-adoption pattern → [[LRN-141]].
- Parallelism audit (user ask "est-ce actif ?"): measured, not assumed — nested probe proves concurrent fan-out (9.1s vs 18s), doctrine already prescribed everywhere safe, remaining serializations motivated. One candidate found: /tour multi-project → parallel runners shipped ([[BDR-084]], user gate "tout paralléliser" + model invariant). Branch feature/tour-parallel UNMERGED. - Parallelism audit (user ask "est-ce actif ?"): measured, not assumed — nested probe proves concurrent fan-out (9.1s vs 18s), doctrine already prescribed everywhere safe, remaining serializations motivated. One candidate found: /tour multi-project → parallel runners shipped ([[BDR-084]], user gate "tout paralléliser" + model invariant). Branch feature/tour-parallel UNMERGED.
## 2026-08-25
- User permanent rules integrated: rules/writing-style.md (always-on) + web-building.md + web-security.md (path-scoped). Security core already in §Security, not duplicated. Carve-outs protect caveman registries + skill templates + brand fonts. [[BDR-085]]. Branch feature/user-writing-web-rules UNMERGED (human gate).
+19
View File
@@ -1,5 +1,24 @@
# TODO # TODO
## 2026-08-25 — user permanent rules: writing + web build + web security (feature/user-writing-web-rules)
User supplied 4-block rule text (écris / site / code / vérification); asked:
coverage check, conflict check, integrate. Verdict: security CORE already in
CLAUDE.global.md §Security (parameterized queries, env-var secrets,
AuthN/AuthZ, fail closed) — NOT duplicated. NEW: writing-style block, design
anti-default list, site done-checklist, web-app specifics (RLS, service key,
IDOR, cookie flags, rate limit, field minimization). Placement: global at
308/320 budget → rules/ instead.
- [x] R1 rules/writing-style.md — always-on (no paths:), scope carve-outs
(registries caveman, code comments, skill templates) + self-check
- [x] R2 rules/web-building.md — paths: web globs; anti-defaults + done
checklist (report missing, never invent) + skill pointers
- [x] R3 rules/web-security.md — paths: code globs; web-app specifics
extending §Security, zero dup of the core
- [x] R4 CLAUDE.md (project) — amend always-on doctrine line (320-budget
exception → rules/), feeds C2 audit
- [x] R5 capitalize BDR-085 + journal + CHANGELOG
- [ ] NO merge — human gate
## 2026-07-30 — adapt config for Claude 5 family / Opus 5 (feature/opus5-config-tuning) ## 2026-07-30 — adapt config for Claude 5 family / Opus 5 (feature/opus5-config-tuning)
User: Opus 5 "needs more freedom" → research (official migration guide + User: Opus 5 "needs more freedom" → research (official migration guide +
web + registres) confirms: over-delegates (inverts LRN-030 Opus 4.8 trait), web + registres) confirms: over-delegates (inverts LRN-030 Opus 4.8 trait),
+7
View File
@@ -7,6 +7,13 @@ Format follows [Keep a Changelog](https://keepachangelog.com/).
## [Unreleased] ## [Unreleased]
### Added ### Added
- **User permanent rules (BDR-085)** — three new rules/ files from the
user's rule text: `writing-style.md` (always-on: em-dash ban, no slop
vocabulary, no hedging chains, deliverable self-check),
`web-building.md` (path-scoped: design anti-defaults + public-site done
checklist), `web-security.md` (path-scoped: RLS, service-key/client
split, IDOR, cookie flags, rate limiting — extends §Security, no dup).
Project CLAUDE.md rules/ doctrine gains the 320-budget exception.
- **/tour multi-project parallel fan-out (BDR-084)** — two or more - **/tour multi-project parallel fan-out (BDR-084)** — two or more
project paths now dispatch one runner per repo in a single message project paths now dispatch one runner per repo in a single message
(independent working trees, nothing collides) instead of processing (independent working trees, nothing collides) instead of processing
+3 -1
View File
@@ -17,7 +17,9 @@ A rule WITH `paths:` YAML frontmatter (glob list) loads lazily — only when
Claude reads a file matching a glob; a rule WITHOUT it loads at session Claude reads a file matching a glob; a rule WITHOUT it loads at session
start, same cost as the global memory. Extract from CLAUDE.global.md only start, same cost as the global memory. Extract from CLAUDE.global.md only
what can be path-scoped (the token win) or what is generated; always-on what can be path-scoped (the token win) or what is generated; always-on
doctrine stays in CLAUDE.global.md. `paths:` globs match against the doctrine stays in CLAUDE.global.md. Exception: a standalone user-authored
rule set that would bust the 320-line density budget may live here WITHOUT
`paths:` (always-on load) — writing-style.md (BDR-085). `paths:` globs match against the
CURRENT project's tree — a broad glob (e.g. `rules/**`) can fire in foreign CURRENT project's tree — a broad glob (e.g. `rules/**`) can fire in foreign
projects; keep rule bodies tiny. projects; keep rule bodies tiny.
Docs: https://code.claude.com/docs/en/memory.md#path-specific-rules Docs: https://code.claude.com/docs/en/memory.md#path-specific-rules
+30
View File
@@ -0,0 +1,30 @@
---
paths: ["**/*.html", "**/*.astro", "**/*.css", "**/*.scss", "**/*.tsx", "**/*.jsx", "**/*.vue", "**/*.svelte"]
---
# Web building — no default reflexes + done checklist
## Avoid unless the user asks for them
- Purple gradient, purple/black, neon, washed-out pastels, rainbow.
- Drop shadow on everything; the same border-radius on every element.
- Bento grid, dot grid, glowing background orbs, decorative color strip.
- Sparkle icons, animated arrows, emojis as icons, decorative fake
terminal window.
- Hover animation on every element; scroll-reveal animations everywhere.
- Three aligned feature cards, three pricing tiers, checkmark bullets.
- Vague hero title ("unleash your potential"): state what the product does.
- Fake testimonials, fake visitor or client counters, invented numbers.
Never, in any context.
- Inter, Geist or Space Grotesk as the default font: propose an
alternative and justify it. Existing brand identities keep their fonts.
## Before declaring a public site done
Check: custom 404 · call to action in the first viewport · per-page
title + description · share/OG image · favicons · robots.txt · sitemap ·
alt text on images · layout tested at 375 px · loading states · form
error messages · confirmation page · real legal mentions · cookie banner
with a working refuse option · audience measurement · contact address ·
compressed images.
Report the missing items to the user instead of inventing them. Internal
tools and dashboards: only the relevant items apply. Deep audits stay
with /seo, /harden, /web-validate.
+21
View File
@@ -0,0 +1,21 @@
---
paths: ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx", "**/*.vue", "**/*.svelte", "**/*.astro", "**/*.php", "**/*.py"]
---
# Web app security — specifics
Extends the global Security section (input validation, parameterized
queries, secrets in env vars, AuthN/AuthZ, fail closed). If a request
breaks one of these rules, say so instead of doing it.
- No API key in code shipped to the browser. Env vars, server-side only.
- The service/admin key never reaches the client: publishable key only.
- Row Level Security enabled on every table (Supabase/Postgres and kin).
- Authentication verified server-side, never only in the browser.
- No IDOR: changing an id in a URL must never expose another user's
data. Authorize object access on every request.
- Passwords hashed (bcrypt/argon2). Session cookies httpOnly + secure
+ sameSite.
- API responses return only the fields the client needs.
- Login rate limiting, upload restrictions (type/size), forced HTTPS,
security headers.
+29
View File
@@ -0,0 +1,29 @@
# Writing style — user-facing prose
Scope: prose written FOR the user: answers, docs, reports, deliverables,
site copy. Does NOT override memory registries (caveman format), code
comments (code style rules), or structured skill/report templates.
Banned:
- Em-dash. Use a comma, a colon, or a period.
- The "it's not X, it's Y" / "ce n'est pas X, c'est Y" frame.
- Emojis, unless explicitly requested.
- Decorative bold. Bold marks a key term, not one word per sentence.
- Rule-of-three enumerations by reflex. Two often suffice, four sometimes.
- Hedging chains ("il est possible que", "could potentially", "in some
cases"). Assert, or say you don't know.
- Restating the user's question before answering it.
- Slop vocabulary, buzzword sense: delve, explorons, plongeons, "il
convient de noter" / "it's worth noting", figurative paysage/landscape,
robuste/robust, transformer/transform. Technical senses stay allowed
(robustness as a review lens, a math transform).
Do:
- Vary sentence and paragraph length. A short sentence after a long one.
- Write like speech. A sentence you cannot say aloud in one breath gets
cut in two.
- A paragraph over a bullet list when prose carries it.
Self-check before handing over a deliverable (text, site, feature):
reread against these rules (plus the web rules for a site) and tell the
user what you corrected to comply, or that nothing needed correcting.