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 explanationnever 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 & 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 :
</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> : {c.description}{' '}
<span className="text-[#6A6A6A]">(onglet « {c.renvoi} »)</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> : 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> : z-scores robustes
(médiane et MAD) par groupe de pairs, ramenés à un percentile.
</li>
<li>
<strong>Score global</strong> : 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> : estimation indicative du redressement
potentiel (rappel d'impôt + pénalités forfaitaires de 40 %), par typologie.
</li>
<li>
Le moteur est <strong>déterministe</strong> (graine fixe) et{' '}
<strong>aveugle</strong> : 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 » : 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 :{' '}
<strong>{stats.score_moyen}</strong> ; montant total estimé :{' '}
<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> : la console ne déclenche
aucune action. Elle propose des dossiers ; l'agent les instruit et décide.
</li>
<li>
<strong>Traçabilité</strong> : chaque décision est journalisée avec horodatage
et matricule de l'agent.
</li>
<li>
<strong>Minimisation</strong> : seuls les signaux utiles au ciblage sont
présentés.
</li>
<li>
<strong>Biais</strong> : 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 % synthétiques</strong> :{' '}
{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 : 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 ; 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>
)
}