Colectica-routing-toolkit

Extrae y valida de forma cruzada la lógica de enrutamiento de cuestionarios a partir de exportaciones de Colectica DDI y Forsta+ (Confirmit Horizons): extracción de esquemas, gráficos de enrutamiento, diff estructural de enrutamiento, simulación de entrevistas y un servidor MCP de solo lectura sobre los resultados.

Documentación

Sistema de Cuestionarios Flowise

Una aplicación Django para analizar y simular archivos JSON de cuestionarios en formato Colectica (p. ej., oleadas de Understanding Society Mainstage). Permite a los diseñadores subir un módulo de cuestionario, extraer su esquema de preguntas y su lógica de enrutamiento, construir un grafo de flujo visual, ejecutar una revisión consultiva asistida por IA mediante Flowise y simular interactivamente el recorrido del cuestionario como encuestado.

También puede ingerir una exportación XML de Forsta+ (Confirmit Horizons) de la misma oleada de cuestionario y comparar estructuralmente su enrutamiento con el enrutamiento derivado de Colectica, mostrando cualquier discrepancia — ramas faltantes, condiciones no coincidentes, ramas "else" solo de Forsta+ — en una GUI dedicada de diff de enrutamiento, con una vista de grafos lado a lado por discrepancia.

Principio arquitectónico central

Django posee todos los datos, la lógica de enrutamiento y la validación. Flowise es solo consultivo.

Flowise (una plataforma externa de agentes LLM) se utiliza para dos propósitos limitados, y su salida siempre es validada/procesada posteriormente por Django antes de ser considerada fiable:

  1. Module Review agentflow — revisa el enrutamiento/cobertura en busca de problemas de diseño. Django envía un payload compacto y valida posteriormente la respuesta contra hechos conocidos, rechazando cualquier cosa que invente nombres de preguntas o modifique el enrutamiento.
  2. Interview Wording agentflow — reformatea el texto/opciones de las preguntas visibles para el encuestado durante el simulador de entrevista. Django valida la respuesta y recurre a un mensaje determinista construido localmente si Flowise no está disponible o devuelve algo inválido — el simulador siempre funciona incluso si Flowise está caído.

Pipeline de procesamiento

Aplicado en la UI/vistas como un orden estricto por módulo subido:

  1. Subir JSON → QuestionnaireModule
  2. Extraer esquema (schema_extractor.ColecticaSchemaExtractor) → NormalizedQuestion filas
  3. Extraer enrutamiento (routing_extractor.ColecticaRoutingExtractor) → RoutingEdge filas (condicional / secuencial / bucle)
  4. Construir grafo (graph_builder.py + graph_enrichment.py) → QuestionnaireGraph (JSON de nodos/aristas + texto Mermaid)
  5. Ejecutar revisión de Flowise (opcional) → ModuleAIReview

Todo se ejecuta de forma síncrona en el ciclo petición/respuesta — no hay cola de tareas Celery/async.

Diff de enrutamiento Colectica vs Forsta+

Un segundo pipeline independiente se ejecuta contra un segundo QuestionnaireModule (source_format auto-detectado como forsta_xml a partir de la extensión .xml en la subida — el mismo formulario de subida que para Colectica), validando de forma cruzada la exportación XML de Forsta+ (Confirmit Horizons) de una agencia de campo contra el enrutamiento derivado de Colectica para la misma oleada:

  1. Subir XML de Forsta+ → QuestionnaireModule
  2. Extraer esquema (forsta_xml_schema_extractor.ForstaXmlSchemaExtractor) → NormalizedQuestion filas
  3. Extraer enrutamiento (forsta_xml_routing_extractor.ForstaXmlRoutingExtractor) → RoutingEdge filas
  4. Emparejar preguntas (question_matcher.build_question_matches) → QuestionMatch filas, emparejando cada pregunta de Colectica con su mejor contraparte de Forsta+ en tres pasadas: coincidencia exacta de texto normalizado, luego respaldo difuso (difflib, umbral 0.75), y luego un paso de reconciliación desempate por nombre — si la coincidencia actual de una pregunta tiene un nombre diferente al suyo, y existe una pregunta no utilizada con el mismo nombre en el otro lado cuyo propio texto también supera el umbral difuso (o es una coincidencia limpia de prefijo/subcadena — el texto fuente de Forsta+ a veces pliega las instrucciones del entrevistador en línea donde Colectica las mantiene separadas), la del mismo nombre se hace cargo. El nombre es un desempate, nunca una anulación: un "falso amigo" con el mismo nombre pero contenido no relacionado se deja en paz.
  5. Comparar enrutamiento (routing_comparator.compare_routing_for_modules) → RoutingDiscrepancy filas — un diff estructural (solo presencia del destino de la arista, no semántica de condiciones). Tanto la pregunta fuente como la destino de cada arista se resuelven mediante QuestionMatch antes de comparar, no se comparan como cadenas de nombre crudas, de modo que un destino presente en ambos lados bajo un nombre diferente (mayúsculas, un sufijo de Forsta+, etc.) no se reporte erróneamente como faltante.

Navegable en /questionnaires/routing-diff/<colectica_module_id>/<forsta_module_id>/, con una página de detalle por discrepancia que muestra los grafos de enrutamiento de ambos sistemas lado a lado.

Servidor de herramientas MCP

Junto a la aplicación Django principal, mcp_server expone un subconjunto curado y de solo lectura de los mismos datos como herramientas MCP (Model Context Protocol) sobre streamable-HTTP, para clientes MCP como Claude Desktop — su propia aplicación Django, su propio proceso independiente, su propio puerto, nunca el runserver principal.

python manage.py runmcp                 # own process, port 8765 by default

Cada petición debe llevar un token de acceso por persona en su ruta URL (https://<host>/t/<token>/mcp) en lugar de una cabecera, ya que las UIs de conectores de clientes MCP generalmente solo aceptan una URL. Los usuarios staff generan/revocan tokens en /questionnaires/mcp-tokens/ — sin secreto compartido, sin necesidad de comando de terminal para incorporar a una nueva persona, y revocar el token de una persona no afecta a nadie más.

Solicitar acceso: no hay registro de autoservicio por diseño. Abre un issue en este repositorio o contacta al mantenedor para solicitar un token.

Herramientas (mcp_server/tools.py), cada una con un prompt MCP correspondiente (mcp_server/prompts.py) que los clientes MCP pueden mostrar como un atajo estilo comando de barra:

ToolPromptNotes
list_moduleslistModulesSolo Colectica
get_module_summaryshowModuleSummarySolo Colectica
list_questionslistQuestionsSolo Colectica
get_questionshowQuestionSolo Colectica
get_routing_edgeslistRoutingEdgesSolo Colectica
trace_variabletraceVariableSolo Colectica
get_module_graphshowModuleGraphColectica + Forsta+; también devuelve sintaxis de diagrama de flujo Mermaid para que un cliente MCP pueda renderizar un diagrama real; los módulos grandes se auto-resumen en lugar de devolver un grafo enorme
evaluate_edge_conditionevaluateConditionColectica + Forsta+; evalúa cualquier cadena de condición contra respuestas hipotéticas
get_routing_diff_reportshowRoutingDiffReportPar Colectica + Forsta+; replica la página de informe de diff de enrutamiento
get_routing_discrepancy_detailshowColecticaForstaDiscrepancyPar Colectica + Forsta+; replica la página de detalle por discrepancia, con los grafos de ambos sistemas incluidos
get_routing_simulationshowRoutingSimulationSolo Colectica

Nunca escribe en la base de datos y nunca dispara un paso del pipeline computacionalmente pesado (extracción, construcción de grafos, emparejamiento/comparación, revisión de IA) por sí mismo — cada herramienta lee datos que otra parte de la aplicación ya calculó y persistió.

Stack tecnológico

  • Django 6.0 (proyecto config/; dos apps, flowise_questionnaire y mcp_server)
  • PostgreSQL (flowise_questionnaire_db)
  • Flowise (externo, autoalojado o en la nube) para revisión/redacción consultiva de IA
  • Sin framework de frontend — plantillas Django renderizadas en servidor (grafos de enrutamiento renderizados en el cliente mediante vis-network, cargado desde un CDN)

Primeros pasos

Requisitos previos

  • Python 3.12+
  • PostgreSQL, con una base de datos flowise_questionnaire_db disponible
  • Una instancia de Flowise en ejecución (opcional — solo necesaria para las funciones de revisión de IA / redacción de entrevista; el resto de la aplicación funciona sin ella)

Configuración

git clone https://github.com/amiravarzamani/colectica-forsta-routing-toolkit.git
cd flowise-questionnaire-system

python3 -m venv venv
source venv/bin/activate        # venv\Scripts\activate on Windows
pip install -r requirements.txt

Copia .env.example a .env y completa SECRET_KEY/DB_PASSWORD/DB_HOSTconfig/settings.py no tiene valores predeterminados para estos y fallará de forma ruidosa al inicio si faltan. Ajusta los ajustes DATABASES y FLOWISE_* en config/settings.py para que coincidan con tu entorno antes de ejecutar las migraciones.

python manage.py migrate
python manage.py createsuperuser   # first user, since login is required app-wide
python manage.py runserver

La aplicación está montada en /questionnaires/ y requiere inicio de sesión (LOGIN_URL = /questionnaires/login/).

Ejecutar pruebas

python manage.py test

Estructura del proyecto

config/                         Django project settings, URLs, WSGI/ASGI
flowise_questionnaire/
  models.py                     QuestionnaireModule, NormalizedQuestion, RoutingEdge,
                                 QuestionnaireGraph, ModuleAIReview, InterviewSimulatorSession/Turn,
                                 QuestionMatch, RoutingDiscrepancy
  services/                     Pipeline logic, in order:
    schema_extractor.py           parse questions out of the Colectica JSON
    routing_extractor.py          parse conditional/sequential/loop routing (Colectica)
    forsta_xml_schema_extractor.py   parse questions out of the Forsta+ XML
    forsta_xml_routing_extractor.py  parse conditional/sequential/loop routing (Forsta+)
    graph_builder.py               build the routing graph
    graph_enrichment.py            annotate the graph
    condition_evaluator.py         evaluate Colectica-syntax routing conditions against answers
    forsta_condition_evaluator.py  evaluate Forsta+-syntax routing conditions against answers
    coverage_intent_builder.py     generate deterministic test-case seed inputs
    routing_simulator.py           check routing coverage
    question_matcher.py            pair Colectica and Forsta+ questions (exact + fuzzy + name-tiebreak)
    routing_comparator.py          structural diff of matched questions' routing edges (source + target resolved via QuestionMatch)
    routing_diff_explainer.py      plain-language explanation text for the routing-diff GUI
    agentflow_payload_builder.py   build the Module Review Flowise payload
    flowise_client.py              send/receive the Module Review agentflow
    interview_router.py            deterministic routing engine for the simulator
    interview_simulator_service.py orchestrate simulator sessions
    answer_validation.py           validate respondent A/B/C input
    question_presentation.py       convert questions to respondent-facing text
    flowise_interview_wording.py   Interview Wording agentflow client + caching/fallback
    interview_simulator_contracts.py  shared dataclasses
  views/
    module_views.py               upload / extract / build-graph / review / graph
    interview_simulator_views.py  start / state / answer / abandon
    routing_simulation_views.py
    routing_diff_views.py         Colectica-vs-Forsta+ report / run / discrepancy-detail
    auth_views.py
mcp_server/
  models.py                      McpAccessToken (per-person access token)
  auth_middleware.py              TokenAuthMiddleware -- validates /t/<token>/mcp on every request
  tools.py                        the MCP tools (see "MCP tool server" above)
  prompts.py                      matching MCP prompts (slash-command shortcuts)
  server.py                       MCPServer instance, tool/prompt registration
  views.py / urls.py              staff-only token management UI (/questionnaires/mcp-tokens/)
  management/commands/runmcp.py   standalone streamable-HTTP server command

Grafo de conocimiento (graphify)

El código fuente se puede explorar mediante graphify, una herramienta que convierte el repositorio en un grafo de conocimiento consultable (god nodes, estructura de comunidades, relaciones entre archivos) en lugar de depender de grep/navegación cruda. La salida se escribe en graphify-out/ (gitignored — es un artefacto local regenerable, no código fuente commiteado).

pip install graphifyy
graphify .                 # build the graph (AST + semantic extraction)
graphify query "<question>"          # BFS/DFS traversal, answers from the graph
graphify path "<A>" "<B>"            # shortest path between two concepts/symbols
graphify explain "<concept>"         # plain-language explanation of a node
graphify update .                    # incremental re-extract after code changes

graphify-out/graph.html se abre como una visualización interactiva independiente; GRAPH_REPORT.md es una auditoría en lenguaje sencillo de god nodes, conexiones sorprendentes y preguntas sugeridas.

Estado / trabajo en curso

  • Los modelos AgentRun, SyntheticProfile, SimulationRun, SimulationCase, ValidationIssue están definidos pero aún no conectados a ninguna vista.
  • El pipeline de importación XML de Forsta+ (Confirmit Horizons) y de diff de enrutamiento Colectica-vs-Forsta+ (ver arriba) está implementado y en uso activo. Consulta forsta_xml_routing_validation_plan.md para el documento de investigación original y la justificación del diseño (ahora también incluye una sección de notas "post-build" que documenta dónde divergió la implementación real del diseño inicial).
  • RoutingDiscrepancy.DiscrepancyType.CONDITION_MISMATCH está definido en el modelo (para un futuro diff semántico/de evaluación de condiciones, a diferencia del diff estructural actual) pero actualmente no es producido por routing_comparator.py — reservado, no es un bug.
  • Una herramienta mcp_server para el resultado más reciente de ModuleAIReview está diseñada pero aún no construida — intencionalmente en espera pendiente de una aprobación separada, no es un descuido.
  • Limitación conocida de question_matcher.py: dos preguntas de Colectica con redacción genérica reutilizada byte-idéntica (p. ej., un seguimiento tipo carta modelo como "¿Y en qué pueblo es eso?" preguntado en más de un contexto de enrutamiento) no se pueden desambiguar solo por similitud de texto, por lo que la incorrecta puede ganar un emparejamiento. El desempate por nombre no ayuda aquí ya que los nombres de las preguntas no colisionan, solo su texto. Actualmente no corregido — necesitaría una señal diferente (p. ej., posición en el grafo de enrutamiento) que la similitud de texto.

Licencia

Aún no hay archivo de licencia — todos los derechos reservados por defecto hasta que se añada uno.