Design Library

Model card - method, guarantees and limits

flair-model-card.tsx

componentskill: design-taste-frontenddocumentationcompliancepublic-recordseditorialdense

Brief

The prompt that produced this. Re-run it to generate more in the same taste.

Aesthetic
administrative prose - DSFR-sober, ruled, bordered cards, unornamented, long-form, legible at length
Reference
FLAIR méthode & conformité tab, model card summary
Intent
make a scoring system auditable by a reader who did not build it, including the parts that undermine confidence in it
Guardrails
always state the formula and its bounds in words a non-author can check, give limits the same visual weight as capabilities, name the data as synthetic wherever a number appears, keep the human-decides guarantee adjacent to the score explanation
never bury limitations below the fold or behind a toggle, present an estimate as an outcome, use a chart where a sentence is more precise, imply the model decides anything

Install

pnpm dlx shadcn@latest add http://localhost:3040/r/flair-model-card.json

Source

Meta block and library type import stripped - this is what pastes cleanly elsewhere.

'use client'

const eur = new Intl.NumberFormat('fr-FR', {
  style: 'currency',
  currency: 'EUR',
  maximumFractionDigits: 0,
})
const nombre = new Intl.NumberFormat('fr-FR')

const meta_donnees = {
  population: { foyers: 412_800, entreprises: 63_140 },
  avertissement: 'Démonstrateur sur données synthétiques — aucune donnée réelle.',
  genere_le: '2026-07-24T08:30:00Z',
  version: '1.4.0',
  annee_reference: 2024,
}

const stats = { score_moyen: 23.4, montant_total_estime: 18_420_000 }

/** Section heading with the DSFR left rule. Red marks the limits block. */
function Titre({ children, alerte = false }: { children: React.ReactNode; alerte?: boolean }) {
  return (
    <h3
      className={`mb-3 border-l-4 pl-3 font-bold text-[#161616] text-base ${
        alerte ? 'border-[#E1000F]' : 'border-[#000091]'
      }`}
    >
      {children}
    </h3>
  )
}

const capacites = [
  {
    titre: "Recherche d'entités",
    description:
      "entreprises issues prioritairement des registres publics officiels ; pour les personnes physiques, consultation des seuls mandats d'entreprise et rôles électifs, sans cache nominatif, sans résolution d'identité et avec audit pseudonymisé.",
    renvoi: 'Recherche',
  },
  {
    titre: 'Analyse de réseaux',
    description:
      "composantes connexes d'entreprises et de dirigeants (dirigeants partagés, chaînes de sociétés radiées), avec score de réseau 0-100 — ce qu'un ciblage dossier par dossier ne voit pas.",
    renvoi: 'Réseaux',
  },
  {
    titre: "Boucle d'apprentissage",
    description:
      'les décisions des agents sont agrégées en multiplicateurs bornés [×0,5 ; ×1,5] par typologie, qui réordonnent la file sans jamais automatiser la décision.',
    renvoi: 'Apprentissage',
  },
  {
    titre: 'Explication contrefactuelle',
    description:
      'chaque fiche dossier indique « ce qui ferait baisser ce score », calculé sur les seuils documentés du moteur.',
    renvoi: 'File de ciblage',
  },
]

export default function FlairModelCard() {
  const genere = new Date(meta_donnees.genere_le).toLocaleString('fr-FR')

  return (
    <main className="min-h-[100dvh] bg-[#F6F6F6] p-4 text-[#161616] sm:p-8">
      <section aria-labelledby="methode-titre" className="mx-auto max-w-5xl space-y-6">
        <div>
          <h2 id="methode-titre" className="mb-1 font-bold text-[#161616] text-xl">
            Méthode &amp; conformité
          </h2>
          <p className="text-[#3A3A3A] text-sm">
            Résumé de la carte modèle, des garanties et des limites du démonstrateur.
          </p>
        </div>

        <article className="border border-[#DDDDDD] bg-white p-5">
          <Titre>Nouvelle génération</Titre>
          <p className="mb-3 text-[#3A3A3A] text-sm leading-relaxed">
            Au-delà du scoring dossier par dossier, le démonstrateur illustre quatre capacités
            complémentaires, présentées dans les onglets dédiés&nbsp;:
          </p>
          <ul className="list-disc space-y-2 pl-5 text-[#3A3A3A] text-sm leading-relaxed">
            {capacites.map((c) => (
              <li key={c.titre}>
                <strong>{c.titre}</strong>&nbsp;: {c.description}{' '}
                <span className="text-[#6A6A6A]">(onglet «&nbsp;{c.renvoi}&nbsp;»)</span>
              </li>
            ))}
          </ul>
        </article>

        <div className="grid grid-cols-1 gap-4 lg:grid-cols-2">
          <article className="border border-[#DDDDDD] bg-white p-5">
            <Titre>Comment le score est calculé</Titre>
            <ul className="list-disc space-y-2 pl-5 text-[#3A3A3A] text-sm leading-relaxed">
              <li>
                <strong>Sous-scores par typologie (0-100)</strong>&nbsp;: fonctions monotones de
                l'écart relatif constaté (ratio détecté/déclaré, percentile dans la population).
              </li>
              <li>
                <strong>Score d'anomalie statistique (0-100)</strong>&nbsp;: z-scores robustes
                (médiane et MAD) par groupe de pairs, ramenés à un percentile.
              </li>
              <li>
                <strong>Score global</strong>&nbsp;: 0,7 × meilleur sous-score de règle + 0,3 ×
                score d'anomalie, borné entre 0 et 100. Un dossier sans signal reste sous 20.
              </li>
              <li>
                <strong>Montant estimé</strong>&nbsp;: estimation indicative du redressement
                potentiel (rappel d'impôt + pénalités forfaitaires de 40&nbsp;%), par typologie.
              </li>
              <li>
                Le moteur est <strong>déterministe</strong> (graine fixe) et{' '}
                <strong>aveugle</strong>&nbsp;: il ne connaît pas la vérité terrain utilisée pour
                l'évaluation.
              </li>
            </ul>
          </article>

          <article className="border border-[#DDDDDD] bg-white p-5">
            <Titre>Explicabilité</Titre>
            <ul className="list-disc space-y-2 pl-5 text-[#3A3A3A] text-sm leading-relaxed">
              <li>
                Chaque dossier proposé est accompagné de <strong>preuves sourcées</strong> avec un
                niveau de fiabilité.
              </li>
              <li>
                La comparaison <strong>déclaré vs détecté</strong> rend l'écart lisible chiffre à
                l'appui.
              </li>
              <li>
                La <strong>chronologie</strong> retrace la réception des signaux.
              </li>
              <li>
                Aucun « score opaque »&nbsp;: l'agent voit toujours pourquoi un dossier remonte.
              </li>
            </ul>

            <div className="mt-5">
              <Titre>Mesure de performance</Titre>
              <p className="text-[#3A3A3A] text-sm leading-relaxed">
                Le mode <code className="bg-[#EEEEEE] px-1">--evaluate</code> mesure
                précision@50/100/200, rappel global et par typologie, et lift vs tirage aléatoire,
                sur la vérité terrain synthétique. Score moyen de la population&nbsp;:{' '}
                <strong>{stats.score_moyen}</strong>&nbsp;; montant total estimé&nbsp;:{' '}
                <strong>{eur.format(stats.montant_total_estime)}</strong>.
              </p>
            </div>
          </article>

          <article className="border border-[#DDDDDD] bg-white p-5">
            <Titre>Cadre et garanties</Titre>
            <ul className="list-disc space-y-2 pl-5 text-[#3A3A3A] text-sm leading-relaxed">
              <li>
                <strong>Humain décideur (RGPD art. 22)</strong>&nbsp;: la console ne déclenche
                aucune action. Elle propose des dossiers&nbsp;; l'agent les instruit et décide.
              </li>
              <li>
                <strong>Traçabilité</strong>&nbsp;: chaque décision est journalisée avec horodatage
                et matricule de l'agent.
              </li>
              <li>
                <strong>Minimisation</strong>&nbsp;: seuls les signaux utiles au ciblage sont
                présentés.
              </li>
              <li>
                <strong>Biais</strong>&nbsp;: les scores mesurent des écarts documentés, pas des
                profils.
              </li>
            </ul>
          </article>

          <article className="border border-[#DDDDDD] bg-white p-5">
            <Titre alerte>Limites du démonstrateur</Titre>
            <ul className="list-disc space-y-2 pl-5 text-[#3A3A3A] text-sm leading-relaxed">
              <li>
                <strong>Données 100&nbsp;% synthétiques</strong>&nbsp;:{' '}
                {nombre.format(meta_donnees.population.foyers)} foyers et{' '}
                {nombre.format(meta_donnees.population.entreprises)} entreprises fictifs, générés de
                façon déterministe. Aucune donnée réelle n'est utilisée.
              </li>
              <li>
                La typologie « piscine » illustre un signal faible&nbsp;: la présence d'une piscine
                n'est pas une fraude en soi.
              </li>
              <li>
                Le journal des décisions est stocké dans le navigateur&nbsp;; il serait persisté
                côté serveur en conditions réelles.
              </li>
              <li>
                Les montants estimés sont indicatifs et ne préjugent pas du résultat d'un contrôle.
              </li>
            </ul>
            <p className="mt-4 border-[#E1000F] border-l-4 bg-[#FFE9E9] px-3 py-2 text-[#3A3A3A] text-sm">
              {meta_donnees.avertissement}  Fichier généré le {genere} (version{' '}
              {meta_donnees.version}, année de référence {meta_donnees.annee_reference}).
            </p>
          </article>
        </div>
      </section>
    </main>
  )
}