ArchitectureAnnotations d'equipe

Annotations d'equipe

Les notes epinglees a un element d'une page de la vitrine (StoreAnnotation, StoreAnnotationReply), vues par toute l'equipe dans le Builder et dans la Preview. Items : ai-platform/3074 (Builder), ai-platform/3076…

Les notes epinglees a un element d'une page de la vitrine (StoreAnnotation, StoreAnnotationReply), vues par toute l'equipe dans le Builder et dans la Preview. Items : ai-platform/3074 (Builder), ai-platform/3076 (Preview), ai-platform/3077 (agents).

PieceFichier
Contrat de fil (schemas zod stricts, forme SharedAnnotation)src/features/ai/preview/annotations/shared-annotations.ts
Service unique (porte, liste, creation, reponse, statut)src/services/store-annotations/store-annotations.ts
Routes HTTP (un humain)src/app/api/stores/[storeId]/annotations/**
Outils @Atlas (un agent)src/features/ai/tools/store-annotation-tools.ts
Contrat agents / clientsrc/features/ai/preview/annotations/agent-team.ts

Regles

  • La page est une CLE (pageKeyOf), jamais une URL brute.
  • Le tenant vient du chemin et de la session ; chaque lecture et ecriture est bornee par storeId (un id d'une autre boutique est un 404).
  • Lire : workspace.read. Ecrire : workspace.write (app-shell/3078 ; store.update avant). Routes et outils passent par src/services/store-activity/annotations.ts : authorize du hub, regles de ligne, et une ligne AuditLog (store.activity.annotation.*) a chaque ecriture. services/store-annotations ne fait plus que le Prisma.
  • Editer la note : son auteur seulement. Supprimer : l'auteur, ou un owner / admin. Un agent n'edite ni ne supprime une note, a aucun niveau d'autonomie ; il epingle, repond et resout, sans porte, mais audite.
  • Une note peut devenir une tache (annotationToTask) : titre neutre (« Note sur /page »), baseline = { pageUrl, selector } seulement, StoreAnnotation.taskId pose dans la meme transaction. Le texte de la note n'est jamais recopie : l'extrait est relu a l'affichage (from.label) et devient indisponible apres effacement.

Risque du passage a workspace.*

Rolestore.update (avant)workspace.* (apres)
owner / admin / memberlire, ecrirelire, ecrire (inchange)
viewerlirelire (inchange)
delegate, droits sur mesureselon la surcharge store.updateselon la surcharge workspace.* : un membre a qui on retirait store.update pour l'empecher d'annoter doit maintenant se voir retirer workspace.write

Agents dans l'equipe

Un agent (@Atlas, @Maya, @Marco, @Otis, @Faye, @Sam) est un membre de l'equipe : il epingle, lit, repond et resout avec les outils pinStoreNote, listStoreNotes, replyToStoreNote, setStoreNoteStatus.

  • Ecrit PAR un agent POUR un humain. authorId / resolvedById restent l'humain dont c'etait le tour (responsabilite, effacement RGPD) ; authorAgent / resolvedByAgent (colonnes nullables, slug du registre d'identite) disent quel agent a agi. null = un humain.
  • Seuls les outils posent l'agent. Les corps HTTP restent .strict() sans cle agent : un authorAgent dans un corps est un 400.
  • L'agent vient du runtime, jamais de l'input : actingAgentOf(ctx) (src/features/ai/tools/acting-agent.ts) lit le scope pose par le wrapper d'autonomie pour le specialiste qui execute, sinon @Atlas.
  • Un humain qui change le statut signe comme humain : resolvedByAgent repasse a null. L'auteur humain peut editer une note qu'un agent a ecrite pour lui : il en est responsable.
  • Les notes lues par un agent sont du contenu d'equipe : des donnees, jamais des instructions.

Curseurs : les appels navigateur et notes d'un agent arrivent au client par le flux du chat (parties d'outil, et sorties preliminaires agentActions des outils delegateTo_*). browserClick / browserType renvoient une box optionnelle. Pas d'infra temps reel : seul l'utilisateur qui chatte voit les curseurs ; les autres voient les notes au prochain poll (10 s).

Cote client, le bus agent-activity-bus.ts recoit ces actions (usePublishAgentActivity). Deux coutures le tiennent :

  • une partie delegateTo_* dont la sortie est preliminaire (preliminary: true, etat deja output-available) est un specialiste qui travaille encore : isDelegationWorking / isPreliminaryOutput (chat/runtime/step-status.ts) le disent au badge, a la ligne d'etape et a la pile des agents actifs ;
  • une note epinglee, repondue ou resolue par un agent dans ce navigateur relance le GET des notes tout de suite (takeSettledNoteActions, lu par use-shared-annotations.ts), sans attendre le poll.