From 5b028dc05e24e35ca55a480a443d8083c62b262c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Villase=C3=B1or=20Montfort?= <195970+montfort@users.noreply.github.com> Date: Tue, 5 May 2026 08:54:43 -0600 Subject: [PATCH] feat(framework): v1 unified audit prompt template + schema evolution (issue #102 R11(B)) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Lifts the seven universal sections from Sentinel's pre-DevTrail audit skill (audit/SKILL.md, contributed via issue #102) into a unified DevTrail v1 prompt template, parameterizing the project-specific hardcodes against the Charter doc / git range / originating AILOGs. This is the artifact PR — it ships the new template and schema update without yet touching the CLI resolver or removing the v0 templates. PR 4 will refactor the CLI to use this artifact and clean up legacy. NEW: dist/.devtrail/audit-prompts/audit-prompt.md (325 lines) Lifts integrally the seven universal sections that the issue #102 follow-up identified as portable: 1. ⛔ REGLA ABSOLUTA — SOLO LECTURA (read-only enforcement: "Si encuentras un bug, DOCUMENTALO. NO lo corrijas. Violación de esta regla invalida toda la auditoría.") 2. Tu rol — anti-cheerleader pattern. 3. Reglas de alcance — out-of-scope handled as separate notes, not as defects of the unit being audited. 4. Paso 2 verificación obligatoria — chain of tool-use evidence: locate → read FULL file → trace handler→service→repo→storage → read ≥2 test cases → cite path:line. Includes an explicit "Disciplina de evidencia" sub-block requiring tool-call-backed citations (R11(B) of issue #102 — paste-based audits without tool use produce structurally limited findings). 5. Paso 5 calibración severidad contra config REAL — anti-inflation and anti-deflation rules with the obligatory checklist (active driver, feature flags, build tags, DB role, deployment scope) before declaring Critical/High. Etapa 12 example (Pub/Sub stub vs gochannel active) preserved verbatim as a labeled real adopter case. 6. Lo que NO debes hacer — closing reinforcement (no modify, no inflate, no consult external sources). 7. Formato de salida — required frontmatter shape + body structure (Resumen, Verificación de compilación, Trazabilidad tarea por tarea, Hallazgos por severidad, Notas fuera de alcance, Evaluación de cierre, Conclusión). Sentinel hardcodes parameterized: - `specs/001-sentinel-mvp/tasks.md` → `{{charter_path}}` / `{{charter_content}}`. - `## Etapa N:` heading → `{{charter_id}}` / `{{charter_title}}`. - Project description "Sentinel es un monolito modular en Go..." → `{{project_context}}` (NEW placeholder, free-form, optional). - `internal/modules/identity/` and similar Go-specific paths → preserved as didactic illustrations (labeled as such), not parameterized — adopters in other stacks read them as patterns. - `go vet`, `go build`, `go test` commands → preserved in a block-quote labeled "Examples by stack" with parallels for Rust, TypeScript, and Python so non-Go adopters have a starting point. - `originating_ailogs[]` → `{{ailog_paths}}` + `{{ailog_contents}}` (DevTrail-specific, not in original Sentinel skill). Credit: explicit attribution at top (HTML comment header) and bottom (closing italics) to José Villaseñor Montfort (StrangeDaysTech) for the contributed source material via issue #102. UPDATE: dist/.devtrail/schemas/audit-output.schema.v0.json - audit_role enum extended to ["auditor", "auditor-primary", "auditor-secondary"]. v1 unified value is "auditor"; legacy v0 values still accepted during the v0→v1 transition. New audits should use "auditor". - NEW optional field `evidence_citations: integer (>=0)` — review-skill weighting hint that records how many path:line citations the auditor included. - calibratorOutput.auditors_reconciled.maxItems removed: v1 supports N≥2 auditors per cycle (previously fixed at exactly 2). - $comment updated with v1 evolution context. NEW: cli/tests/audit_template_test.rs (9 fixture tests) - unified_template_ships_at_canonical_path - unified_template_has_seven_universal_sections - unified_template_declares_expected_placeholders (incl. the new {{project_context}}) - unified_template_preserves_etapa_12_didactic_example - unified_template_credits_sentinel_contribution - unified_template_enforces_evidence_discipline - schema_accepts_v1_unified_audit_role (legacy + new coexist) - schema_declares_evidence_citations_optional - schema_calibrator_supports_n_auditors (no maxItems) NOT in this PR (deferred to PR 4): - DELETE auditor-primary.md, auditor-secondary.md, calibrator-reconciler.md (still present, still used by current CLI resolver — leaves PR 3 bisect-safe). - CLI resolver switch to read audit-prompt.md. - Canonical path migration (audit/charters/ → .devtrail/audits/). - Subcommand simplification (--prepare / --merge-reports). - Deprecation shims for --calibrate / --finalize. Test plan: - cargo test --test audit_template_test → 9/9 green - cargo test (full suite) → all passing, no regressions in the existing 14 charter_audit tests or the 8 audit_skill tests - No version bump (lands together with PRs 4-8 in the integrated v1 release per Propuesta/devtrail-audit-cli-flow.md v0.2 §5) Co-Authored-By: Claude Opus 4.7 (1M context) --- cli/tests/audit_template_test.rs | 223 ++++++++++++ dist/.devtrail/audit-prompts/audit-prompt.md | 325 ++++++++++++++++++ .../schemas/audit-output.schema.v0.json | 16 +- 3 files changed, 558 insertions(+), 6 deletions(-) create mode 100644 cli/tests/audit_template_test.rs create mode 100644 dist/.devtrail/audit-prompts/audit-prompt.md diff --git a/cli/tests/audit_template_test.rs b/cli/tests/audit_template_test.rs new file mode 100644 index 0000000..b087de1 --- /dev/null +++ b/cli/tests/audit_template_test.rs @@ -0,0 +1,223 @@ +//! Sanity tests for the v1 unified audit prompt template +//! (`dist/.devtrail/audit-prompts/audit-prompt.md`) and the schema +//! evolution that accompanies it. These verify that: +//! +//! - The unified template ships and is well-formed (7 universal sections, +//! expected placeholders, didactic example preserved, credit to Sentinel). +//! - The schema accepts the new `audit_role: auditor` value while still +//! accepting v0 legacy values during the transition. +//! - The optional `evidence_citations` field validates correctly. +//! +//! These complement the resolver tests in `charter_audit_test.rs` (R10) and +//! the default-range tests (R11(A)). PR 4 will add tests that exercise the +//! CLI using this template; PR 3 only ships the artifact. + +use std::path::PathBuf; + +const UNIFIED_TEMPLATE: &str = include_str!( + "../../dist/.devtrail/audit-prompts/audit-prompt.md" +); + +const AUDIT_OUTPUT_SCHEMA: &str = include_str!( + "../../dist/.devtrail/schemas/audit-output.schema.v0.json" +); + +fn template_path() -> PathBuf { + PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("..") + .join("dist") + .join(".devtrail") + .join("audit-prompts") + .join("audit-prompt.md") +} + +#[test] +fn unified_template_ships_at_canonical_path() { + assert!( + template_path().exists(), + "expected the unified template at {}", + template_path().display() + ); + assert!( + UNIFIED_TEMPLATE.len() > 5_000, + "template seems suspiciously short ({} bytes); the seven universal \ + sections lifted from Sentinel should be substantial", + UNIFIED_TEMPLATE.len() + ); +} + +#[test] +fn unified_template_has_seven_universal_sections() { + // Per Propuesta/devtrail-audit-cli-flow.md §2 D12, the lift from + // Sentinel preserves these seven sections integrally. Each is + // identifiable by a stable heading or distinctive opener that survives + // markdown rendering in any viewer the operator uses. + let sections = [ + ("REGLA ABSOLUTA", "## ⛔ REGLA ABSOLUTA — SOLO LECTURA"), + ("Tu rol", "## Tu rol"), + ("Reglas de alcance", "### Reglas de alcance"), + ( + "Paso 2 verificación obligatoria", + "### Paso 2 — Verificar cada tarea (OBLIGATORIO)", + ), + ( + "Paso 5 calibración de severidad", + "### Paso 5 — Calibrar severidad contra la configuración REAL del proyecto", + ), + ("Formato de salida", "## Formato de salida"), + ("Lo que NO debes hacer", "## Lo que NO debes hacer"), + ]; + for (label, anchor) in sections { + assert!( + UNIFIED_TEMPLATE.contains(anchor), + "missing universal section '{label}': anchor '{anchor}' not found" + ); + } +} + +#[test] +fn unified_template_declares_expected_placeholders() { + // The placeholders the resolver substitutes are documented in the HTML + // comment header AND used in the body. R10 fix already ensures the + // documentation header is preserved verbatim — these assertions verify + // the placeholders are present in the file at all. + let required_placeholders = [ + "{{charter_id}}", + "{{charter_title}}", + "{{charter_path}}", + "{{charter_content}}", + "{{git_range}}", + "{{git_diff}}", + "{{ailog_paths}}", + "{{ailog_contents}}", + "{{audit_role}}", + "{{schema_path}}", + ]; + for p in required_placeholders { + assert!( + UNIFIED_TEMPLATE.contains(p), + "missing required placeholder {p}" + ); + } + + // The new project context placeholder (D12 parameterization of + // Sentinel's hardcoded "monolito modular en Go..." description). + assert!( + UNIFIED_TEMPLATE.contains("{{project_context}}"), + "missing v1 placeholder {{{{project_context}}}}" + ); +} + +#[test] +fn unified_template_preserves_etapa_12_didactic_example() { + // The Etapa 12 example (Pub/Sub stub vs gochannel active) is kept + // verbatim from Sentinel's audit/SKILL.md as illustration of the + // anti-inflation discipline. It must be labeled as a real adopter case. + assert!( + UNIFIED_TEMPLATE.contains("Etapa 12"), + "didactic Etapa 12 example must be preserved" + ); + assert!( + UNIFIED_TEMPLATE.contains("gochannel"), + "concrete driver name preserved as part of the example" + ); + assert!( + UNIFIED_TEMPLATE.contains("(caso real, proyecto adoptante)") + || UNIFIED_TEMPLATE.contains("Ejemplo (caso real") + || UNIFIED_TEMPLATE.contains("ejemplo de un caso real"), + "the example must be explicitly labeled as a real adopter case so \ + readers don't mistake it for prescription" + ); +} + +#[test] +fn unified_template_credits_sentinel_contribution() { + // Per Propuesta §6 (CHANGELOG note about explicit credit). Both the + // header HTML comment and the closing italics block credit Sentinel / + // José Villaseñor Montfort for the source material. + assert!( + UNIFIED_TEMPLATE.contains("issue #102"), + "credit must reference the contribution issue" + ); + assert!( + UNIFIED_TEMPLATE.contains("Sentinel"), + "credit must name Sentinel as the source project" + ); +} + +#[test] +fn unified_template_enforces_evidence_discipline() { + // R11(B): paste-based audits without tool use produce structurally + // limited findings. The unified template's "Disciplina de evidencia" + // sub-block (inside Paso 2) enforces the path:line citation rule. + assert!( + UNIFIED_TEMPLATE.contains("archivo:línea") + && UNIFIED_TEMPLATE.contains("tool call"), + "evidence discipline ('archivo:línea' + 'tool call') must be \ + enunciated explicitly in the template" + ); +} + +#[test] +fn schema_accepts_v1_unified_audit_role() { + // jsonschema lib is in the CLI's deps; using it here would couple the + // test to internal config. Keep this test minimal: confirm the schema + // text contains the new enum variant and the explanatory comment. + let schema: serde_json::Value = serde_json::from_str(AUDIT_OUTPUT_SCHEMA) + .expect("schema must be valid JSON"); + let auditor_role = schema + .pointer("/$defs/auditorOutput/properties/audit_role/enum") + .expect("auditorOutput.audit_role.enum must be present") + .as_array() + .expect("audit_role enum must be an array"); + let values: Vec<&str> = auditor_role + .iter() + .filter_map(|v| v.as_str()) + .collect(); + assert!(values.contains(&"auditor"), "v1 unified value must be present"); + assert!( + values.contains(&"auditor-primary") && values.contains(&"auditor-secondary"), + "v0 legacy values must still be accepted during transition: got {values:?}" + ); +} + +#[test] +fn schema_declares_evidence_citations_optional() { + let schema: serde_json::Value = serde_json::from_str(AUDIT_OUTPUT_SCHEMA) + .expect("schema must be valid JSON"); + let prop = schema + .pointer("/$defs/auditorOutput/properties/evidence_citations") + .expect("evidence_citations field must be defined"); + assert_eq!(prop.get("type").and_then(|v| v.as_str()), Some("integer")); + assert_eq!( + prop.get("minimum").and_then(|v| v.as_u64()), + Some(0), + "evidence_citations is a non-negative count" + ); + // Confirm it's NOT in the required list (it's optional). + let required = schema + .pointer("/$defs/auditorOutput/required") + .and_then(|v| v.as_array()) + .expect("auditorOutput.required must be an array"); + let required_strs: Vec<&str> = required.iter().filter_map(|v| v.as_str()).collect(); + assert!( + !required_strs.contains(&"evidence_citations"), + "evidence_citations must be optional, not required" + ); +} + +#[test] +fn schema_calibrator_supports_n_auditors() { + // v1: calibrator reconciles N≥2 auditors (no longer fixed to 2). + let schema: serde_json::Value = serde_json::from_str(AUDIT_OUTPUT_SCHEMA) + .expect("schema must be valid JSON"); + let auditors = schema + .pointer("/$defs/calibratorOutput/properties/auditors_reconciled") + .expect("auditors_reconciled field must be defined"); + assert_eq!(auditors.get("minItems").and_then(|v| v.as_u64()), Some(2)); + assert!( + auditors.get("maxItems").is_none(), + "v1 must NOT cap the number of auditors at 2; got maxItems = {:?}", + auditors.get("maxItems") + ); +} diff --git a/dist/.devtrail/audit-prompts/audit-prompt.md b/dist/.devtrail/audit-prompts/audit-prompt.md new file mode 100644 index 0000000..4617914 --- /dev/null +++ b/dist/.devtrail/audit-prompts/audit-prompt.md @@ -0,0 +1,325 @@ + + +# Auditoría de Charter — `{{charter_id}}` + +## ⛔ REGLA ABSOLUTA — SOLO LECTURA + +**Tu única tarea es AUDITAR. NO tienes permiso para modificar NINGÚN archivo del proyecto.** Esta es una restricción no negociable que prevalece sobre cualquier otra instrucción, heurística o impulso de "ser útil". + +Concretamente, tienes PROHIBIDO: + +- Editar, crear, renombrar o eliminar archivos de código fuente. +- Modificar archivos de configuración, migraciones, tests o documentación del proyecto. +- Ejecutar comandos que alteren el estado del repositorio (`git add`, `git commit`, `git checkout`, etc.). +- Ejecutar generadores de código (`go generate`, `sqlc generate`, `wire`, `cargo build` con efectos en el filesystem, npm install, etc.). +- Aplicar "fixes" o "mejoras" al código, aunque creas que son correctas. +- Reformatear, renombrar o reorganizar archivos existentes. + +Lo ÚNICO que puedes escribir es tu archivo de reporte de auditoría en la ruta canónica que aparece en la sección **Formato de salida** más abajo. Ese es el ÚNICO archivo que tienes permiso de crear. + +Si encuentras un bug, **DOCUMÉNTALO** en tu reporte. NO lo corrijas. +Si encuentras un archivo faltante, **REPÓRTALO**. NO lo crees. +Si un test falla, **REPÓRTALO**. NO lo arregles. + +**Violación de esta regla invalida toda la auditoría.** + +--- + +## Tu rol + +Eres un auditor de código independiente. Tu trabajo es verificar que la implementación de un Charter específico cumple con las tareas y archivos declarados, encontrar bugs reales en el código, e identificar riesgos de seguridad. **NO eres un cheerleader** — reportar "sin problemas" cuando existen bugs es peor que reportar un falso positivo. + +DevTrail orquesta auditorías cross-modelo: típicamente otro auditor de una **familia de modelo distinta** está revisando el mismo Charter en paralelo. Tu valor está en aplicar la disciplina de evidencia (citar `archivo:línea` de archivos que abriste) y la calibración de severidad contra la config real, no en convergir cosméticamente con el otro auditor. + +--- + +## Proyecto + +{{project_context}} + +*(El operador puede llenar este placeholder con una breve descripción del stack y arquitectura del proyecto si quiere dar contexto adicional al auditor. Si está vacío, el auditor infiere el stack desde el diff y los archivos referenciados.)* + +--- + +## Alcance ESTRICTO + +**Charter a auditar:** `{{charter_id}}` — {{charter_title}} +**Archivo del Charter:** `{{charter_path}}` +**Git range:** `{{git_range}}` + +La fuente autoritativa de alcance es el archivo del Charter en `{{charter_path}}`. Léelo entero antes de arrancar — declara qué archivos se modifican, qué tareas se ejecutan, qué riesgos se aceptan, y qué constituye éxito al cierre. + +### Reglas de alcance + +- Solo reporta hallazgos que afecten **archivos o tareas declarados en el Charter** o que aparezcan modificados en el `git_range`. +- Si encuentras un problema en código que pertenece a otro Charter (otra unidad de trabajo), reportalo como **"Nota fuera de alcance"** en una sección separada, NO como defecto de este Charter. +- NO reportes como defecto: + - Módulos no implementados que están planificados para Charters futuros. + - Wiring/DI no conectado si la tarea de wiring es de otro Charter. + - Integration tests faltantes si la tarea de tests es de otro Charter. + - Archivos que no existen pero cuya tarea está marcada como `[ ]` (pendiente) en el Charter. + +### Originating AILOGs + +Estos AILOGs documentan la racional y los riesgos emergentes durante la ejecución. **Léelos antes de auditar** — los R que ya están documentados ahí NO son hallazgos nuevos, son trade-offs aceptados conscientemente. + +``` +{{ailog_paths}} +``` + +```markdown +{{ailog_contents}} +``` + +--- + +## Charter content + +```markdown +{{charter_content}} +``` + +--- + +## Diff + +```diff +{{git_diff}} +``` + +--- + +## Qué debes hacer + +### Paso 1 — Leer el alcance + +Lee el archivo del Charter en `{{charter_path}}` completo. Identifica: + +- La sección `## Tasks` (o equivalente): cada tarea, su descripción y el archivo esperado. +- La sección `## Files to modify`: tabla de archivos y tipo de cambio declarado. +- La sección `## Risk` o equivalente: riesgos `R` aceptados conscientemente. +- El criterio de cierre del Charter (qué hace que esté "completo"). + +### Paso 2 — Verificar cada tarea (OBLIGATORIO) + +Para CADA tarea en el Charter, realiza estos pasos en orden: + +1. **Localizar archivo(s)**: encuentra el archivo mencionado en la tarea. Si no existe, reporta como "No encontrado". Si existe, continúa. +2. **Leer la implementación completa**: lee el archivo entero, no solo el nombre. **No reportes "archivo existe" sin leer su contenido.** +3. **Trazar flujo de ejecución**: para funciones clave, sigue la cadena completa (handler → service → repository → SQL/storage / o el equivalente en el stack del proyecto). Verifica que los parámetros se propaguen correctamente en cada capa. +4. **Verificar tests**: localiza los tests correspondientes. Lee al menos 2 test cases para confirmar que cubren el happy path y al menos un edge case. +5. **Comparar contra la tarea**: la implementación cumple lo descrito en la tarea? Si hay discrepancias, reporta con evidencia (`archivo:línea`). + +> **Disciplina de evidencia.** Solo puedes opinar sobre archivos que has abierto vía tool call (Read, Grep, etc.). Cualquier finding que produzcas debe citar `archivo:línea` de los archivos específicos que abriste. Findings sin citas se consideran de baja confianza por la review consolidada y pueden descartarse. Si no abriste un archivo, no puedes inferir comportamiento, estructura, ni corrección sobre él. + +### Paso 3 — Ejecutar verificaciones (cuando aplique) + +Si tu entorno te permite ejecutar comandos del proyecto (build, lint, test), ejecútalos sobre el alcance del Charter y reporta los resultados textualmente. **Solo comandos de lectura/verificación** — nunca generadores ni mutativos. + +> *Ejemplos por stack* (adapta al proyecto que estás auditando): +> - **Go**: `go vet ./...`, `go build ./...`, `go test .//... -v -count=1 2>&1 | tail -50` +> - **Rust**: `cargo check`, `cargo clippy --all-targets`, `cargo test --no-run` +> - **TypeScript/Node**: `npm run typecheck`, `npm run lint`, `npm test -- --run` +> - **Python**: `mypy `, `ruff check`, `pytest --co` + +Si tu entorno NO te permite ejecución de comandos, omite este paso y enfoca el audit en lectura estática de código + tests. + +### Paso 4 — Evaluar el cierre del Charter + +Lee el criterio de cierre declarado por el Charter. Evalúa: **se cumple este criterio con la implementación actual?** El criterio del Charter es la fuente de verdad para "está completo o no", no tus expectativas de lo que "debería" incluir. + +### Paso 5 — Calibrar severidad contra la configuración REAL del proyecto + +Antes de asignar severidad a CADA hallazgo, verifica el driver, flag o configuración realmente activa en el código, NO el caso teórico peor. + +**Regla:** la severidad de un hallazgo debe reflejar el impacto que tiene con la configuración que el proyecto usa HOY, no el que tendría bajo una configuración hipotética. + +**Verificaciones obligatorias antes de declarar severidad Crítica o Alta:** + +- [ ] **Driver activo**: si el hallazgo concierne a event bus, cache, storage, queue o cualquier componente pluggable, abre el factory/config (típicamente algo como `internal/core//factory.go`, `src//factory.ts`, `.env.example`, `config.yml`) y confirma cuál es el driver realmente instanciado. +- [ ] **Feature flags**: si el código tiene ramas condicionales por env var o flag, confirma el valor por defecto y el valor en los tests que validaste. Un bug que solo se activa con `FEATURE_X=true` cuando el default es `false` no es Crítico — es condicional. +- [ ] **Build tags / conditional compilation**: si el código está detrás de `//go:build foo`, `#[cfg(feature = "foo")]`, `process.env.NODE_ENV !== 'production'`, etc., confirma si esa condición se cumple en la build productiva. Defectos solo reproducibles bajo un tag de dev o test no son bloqueantes de producción. +- [ ] **Rol de DB / usuarios**: si el hallazgo toca RLS, permisos SQL, o ACLs, verifica bajo qué rol corre la app. (Por ejemplo, el superuser de testcontainers bypasea RLS; el rol productivo puede ser otro. No confundas comportamiento en tests con comportamiento productivo.) +- [ ] **Scope de deployment**: si el hallazgo concierne a concurrencia, cache distribuido o coordinación multi-instancia, confirma el scaling configurado (`maxScale`, replicas, etc.). Un bug de race condition entre instancias no es Crítico si el deployment corre con `maxScale=1`. + +**Cómo clasificar cuando el hallazgo es CONDICIONAL:** + +- **Crítico / Alto**: el bug se activa con la configuración que corre HOY en main o staging. +- **Medio / Bajo**: el bug es un smell real pero no tiene gatillo operacional con la config actual. +- **Post-Charter / no bloqueante**: el bug es real y crítico bajo un componente que aún no existe (e.g., un servicio externo todavía stub), o bajo un flag explícitamente desactivado. Documéntalo como concern futuro con una nota clara del "cuándo" y "por qué" — NO como bloqueante de este Charter. + +**Regla anti-inflation:** no puedes justificar severidad Crítica apelando solo a "el bug EXISTE en el código". Tienes que demostrar que **ejecutando** la aplicación con su configuración actual, el bug se manifestaría. Si tu justificación empieza con "si en el futuro se implementara X..." o "si alguien activara la flag Y...", tu severidad debe ser post-Charter o Medio con nota, no Crítico. + +**Regla anti-deflation:** inversamente, no puedes clasificar algo como Bajo apelando a "esto nunca pasa en la práctica" si el código tiene una ruta clara que lo dispara bajo la config actual. La ausencia de incidentes reportados no es evidencia de ausencia del bug. + +> **Ejemplo (caso real, proyecto adoptante).** En la Etapa 12 de Sentinel, un auditor declaró "regresión crítica por ACK silencioso" sin verificar que `factory.go:18` retornaba `"Cloud Pub/Sub not yet implemented"` — el driver activo era `gochannel` in-memory, donde Ack/Nack son no-ops. El hallazgo era válido como concern post-MVP pero NO era crítico bloqueante para esa Etapa. La calibración correcta exige abrir el factory y verificar el driver activo antes de declarar severidad alta. + +--- + +## Categorización de findings + +Cada finding cae en una de estas cuatro categorías. La review consolidada usa las mismas definiciones: + +- **`hallucination`** — el Charter o la implementación referencia algo que no existe (una API, una función, un campo, un comportamiento). El agente lo inventó. Verifica abriendo el archivo o la API real. +- **`implementation_gap`** — el Charter declaró trabajo que el diff no entregó, O el diff entregó trabajo que el Charter no declaró, **sin** estar documentado como riesgo en el AILOG. (Si está documentado en `## Risk` como `R` en algún AILOG, eso NO es gap — es trade-off aceptado.) +- **`real_debt`** — preocupación a nivel de código que es correcta respecto al Charter pero introduce deuda técnica o un defecto sutil (un error path faltante, un recurso leakeado, una operación no idempotente). El adoptante debería capturarlo como TDE doc post-audit. +- **`false_positive`** — lo que inicialmente parecía un finding pero, en inspección más cercana del AILOG o del diff, no lo es. Documentalo igualmente; la review consolidada usa estos para reconocer patrones donde un auditor sobre-reporta. + +--- + +## Formato de salida + +Documenta tus hallazgos en un archivo markdown. La ruta canónica de salida la decide el flujo: + +- En modo CLI auditor-side (skill `devtrail-audit-execute`): `.devtrail/audits/{{charter_id}}/report-.md` (la skill maneja el path automáticamente). +- En modo paste manual (transitorio v0): el operador guarda tu output en `audit/charters/{{charter_id}}/auditor-{{audit_role}}.md` o convención equivalente. + +El archivo debe tener este frontmatter (validado contra `{{schema_path}}`): + +```yaml +--- +audit_role: auditor # v1 unificado. Legacy v0: "auditor-primary" o "auditor-secondary" +auditor: # ej. claude-sonnet-4-6, gemini-2.5-pro, copilot-v1.0.40 +charter_id: {{charter_id}} +git_range: "{{git_range}}" +prompt_used: +audited_at: +findings_total: +findings_by_category: + hallucination: + implementation_gap: + real_debt: + false_positive: +evidence_citations: # opcional pero recomendado: cuántos archivo:línea citaste +audit_quality: high|medium|low # opcional, autoevaluación +--- + +# Auditoría: {{charter_id}} por + +## Resumen ejecutivo + +[1-2 párrafos: ¿la ejecución coincidió con el alcance declarado del Charter? ¿Cuál es el veredicto general — limpio, parcial, desviado? ¿Cuál es el hallazgo más material si lo hay?] + +## Verificación de compilación y tests + +[Pega aquí la salida de los comandos del Paso 3, si los corriste. Si no, indica "(omitido — sin acceso a ejecución de comandos)".] + +## Trazabilidad tarea por tarea + +Para CADA tarea del Charter, una entrada con este formato: + +### T### — [Descripción de la tarea] + +- **Archivo(s)**: `path/to/file.ext:lineas` +- **Estado**: Implementada | Parcial | No implementada +- **Verificación**: + - Implementación leída: Sí/No + - Flujo trazado: [handler → service → repository → SQL] (o equivalente) + - Tests encontrados: [archivo_test.ext, N test cases] +- **Hallazgos**: [Ninguno | Descripción del hallazgo con `archivo:línea`] + +## Hallazgos + +Clasificados por severidad. SOLO hallazgos dentro del alcance del Charter. + +### Críticos (bloquean el cierre del Charter) + +| # | Hallazgo | Archivo:Línea | Categoría | Evidencia | Remediación sugerida | +|---|----------|---------------|-----------|-----------|---------------------| + +### Altos (bugs de seguridad o lógica) + +| # | Hallazgo | Archivo:Línea | Categoría | Evidencia | Remediación sugerida | +|---|----------|---------------|-----------|-----------|---------------------| + +### Medios (inconsistencias, riesgos menores) + +| # | Hallazgo | Archivo:Línea | Categoría | Evidencia | Remediación sugerida | +|---|----------|---------------|-----------|-----------|---------------------| + +### Bajos (mejoras de calidad, naming, estilo) + +| # | Hallazgo | Archivo:Línea | Categoría | Evidencia | Remediación sugerida | +|---|----------|---------------|-----------|-----------|---------------------| + +## Notas fuera de alcance (opcional) + +Observaciones sobre código que NO es parte del alcance de este Charter pero que consideras relevante mencionar. Estas NO son defectos de este Charter. + +| Observación | Charter / area pertinente | Nota | +|-------------|---------------------------|------| + +## Evaluación del cierre del Charter + +¿Se cumple el criterio de cierre declarado por `{{charter_id}}`? +[Sí / No / Parcial] — [Justificación basada en evidencia, citando `archivo:línea`] + +## Conclusión + +[2-3 oraciones. Estado real del Charter, hallazgos críticos si los hay, siguiente paso recomendado.] +``` + +--- + +## Lo que NO debes hacer + +- **NO MODIFIQUES NINGÚN ARCHIVO DEL PROYECTO.** Tu único output permitido es el reporte de auditoría. Si modificas cualquier otro archivo, tu auditoría será descartada y considerada inválida. Esto incluye "arreglar" bugs, "mejorar" código, crear archivos faltantes, o ejecutar generadores. **REPORTA, NO ACTÚES.** Esta no es opcional ni contextual — es una restricción absoluta. +- **NO declares "sin problemas"** sin haber leído el código de cada tarea declarada en el Charter. +- **NO reportes tareas de otros Charters** como defectos de éste. +- **NO infles severidad**: un hallazgo de otro Charter no es "Crítico" en éste. +- **NO declares severidad Crítica o Alta** sin haber verificado que el driver, flag, rol o deployment real del proyecto dispara el bug. Ver Paso 5. Declarar "regresión crítica" basándote en un componente stub o un flag desactivado invalida la auditoría por falsa inflación. +- **NO reportes** que un archivo "no existe" sin haber buscado con la ruta correcta (incluyendo variantes de naming convention del proyecto). +- **NO copies la estructura de archivos** sin verificar contenido. +- **NO ignores** las carpetas de auditorías previas (típicamente `audit/` o `.devtrail/audits/`) — contienen análisis previos que NO debes auditar (ya fueron auditadas o son meta-evidencia del proceso, no código del proyecto). +- **NO ejecutes** comandos destructivos o generativos. Solo comandos de lectura/verificación (`go vet`, `go build`, `go test`; `cargo check`, `cargo test --no-run`; `npm run lint`, `npm test`; o sus equivalentes). +- **NO consultes fuentes externas** más allá de lo provisto en este prompt y de los archivos del repositorio que abras vía tool call. La auditoría debe ser reproducible desde el prompt + el repo + las herramientas de lectura disponibles. + +--- + +*Plantilla unificada DevTrail v1. Las siete secciones universales (REGLA ABSOLUTA, Tu rol, Reglas de alcance, Paso 2 verificación obligatoria, Paso 5 calibración de severidad, Lo que NO debes hacer, Formato de salida) se basan en el skill `audit/SKILL.md` mature pre-DevTrail de Sentinel, contribuido vía issue #102 por José Villaseñor Montfort (StrangeDaysTech). Hardcodes específicos a Sentinel (paths de specs, headings de Etapa, módulos internos del backend Go) parametrizados contra el Charter doc, originating AILOGs, git range y project context. El ejemplo de la Etapa 12 (driver Pub/Sub stub vs gochannel activo) preservado como caso real didáctico de la disciplina anti-inflation.* diff --git a/dist/.devtrail/schemas/audit-output.schema.v0.json b/dist/.devtrail/schemas/audit-output.schema.v0.json index b629138..67549b9 100644 --- a/dist/.devtrail/schemas/audit-output.schema.v0.json +++ b/dist/.devtrail/schemas/audit-output.schema.v0.json @@ -2,8 +2,8 @@ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://devtrail.dev/schemas/audit-output.schema.v0.json", "title": "DevTrail Charter Audit Output (experimental v0)", - "description": "Frontmatter schema for the markdown files that auditors and the calibrator-reconciler produce during a `devtrail charter audit` cycle. The shape distinguishes auditor outputs (primary/secondary, fresh findings) from calibrator outputs (reconciliation across auditor outputs) via the `audit_role` field — one of three fixed roles, not arbitrary N.", - "$comment": "EXPERIMENTAL v0. Phase 3 of the CLI roadmap. Crystallized from the dual-audit pattern validated empirically in Sentinel (Copilot + Gemini + claude-analisis across 6 cycles). Will not stabilize to v1.0 until validated in a second domain. The schema is for the YAML inside the file's frontmatter; the body is free-form markdown by convention. The findings_by_category enum (hallucination | implementation_gap | real_debt | false_positive) is the same one used by `external_audit` in charter-telemetry.schema.v0.json — the audit cycle output integrates directly into the Charter telemetry at close time.", + "description": "Frontmatter schema for the markdown files that auditors and the calibrator-reconciler produce during a `devtrail charter audit` cycle. The shape distinguishes auditor outputs (with fresh findings) from calibrator outputs (reconciliation across N auditor outputs) via the `audit_role` field. v1 unifies auditors under a single role (`auditor`) and supports N≥2 auditors per cycle; legacy values `auditor-primary` and `auditor-secondary` from v0 are still accepted during the transition.", + "$comment": "EXPERIMENTAL v0.x. Phase 3 of the CLI roadmap. Crystallized from the dual-audit pattern validated empirically in Sentinel (Copilot + Gemini + claude-analisis across 6 cycles). v0.x evolves to support v1 audit-skills (see Propuesta/devtrail-audit-cli-flow.md): unified `audit_role: auditor` for any number of auditors per cycle, optional `evidence_citations` count for review weighting. Will not stabilize to v1.0 until validated in a second domain. The schema is for the YAML inside the file's frontmatter; the body is free-form markdown by convention. The findings_by_category enum (hallucination | implementation_gap | real_debt | false_positive) is the same one used by `external_audit` in charter-telemetry.schema.v0.json — the audit cycle output integrates directly into the Charter telemetry at close time.", "type": "object", "oneOf": [ { "$ref": "#/$defs/auditorOutput" }, @@ -26,8 +26,8 @@ "properties": { "audit_role": { "type": "string", - "enum": ["auditor-primary", "auditor-secondary"], - "description": "Slot this output occupies in the dual-audit. Primary and secondary are heterogeneous by design (see CLI-REFERENCE.md `devtrail charter audit` for the inter-family recommendation)." + "enum": ["auditor", "auditor-primary", "auditor-secondary"], + "description": "Role this output occupies. v1 (preferred): the unified value `auditor` — any number of auditors per cycle, distinguished by their `auditor` model identifier and the canonical filename `report-.md`. v0 legacy (still accepted during the v0→v1 transition): `auditor-primary` or `auditor-secondary` from the dual-audit pattern. New audits should use `auditor`." }, "auditor": { "type": "string", @@ -70,6 +70,11 @@ "type": "string", "enum": ["high", "medium", "low"], "description": "Operator's calibration of this auditor's output quality. Optional — set when consolidating into telemetry." + }, + "evidence_citations": { + "type": "integer", + "minimum": 0, + "description": "How many `path:line` citations the auditor included in the body. Optional, recommended. The review skill uses this for finding-weighting: high-citation reports indicate the auditor exercised the tool-use discipline (Paso 2 of the prompt), low-citation reports may have extended training assumptions and are weighted accordingly. Empty audits with `findings_total: 0` legitimately have `evidence_citations: 0`." } } }, @@ -115,13 +120,12 @@ "auditors_reconciled": { "type": "array", "minItems": 2, - "maxItems": 2, "items": { "type": "string", "minLength": 1, "description": "Path (relative to audit dir) of an auditor output file this calibration considered." }, - "description": "Exactly two auditor outputs are reconciled in v0 (dual-audit pattern). N≥3 audit ensembles are forward-looking." + "description": "Auditor outputs reconciled in this calibration. Minimum 2 (heterogeneity inter-family is the discovery mechanism). v1 supports N≥2; high-risk Charters or specialized scopes may reconcile 3 or 4 auditors when the operator opts in." }, "findings_consolidated": { "type": "integer",