Audit — pilier marketplace
Huitieme tour de la rotation (docs/team/roster.md, @codebase-auditor). Lecture seule sur le code. Ce tour differe des six precedents : les six piliers restants ont ete audites en une passe, a la demande. La profondeur…
Huitieme tour de la rotation (
docs/team/roster.md, @codebase-auditor).Lecture seule sur le code. Ce tour differe des six precedents : les six piliers restants ont ete audites en une passe, a la demande. La profondeur par pilier est donc moindre, et chaque document dit ou il s'arrete. La sonde commune est la meme partout : les invariants que le roster declare pour le pilier, parce que six tours ont montre que c'est la que l'ecart se loge.
Perimetre :
src/services/marketplace|sell|sponsor/**, routes marketplace, vendor et sell.Etat du depot :
origin/maina3e23edb7, 27 aout 2026.
Ce qui a ete verifie
| Sonde | Resultat |
|---|---|
| Invariant — payout vendeur en escrow, jamais au checkout | respecte |
Appels de transfert Stripe hors du cron marketplace-payouts | 0 |
| La fenetre de dispute est-elle une constante unique | oui — DISPUTE_WINDOW_DAYS = 14 |
| … importee par le cron de payout | oui |
| La fenetre est-elle verifiee cote serveur a l'ouverture d'une dispute | oui |
Aucun constat, et c'est le resultat
Le roster declare pour ce pilier :
« Le payout vendeur est en escrow jusqu'a la fin de la fenetre de dispute (14j), verse par le cron
marketplace-payouts: jamais au checkout. »
L'invariant tient, et il tient proprement :
DISPUTE_WINDOW_DAYS = 14est declare une fois (services/marketplace/disputes.ts:25) et importe par le cron (api/cron/marketplace-payouts/route.ts:33). Les deux moities de la regle, « on refuse une dispute apres 14j » et « on paie apres 14j », lisent le meme nombre. C'est exactement ce quebilling/0054etintegrations/0060reprochaient a d'autres valeurs : ici, c'est fait.grepsurtransfers.create,transfer_dataetapplication_feedansservices/marketplace,api/marketplaceetapi/vendor: aucune occurrence. Il n'existe pas de chemin qui transfere au vendeur en dehors du cron.- L'ouverture d'une dispute revalide la fenetre cote serveur
(
disputes.ts:95), donc un client ne peut pas la contourner en rejouant la requete.
Je n'ouvre pas d'item. La regle du role veut qu'un audit produise des items ; en produire un ici serait du remplissage, et le remplissage est ce qui fait qu'on cesse de lire les audits. Ce que ce document livre est une verification, datee et reproductible, de l'invariant le plus couteux du pilier : celui ou une erreur envoie l'argent d'un acheteur au mauvais moment.
Ce que cet audit n'a pas couvert
Beaucoup, et c'est le prix de la passe unique :
- Stripe Connect — onboarding Express,
account.updated,payout.failed: non ouverts. - KYC et signatures legales (V5.1) : non ouverts. Ce sont pourtant les surfaces qui manipulent de la PII chiffree.
- Le calcul du montant transfere : cet audit verifie quand le payout part, jamais combien. Une erreur de montant serait invisible pour lui.
- L'idempotence du cron de payout, la presence d'un garde-fou
never transferredest ecrite dans l'en-tete du cron ; elle n'a pas ete exercee. - Les remboursements et l'arbitrage admin : non ouverts.
Un auditeur qui ne borne pas sa portee laisse croire qu'il a tout vu.