Aller au contenu

Guidelines

Source of truth for code, UI, and process conventions in Aletheia. Anything written here is authoritative — code that violates these guidelines should be flagged in review and fixed.

This folder is for code authors and Claude. End-user / operator documentation lives in docs/. Roadmap and planning live in roadmap/. Cross-repo API and infra contracts live in contracts/.

Why a separate top-level folder

  • Single audience per file (Claude + developers writing code), single tone.
  • Mechanical scoping for hooks, audits, and PR-time checks (guidelines/**).
  • Drift is visible: a missing file for a recurring UI or backend primitive is an obvious gap.
  • Symmetric with the existing top-level concept folders (roadmap/, contracts/, docs/).

Layout

guidelines/
  README.md                         # this file — index + status of every guideline
  ui/                               # per-component visual rules
    search-sort-filter.md
    lists.md
    forms.md
    detail-pages.md
    dropdowns.md
    badges.md
    design-tokens.md
  ux/                               # system-wide interaction patterns (cross-component)
    page-states.md
    feedback-and-confirmation.md
    navigation.md
    microcopy.md
  backend/                          # Django patterns
    views.md
    models.md
    migrations.md
    forms.md
    admin.md
  security/                         # auth, isolation, PII
    multi-tenant-isolation.md
    auth-and-permissions.md
    pii-and-logging.md
  celery/                           # background jobs and beat schedule
    task-conventions.md
  integrations/                     # external connectors (Doctolib, Pennylane, Logosw, INPI)
    overview.md
    doctolib.md
    pennylane.md
    logosw.md
    inpi.md
  imports/                          # AbstractImporter / ImportRow patterns
    abstract-importer.md
  testing/
    pytest-patterns.md
    asserting-on-translated-strings.md
  i18n/
    translation-rules.md
  development-workflow/
    overview.md

ui/ vs ux/. ui/ is per-component visual rules (badges, lists, forms, dropdowns). ux/ is cross-component interaction patterns (empty/loading/error states, navigation, microcopy, feedback channels). When in doubt: if it's about one component's appearance, it's ui/; if it's a pattern that applies across many components, it's ux/.

Granularity rule. Every topic gets a folder, even if it currently holds a single file. Topics naturally grow (i18n splits into translation rules + model strings + JS strings; dev-workflow splits into git + environments + deploys), and folder-per-topic costs almost nothing today while making future splits painless. Audit globs stay uniform: guidelines/*/....

Naming. Folders and files are kebab-case. File names describe content, not topic (translation-rules.md, not i18n.md inside i18n/). No UPPER_CASE, no dates in filenames.

File format

Every guideline file should open with the same frontmatter so the status table stays accurate without manual bookkeeping:

# {Title}

> **Status:** Implemented | Draft | Placeholder
> **Last reviewed:** YYYY-MM-DD
> **Owner:** (optional)

## Scope
One paragraph: what this guideline covers and when it kicks in.

## Rules
The actual rules — copy-pasteable snippets preferred over prose.

## Known deviations
Where the codebase doesn't yet follow the rule, with a pointer to the roadmap item that closes the gap.

Status

Statuses: - Implemented — content is current and authoritative. - Draft — content exists but hasn't been reviewed against current code. - Placeholder — file exists to mark the gap; content to be written from an audit + skeleton/reference-page extraction.

Path Status Last reviewed Notes
i18n/translation-rules.md Implemented 2026-04-18 Consolidated to French source everywhere (Option B). Documents nl-be rationale, _(f"…") antipattern, percent-format convention, module constants pattern. Two backlog sweeps filed (model strings, template/view drift)
development-workflow/overview.md Draft 2026-04-14 Migrated from docs/DEVELOPMENT_WORKFLOW.md — verify deploy section still matches Makefile + deploy.sh
ui/search-sort-filter.md Implemented 2026-04-18 Authoritative for list/sort/filter stack; one known deviation (finance module) tracked in roadmap/backlog/finance-filter-unify.md
ui/lists.md Implemented 2026-04-18 Mined from skeleton + reference impls (practices, patients, holders); covers file layout, two empty states, action column, density rules; defers sort/filter to search-sort-filter.md
ui/forms.md Implemented 2026-04-18 Mined from skeleton + form-enhancements.{css,js} + holder_form (contextual reference); covers Alpine state, edit-mode safeguards, validation/auto-format hooks
ui/detail-pages.md Implemented 2026-04-18 Mined from skeleton + entity/practice references; covers heading + actions, two-column card grid, audit footer, layout-table-vs-data-table distinction; substitution cheatsheet for the 15 <h5>-in-card-header audit hits
ui/dropdowns.md Implemented 2026-04-19 SearchSelect as the form-picker primitive above ~8 options; explicit queryset .order_by; disabled_choices + "Déjà rattachés" separator; JS load order and FORM_RENDERER dependency; flags 3 deviations (link_practice missing form-enhancements.js, register/finance/websites native-Select FK audit, skeleton lacks SearchSelect example)
ui/badges.md Implemented 2026-04-18 4-state status palette + badge-type family modifier pattern; entity & movement variants; flags 2 internal inconsistencies (naming scheme, hardcoded oklch in module CSS)
ui/design-tokens.md Implemented 2026-04-18 Full catalogue mined from static/css/base.css; includes audit cheatsheet for the 2026-04 hardcoded-value findings
ux/page-states.md Placeholder Empty / loading / error / no-permission states across all pages
ux/feedback-and-confirmation.md Implemented 2026-04-20 Channel decision tree (toast vs banner vs hx-confirm vs _confirm_delete.html vs modal); canonical extra_tags='toast info' pattern; bulk partial-failure 3-way summary; flags 3 deviations (MESSAGE_TAGS not configured, ad-hoc confirm() in 4 sites, _confirm_delete.html structural drift across 8 templates)
ux/navigation.md Implemented 2026-05-01 Layout shell (base.html blocks), sidebar active-state via request.resolver_match, breadcrumbs context shape + section-root helpers, success_url post-create/update → detail, post-delete → list (older modules go to list — drift tracked), Cancel always <a href>, multi-select practice scope (cookie + URL override). Two backlog items + one idea filed
ux/microcopy.md Implemented 2026-05-01 Canonical EN→FR verb glossary (synced with scripts/audit_i18n_source.py); 5 hard rules — imperative button verbs, vous + sentence case, blame-free error tone, 2-line empty states, named-target destructive confirmations; flags 1 deviation (5 Êtes-vous sûr confirm-delete templates — folds into existing ux-confirm-delete-template-convergence sweep)
backend/views.md Placeholder Document SortableFilterableListMixin, HtmxResponseMixin, CBV conventions
backend/models.md Placeholder Document TimeStampedModel, AuditModel, SoftDeleteModel usage
backend/migrations.md Placeholder When to write a data migration, naming conventions
backend/database-schemas.md Implemented 2026-05-08 Schema-location rule (managed → public; unmanaged mirrors + raw landing tables → nomos/pennylane/raw); search_path mechanism, idempotent _move_if_in migration template, drift detection, anti-patterns; flags 4 deviations (5 misnamed *_namespace_tables.py files, qualified-vs-bare references in convention_dentaire_import.py, runtime DDL duplication, no automated drift audit)
backend/forms.md Placeholder Django form / ModelForm conventions, complements ui/forms.md
backend/admin.md Placeholder When to register, list_display / list_filter / inline conventions
security/multi-tenant-isolation.md Placeholder High blast radius — practice scoping rules, queryset filtering
security/auth-and-permissions.md Placeholder Custom User, login, permission decorators / mixins
security/pii-and-logging.md Placeholder What never to log, Sentry scrubbing, PII categories
celery/task-conventions.md Placeholder Task naming, idempotency, retry, beat schedule, failure surfacing
integrations/overview.md Placeholder Shared connector patterns (auth, retry, pagination, persistence)
integrations/doctolib.md Placeholder Doctolib API, daily 3 AM sync, appointment reconciliation
integrations/pennylane.md Placeholder Pennylane Redshift + REST v2, dual-backend abstraction
integrations/logosw.md Placeholder File-based ingestion via apps/collection/ + apps/imports/
integrations/inpi.md Placeholder INPI RNE via apps/annuaire/, code→label mappings
imports/abstract-importer.md Placeholder Document AbstractImporter lifecycle, ImportRow tracking, bulk mode
testing/pytest-patterns.md Placeholder Fixture conventions, integration vs unit boundary
testing/asserting-on-translated-strings.md Implemented 2026-04-23 Never hardcode _()/get_*_display() output in assertions; use Pattern A (stable code) or Pattern B (delegate to object's display helper). Surfaced by the 2026-04 coverage audit when 2 tests silently failed after the French-source sweep

Roadmap for this folder

Linear bring-up (one-time, per cluster)

A "cluster" is a top-level folder under guidelines/ (ui/, backend/, security/, celery/, etc.). Each cluster follows the same 4-step bring-up. The UI cluster was brought up first in 2026-04 and is referenced below as the worked example; other clusters apply the same recipe with their own scope.

  1. Beef up content — turn placeholders into Implemented files by mining the codebase: recent "consistency sweep" or refactor commits in the cluster's area, the cleanest reference implementations, any relevant skeleton/template files, and external references where applicable. Spawn the Placeholder graduation workflow (template below) per primitive. Worked example: UI cluster mined templates/skeletons/ + reference pages (patients, holders, practices) for the per-component rules.

  2. Retroactive audit — once a primitive's guideline is Implemented, spawn the Audit pass workflow (template below). The subagent grep-walks the cluster's relevant code paths against the new rules and produces a backlog file. Worked example: UI audit walked templates/**/*.html + static/css/* + apps/**/*.py for the i18n-related rule. Other clusters scope differently — security audits target apps/*/views.py + apps/*/admin.py; celery audits target apps/*/tasks.py + config/celery.py; etc.

  3. Proactive enforcementLive as of 2026-04-18, layered. The enforcement layers and forcing semantics are cluster-agnostic; only the rules added to the checker grow per-cluster. Two layers consume the same script (scripts/check_conformance.py — name is historical, the script enforces both UI and i18n rules and is structured to grow with new cluster rules):

  4. Layer A — PostToolUse hook (advisory). .claude/settings.json invokes the script after every Edit/Write/NotebookEdit. Prints [BLOCK] and [WARN] violations to stdout so Claude sees them in the tool result and self-corrects on the next turn. Never fails (exit 0 always).
  5. Layer B — Git pre-commit hook (forcing). .githooks/pre-commit runs the script with --strict against staged files on every git commit. Aborts the commit if any block-severity violation is found. Install with make setup-hooks (one-time per clone). Bypass --no-verify is reserved for genuine emergencies; Claude must not use it without explicit user permission.
  6. Rules + severity:
    • block (deterministic, safe to fail commits): rules with zero false-positive risk. Currently encoded: raw bg-*/text-bg-*/bg-outline-* on badges; <h5>/<h6> in card-header-neutral; <tr><th>X</th><td> layout-table signature; literal oklch()/#hex/rgb() outside static/css/base.css; _(\s*f"…") antipattern. Future clusters add their own deterministic rules (e.g. security: Model.objects.all() on practice-scoped models; celery: bare-name @task decorators).
    • warn (heuristic, kept advisory to avoid false-positive friction): English source string in _() / {% trans %} matching the curated dictionary from audit_i18n_source.py. Cluster-specific heuristic checks (e.g. backend: model without TimeStampedModel) would also live here.
  7. Manual check across the tree: make check-conformance.
  8. Out of scope (covered by audit scripts / subagents instead): semantic checks that need judgment (e.g. "layout table vs data table?", "is this empty state appropriate?"), full-codebase heuristic sweeps that risk false positives at hook scale (use the dedicated audit scripts in scripts/ for those).

  9. CLAUDE.md tightening — once a cluster's guidelines reach Implemented status, any rules duplicated in CLAUDE.md become thin pointers into guidelines/<cluster>/. Worked example: the 2026-04 UI cluster bring-up retired the entire "UI Design System" → "Pending guideline migration" subsection of CLAUDE.md as each UI primitive graduated. Future clusters follow the same pattern: rule duplications in CLAUDE.md get retired into pointers as the corresponding guideline lands.

Status of the bring-up across clusters (as of 2026-04-19): - ✅ UI cluster: 8/8 primitives Implemented; audit done; enforcement live; CLAUDE.md tightened. - ✅ i18n cluster: 1/1 primitive Implemented; convergence sweep done; rolling audit tooling kept. - 🔄 All other clusters (ux/, backend/, security/, celery/, integrations/, imports/, testing/, development-workflow/): placeholders prepped with self-sufficient structure (per "What a good placeholder contains" below); ready to graduate via the Placeholder graduation workflow whenever a trigger fires.

Three reusable workflows

Three subagent-runnable workflows cover everything that happens to a guideline after the cluster's Linear bring-up reaches it. Each has its own template later in this section.

Workflow Question Output
Audit pass "Does the code follow the rules?" Audit-derived backlog file → fixes applied → spin-out deferrals → done
Challenge pass "Are the rules the right rules?" Keep / Change / Add / Drop report → guideline updates or Ideas
Placeholder graduation "Should the placeholder become Implemented?" Implemented guideline + signals to triage

Cadence and complementarity:

  • Audit (continuous, mechanical) surfaces violations of existing rules. Eventually hook-driven via make check-conformance and the pre-commit hook for deterministic rules; subagent-driven for heuristic ones.
  • Challenge (periodic, judgmental) questions the rules themselves — surfaces missing rules, stale assumptions, primitives that should exist but don't.
  • Placeholder graduation (one-time per primitive, often parallel-session) turns a Placeholder into an Implemented guideline. Triggered by enforcement need, recurring questions, drift accumulation, or adjacent work.

Audit alone produces a locally-consistent codebase converging on possibly-suboptimal rules. Challenge alone produces evolving rules nobody adopts. Graduation alone produces guidelines without enforcement. Use all three; the templates below are the recipes.

Audit pass — template

Run an audit against one Implemented guideline at a time. The audit surfaces every place the codebase diverges from the rules, files them as a backlog item, and the work to address them follows the standard backlog → done flow (with the spin-out convention for any deferrals — see roadmap/ROADMAP.md "How this works").

Triggers — run an audit when one is true: - Just graduated — the guideline flipped Placeholder/Draft → Implemented. Verify the codebase against the new rules; surface the gap. - Hook upgrade — a new rule just landed in scripts/check_conformance.py. The hook will catch future violations; the audit catches the existing ones. - Periodic — guideline has been Implemented for ≥ 6 months without an audit pass. Drift accumulates silently. - Code-review signal — reviewers keep catching the same kind of violation in PRs. Time to find them all at once instead of one at a time. - Incident-driven — a bug or near-miss pointed at a guideline rule that wasn't being followed somewhere. Sweep for similar cases.

Process:

  1. Pick one Implemented guideline. Write the trigger in one sentence: "Audit ui/badges.md because [reason]." Confirm status is Implemented (not Draft or Placeholder — auditing against unstable rules wastes the subagent's work).

  2. Spawn an audit subagent. Skeleton prompt — substitute <primitive> with the guideline's relative path (e.g. ui/badges.md):

TASK: Audit the Aletheia codebase for violations of the rules in guidelines/<primitive>.md. This is a one-shot scan against a single Implemented guideline.

Working directory: /Users/baudry/coding/aletheia/aletheia_v2

READ FIRST: guidelines/<primitive>.md. Note the Hard rules section — those are the audit targets. Skip rules with severity='warn' or "When to break the rules" exceptions unless explicitly asked.

FOR EACH HARD RULE: - Construct a precise grep / multi-pattern search (cover variants — e.g. for bg-* badges, also search text-bg-* and bg-outline-*; for _(...) strings, also check gettext_lazy(...) and {% trans %}). - Run the search across the relevant scope (templates, apps//.py, static/css/, etc. — match the rule's scope from the guideline). - List file:line for each violation. Cap at top 10-15 per rule with a count summary if the total is high. - Per rule, include a one-line "fix hint" pointing at the canonical pattern in the guideline.

LESSONS FROM PRIOR AUDITS (encode these into your search patterns): - Subagent grep patterns drift toward false positives — for any rule that surfaced overstated counts in past audits (e.g. <table> in detail pages flagged data tables as layout tables), validate the layout-table-vs-data-table distinction by spot-checking the candidates' structure (single-<th> per <tr> = layout; multi-<th> in <thead> = data). - Subagent grep patterns also miss variants — always run multi-pattern searches, not single-pattern. - Check for canonical references in the codebase before classifying findings as violations — a file may already use the right pattern and serve as the model for the others (e.g. GLTrialBalanceImportView was the canonical i18n reference all along). - Subagent reports describe intent, not facts — verify any "fixed/unfixed" claim independently when consuming this report.

OUTPUT: a single Markdown report with one section per hard rule. Each section: rule recap (one line), violation count (audit + actual / verified if you re-counted), top 10-15 file:line examples, one-line fix hint, concentration map (which 3-5 apps/folders have the most violations).

Cap at 500-600 words. Don't write any files (the consuming session will turn this report into a backlog file). Don't propose architecture changes. Just the audit report.

  1. Triage the report into a backlog file. Take the subagent's report and create roadmap/backlog/<primitive>-audit-YYYY-MM.md with:
  2. Status table at the top — finding | audit count | actual count | status (PENDING initially) | commit (filled when applied).
  3. Findings sections — one per rule, with the file:line lists and fix hints.
  4. Approach — phases or per-app PRs to address the work.
  5. Definition of done — checkbox list including "0 / 0 violations on make check-conformance re-run."

  6. Pick up the backlog and address. Apply fixes per the chosen approach (often per-app PRs).

  7. Verification re-run. After the fixes land, re-spawn the same audit subagent with the same prompt. The verification surfaces:

  8. Confirms 0 remaining violations (the success signal).
  9. Catches missed-variant violations the first audit's pattern didn't cover (e.g. bg-outline-secondary slipped past the original bg-* pattern). Fix any of these inline; they don't justify another full audit cycle.

  10. Handle deferrals via spin-out (per roadmap/ROADMAP.md "Done means zero follow action — handle deferrals with spin-out"). Each explicit "decided not to act" item becomes its own ≤30-line backlog file with deviation + rationale + revisit trigger + cross-ref to the parent audit.

  11. Close the audit file. Move to roadmap/done/. Update ROADMAP.md (remove from Backlog, add to Recently Completed). Optionally: encode any new deterministic rules in scripts/check_conformance.py so the same drift doesn't return.

What NOT to audit: - Placeholders or Drafts. Audit needs stable rules; auditing against rules that may change wastes work. - Heuristic-only guidelines (e.g. UX microcopy tone). Audit those informally; they don't fit the deterministic-grep model. - Anything with no measurable hard rules (purely descriptive guidelines). Re-frame the guideline before auditing.

Output convention: - Backlog file: roadmap/backlog/<primitive>-audit-YYYY-MM.md (e.g. ui-design-system-mechanical-fixes-2026-04.md). - Spun-out deferrals: roadmap/backlog/<area>-<thing>.md (no -audit- infix; they're standalone backlog items). - Done file: same name, moved to roadmap/done/.

Reference example (the convention's mature form): the 2026-04 UI design-system audit (roadmap/done/ui-design-system-mechanical-fixes-2026-04.md) — surfaced 67 violations across 4 rules, all addressed via Phases A+B+C, with 2 single-occurrence deviations spun out as ui-tokenise-avatar-size.md and ui-tokenise-progress-bar-size.md. The verification re-run caught one missed-variant (bg-outline-secondary) the original audit's pattern missed.

Challenge pass — template

Run a challenge against one primitive at a time. Cap at 1-2 challenges per quarter, only against primitives showing a real signal (see triggers below). Resist the urge to re-litigate everything.

Triggers — run a challenge when one is true: - Recurring deviations in audit output for the same primitive (3+ deferred items in a row → the rule is missing, not the code is wrong). - User pain surfaces in real flows (e.g. "I had to fix the dropdown sorting on every form" → ui/dropdowns.md needs a challenge). - External drift — a new reference design system landed (Material You, Geist, Primer) and our equivalent primitive feels old. - Time-based — primitive is Implemented but hasn't been reviewed in >12 months.

Process:

  1. Pick one primitive. Write the trigger in one sentence: "Challenge ui/forms.md because [reason]." If you can't fill that sentence, don't run the challenge.

  2. Spawn a challenge subagent. Skeleton prompt:

    Read guidelines/<primitive>.md. Then: - Survey 5 real implementations in the codebase that should follow it. Note where the rule fits, where it doesn't, where the implementation diverged anyway. - Compare to 1-2 external references (name them: e.g. GitHub Primer forms, Vercel Geist forms). - Identify 3 things the current rule does not address but should. - Identify 1-2 rules that look outdated or rarely useful and propose retiring or rewording them. - Output: a single Markdown report under 500 words, structured as "Keep / Change / Add / Drop." Don't write to any guideline file — just propose.

  3. Triage the report. For each Keep/Change/Add/Drop:

  4. Quick wins (clear consensus, low risk) → edit the guideline directly, bump Last reviewed, note the change in commit message.
  5. Bigger changes (need design discussion) → file as roadmap/ideas/guideline-<primitive>-challenge.md. Promote to backlog only after discussion.
  6. Rejected → note inline in the guideline as a "Considered and rejected" anchor (so the next challenge doesn't re-propose it).

  7. Bump status if material. A challenge that significantly rewrites a guideline resets its status to Draft until re-reviewed against current code. A challenge that confirms-with-tweaks keeps it Implemented but updates Last reviewed.

  8. Close the loop. Add a one-liner to the bottom of the challenged guideline: "Last challenged: YYYY-MM-DD — see roadmap/ideas/... (or commit <sha>) for outcome."

Output convention: - Challenge reports go to roadmap/ideas/guideline-<primitive>-challenge-YYYY-MM.md if bigger than a quick edit. - Audit reports go to roadmap/backlog/<primitive>-audit-YYYY-MM.md (the convention used 2026-04).

What NOT to challenge: - Placeholders. If the guideline isn't Implemented yet, you're writing it, not challenging it. - Rules that came from a recent incident or post-mortem. Those have their reason in the commit message; respect it. - Anything you'd reword purely for style. Challenges need to surface a real gap, not a rewrite for taste.

Placeholder graduation — template

The flip side of "challenge an Implemented guideline" is "graduate a Placeholder to Implemented." Same shape: a bounded one-primitive task, ideally runnable in a parallel session without re-deriving context. If a placeholder is too thin to support that, the placeholder itself needs to be beefed up first (see "What a good placeholder contains" below).

Triggers — graduate a placeholder when one is true: - Enforcement need — a new rule wants to land in scripts/check_conformance.py (or another forcing layer), but its source guideline is still a placeholder. The rule needs the doc to back it up. - Recurring questions — "how do we do X?" comes up in 2+ recent PRs/conversations and the placeholder is the natural home. - Drift accumulationmake check-conformance or a periodic audit surfaces violations that have nowhere to point ("see guidelines/ui/X.md" → placeholder). - Adjacent work — you're touching the same primitive for product reasons; document it while context is loaded.

Process:

  1. Pick one placeholder from the status table above. Confirm it's truly a Placeholder (not Draft) and read its current content — if it has fewer than the items in "What a good placeholder contains" below, beef it up before spawning a session.

  2. Spawn a graduation session in a fresh claude CLI terminal. Skeleton prompt — substitute <primitive> with the placeholder's relative path (e.g. ui/dropdowns.md). The session does graduation and signal triage in one shot: cheap inline fixes are applied; backlog/idea items are filed with a Status: Provisional marker that you confirm or delete afterwards.

TASK: Flesh out guidelines/<primitive>.md from Placeholder to Implemented. A developer or Claude reading the result should be able to apply the rules without grepping the codebase. ALSO triage and provisionally file every signal you find while doing the work — see PROCESS step 5 below.

READ FIRST (in this order — establishes the conventions you must respect): 1. CLAUDE.md — project conventions (Makefile-only commands; LANGUAGE_CODE='nl-be' is intentional; commit message style Area: action). 2. guidelines/README.md — index, status table, layout rules. Update the status table at the end when you're done. 3. guidelines/<primitive>.md — the placeholder. Its "Reference structural sibling" tells you which Implemented guideline to mirror in shape; its "Sources to mine" lists the codebase entry points; its "Out of scope" tells you what to defer to other guidelines. 4. The structural sibling named in the placeholder (e.g. guidelines/ui/forms.md for component-style guidelines). 5. guidelines/i18n/translation-rules.md — French source for all _() and {% trans %} strings. 6. roadmap/ROADMAP.md "How this works" — for the spin-out and Provisional conventions you'll apply in PROCESS step 5.

PROCESS: 1. Read the codebase sources listed in the placeholder's "Sources to mine" section. 2. Write guidelines/<primitive>.md matching the structural sibling's shape (Status banner → Sources of truth → Scope → Hard rules → Required structure → conventions → Anti-patterns → Known deviations → When to break the rules). Aim for 200-280 lines. 3. Update guidelines/README.md status table: flip the row to Implemented + today's date + a one-line summary. 4. Run make check-conformance to confirm zero violations on your edits. 5. Triage signals found while reading the codebase. For each signal, classify and act in the same session: - Inline fix — mechanical, deterministic, ≤5 lines of code change, zero design judgment. Apply the fix. Run python3 scripts/check_conformance.py <file> to verify the fix doesn't introduce new violations. Mention each inline fix in the graduation commit message. - Backlog — real work to schedule (audit, refactor, multi-file change). File at roadmap/backlog/<area>-<thing>-YYYY-MM.md (or just <area>-<thing>.md for items without a dated context) using the standard backlog template (Area / Effort / Depends on header, Problem, Approach). Prepend the file with the Provisional marker (template below). - Idea — design choice, "useful someday" item, or anything without a clear trigger. File at roadmap/ideas/<area>-<thing>.md using the lightweight ideas format (no metadata required). Prepend with the Provisional marker. - Report-only — edge case you're unsure about. Don't file. List in REPORT BACK; the human will decide.

Provisional marker to prepend to every filed backlog/idea item:

> **Status:** Provisional — surfaced by the YYYY-MM-DD graduation of `guidelines/<primitive>`. Confirm or delete.
> **Filed by:** graduation session (single-shot triage; user override expected).
The user will confirm (delete the marker lines), edit, or git rm each filed item later.

Be conservative — only file if the signal is truly worth tracking. Don't pad. If in doubt, prefer Report-only. 6. Commit everything together (graduated guideline + status table + any inline fixes + provisional backlog/idea files). The pre-commit hook (--strict) will block on [BLOCK]-severity violations — fix them, never --no-verify.

CONSTRAINTS: - Hook is live: edits to templates/**, static/css/*, apps/**/*.py trigger scripts/check_conformance.py advisory output. - All Django commands via make targets; never raw docker compose exec or python manage.py. - Code identifiers stay English; only _()-wrapped display strings are French.

REPORT BACK: - Line count of the graduated guideline. - Commit hash. - The 3-5 hard rules you encoded. - Signals handled — list of inline fixes applied (file:line + one-line description), backlog files filed (path + one-line description + classification rationale), idea files filed (same), and any report-only signals (unsure cases for the user).

  1. Confirm provisional artifacts. Walk through each roadmap/backlog/... and roadmap/ideas/... file the session filed. For each:
  2. Accept as-is → delete the Status: Provisional and Filed by: lines. Commit.
  3. Edit then accept → tweak content, delete the marker lines. Commit.
  4. Rejectgit rm the file. Commit.
  5. Promote to in-progress → standard backlog → in-progress flow.

Provisional items left unconfirmed remain visible (the marker is conspicuous) and will surface in the next backlog review. They don't block anything.

  1. Optional follow-up: encode in the hook. If the new guideline has rules amenable to deterministic regex enforcement (no false-positive risk), add them to scripts/check_conformance.py with severity='block'. If they're heuristic, add as severity='warn'. Update the README's "Proactive enforcement" section accordingly.

What a good placeholder contains (so the graduation prompt is self-sufficient — no per-primitive customisation needed): - Status banner with Status: Placeholder and empty Last reviewed. - Reference structural sibling — which Implemented guideline (e.g. guidelines/ui/forms.md) to mirror in shape and depth. - Scope paragraph — what the guideline will cover. - Out of scope subsection — what NOT to cover, with explicit cross-refs to the guidelines that own those concerns. Prevents duplication. - Sources to mine — concrete file paths (with line ranges where useful), reference implementations, recent commits that surface the patterns. - Starter hard rules to investigate — bullet list of suspected rules the author should validate against the codebase. The graduating session may keep, refine, or drop each. - Decision points to settle — explicit "the author needs to choose between A and B" items. Surfaces design judgments that shouldn't be made silently.

guidelines/ui/dropdowns.md is the canonical example of a self-sufficient placeholder. Use it as a template when filing new ones.

What NOT to graduate this way: - Files that are already Draft — those need a verification pass against current code, not a from-scratch write. Edit directly. - Placeholders whose scope isn't yet decided — beef up the placeholder (Reference sibling + Out-of-scope) before graduating. - Anything that would duplicate an Implemented guideline — split or merge first.

Output convention: - Graduation lands as one commit per primitive (occasionally split if the work also needs a hook-rule addition or a separate audit run).

Update this README's status table whenever a file's status changes — it is the only manually-maintained index.