rp-telemetry

Par wix · skills

Compagnon de télémétrie toujours actif pour les runs de migration RePlatform. Enregistre ce qui s'est passé durant un run — arrêts, erreurs, pertes de fidélité, lacunes API, lacunes de couverture des skills, décisions utilisateur, défauts de pipeline — via un script d'enregistrement validé, ainsi que le récapitulatif du run (étapes, timings, volumes, vérification). Chargé par l'orchestrateur au démarrage du run et maintenu actif pendant toute sa durée.

npx skills add https://github.com/wix/skills --skill rp-telemetry

rp-telemetry

Capturez la télémétrie par exécution qui nous indique ce qu'il faut améliorer dans les skills et dans l'outillage Wix sous-jacent. Cette skill reste active aux côtés des skills de migration pour l'intégralité de l'exécution ; les skills de migration elles-mêmes ne sont pas modifiées et ne savent rien de la télémétrie.

La règle unique qui gouverne tout ce que vous enregistrez

Observation, pas diagnostic. Chaque champ enregistre ce qui a été observé — ce qui s'est passé, ce qui était attendu, ce qui s'est réellement produit, où et à quelle fréquence. Ne jamais enregistrer une cause profonde, une correction, une recommandation ou un contournement présenté comme une solution. Il n'y a délibérément aucun champ pour eux ; le schéma rejette les champs inconnus. La cause profonde est dérivée plus tard, au moment de l'examen, par un agent examinateur avec le contexte complet — pas affirmée par vous sur le moment.

Trois règles de discipline s'appliquent à chaque champ en texte libre (what_happened, expected, actual) :

  • Types, pas instances. Référencez les types et classes d'entités, jamais les données client spécifiques. entity_type: "product" — jamais le nom d'un produit, le SKU, le prix ou le contenu du corps.
  • Secret-safe. Aucune credential, token, URL, valeur de config ou contenu de fichier — l'enregistreur exécute également un nettoyage mécanique en dernière ligne de défense, mais ne vous y fiez pas.
  • Court et structurel. Une phrase ou deux, max 400 caractères. Préférez exposer expected-vs-actual plutôt que de narrer. Les champs codés portent la structure.
  • Pas de narration de remédiation. « La lib canonique a été corrigée et resynchronisée » est une histoire de correction, pas une observation — même si c'est vrai (backports en mode dev). Enregistrez ce qui a été observé comme fonctionnant (« ajouter fieldsets=FULL a retourné le champ ; la recherche a réussi ») et laissez la réparation au journal d'exécution.

L'enregistreur

Toute la télémétrie est persistée via l'enregistreur fourni — ne jamais rédiger ou éditer manuellement run-telemetry.json ou les fichiers telemetry/. Exécutez-le depuis ce répertoire de ressources (voir CONVENTIONS.md), en le pointant vers le projet de migration actif :

node scripts/rp-telemetry.js <command> [...] --project <abs path to migrations/<project>>

L'enregistreur est propriétaire de tout ce qui est mécanique : validation de schéma (il rejette les énumérations invalides et les champs inconnus — corrigez et réessayez, ne devinez jamais), horodatages, repliement d'événements par classe, le modèle run/attempt/session resume, le nettoyage de confidentialité et la porte de bien-formedness à la finalisation. Il imprime un résultat JSON par appel ; {"ok":false,...} liste exactement ce qu'il faut corriger.

Appel Quand
start '<dims-json>' Au début de l'exécution — avant toute autre étape du pipeline. Reprend automatiquement une exécution non finalisée.
dims '<dims-json>' Chaque fois qu'une dimension devient connue en cours d'exécution (version de la plateforme et extensions après la découverte, site_id après le provisionnement).
stage start <stage> / stage end <stage> --outcome <outcome> À chaque limite de stage. Résultats : passed, halted, failed, skipped.
meter [--api-ms N --model-ms N --script-ms N --input-tokens N …] Latences mesurées/décomptes de tokens pour un stage. Appelez-le chaque fois que vous avez des chiffres réels ; voir « Metering » ci-dessous.
wait start [--halt <subtype> --skill <s> [--what '<text>']] / wait end Le moment où l'exécution s'arrête pour l'utilisateur, et le moment où elle reprend. C'est ainsi que la latence utilisateur reste hors de active_ms — ne jamais estimer le temps écoulé vous-même. Passez --halt pour un arrêt needs-user et l'enregistreur émet l'événement halt_needs_user appairé pour vous.
record '<event-json>' Le moment où quelque chose d'observable se produit (taxonomie ci-dessous).
finalize '<rollup-json>' Quand l'exécution atteint un état terminal.
rebuild [--attempt <n>] [--push] Uniquement sur demande, pour réassembler le document de signal d'une exécution passée à partir de son journal archivé après une correction d'enregistreur — jamais pendant une exécution. --push ré-émet l'exécution reconstruite au sink BI (remplissage après une panne ; idempotent — l'examinateur déduplique au moment de la requête).
status Pour vous orienter après une reprise.

Cycle de vie de l'exécution

  1. start comme premier acte de télémétrie de l'exécution, avec toutes les dimensions déjà connues :

    node scripts/rp-telemetry.js start '{"source_platform":"wordpress",
      "source_site_url":"https://client-site.example","source_acquisition":"public_storefront",
      "delivery_mode":"management","destination_strategy":"new_site",
      "runtime_env":{"agent_runtime":"claude-code","model":"<model id>"}}' --project <dir>

    start sur un projet avec une exécution non finalisée la reprend (même exécution, même tentative, une session de plus) et ferme tout intervalle wait ouvert. start après une exécution finalisée ouvre la tentative suivante. Ne jamais essayer de gérer vous-même l'identité de l'exécution.

    source_acquisition est un ensemble ouvert de tokens de classe, mais réutilisez un token établi (admin_api, public_storefront, public_content, file_export) plutôt que de frapper un synonyme — le repliement inter-exécution dépend de tokens stables.

    La provenance des skills est auto-estampillée — vous ne la passez pas. À start, l'enregistreur appose deux identifiants sur l'exécution pour que chaque enregistrement puisse être retraçable aux skills qui l'ont produit :

    • skills_version — le label de version sémantique du bundle (depuis VERSION). Grossier et bump manuel par conception ; c'est la clé group-by/order-by qui lie les problèmes à une ligne de version (« tous les problèmes sur 1.2.x », « régression depuis 1.1.0 »).
    • skills_commit — le commit source exact à partir duquel le bundle a été construit : l'instantané vendorisé précis au sein d'une version. De nombreux commits sortent sous un skills_version bump manuel, donc une exécution rapportant 1.0.0 est autrement inattribuable au changement qui a produit son problème. L'enregistreur le résout, en ordre d'autorité, à partir du sourceCommit estampillé dans .publish-manifest.json à la publication (la seule source qui fonctionne dans un runtime partenaire, et la seule correcte une fois que le bundle est vendorisé dans wix/skills), sinon un git rev-parse --short HEAD mode dev du checkout source, sinon null.

    Les deux peuvent être remplacés en passant skills_version / skills_commit dans les dims start (un runtime avec une meilleure provenance que l'enregistreur peut déduire), mais normalement vous les laissez auto-résoudre.

  2. Les limites de stage au fur et à mesure que le pipeline avance. Mappez les étapes de l'orchestrateur aux stages comme ceci :

    Stage Couvre
    config Tout avant la découverte : résolution du projet, fichiers de config, collecte d'entrée en amont
    discovery Découverte source (rp-discovery + adaptateur source)
    mcp_gate La porte de prérequis Wix MCP entre la découverte et le mapping
    mapping rp-mapper produisant le plan de mapping
    mapping_review Le point de contrôle d'examen du mapping (face à l'utilisateur)
    setup_discovery rp-setup-discovery
    codegen rp-import-codegen
    approval_gate La porte d'approbation du plan d'exécution (face à l'utilisateur)
    setup_provisioning Création de site, installations d'app, collections — rp-execute-setup
    storefront_build La compilation + publication wix-headless en mode website ; skipped en mode management
    extract Extraction source sur disque, avant toute écriture (rp-execute-import)
    import Les écritures d'import (rp-execute-import)
    finish Vérifications spot-check, rapport d'achèvement, remise

    Les stages se lient au moment où le travail s'exécute réellement, pas à leur ordre canonique. Si l'orchestration exécute l'extraction en amont (ex. extract + dry-run avant la porte d'approbation, à l'intérieur de la phase codegen), fermez le stage ouvert, encadrez l'extraction dans son propre stage extract, puis rouvrez — un stage peut être entré plus d'une fois, et son active_ms somme les entrées. Réserver une extraction réelle dans codegen (et laisser extract comme un stage token de quelques millisecondes) est exactement la mal-attribution que le stage extract existe pour prévenir.

    Quand le stage discovery se termine, toujours estampillez ce qu'il a appris : dims '{"source_platform_version":"...","source_extensions":["..."]}' — passez [] explicitement quand la découverte n'a trouvé aucune extension ; un null laissé derrière est signalé dans telemetry_health comme source_extensions_null_after_discovery.

  3. wait start / wait end autour de chaque arrêt needs-user : demandes de credential, le point de contrôle d'examen du mapping, la porte d'approbation, tout arrêt-to-needs-user. Passez la classe d'arrêt sur le même appel — wait start --halt missing_input --skill rp-mapper --what "run halted at the mapping-review checkpoint awaiting approval" — et l'enregistreur émet l'événement halt_needs_user appairé mécaniquement ; un wait bloqué sans événement halt dans son stage est signalé dans telemetry_health (wait_without_halt_event:<stage>). Si la session est sur le point de se terminer sur un arrêt, laissez le wait ouvert — le start de la reprise le ferme, donc la latence utilisateur du jour au lendemain atterrit dans waiting_ms où il appartient. Si vous reprenez le travail réel pendant qu'un wait est ouvert (ex. enquêter quelque chose avant que l'utilisateur ait répondu), wait end d'abord et wait start à nouveau quand vous retournez à l'attente — le travail actif ne doit jamais être compté comme attente.

  4. record les événements au fur et à mesure qu'ils se produisent (section suivante). Enregistrez au moment présent, pas rétrospectivement — l'improvisation et les arrêts ne sont sûrement connaissables que quand ils se produisent.

  5. finalize une seule fois, à un état terminal, avec le rollup :

    node scripts/rp-telemetry.js finalize '{"terminal_state":"completed",
      "volumes":[{"entity_type":"product","target":"native","target_surface":"stores/v3",
        "discovered":142,"planned":142,"attempted":142,"succeeded":139,"failed":3,
        "skipped":0,"already_imported":0}],
      "verification":[{"subject":"product","method":"query_back","checked":10,"passed":10,"failed":0}],
      "operator_acceptance":"accepted"}' --project <dir>
    • volumes proviennent des artefacts d'exécution (manifeste, journal d'audit, crosswalk) : planned et target/target_surface du plan approuvé ; already_imported est le scope crosswalk-skipped d'une tentative antérieure — ne jamais le replier dans skipped.
    • Inclure une ligne de volume pour chaque type d'entité que la découverte a trouvé en usage — y compris les types exclus par décision utilisateur ou sans cible Wix propre (discovered: N, skipped: N, target: none là où aucune cible n'existe, planned 0 ou null). « Ce que nous ne pouvons pas ou avons choisi de ne pas importer » doit être l'arithmétique de la couche signal, jamais une fouille en profondeur — les lignes uniquement pour les types importés effacent silencieusement la moitié exclue du plan approuvé.
    • verification rend les spot-checks de l'étape finish comptables. checked: 0 est un honnête « écrit mais non vérifié » — rapportez-le plutôt que de le dissimuler.
    • Ne pas finaliser un arrêt que vous vous attendez que l'utilisateur reprenne — laissez l'exécution non finalisée avec le wait ouvert. Finalisez avec halted_needs_user uniquement quand l'exécution est véritablement fermée dans un état bloqué. Un utilisateur qui refuse le plan est abandoned_by_user (plus un événement user_decision avec subtype: declined), jamais halted_needs_user ou failed.

Metering — diviser active_ms en où le temps s'est réellement dépensé

active_ms seul ne peut pas localiser un goulot : c'est le wall-clock entre deux limites de stage, fusionnant le raisonnement du modèle + l'exécution du sous-processus + la latence de l'API distante + le temps de réparation de défaut en un seul nombre. meter le divise, et le coût est dérivé des décomptes de tokens.

# un script généré rapportant son propre travail mesuré
node scripts/rp-telemetry.js meter --api-ms 250000 --api-calls 73 --api-retries 2 --script-ms 1200 --project <dir>
# le runtime de l'agent rapportant sa propre utilisation pour le stage qu'il vient de terminer
node scripts/rp-telemetry.js meter --model-ms 42000 --input-tokens 8000 --output-tokens 1500 --cache-read-tokens 120000 --project <dir>

Dérivez la moitié API mécaniquement — ne la comptez pas manuellement. Après qu'un import généré s'exécute :

node scripts/meter-from-audit.js --project <migration dir> --stage import   # --dry-run pour prévisualiser

Il lit logs/import-audit.ndjson et émet api_ms / api_calls / api_retries mesuré. Il existe parce qu'une écriture en masse enregistre une ligne d'audit par item, chacune portant la latence totale du batch — en sommant les lignes multiplie la latence d'un appel par son décompte d'items, ce qui sur une exécution réelle a rapporté 1 050 992 ms de temps API à l'intérieur d'un stage qui n'existait que pour 346 505 ms. L'assistant replie les lignes par distinct (runId, endpoint, batch, latencyMs), donc un batch compte une fois tandis que les appels véritablement distincts comptent chacun.

Champs : durées model_ms / api_ms / script_ms ; décomptes input_tokens, output_tokens, cache_read_tokens, cache_write_tokens, api_calls, api_retries. Par défaut le stage ouvert ; --stage <stage> cible un autre. Les appels répétés s'accumulent, donc chaque invocation de script et chaque réintrée de stage rapportent indépendamment.

Les règles qui gardent les chiffres fiables :

  • Mesurez, ne devinez jamais. Chaque champ est un nombre quelque chose a réellement observé — le temps écoulé d'un script, la somme latencyMs d'un journal d'audit, l'utilisation rapportée du runtime. Si vous n'avez pas de mesure, omettez le champ ; le lacune est rapporté comme unattributed_ms et signalé, ce qui est bien plus utile qu'une devinette.
  • Ne mettez pas en mètre le même intervalle deux fois. Les mètres se somment, donc re-rapporter le temps API d'un stage après une reprise le compte deux fois. L'enregistreur signale stage_over_attributed:<stage> quand le temps attribué dépasse le temps écoulé, parce que unattributed_ms se pince à zéro et sinon le cacherait.
  • Le coût est dérivé, jamais enregistré. Passez model_pricing_snapshot dans les dims start ({ "<model>": { "input_per_mtok": 15, "output_per_mtok": 75, "cache_read_per_mtok": 1.5 } }) et le rollup calcule cost.estimated_cost_usd. Un chiffre en dollars stocké se trompe silencieusement quand les prix catalogue changent ; les tokens plus un instantané daté restent recompilables. Sans un instantané, le coût est null avec cost_basis: "no_pricing_snapshot" — jamais un nombre fabriqué.
  • contained_recovery est dérivé, pas auto-rapporté. Tout error ou pipeline_defect dans un stage le marque, parce qu'un stage qui a dépensé son temps à déboguer est celui qu'un agent est le moins susceptible de se rappeler de signaler. timing.stages_with_recovery les énumère, donc une exécution propre et une chasse aux bogues sont distinguables au lieu que les deux lisent comme « c'est ce que le stage coûte ».

Le rollup's timing.agentic_ms vs timing.deterministic_ms (et agentic_share) est le nombre qui montre si le déplacement du travail vers du code déterministe paie. agentic_share est null quand rien n'a été mis en mètre plutôt que 0, ce qui lirait faussement comme une exécution entièrement déterministe.

Collecter operator_acceptance

À la remise de finition, posez à l'opérateur une simple question : le résultat migré leur semble-t-il correct — accepted, rework_needed ou rejected ? Enregistrez sa réponse dans finalize. Si l'exécution n'atteint jamais finish ou qu'il ne répond pas, elle reste unknown. C'est le seul champ séparant « complété et bon » de « complété et inutilisable » — posez la question, mais ne pressez ni n'interprétez jamais ; leur verdict tel que donné, grossier par conception.

Taxonomie des événements — quand enregistrer quoi

Les événements sont repliés par classe de problème par l'enregistreur (même type + stage + entity type + surfaces API + app + code erreur + subtype se replient en un événement avec un count), donc enregistrez chaque classe d'occurrence une fois et passez count quand vous avez observé beaucoup à la fois — ex. un script généré rapportant 4 000 défaillances d'écriture identiques est un appel record avec "count": 4000. Les problèmes distincts sont des subtypes ou codes erreur distincts, pas des counts plus gros.

Chaque événement a besoin de : event_type, stage (par défaut le stage ouvert), skill (la ressource rp-* active, ex. "rp-mapper"), severity (blocking | degraded | cosmetic | info), et what_happened. Ajoutez entity_type, wix_api_surface (ex. stores/v3), source_api_surface (classe d'endpoint comme wp/v2/posts — jamais une URL), wix_app_id, et error_code chaque fois qu'ils s'appliquent — ce sont les clés group-by inter-exécutions.

  1. halt_needs_user — l'exécution s'est arrêtée à un état needs-user défini. Préférez la forme mécanique — wait start --halt <subtype> … l'émet pour vous (étape du cycle de vie 3) ; enregistrez-la vous-même uniquement pour un arrêt sans intervalle wait. subtype : missing_input (entrée/credential requise manquante/invalide) | manual_only (étape véritablement manuelle, pas d'API) | systemic_failure (défaillance systémique ou risque de perte de données).

  2. manual_action_required — le plan d'exécution a signalé quelque chose comme « ne peut pas être fait, nécessite action manuelle » (ex. une mise à niveau de plan de stockage), que l'exécution s'y soit arrêtée ou non. subtype : plan_or_billing | dashboard_only | external_dependency | other.

  3. error — une erreur API ou script, y compris les erreurs récupérées. Portez error_code (obligatoire — c'est le discriminateur ; pas de subtype), retry_count, et recovered. Enregistrez un événement par chaîne de retry résolue, après que le résultat soit connu — le recovered final, le retry_count total — jamais un appel par tentative (les appels par-tentative se replient en une classe, et les champs de la première tentative échouée enterreraient la récupération). Quand la récupération a nécessité un changement (pas juste un retry), actual doit enregistrer quel changement l'a fait réussir, comme une observation : « réessayé avec la description en texte brut au lieu de HTML ; l'écriture a réussi » — jamais « le correctif est X ». Si ce changement s'est écarter du chemin documenté — y compris un changement à une commande ou valeur planifiée, comme simplifier une entrée que le plan a spécifiée — émettez également un événement skill_coverage_gap appairé (undocumented_workaround).

  4. fidelity_loss — la migration a techniquement procédé mais a perdu quelque chose. subtype : dropped_field | unverified_enum | no_target (entité source sans cible Wix propre) | coerced_value. Pour une perte déclenchée par des enregistrements spécifiques, mettez en ligne la forme assainie de l'enregistrement offensant dans observed_shapes — noms et types de champs et quel champ a été supprimé/coercé, jamais les valeurs.

  5. api_gap — une capacité API Wix manquante ou insuffisante. subtype : missing_api | missing_capability (l'API existe mais ne peut pas exprimer l'opération) | internal_only (la capacité existe mais n'est pas publiquement exposée) | other. Portez wix_api_surface (obligatoire) et error_code — cette signature est appairée centralement inter-exécutions. Ne jamais écrire dans aucun fichier de carnet ; l'événement est l'obligation entière par exécution.

  6. skill_coverage_gapl'auto-rapport permanent, et le signal de plus haute valeur pour améliorer les skills. Chaque fois que vous agissez au-delà de ce que la skill active vous a explicitement dit de faire — vous devinez une valeur, contournez une instruction manquante, résolvez une ambiguïté par jugement, ou gérez un cas que la skill ne couvre pas — enregistrez-le à ce moment. subtype : guessed_value | undocumented_workaround | ambiguous_instruction | path_not_covered. Décrivez la situation et l'action entreprise comme une observation : « la skill n'a pas spécifié quelle valeur enum mappe à X, donc une valeur a été choisie pour procéder » — jamais « la skill devrait ajouter Y ». Si vous êtes incertain de si quelque chose compte comme improvisation, c'est le cas — enregistrez-le.

  7. user_decision — la réponse de l'utilisateur à chaque point de contrôle ou fourche défini : le point de contrôle d'examen du mapping, la porte d'approbation, et les fourches d'intake (anonymisation des commentaires, mode de livraison, accessibilité des médias, …). subtype : accepted | declined | deferred | amended ; decision_point (obligatoire) nomme la fourche, ex. mapping_review, approval_gate, comments_anonymization. Enregistrez la décision, pas le raisonnement verbatim de l'utilisateur. Une acceptation amended dont le changement a exposé un problème de mapping surfacise aussi ce problème comme fidelity_loss ou skill_coverage_gap. Un declined à un point de contrôle terminal s'apparie avec terminal_state: abandoned_by_user.

  8. pipeline_defect — notre propre machine de migration s'est mal comportée : pas une erreur API Wix, pas un défaut source, pas votre improvisation. subtype : state_inconsistency (deux artefacts d'état du pipeline sont en désaccord) | ordering_violation (une étape a couru avant que la sortie de son prérequis n'existe) | record_defect (un enregistrement/journal du pipeline est mal formé ou trompeur comme preuve) | other. Nommez les artefacts et leurs états dans what_happened — noms et états, jamais le contenu.

evidence_refs — rare, pas routinier

Rédigez chaque événement pour être autosuffisant : champs codés + texte libre borné + observed_shapes devrait laisser un examinateur le trier sans ouvrir aucun artefact. Ajoutez evidence_refs ({"artifact":"execution-log.md","locator":"## Import"}) uniquement pour l'événement exceptionnel dont le signal ne peut vraiment pas porter l'observation complète. Utilisez les chemins relatifs à la racine du projet et préférez les titres de section comme localisateurs (les plages de lignes se cassent quand les fichiers se régénèrent). Ne jamais référencer des fichiers config porteurs de secrets.

Ce qu'il ne faut jamais faire

  • Ne jamais rédiger, éditer ou relire manuellement run-telemetry.json ou les fichiers telemetry/ — l'enregistreur ajoute ; vous ne l'appelez que.
  • Ne jamais enregistrer les valeurs des données client, noms, URLs au-delà de l'origine source enregistrée, ou les secrets — dans aucun champ, y compris les formes et localisateurs.
  • Ne jamais enregistrer un correctif, une cause profonde ou une recommandation — uniquement les observations.
  • Ne jamais estimer les durées — l'horodatage provient des appels limite stage/wait.
  • Ne jamais sauter un appel rejeté : corrigez les champs énumérés et réessayez. Les rejets sont comptabilisés contre la santé de la télémétrie de toute façon.
  • Ne jamais créer ou mettre à jour les fichiers de carnet d'amélioration/demande de fonctionnalité pendant une exécution — ceux-ci sont maintenus centralement à partir de la télémétrie de nombreuses exécutions, pas par exécution.
  • Ne jamais supprimer ou réduire les artefacts du projet pour des raisons de télémétrie — la capture est une vue non-destructive ; la taille n'est pas une raison de laisser tomber quoi que ce soit.

Skills similaires