Skip to content

fix: normalize comparable behavioral observations while preserving native tool identity #727

Open

Description

@cdeust

Problem and evidence

Codex rollout_activity preserves exec/apply_patch names. Downstream behavioral observations recognize Claude Edit/Write/Read/Grep names. Hook event normalization does not normalize this transcript reader.

Production function replay with three operations and identical duration=None: Edit gives activeReflective=0.3; Read gives -0.3; apply_patch and exec each produce an empty observation. This establishes a naming-dependent difference. An opaque exec cannot automatically be classified as a read.

Acceptance evidence

  • Preserve native names as provenance and define common signals for explicitly observable operations.
  • Equivalent explicit edits produce equal EMA/persona inputs across clients.
  • Opaque commands remain unknown rather than receiving an invented category.
  • Cover transcript-derived EMA, persona and feature activation independently of hook normalization.

Scope and related work

Distinct from #716 continuation, #710 injection and repaired toolsUsed population in #591.

Raised by the global Hindsight/Cortex audit. The target is a measurable local-first experience with the same supported semantics in Claude and Codex. Acceptance criteria describe a target, not current conformance. Static findings refer to the pinned source; probes identify their boundary.

Primary references

mcp_server/infrastructure/transcript_rollout.py:70; mcp_server/core/profile_builder.py:104; mcp_server/core/persona_vector.py:49; mcp_server/core/sparse_dictionary_activation.py:102

Activity

  1. cdeust commented on Nov 5, 2026

    @cdeust
    OwnerAuthor

    CI autopilot : tranche 1 livrée dans #882 (Refs #727, pas Closes).

    • Cause racine : l'observation de style incrémentale (profile_builder._build_style_observation) reconnaissait les noms d'outils Claude seulement, donc un apply_patch Codex ne comptait pas comme une édition. Le nouveau module core/tool_operation.py associe chaque nom natif à l'opération qu'il rend explicite ; les noms natifs restent dans toolsUsed ; exec reste inconnu.
    • Preuve : le rejeu de l'issue (duration=None) donne maintenant {"activeReflective": 0.3} pour Edit et pour apply_patch, et {} pour exec. Gate de mutation local : 0 survivant dans le périmètre.

    Tranches restantes :

    1. persona_vector : lit toolPreferences par nom natif (Edit, Read, Grep).
    2. sparse_dictionary_activation et style_classifier (chemin de reconstruction complète) : comptent Read/Edit/Write/Grep par nom.
    3. Test croisé Claude/Codex sur l'EMA, la persona et l'activation de features dérivées des transcripts, hors normalisation des hooks.

    Generated by Claude Code

  2. added a commit that references this issue on Nov 6, 2026
  3. cdeust commented on Nov 6, 2026

    @cdeust
    OwnerAuthor

    CI autopilot : tranche 2 (persona_vector) en hold. Elle ne se fait pas sans une décision sur le modèle de données.

    Constat sur main @ 499c69d2 :

    • core/persona_vector._compute_behavioral_dims lit toolPreferences[<nom natif>].ratio, c'est-à-dire la fraction des sessions qui utilisent cet outil précis (core/session_shape.extract_tool_preferences, maintenu aussi en incrémental par profile_builder._update_tool_preferences). riskTolerance vaut (Edit − Read)·2 et focusScope vaut (Glob + Grep)·2 − 0,5. Pour Codex, apply_patch et exec ne comptent donc nulle part.
    • On ne peut pas reconstruire la fraction de sessions qui ont une édition à partir des ratios par outil, parce que les sessions se recouvrent : additionner Edit et apply_patch surestime, prendre le maximum sous-estime. Il faut un ratio par opération calculé sur les sessions elles-mêmes, donc un nouveau champ de profil (par exemple operationPreferences: {edit, read}), en construction complète comme en incrémental.

    Questions à trancher :

    1. Sens de riskTolerance : faut-il passer au modèle d'opérations de core/tool_operation (EDIT = Edit/Write/apply_patch, READ = Read/Grep) ? Pour Claude, cela modifie la valeur actuelle : Write compterait comme édition, et Grep pèserait à la fois sur riskTolerance (lecture) et sur focusScope. L'autre option est de garder Edit seul et Read seul, mais aucun équivalent Codex exact n'existe alors, puisque apply_patch couvre Edit et Write.
    2. Profils déjà stockés : ils n'ont pas le nouveau champ. Comme le dépôt interdit les replis silencieux et les shims, faut-il une migration ponctuelle (reconstruction via rebuild_profiles) ou un refus explicite tant que le profil n'est pas reconstruit ?
    3. autonomy (Agent, Bash) : exec reste inconnu (critère 3 de l'issue). À confirmer : Bash côté Claude reste-t-il compté alors que son homologue Codex ne l'est pas ?

    Rien n'a été poussé. Une fois ces choix faits, la tranche consiste à : ajouter le champ par opération, faire lire ce champ par persona_vector, et ajouter un test croisé Claude/Codex sur la persona.


    Generated by Claude Code

  4. added
    autopilot:holdCI autopilot stood down: a human decision is required
    on Nov 6, 2026
  5. cdeust commented on Nov 12, 2026

    @cdeust
    OwnerAuthor

    Décision : cette issue n'attend plus de réponse du propriétaire.

    Le propriétaire a demandé le 12 novembre 2026 que les issues avancent sans lui ; il ne répondra pas aux questions posées ici. Ce commentaire de cdeust lève le hold et précise la demande. Il vaut pour toute la suite de cette issue.

    • Tranche toi-même chaque question restée ouverte : d'abord une décision écrite et acceptée du dépôt (ADR accepté, docs/), puis ce que le texte de l'issue propose ou exclut, puis les standards du dépôt ; à défaut, la plus petite tranche qui réalise ce que l'issue demande. Une valeur qui manque se mesure, elle ne s'invente pas.
    • Écris la décision dans un commentaire marqué <!-- ci-autopilot decision --> (ce qui est retenu, la raison et sa source, ce qui est écarté, comment revenir en arrière), puis livre la tranche dans une PR. Une décision écrite ne se rejoue pas aux passages suivants.
    • Ne repose pas autopilot:hold pour une question : seulement pour l'irréversible, un accès que tu n'as pas, une dépendance nommée encore ouverte ou le plafond de tentatives, en nommant exactement ce qui manque.
    • Jamais de tag, de release, de montée de version du projet ni de déclenchement manuel d'un workflow.

    Règle complète : #343 (comment)

    Écrit par la session « écosystème autonome » sur instruction du propriétaire (12 novembre 2026).


    Generated by Claude Code

  6. removed
    autopilot:holdCI autopilot stood down: a human decision is required
    on Nov 12, 2026
  7. cdeust commented on Nov 12, 2026

    @cdeust
    OwnerAuthor

    Hold autopilot:hold levé : un commentaire de cdeust (« Décision : cette issue n'attend plus de réponse du propriétaire », 12/11/2026) a été posté après la pose du hold.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions