Audit final de parcours — nouvel utilisateur / power user / admin (2026-09-11)
Lecture seule sur le code, sauf les correctifs listes en tete de chaque section (appliques dans la meme session, testes, pnpm test + pnpm typecheck + pnpm lint verts avant commit). Demande initiale : un dernier audit…
Lecture seule sur le code, sauf les correctifs listes en tete de chaque section (appliques dans la meme session, testes,
pnpm test+pnpm typecheck+pnpm lintverts avant commit). Demande initiale : un dernier audit complet une fois toutes les sessions fleet precedentes terminees, pour fermer les derniers trous avant l'accueil massif d'utilisateurs reels. Aucune refonte, aucune nouvelle feature — audit de coherence uniquement.
Etat au demarrage
origin/mainaac77568(PR #1018 mergee), aucune branchefleet/*sur origin,pnpm fleet:status:active locks 0.- 25 items de backlog portaient
status: "claimed"ou"in-progress"avec une branche absente d'origin : verrous fantomes. Verification PR par PR (pull_request_read, methodeget, jamaislist— son champmergedn'est pas fiable) : les 25 sont mergees. Tous archives dans cette session, avecpr:renseigne et une section## Livre(ou la section narrative existante suffisait deja) — voirbacklog/_archive/*. - L'audit complet du 2026-09-03 avait ouvert 113 items references par ce
document (dont les 4 P0 cross-tenant) : les 113 sont archives. Les 4
P0 (
ai-platform/0160,0161,integrations/0163,commerce-systems/0162) sont verifiees corrigees en code, pas seulement sur parole (lu ligne a ligne :getStoreAccesspose avant tout acces, CSP nonce en en-tete sur le proxy preview).
Methode
Huit agents en lecture seule, un par pilier concerne, charges de tracer les parcours majeurs de trois personas (nouvel utilisateur, power user, admin) en lisant le code (pas de serveur dev/DB disponible en session distante) et de chercher des regressions, dead ends et incoherences residuelles entre systemes desormais stabilises — en particulier dans les zones a fort volume de PR recentes (pricing v4.0, refonte menu Features, purge ContextIQ, pages Spy). Consigne explicite : aucune nouvelle feature, aucun refonte.
Correctifs appliques dans cette session
| # | Constat | Fichier(s) | Gravite |
|---|---|---|---|
| 1 | DELETE /api/integrations/shopify/custom-app ecrivait status: "disconnected", valeur absente de l'enum Postgres ConnectionStatus (pending|paired|active|revoked) : le write levait, 500 systematique, token + secret jamais effaces | src/app/api/integrations/shopify/custom-app/route.ts, src/types/integrations.ts, test associe | Majeur — un marchand ne pouvait pas deconnecter sa boutique Shopify |
| 2 | /[orgSlug]/~/agents lit et ecrit l'autonomie des agents via withSessionAuth({ requireOrg: true }) sans jamais passer ?orgId= : un membre de deux orgs ouvrant l'org B lisait/ecrivait l'autonomie de l'org A (fallback sur l'adhesion la plus ancienne) | src/app/(dashboard)/[orgSlug]/~/agents/page.tsx, src/components/patterns/agent-autonomy/autonomy-selector.tsx | Bloquant — gouverne si l'IA agit sans validation |
| 3 | Trois helpers de mutation (updateOrganization, updateStore, updateUser) n'inspectaient jamais res.ok / le shim d'erreur : un refus serveur (403 role insuffisant, 400 validation) laissait le patch optimiste en place et l'appelant affichait "Changes saved" | src/components/contexts/tenant-context.tsx | Majeur |
| 4 | Suppression compte/org/store : les trois onDelete du SettingsDropdown n'inspectaient pas res.ok — un 403 (non-owner) ou un 500 (echec RGPD) etait annonce comme un succes et redirigeait l'utilisateur | src/components/shells/app-shell/shell-client.tsx | Majeur — chemin Article 17 |
| 5 | Zone de danger + formulaire de [orgSlug]/[storeSlug]/settings rendus a tous les roles alors que DELETE est owner-only (access.isOwner) : un viewer pouvait taper le nom, confirmer, et recevoir "Owner only" | settings-manager.tsx | Majeur |
| 6 | onSave du formulaire store n'attendait pas updateStore(...) (pas de await) : meme apres le correctif #3, l'erreur devenait un rejet de promesse non gere au lieu de remonter au try/catch d'EntityForm | settings-manager.tsx | Majeur |
| 7 | Page /pricing correcte ($79/$199/$399) mais la home (FAQ + FAQPage JSON-LD) vendait encore $49/mo Pro et "$49-$299/mois" dans les 6 locales — servi aux answer engines comme reponse structuree au prix | messages/*.json (home.faq.groups.pricing.items.cost.a, …comparisons.items.vsFreelancer.a) | Critique — premiere page du parcours, contredite au clic suivant |
| 8 | /features/workspace affirmait encore "Included credits match the plan price" (la regle 1:1 que l'ADR 0012 a explicitement retiree), en 6 locales (FR traduit, EN/DE/ES/IT/PT identiques = jamais traduits) | messages/*.json (marketingPages.features.subpages.workspace.howItWorks[2]) | Majeur |
| 9 | /network/referral calculait l'exemple de gain sur l'ancien prix Pro ($49 → $14.70/mois), sous-estimant la vraie commission de $9/mois/parrainage ($79 → $23.70) | src/app/(marketing)/network/referral/page.tsx + messages/*.json (desormais derive de PLAN_PRICING + AFFILIATE_COMMISSION_PCT, ICU params) | Haute |
| 10 | Bloc i18n fantome pricing.plans.* / pricing.subscription.* / pricing.enterprise.* (top-level, distinct de nav.pricing.* qui est le vrai lu par la navbar) : zero lecteur, mais memes chemins de cles que la nav — piege de derive qui aurait fait revenir $49 en prod au premier refactor de la nav | messages/*.json | Moyenne (latent) |
| 11 | Copy "Systems installed on this store" (6 locales) — regression du retrait documente dans CLAUDE.md (rien ne lit SystemInstall) | messages/*.json (features.workflow.systemsTab.intro), docblock systems-tab.tsx | Haute |
| 12 | llms.txt/llms-full.txt/community/docs gardaient des mentions "CLI"/"SDK" retirees (marketplace/0587), dont une auto-contradiction a 41 lignes d'ecart dans le meme fichier | src/app/llms.txt/route.ts, llms-full.txt/route.ts, community/docs/page.tsx, messages/*.json (3 cles × 6 locales) | Moyenne |
| 13 | Lien mort /docs/marketplace/verified-revenue (aucune route /docs/* n'existe) sur le formulaire d'edition vendeur | sell/dashboard/[id]/edit/page.tsx, ancre #faq ajoutee sur /sell | Mineure mais 404 franc |
| 14 | Formulaire admin de resolution de litige : defaut sur REFUND_FULL, qui leve toujours escrow-refund-manual sur un litige de deal (pas d'escrow cable) — l'admin voyait le code d'erreur brut au lieu de l'option correcte | account/disputes/[id]/_components/admin-resolve-form.tsx + page appelante | Haute — chemin de mediation d'argent |
| 15 | Copy "magic-link" residuelle dans /account/settings/authentication (6 locales) + 2 docblocks — le magic link est retire depuis security-identity/0267, OTP seul provider | messages/*.json, (minimal)/auth/page.tsx, api/organizations/invitations/route.ts | Mineure |
Trois nouveaux tests de regression source-level (memes conventions que
connector-oauth-entrypoints.test.ts : un template literal n'a ni
compilateur ni routeur pour repondre de lui) :
src/test/agents-autonomy-scopes-to-current-org.test.ts,
src/test/store-settings-danger-zone-is-owner-gated.test.ts,
src/test/tenant-mutations-check-res-ok.test.ts.
Ce qui reste ouvert — reference complete par pilier
Les huit rapports d'agent complets (chaque constat cite fichier:ligne + preuve verbatim) ne sont pas reproduits ici pour eviter un second fichier de 500 Ko : ils ont ete lus integralement pour produire ce resume et les items de backlog ouverts ci-dessous. Ce qui suit est la liste des constats non corriges dans cette session, par gravite decroissante.
P0/P1 — a traiter en priorite par le pilier concerne
marketplace— La porte KYC unique (ADR 0011,apaSignedAtsurDILIGENCE → APA_SIGNED) est contournable : le VENDEUR peut signer l'APA sans aucune verification KYC (l'exemption vendeur est deliberee et testee), et c'est cette meme colonne partagee que lit la transition — donc sur un deal ou le vendeur signe en premier, l'acheteur n'est jamais verifie avant l'entree en escrow.src/services/marketplace/seller.ts:545-551(le check ne testedeal.buyerId === userId) +deal-stage-policy.ts:106(bouton seller-only) +sell/deals/[id]/[doc]/page.tsx. Correctif : deplacer la condition sur la TRANSITION (DEAL_ADVANCE.DILIGENCE.requires), jamais sur qui signe. →backlog/marketplace/0596.ai-platform—useResumePendingMessage(0590) est branche a l'envers : mort sur le SEUL mount dashboard (qui passeonAuthRequired, donc la gardeif (onAuthRequired || sent.current) returnsort tout de suite), vivant sur ~20 pages marketing (MarketingFaqSection,/pricing) qui ne le passent pas — un visiteur connecte avec du solde y envoie un tour/api/chatfacture dans un composer compact dont la transcription n'est jamais rendue. Meme racine : le bouton Envoyer et le chip Audit/Scan sont inertes pour un visiteur deconnecte sur ces memes pages (onAuthRequiredoptionnel, jamais fourni). →backlog/ai-platform/0597.ai-platform— Le separateur de compaction (0394) va s'afficher sur chaque tour passe 15 messages au lieu de marquer une coupure unique :droppedCountest un etat permanent (croissant de 2 a chaque echange), pas un evenement, etgetCompaction: () => droppedTurns > 0 ? {...} : undefined(handler.ts:1319) le re-declare a chaque tour. Regression exacte de ce que l'item 0394 voulait eviter. →backlog/ai-platform/0598.app-shell— Revenir d'un pas dans l'onboarding apres un reload cree une DEUXIEME organisation (le garde d'idempotence est unuseRef, ne survit pas au reload que le wizard sait par ailleurs reprendre), effacecurrentStore, et peut terminer le wizard sur un 404 (onboarding.tsx:372-382). →backlog/app-shell/0599.app-shell/marketplace— Les cinq surfaces acheteur (/account/orders,/offers,/deals,/disputes,/saved) n'ont aucune entree de navigation permanente :/account/dealsa litteralement zero lien entrant dans tout le depot hors sa propre balise canonical. Meme defaut que celui deja corrige pour~/listings(marketplace/0145), reproduit sur cinq surfaces a la fois. →backlog/app-shell/0600.intelligence— Consentement beta Intelligence :roleest selectionne puis jamais verifie (unviewerpeut engager la boutique dans le partage de donnees L4↔L1), aucunAuditLogsur l'action, et aucun chemin de revocation cote produit (revokedAtn'est ecrit nulle part).src/app/api/intelligence/beta/consent/route.ts:31-59. →backlog/intelligence/0601.commerce-systems—/systems/aeoet/systems/seoaffichent un score 0/100 · "needs improvement" ET "No recommendation: nominal state" simultanement pour un store jamais audite (capturedAt: nullrendu comme rien du tout). Contredit le principe du pilier ("un systeme qui affiche un score explique le score") et le voisin/systems/vitalsqui modelise correctement l'absence ennull. →backlog/commerce-systems/0602.commerce-systems— Boucle cassee sur/systems/tracking: le CTA "Run scan" pointe vers un scan PUBLIC qui ne portera jamaisstoreId(donc n'apparaitra jamais dans l'historique juste en dessous), et l'historique qui EST attribue au store porte un lien "View" qui 404 systematiquement (les scans lances depuis @Atlas mintent unshareIdsynthetique sans rapport persiste). →backlog/commerce-systems/0603.billing—/[orgSlug]/~/billingappellecreditCycle()sans son second argument (cycleAnchorDay), donc affiche la fenetre de cycle 1er-du-mois pour toute org dont l'ancre n'est pas le jour 1 — la carte usage voisine (org-usage-card.tsx) le fait correctement 30 lignes plus loin dans le meme repertoire. →backlog/billing/0604.growth-web— Le bouton "Customize" de la banniere cookies promet un centre de preferences ;/legal/cookiesn'a aucun controle (juste de la prose), et un visiteur qui a clique "Accept all" n'a plus aucun moyen produit de revenir dessus (le retrait passe par les devtools). RGPD. →backlog/growth-web/0605.marketplace—/sellaffiche 3% de commission dans son hero (derive deBOOSTECOM_MARKETPLACE_FEE_RATE) et 5% dans la modaleSellStoreWizardmontee 100 lignes plus bas sur la MEME page (COMMISSION_PCT = 5en dur). Le 5% contredit ce que le checkout facture reellement. →backlog/marketplace/0606.marketplace—marketplace/0587(retrait categorie CLI) n'est pas fini cote serveur :POST /api/vendor/marketplace/listings,POST /api/admin/marketplace/listingset le registreMARKETPLACE_LISTING_TYPESacceptent toujourstype: "CLI". Une soumission publique de type CLI reste possible, approuvable en admin, et l'email d'approbation pointe vers une URL qui 301 loin du listing. →backlog/marketplace/0607.
P2 — reels mais moins urgents, un item chacun ou groupes
integrations— Split-brainConnector(Google/Meta/Klaviyo) vsIntegrationConnection(Shopify/Figma seulement) : la bande connecteurs du composer (connectors-inline.tsx) lit/api/stores/[storeId]qui ne voit que la seconde table, donc Google/Meta/Klaviyo ne peuvent JAMAIS apparaitre "connected" dans le chat malgre un OAuth reussi. →backlog/integrations/0608.integrations— Revocation Klaviyo jamais appelee (revokeTokenexiste, zero appelant) ; echec de refresh Figma avale en silence (catch {}sans log, viole la regle non-negociable du pilier) ; branchechrome-extensiondeconnectors-inline.tsxinjoignable depuisCONNECTOR_ORDER— un id CWS y a ete pose aujourd'hui dans du code mort. → groupes dansbacklog/integrations/0609.app-shell—/[orgSlug]/[storeSlug]/intelligencen'a aucune porte de navigation, et son propre docblock affirme le contraire ("from the store nav") alors questoreRoutesn'a pas d'entreeintelligence. →backlog/app-shell/0610.commerce-systems— Le plan d'action strategique envoie l'action CRO vers/insights(qui n'a pas de funnel) au lieu de/systems/conversion(qui en a un, calcule par la meme fonction) ; trois Systems du registre (conversion,seo,tracking) ne sont jamais lies depuis le plan ; la copie du plan est du francais code en dur dans une app a six locales (src/features/action-plan/synthesizer.ts). →backlog/commerce-systems/0611.marketplace— L'ecritureAdminAuditLogd'une resolution de litige estcatch {}silencieuse APRES l'execution du remboursement Stripe : un echec laisse zero trace de qui a decide quoi pour combien. →backlog/marketplace/0612.growth-web—/features/intelligenceaffiche "Twenty probes" (titre de section) et "30+ probes" (badge + stat) dans le meme viewport, dans les six locales ; le vrai compte est 35 cles / 34 sondes (probes/index.ts). →backlog/growth-web/0613.growth-web—/community/docsvend 362 endpoints REST versionnes et une doc a plusieurs versions qui n'existent pas (content/docs/en/ne contient qu'un fichier), en pointant sur/features/apidont la FAQ dit l'inverse ("Not yet, and we would rather say so than sell one"). →backlog/growth-web/0614.growth-web— Parcours d'installation Spy : l'etape "Pin" se coche automatiquement pour 100% de l'audience visee (la page n'est ouverte que parchrome.runtime.onInstalled, doncinstalledest toujours vrai, et le seul conseil actionnable — "epingle-moi" — se cache exactement pour eux) ; le tutoriel MDX renvoie vers une fiche marketplace dont le CTA mene a la home, jamais au Chrome Web Store. →backlog/growth-web/0615.
P3 — mineurs, coherence/doc uniquement (pas d'item individuel — a corriger a l'occasion d'un passage dans le fichier concerne)
docs/architecture/marketplace.mdaffirme un ISR (revalidate = 300) que le layout racine (nonce CSP) desactive de fait ; contredit sa propre section 10, quinze lignes plus bas.- Plusieurs commentaires perimes dans
shell-client.tsx/sub-header-nav.tsx(routesrules/connectorsnon mappees dansactiveTab, entree~/activityqui ne mene nulle part,studiotoujours cite comme "deux contextes" alors qu'il n'en a plus aucun dans la barre). /account/settings/privacyreste orpheline (aucun lien entrant) malgre un controle produit reel (opt-out classement).setFeedbackResponse,updateRoadmapItem,deleteRoadmapItem,updateChangelogEntry: quatre server actions admin sans appelant.CompactionSeparator/ComposerUrlSuggestions: deux composants ayant perdu leur dernier appelant lors des livraisons recentes (0394, 0573), a trancher (brancher ou supprimer) au prochain passage sur ces fichiers.
Verification
pnpm test: suite complete verte (voir run post-correctif).pnpm typecheck: vert.pnpm lint: vert.pnpm i18n:parity,pnpm docs:claims,pnpm copy:dashes,pnpm copy:case: verts apres chaque lot d'editsmessages/*.json.pnpm fleet:status:active locks 0, plus aucun itemclaimed/in-progressorphelin.
Verdict
Le produit est structurellement pret : l'auth, le RBAC, l'isolation tenant, l'idempotence billing et les quatre P0 du 3 septembre tiennent a l'epreuve d'un second passage independant. Les quinze correctifs ci-dessus fermaient des dead ends et incoherences reelles introduits ou manques par le rythme de livraison des derniers jours (pricing v4.0, refonte Features, purge ContextIQ). Les points restants (KYC bypass, navigation acheteur absente, split-brain connecteurs, boucle scan cassee) sont reels et meritent chacun leur item — aucun n'est bloquant pour un premier accueil d'utilisateurs, mais le contournement KYC et l'absence de nav acheteur sont a traiter en priorite haute avant une croissance de volume sur le marketplace.