Skip to content

Detección del Proceso de Escritura

Convierte los registros de pulsaciones de Potato en marcas auditables para respuestas de texto libre pegadas, transcritas o generadas por máquina, con umbrales que puedes leer y sobrescribir.

La detección del proceso de escritura lee la dinámica de tecleo capturada por el Registro de Pulsaciones y produce marcas con nombre y con las pruebas adjuntas, de modo que puedes ver qué valores de características dispararon cada una y descartar las que no te convenzan.

Necesita Potato 2.7.2 o posterior, y solo se ejecuta donde el registro de pulsaciones ya está activo. Como keystroke_logging.enabled es false por defecto, un proyecto que nunca lo activó no tiene nada sobre lo que detectar.

Advertencia: Las marcas son indicios para que los revise una persona. No son prueba de mala conducta, y nunca deben conectarse a rechazos automáticos, retención de pagos ni expulsiones de participantes. Alguien rápido y fluido que produce un primer borrador limpio se parece de verdad a una transcripción. Un anotador que trabaja desde el móvil se parece de verdad a alguien que pega. Las reglas de abajo están construidas para reducir esas coincidencias, y las coincidencias siguen ocurriendo. La sección de falsos positivos forma parte de la funcionalidad, no es una nota legal.

Tres niveles

NivelQué es¿Necesita datos etiquetados?Por defecto
1. ReglasSeis marcas con nombre, con umbrales explícitos y pruebas visiblesNoActivo
2. CalibraciónUmbrales reajustados a los anotadores de tu propio proyectoNoInactivo
3. SupervisadoUn clasificador que entrenas con tus propias etiquetasInactivo

Potato no distribuye ningún modelo preentrenado. No hay un corpus etiquetado en el repositorio, así que cualquier coeficiente que publicáramos vendría con una cifra de validación que nos habríamos inventado. En su lugar tienes seis reglas que puedes leer y discutir. Si tienes etiquetas reales, el nivel 3 es la vía que reproduce las exactitudes de la literatura.

Nivel 1: las reglas

Cada marca devuelve los valores de las características que la dispararon, de modo que puedes defender o descartar cualquiera de ellas por separado.

paste_dominant

Gravedad: suspect. Se dispara cuando pasted_fraction >= 0.5, es decir, cuando la mitad o más del texto final llegó pegada.

Se suprime cuando todos los pegados se clasificaron como self (reordenar tu propio borrador) o instance_text (citar el pasaje que se está anotando).

silent_insertion

Gravedad: suspect. Se dispara cuando external_insert_ratio >= 0.3, es decir, cuando casi un tercio de los caracteres insertados apareció sin una pulsación correspondiente.

Esta es la señal individual de mayor valor. El pegado, el autorrelleno, el dictado y la inyección programática aparecen todos aquí, incluso cuando la página suprime el propio evento de pegado. Es una operacionalización directa del «recuento de pulsaciones anómalamente bajo en relación con la longitud de la respuesta» de Asher et al.

Se suprime con teclados en pantalla (virtual_keyboard) y durante la composición IME, donde keydown no se emite de forma fiable y toda inserción parecería silenciosa. La regla usa la proporción que tiene en cuenta el origen, así que citar de forma legítima no cuenta.

transcription_rhythm

Gravedad: review. Se dispara cuando se cumplen las tres condiciones:

  • iki_log_cv <= 0.06, un ritmo de tecleo metronómico
  • revision_ratio <= 0.02, prácticamente sin borrados
  • menos de 0,5 pausas de 2 segundos o más por cada 100 caracteres

Conjuntiva a propósito. Cada una por separado tiene una lectura inocente. Juntas son la firma de copiar al teclado que describen Crossley et al.: lineal, por ráfagas y con poca varianza.

Se omite por completo en respuestas de menos de 80 caracteres o 40 pulsaciones, donde no hay ritmo del que hablar.

offscreen_composition

Gravedad: suspect. Se dispara cuando una inserción grande de origen externo (80 caracteres o más) va inmediatamente después de 10 segundos o más fuera de la página. Es el patrón de «me fui a ChatGPT, volví y pegué».

Se suprime cuando el origen de la inserción era el pasaje o el propio texto del anotador, ya que apartarse un momento y luego citar el pasaje es un comportamiento normal.

implausible_speed

Gravedad: review. Se dispara por encima de 900 caracteres por minuto (unas 180 wpm) sostenidos a lo largo de toda una respuesta.

synthetic_input

Gravedad: suspect. Se dispara con cualquier evento con isTrusted === false, es decir, el navegador informando de que la entrada la generó un script y no una persona. La automatización de navegador, los scripts inyectados y algunas herramientas de accesibilidad producen esto.

Niveles de veredicto

NivelSignificado
okNo se disparó ninguna marca
reviewAl menos una marca de gravedad review
suspectAl menos una marca de gravedad suspect

Sobrescribir umbrales

yaml
keystroke_logging:
  detection:
    thresholds:
      paste_dominant.pasted_fraction: 0.4
      silent_insertion.ratio: 0.25
      transcription_rhythm.iki_log_cv: 0.05
      transcription_rhythm.revision_ratio: 0.02
      transcription_rhythm.pause_2s_per_100_chars: 0.5
      offscreen_composition.blur_ms: 15000
      offscreen_composition.insert_chars: 100
      implausible_speed.chars_per_min: 1000

Los umbrales se evalúan en el servidor y nunca se envían al navegador. Publicarlos le diría a un anotador con qué lentitud exacta tiene que pegar para quedarse por debajo de la marca.

Nivel 2: calibración del proyecto

Las características de pulsaciones varían bastante según la tarea de escritura (Conijn et al. 2019), y los umbrales fijos sobre una magnitud con distribución de mezcla están sesgados (Roeser et al. 2021). Un corte que funciona para una justificación de una frase está mal para un ensayo de cinco párrafos.

La calibración sitúa cada umbral en un percentil de cola de las sesiones de tu propio proyecto.

bash
# Inspect the fit without saving it
python -m potato.typing_detect calibrate config.yaml --dry-run
 
# Save it
python -m potato.typing_detect calibrate config.yaml
yaml
keystroke_logging:
  detection:
    calibrate: true    # use the saved fit

La calibración requiere al menos 30 sesiones utilizables (de 80 caracteres o más, no móviles). Por debajo de eso devuelve insufficient_data y siguen vigentes los valores por defecto.

Advertencia: Un corte por percentil es una definición relativa de valor atípico. Por construcción marca aproximadamente tail_fraction (5 % por defecto) de las sesiones incluso en una población donde nadie está haciendo nada mal. Te dice dónde mirar primero. No es una prueba. Los umbrales calibrados se acotan además a un máximo de 3x los valores por defecto, para que una población homogénea no pueda arrastrar un corte hasta su propia mediana y empezar a marcar a anotadores honestos.

Un thresholds: explícito siempre gana a un valor calibrado, que siempre gana al valor por defecto.

Nivel 3: clasificador supervisado

Si tienes sesiones etiquetadas, entrena un modelo de verdad:

python
from potato import typing_store
from potato.typing_detect import fit_supervised
 
rows = typing_store.feature_matrix(task_dir, project)
labels = [...]   # 1 = non-composed, 0 = composed
 
result = fit_supervised(rows, labels, model="random_forest")
print(result["cv_accuracy_mean"], result["feature_importances"])

Requiere scikit-learn, que se importa de forma diferida y no es una dependencia de Potato.

Conseguir etiquetas sin un estudio aparte

La fase de entrenamiento de Potato puede generarlas por ti. Pide a los anotadores que copien un pasaje que les des como tarea de calentamiento. Sus sesiones de copia son ejemplos genuinos de transcripción y sus respuestas normales son ejemplos de redacción, lo que te da un conjunto etiquetado desde dentro de tu propio proyecto, sobre tu propia tarea y con tus propios anotadores. Esto refleja cómo construyeron su corpus Crossley et al., y el ejemplo de calibración lo monta de principio a fin.

Falsos positivos

El modo de fallo de esta funcionalidad es acusar a un anotador honesto. Estos son los casos que se parecen legítimamente a los patrones de arriba.

SituaciónA qué regla se pareceCómo lo trata Potato
Citar el pasaje que se está anotandopaste_dominant, silent_insertion, offscreen_compositionSuprimido mediante paste_source: instance_text
Mover de sitio tu propio borradorLas mismasSuprimido mediante paste_source: self
Teclear en un móvil o una tabletasilent_insertionSuprimido mediante virtual_keyboard
Entrada no latina con un IMEsilent_insertionSuprimido mediante composition_events
Alguien rápido y fluido, borrador limpiotranscription_rhythm, implausible_speedReglas conjuntivas; review y no suspect; calibración
Respuestas muy cortastranscription_rhythmSe omiten por debajo de 80 caracteres / 40 pulsaciones
Dictado o reconocimiento de vozsilent_insertionSin tratar. Va a marcar. Excluye a esos anotadores o sube el umbral.
Lectores de pantalla y algunas tecnologías de apoyosynthetic_inputTratado solo en parte. Algunas herramientas producen eventos no confiables.
Autocorrección en el móvilsilent_insertionEn parte. insertReplacementText cuenta como externo.
Extensiones del navegador como las de gramáticasilent_insertion, synthetic_inputSin tratar. Va a marcar.

Los cuatro últimos son limitaciones reales y no descuidos. Si tu grupo de participantes incluye personas que dictan, que usan tecnología de apoyo o que usan extensiones de escritura, o dejas esas reglas fuera de tus criterios de revisión, o tratas cada marca como una invitación a preguntar al anotador y no a actuar.

Accesibilidad

synthetic_input se basa en isTrusted, que algunas tecnologías de apoyo también disparan. Marcar a un anotador con discapacidad por usar las herramientas que necesita para trabajar es un resultado inaceptable.

Esa regla no tiene umbral, así que no hay ningún valor que puedas poner para hacerla inalcanzable. Si tu estudio está abierto a personas que usan tecnología de apoyo, o excluyes synthetic_input de los criterios de revisión que escribas, o desactivas la detección por completo y analizas tú mismo las características exportadas:

yaml
keystroke_logging:
  enabled: true
  detection:
    enabled: false

Las reglas basadas en umbrales sí se pueden hacer inalcanzables poniendo un corte absurdo, por ejemplo implausible_speed.chars_per_min: 1000000.

Intervención en tiempo real

yaml
keystroke_logging:
  detection:
    on_external_insert: flag   # allow | warn | block | flag
ValorComportamiento
allowNo hacer nada más allá de registrar
warnAviso no bloqueante al pegar contenido externo, pero no al citarse a uno mismo ni al pasaje
blockImpedir pegar y soltar en los campos instrumentados
flagPor defecto. Registrar en silencio; ya decidirás después

block es un instrumento tosco. También bloquea las citas legítimas, y un participante decidido puede volver a teclear el texto. Usar flag y revisar después suele ser mejor.

Panel de administración

El panel Writing Process, dentro de la pestaña Behavioral del Panel de Administración, muestra las medianas por anotador, las tasas de pegado, las tasas de inserción silenciosa y cada sesión marcada con sus pruebas.

Informa de writing_process_risk, la proporción de sesiones de un usuario que dispararon cada marca, ponderada hacia las señales con la explicación inocente menos probable. Es una ayuda para ordenar, mantenida a propósito aparte del suspicion_score ya existente, para que ninguno de los dos números cambie en silencio el significado del otro.

Base en la investigación

Todas las citas de abajo están verificadas contra el registro de Crossref o de DataCite.

Crossley, Tian, Choi, Holmes y Morris (2024) recogieron 500 ensayos argumentativos, hicieron que otros trabajadores los transcribieran y separaron lo auténtico de lo transcrito con un 99 % de exactitud usando un random forest (96-98 % con otros modelos). Sus familias de características son lo que captura Potato: tiempos de pausa antes de frases y de palabras, recuentos de inserciones y borrados, relaciones producto-proceso, ráfagas, revisión y varianza del proceso. Su hallazgo es el objetivo de diseño. La escritura auténtica muestra pausas más largas, más inserciones y borrados y mayor varianza; la transcripción es lineal y va por ráfagas.

Deane, Zhang, Hao y Li, y por separado Zhang, Feng, He, Li y Zhu, confirman de forma independiente la separación entre copiar al teclado y escribir de forma natural, estos últimos con un modelo de aprendizaje profundo. Asher, Gold, Chen y Carvalho es el caso específico de crowdsourcing: una herramienta de pulsaciones en Prolific que marca a los participantes que pegan en los campos de respuesta o cuyo recuento de pulsaciones es anómalamente bajo para la longitud de su respuesta.

Para las medidas de proceso subyacentes, consulta Leijten y Van Waes (Inputlog) para las medidas de registro estándar, Chenoweth y Hayes para el constructo de ráfaga, Conijn, Roeser y van Zaanen para la dependencia de las características de pulsaciones respecto a la tarea, y Roeser, De Maeyer, Leijten y Van Waes para por qué los umbrales de pausa fijos están sesgados.

Referencias

  1. Crossley, S., Tian, Y., Choi, J. S., Holmes, L., & Morris, W. (2024). Plagiarism Detection Using Keystroke Logs. EDM 2024 (Short Papers). doi:10.5281/zenodo.12729864
  2. Deane, P., Zhang, M., Hao, J., & Li, C. Using Keystroke Dynamics to Detect Nonoriginal Text. Journal of Educational Measurement, 63(1). doi:10.1111/jedm.12431
  3. Asher, M. W., Gold, G., Chen, E., & Carvalho, P. F. (2026). Chatbots Are Undermining Crowdsourced Research in the Behavioral Sciences: Detecting Artificial Intelligence-Assisted Cheating With a Keystroke-Based Tool. Advances in Methods and Practices in Psychological Science, 9(1). doi:10.1177/25152459261424723
  4. Zhang, M., Feng, L., He, X., Li, C., & Zhu, M. (2026). Disentangling copy typing and natural writing behaviors using keystroke logs and deep learning model. Assessing Writing. doi:10.1016/j.asw.2026.101070
  5. Leijten, M., & Van Waes, L. (2013). Keystroke Logging in Writing Research: Using Inputlog to Analyze and Visualize Writing Processes. Written Communication, 30(3), 358-392. doi:10.1177/0741088313491692
  6. Chenoweth, N. A., & Hayes, J. R. (2001). Fluency in Writing: Generating Text in L1 and L2. Written Communication, 18(1), 80-98. doi:10.1177/0741088301018001004
  7. Conijn, R., Roeser, J., & van Zaanen, M. (2019). Understanding the keystroke log: the effect of writing task on keystroke features. Reading and Writing, 32(9), 2353-2374. doi:10.1007/s11145-019-09953-8
  8. Roeser, J., De Maeyer, S., Leijten, M., & Van Waes, L. (2021). Modelling typing disfluencies as finite mixture process. Reading and Writing. doi:10.1007/s11145-021-10203-z
  9. Lee, M., Liang, P., & Yang, Q. (2022). CoAuthor: Designing a Human-AI Collaborative Writing Dataset for Exploring Language Model Capabilities. CHI 2022. doi:10.1145/3491102.3502030

Lecturas Adicionales

Para detalles de implementación, consulta la documentación fuente.