swapit — inventaire des toxiques ménagers + moteur d'échange
Ce qu'est cette compétence
swapit transforme une inquiétude vague ("il y a probablement beaucoup de plastique et de BPA chez moi") en un plan concret, priorisé et traçable. Elle est étatique : votre inventaire ménager vit sur le disque et persiste entre les sessions. Elle est local d'abord : zéro service payant, rien ne quitte votre appareil sauf si vous optez explicitement pour le commun (M3).
Un passage produit :
- Un inventaire des objets que vous possédez, chacun étiqueté avec sa classe d'objet générique.
- Un score de risque par objet qui reflète l'exposition réelle — une poêle antiadhésive rayée utilisée quotidiennement à haute température est bien plus prioritaire qu'un bac en plastique inutilisé dans le garage.
- Une liste "à échanger en priorité" classée — les 5% de changements qui réduisent le plus l'exposition.
- Un suivi des échanges — alternative choisie, statut d'approvisionnement, liste de vérification, signets.
- Un rapport HTML partageable (et, en M2, un tableau de bord en direct avec
swapit serve).
Les trois domaines (et l'invariant de confidentialité)
| Domaine | Ce qu'il contient | Partage |
|---|---|---|
| 1 · Connaissances | dangers → classes d'objets → alternatives (faits génériques, cités) | partageable ; mis en cache et (M3) synchronisé avec le commun |
| 2 · Inventaire | vos objets, pièces, quantités, marques, photos, échanges, signets | PRIVÉ — ne quitte jamais l'appareil |
| 3 · Commun (M3) | contributions anonymisées enrichissant le graphe de connaissances partagé | optionnel, révisé, faits génériques uniquement |
Invariant de confidentialité (contraignant) : L'inventaire du domaine 2 (objets, pièces, quantités, marques, photos, informations d'achat, emplacement) ne franchit jamais la frontière de synchronisation. Seuls les faits génériques du domaine 1 sont partageables, via une option explicite + un
swapit sync --dry-runrévisable. Appliqué par un sérialiseur basé sur une liste d'autorisation (scripts/anonymize.py) côté client et un filet de sécurité côté serveur du commun, plus des tests de fuzz affirmant que tout objet d'inventaire réel est rejeté par la barrière. Liste des champs interdits :anonymize.CONTRIBUTION_FORBIDDEN(le sous-ensemble structurel de l'inventaire destate.PRIVATE_FIELDS).
Modèle de données
L'état vit dans ~/.config/swapit/ (remplacez avec $SWAPIT_HOME ; respecte $XDG_CONFIG_HOME).
~/.config/swapit/
├── knowledge/ hazards.jsonl · item-classes.jsonl · alternatives.jsonl · products.jsonl · procurement.jsonl
├── inventory/ events.jsonl (journal d'audit en ajout seul) · items.json · swaps.json · rooms.json · bookmarks.json
├── contributions/ queue.jsonl (M3)
├── sync/ config.json · sync-log.jsonl (M3)
└── photos/
Schémas des nœuds (voir seed/*.jsonl pour l'ensemble de données complet et cité) :
- hazard —
id · name · aliases · class · mechanism · exposure_routes · regulatory · severity(0-3) · evidence_strength · sources - item_class —
id · name · category · description · hazards[]{hazard_id, presence_likelihood, rationale} · detection_hints · sources - alternative —
id · name · replaces[] · material · rationale · tradeoffs · caveats · avoids_hazards · residual_concerns · sources - procurement_option (où acheter, public) —
id · alternative · item_class · retailer · region(ISO-3166-1 a2) · area · url · price_min · price_max · currency · as_of · availability · confidence · corroboration_count - item (privé) —
id · name · item_class · room · quantity · brand · condition · usage{frequency, food_contact, heat, child_contact} · status · notes · photos - swap (privé) —
id · item_id · chosen_alternative · procurement{status, cost, vendor} · checklist[] · bookmarks[]
Modèle de risque
risk = severity × presence_likelihood × evidence × exposure_relevance × frequency × condition
- exposure_relevance active la voie d'exposition d'un danger en fonction de la manière dont l'objet est utilisé (contact alimentaire + chaleur maximise un danger par ingestion/contact alimentaire-chaleur ; le contact cutané compte pour les soins personnels ; l'inhalation pour le nettoyage/le mobilier ; le contact avec les enfants amplifie).
- Score de l'objet = somme pondérée du risque par danger → seuil élevé / moyen / faible.
- C'est l'intelligence de priorisation — l'analogue du "mode de défaillance dominant" du procureur : corrigez d'abord les quelques objets qui génèrent le plus d'exposition, pas une liste de culpabilité de tout ce qui est en plastique.
Modes
| Mode | Ce qu'il fait |
|---|---|
init | créer l'état + charger le graphe de connaissances initial |
add | ajouter un objet ménager (nom, classe, pièce, état, usage) → affiche son évaluation |
assess | évaluer un objet ou une classe d'objet ad hoc → dangers + risque + alternatives classées |
list | lister l'inventaire, filtrer par --room/--band/--status/--class/--hazard, trier par risque |
swap | créer/mettre à jour un plan d'échange : choisir une alternative, définir le statut, liste de vérification, signet, coût |
score | résumé de l'exposition du foyer + classement des priorités d'échange |
report | générer le rapport HTML autonome (Catégorie-C) |
procure | briefing de passation au procureur + offres d'achat connues pour la cible de l'échange (filtrer par --region) ; enregistrer une offre trouvée (--retailer/--url/--price-*) dans le commun public |
knowledge | parcourir/rechercher le graphe de connaissances (list/search/show) |
rooms | lister/ajouter des pièces |
selfheal | valider les arêtes du graphe de connaissances + les références d'inventaire + les fondations ; quitter avec un code non nul en cas d'erreur |
serve | tableau de bord local en direct sur http://127.0.0.1:8731 — tableau kanban, liste de vérification, signets, statut ; chaque clic écrit dans l'état |
contribute | mettre en file d'attente un fait anonymisé — product / hazard (item-class→hazard) / alternative / procurement (offre d'achat publique) / item-class (nouveau nœud de taxonomie) ; appliqué localement + filtré pour le commun |
sync | pousser la file d'attente des contributions + tirer les connaissances de la communauté (optionnel) ; --dry-run prévisualise exactement ce qui serait envoyé ; --configure définit le point de terminaison |
Flux typique
swapit init
swapit add --name "Vieille poêle Teflon" --class nonstick-cookware --room kitchen \
--condition scratched --frequency daily --food-contact --heat
swapit score # quoi échanger en premier
swapit swap itm_xxxx --to cast-iron-skillet --status sourcing --add-task "acheter une poêle de 25 cm"
swapit procure itm_xxxx # -> passer le briefing à la compétence `procurer`
swapit report --open # HTML partageable
Composition avec d'autres compétences
procurer—swapit procure <item>construit le besoin ("remplacer 3 bouteilles en polycarbonate par du verre/de l'acier") et l'invite prête pour le procureur ; le procureur retourne des sources citées + une enveloppe budgétaire.bookkeeping(P6) — une découverte nouvelle et durable concernant un danger/produit (par exemple une classe d'objet nouvellement caractérisée) est classée de manière proactive dansresearch/entities/et peut ensuite alimenter le commun.health— contexte d'exposition personnel.content-creation— publications éducatives à partir du graphe.
Discipline de fondation
Les connaissances initiales citent uniquement des organismes faisant autorité (NIEHS, ATSDR/CDC, US EPA, US FDA, ECHA/EU REACH, CA OEHHA Prop 65, WHO, EWG). Chaque enregistrement comporte ≥1 source ; verified: false les marque comme étant de qualité de référence (non fraîchement récupérées) — exécutez un passage sourcé (ou le commun) pour les rafraîchir. selfheal échoue si un nœud perd sa citation. Il s'agit de conseils aux consommateurs fondés sur la science de la santé publique, et non d'un avis médical ou juridique.
Ressources
scripts/swapit.py— point d'entrée CLI + gestionnaires de commandesscripts/state.py— couche d'état à deux domaines (PRIVATE_FIELDSdéfinit la frontière de synchronisation)scripts/ops.py— le chemin d'écriture unique de mutation d'état (partagé par CLI et tableau de bord)scripts/knowledge.py— chargement du graphe de connaissances + résolution des arêtesscripts/risk.py— moteur de notation du risque d'expositionscripts/report.py— générateur de rapport HTML autonome (Catégorie-C)scripts/server.py— tableau de bord en directswapit serve(serveur http.stdlib, localhost uniquement)scripts/anonymize.py— la barrière de confidentialité : constructeurs de faits sur liste d'autorisation + analyse des champs interditsscripts/sync.py— client de synchronisation du commun (file d'attente, prévisualisation--dry-run, push/pull, fusion)scripts/selfheal.py— validateur d'intégritétemplates/dashboard.html— le tableau de bord en direct (CSS/JS en ligne, Catégorie-C)commons/— le serveur de référence du commun en réseau (FastAPI + SQLite ; déploiement filtré)seed/{hazards,item-classes,alternatives}.jsonl— connaissances de démarrage fondéestests/— tests du risque, des connaissances, de l'auto-réparation, du CLI, de la confidentialité/anonymisation, de la synchronisation, du rapport et du serveur
Collaboration (le commun)
Les contributions sont uniquement des faits génériques — swapit contribute product|hazard|alternative|procurement|item-class construit un fait anonymisé (un mappage public produit→classe d'objet, une correction d'arête de danger, une alternative, une offre d'achat, ou un nouveau nœud de taxonomie), l'applique localement et le met en file d'attente. swapit sync --dry-run montre exactement ce qui serait envoyé ; swapit sync pousse la file d'attente et tire les connaissances de la communauté (optionnel, après --configure). Des faits identiques provenant de différents utilisateurs se corroborent (adressés par contenu) plutôt que de se dupliquer ; le commun sert un fait une fois que deux contributeurs distincts le corroborent (corroboration >= 2) — la modération est filtrée par corroboration, pas par confiance, car confidence est fourni par l'appelant et un seul soumissionnaire pourrait autrement s'auto-approuver. L'invariant de confidentialité est appliqué des deux côtés (barrière anonymize côté client + filet de sécurité côté serveur) — l'inventaire ne franchit jamais la frontière.
Commun d'approvisionnement (achat)
Un fait procurement_option est une offre publique : une alternative plus sûre vendue par un retailer dans une region (ISO-3166-1 alpha-2), avec url optionnel, price_min/price_max + currency + as_of, area et availability. Il est adressé par contenu sur (alternative, retailer, region) — la même offre se corrobore entre utilisateurs ; une région différente est un fait différent (l'axe d'échelle géographique). Prix/url/zone sont des données de marché affinables : une corroboration avec un as_of strictement plus récent rafraîchit le prix vers l'avant, ne régressant jamais les données plus fraîches. La frontière de confidentialité est nette — l'offre publique utilise retailer + price_* et jamais le vendor/cost privé (où vous avez acheté et ce que vous avez payé restent dans le Domaine 2). swapit procure <item> --region <CC> remonte les offres connues et enregistre les nouvelles que vous trouvez — faisant croître un ensemble de données ouvert, détaillé et géo-ciblé que tout le monde peut utiliser.
Feuille de route
- M1 (livré, 0.1.0) — modèle de données, connaissances initiales, CLI, moteur de risque, rapport HTML statique, auto-réparation.
- M2 (livré, 0.2.0) —
swapit serve: tableau de bord local en direct avec lecture/écriture dans l'état. - M3 (0.3.0) — collaboration anonymisée + commun en réseau (
commons/, FastAPI + SQLite). Invariant de confidentialité appliqué par sérialisation sur liste d'autorisation + tests de fuzz côté client et serveur. - M4 (cette version, 0.4.0) — approvisionnement géo-ciblé + croissance de la taxonomie via le commun : les types de faits
procurement_option(où acheter public, indexé par(alternative, retailer, region), rafraîchissement de prix uniquement vers l'avant) etitem_class(croissance de la taxonomie filtrée par corroboration) ;procureremonte et enregistre les offres ; offres initiales couvrant US/CO/DE/GB ; parité de hachage inter-langues verrouillée par des vecteurs épinglés. Le déploiement en direct sur l'infrastructure broomva.tech est conditionné à un accord explicite (identifiants/DNS) ; la compétence est entièrement fonctionnelle hors ligne sans cela.