clckernel 1.2.17 → 1.2.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.es.md CHANGED
@@ -20,11 +20,14 @@ Los agentes de programación con IA (Cursor, Claude Code, Windsurf, Copilot) cod
20
20
  ## 📋 Tabla de Contenidos
21
21
  - [🎯 Casos de Uso](#-casos-de-uso)
22
22
  - [🏛️ El Proceso Unificado de IA (AIUP)](#️-el-proceso-unificado-de-ia-aiup)
23
+ - [🔍 Desarrollo Guiado por Revisión (RDD) y los 4 Lentes](#-desarrollo-guiado-por-revisión-rdd-y-los-4-lentes)
23
24
  - [⚡ Guía Paso a Paso (Ciclo Completo)](#-guía-paso-a-paso-ciclo-completo)
24
25
  - [🎮 Interfaz Universal de Comandos](#-interfaz-universal-de-comandos)
25
26
  - [🔄 Actualización de Proyectos Existentes](#-actualización-de-proyectos-existentes)
26
27
  - [🌐 Ecosistemas Soportados y Arquetipos](#-ecosistemas-soportados-y-arquetipos)
28
+ - [🏛️ Arquitectura: Standalone vs. Simbiosis con Gentle AI](#-arquitectura-standalone-vs-simbiosis-con-gentle-ai)
27
29
  - [🧩 Herramientas Complementarias (Opcionales)](#-herramientas-complementarias-opcionales)
30
+ - [📖 Glosario de Términos Clave](#-glosario-de-términos-clave)
28
31
  - [📄 Licencia](#-licencia)
29
32
 
30
33
  ---
@@ -62,6 +65,28 @@ Los agentes de programación con IA (Cursor, Claude Code, Windsurf, Copilot) cod
62
65
 
63
66
  ---
64
67
 
68
+ <a id="rdd-y-lentes"></a>
69
+ ## 🔍 Desarrollo Guiado por Revisión (RDD) y los 4 Lentes
70
+
71
+ CLC Kernel estructura todas sus compuertas de auditoría bajo los principios de **Review-Driven Development (RDD)**, organizando cada salvaguarda en torno a los **4 Lentes Canónicos de Revisión**:
72
+
73
+ ```
74
+ ┌─────────────────────────────────────────────────────────────────────────────┐
75
+ │ LOS 4 LENTES CANÓNICOS DE REVISIÓN │
76
+ ├─────────────────────┬───────────────────┬───────────────────┬───────────────┤
77
+ │ 🎯 CORRECTITUD │ 🛡️ SEGURIDAD │ 🏛️ ARQUITECTURA │ ⚡ RENDIMIENTO│
78
+ │ Bugs funcionales, │ Fuga de secretos, │ Violación capas, │ N+1 queries, │
79
+ │ scope drift, TDD, │ bypass permisos, │ límites de dominio│ tamaño bundle,│
80
+ │ contratos API │ eval peligroso │ deps circulares │ memory leaks │
81
+ └─────────────────────┴───────────────────┴───────────────────┴───────────────┘
82
+ ```
83
+
84
+ Al ejecutar `clckernel audit` (o `node tools/audit.js`), CLC Kernel genera:
85
+ 1. **Informe Educativo para Humanos (`05-audit-report.md`):** Explica detalladamente qué pasó, falló o fue omitido agrupado por cada lente.
86
+ 2. **Recibo Inmutable de Auditoría (`audit-receipt.json`):** Un archivo JSON inmutable y legible por máquina vinculado al `commitHash` actual que certifica el resultado para compuertas automatizadas de revisión (como Gentle AI).
87
+
88
+ ---
89
+
65
90
  <a id="guia-paso-a-paso"></a>
66
91
  ## ⚡ Guía Paso a Paso (Ciclo Completo)
67
92
 
@@ -169,6 +194,49 @@ clckernel update
169
194
 
170
195
  ---
171
196
 
197
+ <a id="arquitectura-simbiosis"></a>
198
+ ## 🏛️ Arquitectura: Standalone vs. Simbiosis con Gentle AI
199
+
200
+ CLC Kernel está diseñado bajo una **filosofía de cero dependencias forzadas**: opera como un motor de gobernanza 100% autosuficiente y local, ofreciendo a su vez interoperabilidad nativa y fluida con el ecosistema de [Gentle AI](https://github.com/Gentleman-Programming/gentle-ai).
201
+
202
+ <div align="center">
203
+ <img src="./docs/Architecture/clckernel-symbiosis.visual-check.2048x1320.dark.png" alt="CLC Kernel Standalone vs Simbiosis con Gentle AI (Diagrama Archify)" width="100%" />
204
+ </div>
205
+
206
+ > 💡 *Diagrama Interactivo: Generado con [Archify](https://github.com/tt-a1i/archify). Podés abrir [`docs/Architecture/clckernel-symbiosis.html`](./docs/Architecture/clckernel-symbiosis.html) para explorar la animación de flujo, cambiar entre modo claro/oscuro e inspeccionar detalles de cada nodo.*
207
+
208
+ ```mermaid
209
+ flowchart TD
210
+ subgraph CORE["🤖 CLC KERNEL (Motor Central de Gobernanza)"]
211
+ SSOT["1. Ley SSOT<br/>(AGENTS.md y Symlinks para IDEs)"]
212
+ AIUP["2. Arnés AIUP<br/>(SDD + HITL + TDD Rojo-a-Verde)"]
213
+ AST["3. Linters AST &lt;5ms<br/>(Reglas de Capas, Secretos y Migraciones)"]
214
+ RECEIPT["4. Motor de Auditoría 4-Lentes<br/>(Genera audit-receipt.json)"]
215
+ SSOT --> AIUP --> AST --> RECEIPT
216
+ end
217
+
218
+ RECEIPT -->|audit-receipt.json| MODES{Modo de Ejecución}
219
+
220
+ subgraph MODE1["🟢 MODO 1: STANDALONE (100% Local y Desconectado)"]
221
+ M1_1["• Cero dependencias externas"]
222
+ M1_2["• Ejecución nativa AST en &lt; 5ms"]
223
+ M1_3["• Hook Git pre-commit bloquea físicamente commits inválidos"]
224
+ M1_4["• Reporte autosuficiente 05-audit-report.md"]
225
+ end
226
+
227
+ subgraph MODE2["🟣 MODO 2: + SIMBIOSIS CON GENTLE AI"]
228
+ M2_1["🧠 Engram (MCP): Contexto persistente y seguimiento de ADRs"]
229
+ M2_2["🛡️ Gentle AI (RDD): Revisión multi-agente adversarial"]
230
+ M2_3["🕸️ Graphify: Topología de código y análisis de impacto"]
231
+ M2_4["🔗 Sin bloqueo de proveedor: Consume audit-receipt.json sin fricción"]
232
+ end
233
+
234
+ MODES -->|Solo Local| MODE1
235
+ MODES -->|Con Herramientas Companion| MODE2
236
+ ```
237
+
238
+ ---
239
+
172
240
  <a id="herramientas-complementarias"></a>
173
241
  ## 🧩 Herramientas Complementarias (Opcionales)
174
242
 
@@ -179,6 +247,24 @@ CLC Kernel se enfoca estrictamente en gobernanza y opera con **cero dependencias
179
247
 
180
248
  ---
181
249
 
250
+ <a id="glosario"></a>
251
+ ## 📖 Glosario de Términos Clave
252
+
253
+ | Término | Definición |
254
+ |---|---|
255
+ | **SDD** *(Spec-Driven Development)* | Metodología orientada a especificaciones previas donde los contratos técnicos, esquemas, criterios de aceptación y escenarios de prueba se redactan en specs locales gitignoradas (`sdds/{cambio}/spec.md`) antes de modificar código fuente. |
256
+ | **RDD** *(Review-Driven Development)* | Metodología de verificación adversarial y estructurada donde los cambios se auditan a través de cuatro lentes ortogonales (Correctitud, Seguridad, Arquitectura y Rendimiento) para garantizar compuertas sistemáticas de calidad antes del merge o commit. |
257
+ | **AIUP** *(AI Unified Process)* | El ciclo de vida gobernado de punta a punta implementado por CLC Kernel: Investigación $\rightarrow$ SDD local $\rightarrow$ Aprobación Human-in-the-Loop (HITL) $\rightarrow$ TDD Rojo a Verde $\rightarrow$ Compuerta de Auditoría AST $\rightarrow$ Conventional Commit. |
258
+ | **HIT / HITL** *(Human-in-the-Loop)* | Compuerta obligatoria de aprobación donde un ingeniero humano valida contratos, decisiones arquitectónicas y pruebas propuestas antes de que un agente autónomo edite código de producción. |
259
+ | **TDD** *(Test-Driven Development)* | Práctica de ingeniería de reproducir bugs o especificar nuevas funcionalidades mediante un test automatizado que falle (Fase Roja) antes de escribir el código mínimo de producción para que pase (Fase Verde). |
260
+ | **Guard AST** *(Salvaguarda de Árbol de Sintaxis Abstracta)* | Script liviano de análisis estático sin dependencias foráneas escrito en el lenguaje nativo del stack (Python `ast`, TypeScript Compiler API, Go `go/parser`, RuboCop, etc.) que se ejecuta en menos de 5ms para bloquear físicamente violaciones antes del commit. |
261
+ | **SSOT** *(Single Source of Truth / Única Fuente de Verdad)* | Principio de gobernanza centralizada donde `AGENTS.md` funciona como la ley única, proyectándose automáticamente a todos los entornos de agentes (`CLAUDE.md`, `GEMINI.md`, `.cursorrules`, Copilot) mediante symlinks del sistema de archivos. |
262
+ | **Recibo de Auditoría** *(Audit Receipt)* | Artefacto JSON inmutable y legible por máquina (`audit-receipt.json`) producido por el motor de auditoría con la marca de tiempo, hash del commit, veredictos por cada lente y metadatos de compatibilidad RDD para Gentle AI. |
263
+ | **ADR** *(Architectural Decision Record)* | Documento estandarizado bajo `docs/Journal/` que captura decisiones arquitectónicas clave, contexto histórico, alternativas evaluadas y consecuencias. |
264
+ | **Agent-OS** | Arquetipo de sistema operativo para flujos de agentes y dominios no técnicos (por ejemplo: Marketing OS, Content Ops, Research OS) gobernado por arquitectura de dos capas, validación estricta de esquemas y compuertas HITL. |
265
+
266
+ ---
267
+
182
268
  <a id="licencia"></a>
183
269
  ## 📄 Licencia
184
270
  MIT © [CarlosLeonCode](https://github.com/carlosleoncode)
package/README.md CHANGED
@@ -20,11 +20,14 @@ AI coding agents (Cursor, Claude Code, Windsurf, Copilot) code fast, but without
20
20
  ## 📋 Table of Contents
21
21
  - [🎯 Use Cases](#-use-cases)
22
22
  - [🏛️ The AI Unified Process (AIUP)](#️-the-ai-unified-process-aiup)
23
+ - [🔍 Review-Driven Development (RDD) & the 4 Canonical Lenses](#-review-driven-development-rdd--the-4-canonical-lenses)
23
24
  - [⚡ Step-by-Step Guide (Full Lifecycle)](#-step-by-step-guide-full-lifecycle)
24
25
  - [🎮 Universal Command Interface](#-universal-command-interface)
25
26
  - [🔄 Updating an Existing Project](#-updating-an-existing-project)
26
27
  - [🌐 Supported Stacks & Archetypes](#-supported-stacks--archetypes)
28
+ - [🏛️ Architecture: Standalone vs. Gentle AI Symbiosis](#-architecture-standalone-vs-gentle-ai-symbiosis)
27
29
  - [🧩 Optional Ecosystem Companions](#-optional-ecosystem-companions)
30
+ - [📖 Glossary of Key Terms](#-glossary-of-key-terms)
28
31
  - [📄 License](#-license)
29
32
 
30
33
  ---
@@ -62,6 +65,28 @@ AI coding agents (Cursor, Claude Code, Windsurf, Copilot) code fast, but without
62
65
 
63
66
  ---
64
67
 
68
+ <a id="rdd-and-lenses"></a>
69
+ ## 🔍 Review-Driven Development (RDD) & the 4 Canonical Lenses
70
+
71
+ CLC Kernel structures all verification and audit gates around **Review-Driven Development (RDD)**, categorizing every safeguard across the **4 Canonical Review Lenses**:
72
+
73
+ ```
74
+ ┌─────────────────────────────────────────────────────────────────────────────┐
75
+ │ THE 4 CANONICAL REVIEW LENSES │
76
+ ├─────────────────────┬───────────────────┬───────────────────┬───────────────┤
77
+ │ 🎯 CORRECTNESS │ 🛡️ SECURITY │ 🏛️ ARCHITECTURE │ ⚡ PERFORMANCE│
78
+ │ Functional bugs, │ Secret leaks, │ Layer violations, │ N+1 queries, │
79
+ │ scope drift, TDD, │ permission bypass,│ domain boundaries,│ bundle size, │
80
+ │ API contracts │ dangerous eval │ circular deps │ memory leaks │
81
+ └─────────────────────┴───────────────────┴───────────────────┴───────────────┘
82
+ ```
83
+
84
+ When you run `clckernel audit` (or `node tools/audit.js`), CLC Kernel generates:
85
+ 1. **Human-Readable Educational Report (`05-audit-report.md`):** Explains exactly what passed, failed, or was skipped grouped by lens.
86
+ 2. **Machine-Readable Audit Receipt (`audit-receipt.json`):** An immutable JSON receipt bound to the active `commitHash` certifying the verdict for automated review gates (such as Gentle AI).
87
+
88
+ ---
89
+
65
90
  <a id="step-by-step-guide"></a>
66
91
  ## ⚡ Step-by-Step Guide (Full Lifecycle)
67
92
 
@@ -169,6 +194,49 @@ clckernel update
169
194
 
170
195
  ---
171
196
 
197
+ <a id="architecture-symbiosis"></a>
198
+ ## 🏛️ Architecture: Standalone vs. Gentle AI Symbiosis
199
+
200
+ CLC Kernel is architected with a **zero-lock-in philosophy**: it functions as a 100% self-sufficient local governance engine, while offering seamless, native interoperability with the [Gentle AI](https://github.com/Gentleman-Programming/gentle-ai) ecosystem.
201
+
202
+ <div align="center">
203
+ <img src="./docs/Architecture/clckernel-symbiosis.visual-check.2048x1320.dark.png" alt="CLC Kernel Standalone vs Gentle AI Symbiosis (Archify Diagram)" width="100%" />
204
+ </div>
205
+
206
+ > 💡 *Interactive Diagram: Built with [Archify](https://github.com/tt-a1i/archify). Open [`docs/Architecture/clckernel-symbiosis.html`](./docs/Architecture/clckernel-symbiosis.html) for full trace animation, theme switching, and deep-link node inspection.*
207
+
208
+ ```mermaid
209
+ flowchart TD
210
+ subgraph CORE["🤖 CLC KERNEL (Core Governance Engine)"]
211
+ SSOT["1. SSOT Law<br/>(AGENTS.md & IDE Mirrors)"]
212
+ AIUP["2. AIUP Harness<br/>(SDD + HITL + TDD Red-to-Green)"]
213
+ AST["3. AST Guards &lt;5ms<br/>(Layer, Secret & Migration Rules)"]
214
+ RECEIPT["4. 4-Lens Audit Engine<br/>(Emits audit-receipt.json)"]
215
+ SSOT --> AIUP --> AST --> RECEIPT
216
+ end
217
+
218
+ RECEIPT -->|audit-receipt.json| MODES{Deployment Mode}
219
+
220
+ subgraph MODE1["🟢 MODE 1: STANDALONE (100% Local & Offline)"]
221
+ M1_1["• Zero foreign dependencies"]
222
+ M1_2["• Native stack AST execution in &lt; 5ms"]
223
+ M1_3["• Git pre-commit hook physically blocks invalid commits"]
224
+ M1_4["• Self-contained 05-audit-report.md"]
225
+ end
226
+
227
+ subgraph MODE2["🟣 MODE 2: + GENTLE AI SYMBIOSIS"]
228
+ M2_1["🧠 Engram (MCP): Persistent context & ADR tracking"]
229
+ M2_2["🛡️ Gentle AI (RDD): Multi-agent adversarial review"]
230
+ M2_3["🕸️ Graphify: Codebase topology & blast radius analysis"]
231
+ M2_4["🔗 Zero-Lock-In: Consumes audit-receipt.json seamlessly"]
232
+ end
233
+
234
+ MODES -->|Local Only| MODE1
235
+ MODES -->|With Companions| MODE2
236
+ ```
237
+
238
+ ---
239
+
172
240
  <a id="ecosystem-companions"></a>
173
241
  ## 🧩 Optional Ecosystem Companions
174
242
 
@@ -179,6 +247,24 @@ CLC Kernel focuses strictly on governance and runs with **zero foreign dependenc
179
247
 
180
248
  ---
181
249
 
250
+ <a id="glossary"></a>
251
+ ## 📖 Glossary of Key Terms
252
+
253
+ | Term | Definition |
254
+ |---|---|
255
+ | **SDD** *(Spec-Driven Development)* | A specification-first methodology where detailed technical contracts, schemas, acceptance criteria, and test scenarios are authored in local, gitignored specs (`sdds/{change}/spec.md`) before modifying source code. |
256
+ | **RDD** *(Review-Driven Development)* | An adversarial and structured code verification methodology where changes are audited across four orthogonal lenses (Correctness, Security, Architecture, Performance) to ensure systematic quality gates before merge or commit. |
257
+ | **AIUP** *(AI Unified Process)* | The end-to-end governed lifecycle implemented by CLC Kernel: Research $\rightarrow$ Local SDD $\rightarrow$ Human-in-the-Loop (HITL) approval $\rightarrow$ TDD Red-to-Green $\rightarrow$ AST Guard Audit Gate $\rightarrow$ Conventional Commit. |
258
+ | **HIT / HITL** *(Human-in-the-Loop)* | A mandatory approval gate where a human engineer validates contracts, architecture decisions, and proposed tests before an autonomous agent executes production code edits. |
259
+ | **TDD** *(Test-Driven Development)* | The engineering practice of writing a failing automated regression test (Red Phase) to reproduce an issue or specify a new feature before writing the minimal production code to make it pass (Green Phase). |
260
+ | **AST Guard** *(Abstract Syntax Tree Safeguard)* | A lightweight, zero-dependency static analysis script in the stack's native language (Python `ast`, TypeScript Compiler API, Go `go/parser`, RuboCop, etc.) executing in under 5ms to physically block architectural violations before git commits. |
261
+ | **SSOT** *(Single Source of Truth)* | The centralized governance principle where `AGENTS.md` acts as the single source of truth, mirrored automatically to all AI IDE config files (`CLAUDE.md`, `GEMINI.md`, `.cursorrules`, Copilot) via filesystem symlinks. |
262
+ | **Audit Receipt** | An immutable, machine-readable JSON artifact (`audit-receipt.json`) produced by the audit engine containing the timestamp, commit hash, per-lens verdicts, and Gentle AI RDD compatibility metadata. |
263
+ | **ADR** *(Architectural Decision Record)* | A standardized document in `docs/Journal/` capturing significant architectural decisions, context, evaluated alternatives, and consequences. |
264
+ | **Agent-OS** | An operating system archetype for non-tech domain workflows (e.g. Marketing OS, Content Ops, Research OS) governed by dual-layer architecture, strict schema validation, and HITL checkpoints. |
265
+
266
+ ---
267
+
182
268
  <a id="license"></a>
183
269
  ## 📄 License
184
270
  MIT © [CarlosLeonCode](https://github.com/carlosleoncode)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clckernel",
3
- "version": "1.2.17",
3
+ "version": "1.2.18",
4
4
  "description": "CLC Kernel — The Universal Polyglot AI Agent Governance Engine (Next.js, FastAPI, Django, Astro, Rails, Go, Rust, Laravel).",
5
5
  "main": "./bin/cli.js",
6
6
  "files": [
package/src/catalog.js CHANGED
@@ -28,152 +28,152 @@ const SAFEGUARD_CATALOG = [
28
28
  { name: 'scan_secrets', labels: ['scan_secrets', 'scan_secrets.js', 'scan_secrets.py'],
29
29
  checks: 'Secret & private-key leak scan', verify: ['verify_secret_leaks', 'verify_no_hardcoded_secrets'],
30
30
  applies_when: 'always', severity: 'error', gate_mode: 'hard', config_keys: ['scope', 'exclude_paths'],
31
- phase: 'audit', file: 'scan_secrets.js+scan_secrets.py', manifest: true, planned: false },
31
+ phase: 'audit', file: 'scan_secrets.js+scan_secrets.py', manifest: true, planned: false, lens: 'security' },
32
32
 
33
33
  { name: 'check_architecture', labels: ['check_architecture', 'check_architecture.js', 'check_architecture.py'],
34
34
  checks: 'Clean Architecture layer / server-component boundaries', verify: ['verify_architecture_layers', 'verify_server_component_boundaries'],
35
35
  applies_when: 'frontend,backend', severity: 'error', gate_mode: 'hard', config_keys: ['scope', 'exclude_paths'],
36
- phase: 'audit', file: 'check_architecture.js+check_architecture.py', manifest: true, planned: false },
36
+ phase: 'audit', file: 'check_architecture.js+check_architecture.py', manifest: true, planned: false, lens: 'architecture' },
37
37
 
38
38
  { name: 'check_custom', labels: ['check_custom', 'check_custom.js', 'check_custom.py'],
39
39
  checks: 'User-defined regex rules from `.clc-forge.yml`', verify: ['verify_custom_rules', 'verify_user_defined_regex_rules'],
40
40
  applies_when: 'always', severity: 'error', gate_mode: 'hard', config_keys: ['scope', 'exclude_paths'],
41
- phase: 'audit', file: 'check_custom.js+check_custom.py', manifest: true, planned: false },
41
+ phase: 'audit', file: 'check_custom.js+check_custom.py', manifest: true, planned: false, lens: 'architecture' },
42
42
 
43
43
  { name: 'check_a11y', labels: ['check_a11y', 'check_a11y.js'],
44
44
  checks: 'ARIA + alt accessibility', verify: ['verify_a11y', 'verify_accessibility'],
45
45
  applies_when: 'frontend', severity: 'error', gate_mode: 'hard', config_keys: ['scope', 'exclude_paths'],
46
- phase: 'audit', file: 'check_a11y.js', manifest: true, planned: false },
46
+ phase: 'audit', file: 'check_a11y.js', manifest: true, planned: false, lens: 'correctness' },
47
47
 
48
48
  { name: 'check_ui_reuse', labels: ['check_ui_reuse', 'check_ui_reuse.js'],
49
49
  checks: 'UI primitive reuse from components/ui/', verify: ['verify_ui_reuse', 'verify_component_reuse'],
50
50
  applies_when: 'frontend', severity: 'warning', gate_mode: 'advisory', config_keys: ['scope', 'exclude_paths'],
51
- phase: 'audit', file: 'check_ui_reuse.js', manifest: true, planned: false },
51
+ phase: 'audit', file: 'check_ui_reuse.js', manifest: true, planned: false, lens: 'architecture' },
52
52
 
53
53
  { name: 'check_performance', labels: ['check_performance', 'check_performance.js'],
54
54
  checks: 'next/image + tree-shaking', verify: ['verify_performance', 'verify_image_optimization'],
55
55
  applies_when: 'frontend', severity: 'warning', gate_mode: 'advisory', config_keys: ['scope', 'exclude_paths'],
56
- phase: 'audit', file: 'check_performance.js', manifest: true, planned: false },
56
+ phase: 'audit', file: 'check_performance.js', manifest: true, planned: false, lens: 'performance' },
57
57
 
58
58
  { name: 'check_responsive', labels: ['check_responsive', 'check_responsive.js'],
59
59
  checks: 'Mobile-first responsiveness, fixed-width overflow & touch target size', verify: ['verify_responsive', 'verify_mobile_adaptability'],
60
60
  applies_when: 'frontend', severity: 'warning', gate_mode: 'advisory', config_keys: ['scope', 'exclude_paths'],
61
- phase: 'audit', file: 'check_responsive.js', manifest: true, planned: false },
61
+ phase: 'audit', file: 'check_responsive.js', manifest: true, planned: false, lens: 'performance' },
62
62
 
63
63
  { name: 'check_seo', labels: ['check_seo', 'check_seo.js'],
64
64
  checks: 'SEO metadata, OpenGraph, GEO tags, semantic HTML & LCP priority', verify: ['verify_seo', 'verify_geo_metadata', 'verify_core_web_vitals'],
65
65
  applies_when: 'frontend', severity: 'warning', gate_mode: 'advisory', config_keys: ['scope', 'exclude_paths'],
66
- phase: 'audit', file: 'check_seo.js', manifest: true, planned: false },
66
+ phase: 'audit', file: 'check_seo.js', manifest: true, planned: false, lens: 'performance' },
67
67
 
68
68
  { name: 'check_storybook', labels: ['check_storybook', 'check_storybook.js'],
69
69
  checks: 'Storybook coverage (`.stories.tsx`)', verify: ['verify_storybook_coverage'],
70
70
  applies_when: 'frontend', severity: 'warning', gate_mode: 'advisory', config_keys: ['scope', 'exclude_paths'],
71
- phase: 'audit', file: 'check_storybook.js', manifest: true, planned: false },
71
+ phase: 'audit', file: 'check_storybook.js', manifest: true, planned: false, lens: 'performance' },
72
72
 
73
73
  { name: 'check_api_contracts', labels: ['check_api_contracts', 'check_api_contracts.js'],
74
74
  checks: 'Zod response-schema parsing', verify: ['verify_api_contracts', 'verify_response_schemas'],
75
75
  applies_when: 'frontend', severity: 'error', gate_mode: 'hard', config_keys: ['scope', 'exclude_paths'],
76
- phase: 'audit', file: 'check_api_contracts.js', manifest: true, planned: false },
76
+ phase: 'audit', file: 'check_api_contracts.js', manifest: true, planned: false, lens: 'correctness' },
77
77
 
78
78
  { name: 'check_migrations', labels: ['check_migrations', 'check_migrations.py'],
79
79
  checks: 'Alembic/Django migration idempotency', verify: ['verify_migration_idempotency'],
80
80
  applies_when: 'backend,fastapi,django', severity: 'error', gate_mode: 'hard', config_keys: ['scope', 'exclude_paths'],
81
- phase: 'audit', file: 'check_migrations.py', manifest: true, planned: false },
81
+ phase: 'audit', file: 'check_migrations.py', manifest: true, planned: false, lens: 'architecture' },
82
82
 
83
83
  { name: 'verify_tdd', labels: ['verify_tdd', 'verify_tdd.py'],
84
84
  checks: 'Real red→green TDD validation', verify: ['verify_tdd_red_green', 'verify_tdd_evidence'],
85
85
  applies_when: 'backend', severity: 'error', gate_mode: 'hard', config_keys: ['scope', 'exclude_paths'],
86
- phase: 'audit', file: 'verify_tdd.py', manifest: false, planned: false },
86
+ phase: 'audit', file: 'verify_tdd.py', manifest: false, planned: false, lens: 'correctness' },
87
87
 
88
88
  { name: 'check_scope', labels: ['check_scope', 'check_scope.py'],
89
89
  checks: 'git-diff vs SDD-authorization scope guardrail', verify: ['verify_scope_authorization', 'verify_sdd_scope'],
90
90
  applies_when: 'always', severity: 'error', gate_mode: 'hard', config_keys: ['scope', 'exclude_paths'],
91
- phase: 'audit', file: 'check_scope.py', manifest: false, planned: false },
91
+ phase: 'audit', file: 'check_scope.py', manifest: false, planned: false, lens: 'correctness' },
92
92
 
93
93
  { name: 'celery_guard', labels: ['celery_guard', 'celery_guard.py'],
94
94
  checks: 'Broker URL exposure, ignore_result, result backend', verify: ['verify_celery_broker_config'],
95
95
  applies_when: 'celery', severity: 'error', gate_mode: 'hard', config_keys: ['scope', 'exclude_paths'],
96
- phase: 'audit', file: 'celery_guard.py', manifest: true, planned: false },
96
+ phase: 'audit', file: 'celery_guard.py', manifest: true, planned: false, lens: 'security' },
97
97
 
98
98
  { name: 'redis_guard', labels: ['redis_guard', 'redis_guard.py'],
99
99
  checks: 'decode_responses, connect timeout, hardcoded URLs', verify: ['verify_redis_config'],
100
100
  applies_when: 'redis', severity: 'error', gate_mode: 'hard', config_keys: ['scope', 'exclude_paths'],
101
- phase: 'audit', file: 'redis_guard.py', manifest: true, planned: false },
101
+ phase: 'audit', file: 'redis_guard.py', manifest: true, planned: false, lens: 'security' },
102
102
 
103
103
  { name: 'postgres_guard', labels: ['postgres_guard', 'postgres_guard.py'],
104
104
  checks: 'Raw SQL string formatting, hstore misuse', verify: ['verify_postgres_sql_usage'],
105
105
  applies_when: 'postgresql', severity: 'error', gate_mode: 'hard', config_keys: ['scope', 'exclude_paths'],
106
- phase: 'audit', file: 'postgres_guard.py', manifest: true, planned: false },
106
+ phase: 'audit', file: 'postgres_guard.py', manifest: true, planned: false, lens: 'security' },
107
107
 
108
108
  { name: 'docker_guard', labels: ['docker_guard', 'docker_guard.py'],
109
109
  checks: 'Non-root USER, ENV secrets, missing HEALTHCHECK', verify: ['verify_dockerfile_security'],
110
110
  applies_when: 'docker', severity: 'error', gate_mode: 'hard', config_keys: ['scope', 'exclude_paths'],
111
- phase: 'audit', file: 'docker_guard.py', manifest: true, planned: false },
111
+ phase: 'audit', file: 'docker_guard.py', manifest: true, planned: false, lens: 'security' },
112
112
 
113
113
  { name: 'check_symlinks', labels: ['check_symlinks', 'check_symlinks.js'],
114
114
  checks: 'AI IDE symlinks and rule mirror verification', verify: ['verify_symlinks', 'verify_rule_mirrors'],
115
115
  applies_when: 'agent-os', severity: 'error', gate_mode: 'hard', config_keys: ['scope'],
116
- phase: 'audit', file: 'check_symlinks.js', manifest: true, planned: false },
116
+ phase: 'audit', file: 'check_symlinks.js', manifest: true, planned: false, lens: 'architecture' },
117
117
 
118
118
  { name: 'check_hitl', labels: ['check_hitl', 'check_hitl.js'],
119
119
  checks: 'Human-in-the-Loop review checkpoint validator in subagent skills', verify: ['verify_hitl', 'verify_human_review_checkpoints'],
120
120
  applies_when: 'agent-os', severity: 'error', gate_mode: 'hard', config_keys: ['scope'],
121
- phase: 'audit', file: 'check_hitl.js', manifest: true, planned: false },
121
+ phase: 'audit', file: 'check_hitl.js', manifest: true, planned: false, lens: 'architecture' },
122
122
 
123
123
  { name: 'check_domain_data', labels: ['check_domain_data', 'check_domain_data.js'],
124
124
  checks: 'Domain deliverables schema and clean state integrity', verify: ['verify_domain_data', 'verify_clean_state_metrics'],
125
125
  applies_when: 'agent-os', severity: 'error', gate_mode: 'hard', config_keys: ['scope'],
126
- phase: 'audit', file: 'check_domain_data.js', manifest: true, planned: false },
126
+ phase: 'audit', file: 'check_domain_data.js', manifest: true, planned: false, lens: 'architecture' },
127
127
 
128
128
  { name: 'check_test_calendar_sync', labels: ['check_test_calendar_sync', 'check_test_calendar_sync.js'],
129
129
  checks: 'Test calendar harness synchronization and parity check', verify: ['verify_calendar_sync', 'verify_test_calendar_sync'],
130
130
  applies_when: 'agent-os', severity: 'error', gate_mode: 'hard', config_keys: ['scope'],
131
- phase: 'audit', file: 'check_test_calendar_sync.js', manifest: true, planned: false },
131
+ phase: 'audit', file: 'check_test_calendar_sync.js', manifest: true, planned: false, lens: 'performance' },
132
132
 
133
133
  { name: 'ruff', labels: ['ruff'],
134
134
  checks: 'Python AST linter (external CLI)', verify: ['verify_python_lint'],
135
135
  applies_when: 'backend', severity: 'warning', gate_mode: 'advisory', config_keys: [],
136
- phase: 'test', file: null, manifest: true, planned: false },
136
+ phase: 'test', file: null, manifest: true, planned: false, lens: 'correctness' },
137
137
 
138
138
  { name: 'pytest', labels: ['pytest'],
139
139
  checks: 'Test runner (external CLI)', verify: ['verify_test_coverage'],
140
140
  applies_when: 'backend', severity: 'warning', gate_mode: 'advisory', config_keys: [],
141
- phase: 'test', file: null, manifest: true, planned: false },
141
+ phase: 'test', file: null, manifest: true, planned: false, lens: 'correctness' },
142
142
 
143
143
  { name: 'tsc', labels: ['tsc'],
144
144
  checks: 'TypeScript typecheck (external)', verify: ['verify_typescript_types'],
145
145
  applies_when: 'frontend', severity: 'error', gate_mode: 'hard', config_keys: [],
146
- phase: 'test', file: null, manifest: true, planned: false },
146
+ phase: 'test', file: null, manifest: true, planned: false, lens: 'correctness' },
147
147
 
148
148
  { name: 'lint', labels: ['lint', 'lint-staged'],
149
149
  checks: 'lint-staged (external)', verify: ['verify_lint_staged'],
150
150
  applies_when: 'frontend', severity: 'warning', gate_mode: 'advisory', config_keys: [],
151
- phase: 'test', file: null, manifest: true, planned: false },
151
+ phase: 'test', file: null, manifest: true, planned: false, lens: 'correctness' },
152
152
 
153
153
  { name: 'graphify', labels: ['graphify'],
154
154
  checks: 'Memory graph (external, graceful-skip)', verify: ['verify_memory_graph'],
155
155
  applies_when: 'always', severity: 'warning', gate_mode: 'advisory', config_keys: [],
156
- phase: 'review', file: null, manifest: false, planned: false },
156
+ phase: 'review', file: null, manifest: false, planned: false, lens: 'architecture' },
157
157
 
158
158
  { name: 'gentle_ai_review', labels: ['gentle_ai_review', 'gentle-ai'],
159
159
  checks: 'Native bounded review gate (external, graceful-skip)', verify: ['verify_rdd_review_gate'],
160
160
  applies_when: 'always', severity: 'error', gate_mode: 'hard', config_keys: [],
161
- phase: 'review', file: null, manifest: false, planned: false },
161
+ phase: 'review', file: null, manifest: false, planned: false, lens: 'architecture' },
162
162
 
163
163
  { name: 'check_openapi_drift', labels: ['check_openapi_drift', 'check_openapi_drift.py'],
164
164
  checks: 'FastAPI OpenAPI schema drift vs app routes', verify: ['verify_openapi_drift'],
165
165
  applies_when: 'fastapi', severity: 'error', gate_mode: 'hard', config_keys: ['scope', 'exclude_paths'],
166
- phase: 'audit', file: 'check_openapi_drift.py', manifest: true, planned: true },
166
+ phase: 'audit', file: 'check_openapi_drift.py', manifest: true, planned: true, lens: 'correctness' },
167
167
 
168
168
  { name: 'check_db_efficiency', labels: ['check_db_efficiency', 'check_db_efficiency.py'],
169
169
  checks: 'ORM N+1 / select_related / prefetch_related', verify: ['verify_db_efficiency', 'verify_no_n_plus_1'],
170
170
  applies_when: 'django|sqlalchemy', severity: 'error', gate_mode: 'hard', config_keys: ['scope', 'exclude_paths'],
171
- phase: 'audit', file: 'check_db_efficiency.py', manifest: true, planned: false },
171
+ phase: 'audit', file: 'check_db_efficiency.py', manifest: true, planned: false, lens: 'performance' },
172
172
 
173
173
  { name: 'check_observability', labels: ['check_observability', 'check_observability.py'],
174
174
  checks: 'structlog structured logging; bare print/logger ban', verify: ['verify_structured_logging'],
175
175
  applies_when: 'backend', severity: 'warning', gate_mode: 'advisory', config_keys: ['scope', 'exclude_paths'],
176
- phase: 'audit', file: 'check_observability.py', manifest: true, planned: true },
176
+ phase: 'audit', file: 'check_observability.py', manifest: true, planned: true, lens: 'performance' },
177
177
  ];
178
178
 
179
179
  // Freeze the registry so config validation and generation can rely on it.
@@ -195,6 +195,9 @@ const VALID_APPLIES_WHEN = [
195
195
  'agent-os',
196
196
  ];
197
197
 
198
+ /** Canonical 4 RDD Lenses */
199
+ const VALID_LENSES = ['correctness', 'security', 'architecture', 'performance'];
200
+
198
201
  /** Normalize an input label for catalog lookup. */
199
202
  function normalizeLabel(name) {
200
203
  return typeof name === 'string' ? name.trim().toLowerCase() : '';
@@ -226,13 +229,21 @@ function gateFor(name) {
226
229
  return entry ? entry.gate_mode : null;
227
230
  }
228
231
 
232
+ /** Canonical RDD review lens for a guard name/label; null when unknown. */
233
+ function lensFor(name) {
234
+ const entry = applyTo(name);
235
+ return entry ? entry.lens : null;
236
+ }
237
+
229
238
  module.exports = {
230
239
  SAFEGUARD_CATALOG,
231
240
  VALID_SEVERITIES,
232
241
  VALID_GATE_MODES,
233
242
  VALID_PHASES,
234
243
  VALID_APPLIES_WHEN,
244
+ VALID_LENSES,
235
245
  applyTo,
236
246
  severityFor,
237
247
  gateFor,
248
+ lensFor,
238
249
  };
package/tools/audit.js CHANGED
@@ -2,7 +2,9 @@
2
2
  /**
3
3
  * Modular Audit Orchestrator — JS
4
4
  * Discovers check_*.js guard scripts at runtime, runs each with graceful
5
- * degradation, and generates an English audit report (05-audit-report.md).
5
+ * degradation, categorizes results into the 4 Canonical RDD Lenses,
6
+ * and generates both an English audit report (05-audit-report.md) and
7
+ * an immutable, machine-readable audit receipt (audit-receipt.json).
6
8
  * Self-contained: uses only Node.js built-ins.
7
9
  */
8
10
 
@@ -11,10 +13,59 @@ const path = require('path');
11
13
 
12
14
  const REPO_ROOT = path.resolve(__dirname, '..');
13
15
 
16
+ // ── 4 Canonical RDD Lenses Mapping ──────────────────────────────────────────
17
+
18
+ const LENS_MAP = {
19
+ // Correctness
20
+ verify_tdd: 'correctness',
21
+ check_scope: 'correctness',
22
+ check_a11y: 'correctness',
23
+ check_api_contracts: 'correctness',
24
+ check_openapi_drift: 'correctness',
25
+ pytest: 'correctness',
26
+ tsc: 'correctness',
27
+ lint: 'correctness',
28
+ ruff: 'correctness',
29
+ // Security
30
+ scan_secrets: 'security',
31
+ docker_guard: 'security',
32
+ redis_guard: 'security',
33
+ celery_guard: 'security',
34
+ postgres_guard: 'security',
35
+ // Architecture
36
+ check_architecture: 'architecture',
37
+ check_custom: 'architecture',
38
+ check_ui_reuse: 'architecture',
39
+ check_symlinks: 'architecture',
40
+ check_hitl: 'architecture',
41
+ check_domain_data: 'architecture',
42
+ check_migrations: 'architecture',
43
+ graphify: 'architecture',
44
+ gentle_ai_review: 'architecture',
45
+ // Performance
46
+ check_db_efficiency: 'performance',
47
+ check_performance: 'performance',
48
+ check_seo: 'performance',
49
+ check_responsive: 'performance',
50
+ check_storybook: 'performance',
51
+ check_test_calendar_sync: 'performance',
52
+ check_observability: 'performance',
53
+ };
54
+
55
+ function getLensForGuard(guardName) {
56
+ try {
57
+ const { lensFor } = require('../src/catalog');
58
+ const lens = lensFor(guardName);
59
+ if (lens) return lens;
60
+ } catch {}
61
+ return LENS_MAP[guardName] || 'architecture';
62
+ }
63
+
14
64
  // ── Helpers ──────────────────────────────────────────────────────────────────
15
65
 
16
- function getActiveSddDir() {
17
- const sddsDir = path.join(REPO_ROOT, 'sdds');
66
+ function getActiveSddDir(baseDir) {
67
+ const root = baseDir || REPO_ROOT;
68
+ const sddsDir = path.join(root, 'sdds');
18
69
  if (!fs.existsSync(sddsDir)) {
19
70
  fs.mkdirSync(sddsDir, { recursive: true });
20
71
  }
@@ -25,7 +76,7 @@ function getActiveSddDir() {
25
76
  if (dirs.length > 0) {
26
77
  return path.join(sddsDir, dirs[0]);
27
78
  }
28
- const defaultDir = path.join(sddsDir, 'frontend-audit');
79
+ const defaultDir = path.join(sddsDir, 'audit-run');
29
80
  fs.mkdirSync(defaultDir, { recursive: true });
30
81
  return defaultDir;
31
82
  }
@@ -34,8 +85,9 @@ function getActiveSddDir() {
34
85
  * Discover all check_*.js guard scripts in the tools/ directory.
35
86
  * Returns absolute paths sorted alphabetically for deterministic ordering.
36
87
  */
37
- function discoverGuards() {
38
- const toolsDir = __dirname;
88
+ function discoverGuards(toolsDirParam) {
89
+ const toolsDir = toolsDirParam || __dirname;
90
+ if (!fs.existsSync(toolsDir)) return [];
39
91
  return fs.readdirSync(toolsDir)
40
92
  .filter(f => (f.startsWith('check_') || f.startsWith('scan_')) && f.endsWith('.js') && f !== path.basename(__filename || 'audit.js'))
41
93
  .sort()
@@ -50,12 +102,13 @@ function discoverGuards() {
50
102
  */
51
103
  async function runGuard(guardPath, targetDir) {
52
104
  const guardName = path.basename(guardPath, '.js');
105
+ const lens = getLensForGuard(guardName);
53
106
  try {
54
107
  const mod = require(guardPath);
55
108
  const fn = typeof mod === 'function' ? mod : Object.values(mod)[0];
56
109
  if (typeof fn !== 'function') {
57
110
  return {
58
- exitCode: 0, skipped: true, name: guardName,
111
+ exitCode: 0, skipped: true, name: guardName, lens,
59
112
  data: { message: `Guard ${guardName} does not export a function` },
60
113
  };
61
114
  }
@@ -65,11 +118,12 @@ async function runGuard(guardPath, targetDir) {
65
118
  exitCode: result.exitCode || 0,
66
119
  skipped: Boolean(result.skipped),
67
120
  name: result.name || guardName,
121
+ lens,
68
122
  data: result.data || result,
69
123
  };
70
124
  } catch (e) {
71
125
  return {
72
- exitCode: 0, skipped: true, name: guardName,
126
+ exitCode: 0, skipped: true, name: guardName, lens,
73
127
  data: { message: `Guard unavailable: ${e.message}` },
74
128
  };
75
129
  }
@@ -84,8 +138,9 @@ function formatGuardSection(name, result) {
84
138
  const lines = [];
85
139
  const icon = result.skipped ? '⏭️' : result.exitCode === 0 ? '✅' : '❌';
86
140
  const status = result.skipped ? 'SKIPPED' : result.exitCode === 0 ? 'PASSED' : 'FAILED';
141
+ const lensBadge = (result.lens || 'architecture').toUpperCase();
87
142
 
88
- lines.push(`### ${icon} ${name.replace(/_/g, ' ').replace(/\b\w/g, c => c.toUpperCase())} — ${status}`);
143
+ lines.push(`### ${icon} ${name.replace(/_/g, ' ').replace(/\b\w/g, c => c.toUpperCase())} [${lensBadge}] — ${status}`);
89
144
  lines.push('');
90
145
 
91
146
  if (result.skipped) {
@@ -96,15 +151,21 @@ function formatGuardSection(name, result) {
96
151
  lines.push(`> ${result.data?.message || 'Issues found'}`);
97
152
  lines.push('');
98
153
  const violations = result.data?.violations || result.data?.findings || {};
99
- const files = Object.keys(violations);
100
- if (files.length > 0) {
101
- for (const file of files) {
102
- const items = violations[file];
103
- for (const item of items) {
104
- const loc = item.lineNo ? ` (line ${item.lineNo})` : '';
105
- const label = item.label || item.rule || item.rule || item.module || '';
106
- const msg = item.message || item.reason || '';
107
- lines.push(`- \`${file}\`${loc}: ${label ? `[${label}] ` : ''}${msg}`);
154
+ if (Array.isArray(violations)) {
155
+ for (const item of violations) {
156
+ lines.push(`- ${item.file ? `\`${item.file}\`: ` : ''}${item.message || item.reason || JSON.stringify(item)}`);
157
+ }
158
+ } else {
159
+ const files = Object.keys(violations);
160
+ if (files.length > 0) {
161
+ for (const file of files) {
162
+ const items = violations[file];
163
+ for (const item of items) {
164
+ const loc = item.lineNo ? ` (line ${item.lineNo})` : '';
165
+ const label = item.label || item.rule || item.module || '';
166
+ const msg = item.message || item.reason || '';
167
+ lines.push(`- \`${file}\`${loc}: ${label ? `[${label}] ` : ''}${msg}`);
168
+ }
108
169
  }
109
170
  }
110
171
  }
@@ -127,8 +188,8 @@ function generateReport(results, sddDir) {
127
188
 
128
189
  sections.push(`# Code Audit Report: ${taskName}`);
129
190
  sections.push('');
130
- sections.push('> **Note for reviewer:** This report summarizes security, architecture, accessibility,');
131
- sections.push('> API contracts, performance, UI reuse, and testing coverage to facilitate review.');
191
+ sections.push('> **Review-Driven Development (RDD) Report:**');
192
+ sections.push('> Segmented across the 4 Canonical Review Lenses (Correctness, Security, Architecture, Performance).');
132
193
  sections.push('');
133
194
  sections.push('---');
134
195
  sections.push('');
@@ -144,9 +205,26 @@ function generateReport(results, sddDir) {
144
205
  sections.push('---');
145
206
  sections.push('');
146
207
 
147
- for (const result of results) {
148
- sections.push(formatGuardSection(result.name, result));
208
+ const lenses = ['correctness', 'security', 'architecture', 'performance'];
209
+ const lensHeaders = {
210
+ correctness: '## 🎯 Correctness Lens',
211
+ security: '## 🛡️ Security Lens',
212
+ architecture: '## 🏛️ Architecture Lens',
213
+ performance: '## ⚡ Performance Lens',
214
+ };
215
+
216
+ for (const lens of lenses) {
217
+ sections.push(lensHeaders[lens]);
149
218
  sections.push('');
219
+ const lensResults = results.filter(r => r.lens === lens);
220
+ if (lensResults.length === 0) {
221
+ sections.push('_No guards registered for this lens._\n');
222
+ } else {
223
+ for (const result of lensResults) {
224
+ sections.push(formatGuardSection(result.name, result));
225
+ sections.push('');
226
+ }
227
+ }
150
228
  sections.push('---');
151
229
  sections.push('');
152
230
  }
@@ -154,33 +232,107 @@ function generateReport(results, sddDir) {
154
232
  return sections.join('\n');
155
233
  }
156
234
 
235
+ /**
236
+ * Generate an immutable machine-readable audit receipt (audit-receipt.json).
237
+ */
238
+ function generateReceipt(results, targetDir) {
239
+ const lenses = ['correctness', 'security', 'architecture', 'performance'];
240
+ const lensSummary = {};
241
+
242
+ let hasFailure = false;
243
+ for (const lens of lenses) {
244
+ const lensResults = results.filter(r => r.lens === lens);
245
+ const passed = lensResults.filter(r => !r.skipped && r.exitCode === 0).length;
246
+ const failed = lensResults.filter(r => !r.skipped && r.exitCode !== 0).length;
247
+ const skipped = lensResults.filter(r => r.skipped).length;
248
+ if (failed > 0) hasFailure = true;
249
+
250
+ lensSummary[lens] = {
251
+ status: failed > 0 ? 'FAILED' : 'PASSED',
252
+ passed,
253
+ failed,
254
+ skipped,
255
+ };
256
+ }
257
+
258
+ let commitHash = 'UNKNOWN';
259
+ let gentleAiDetected = false;
260
+ try {
261
+ const { execSync } = require('child_process');
262
+ commitHash = execSync('git rev-parse HEAD', { cwd: targetDir, stdio: ['ignore', 'pipe', 'ignore'], encoding: 'utf-8' }).trim();
263
+ } catch {}
264
+
265
+ try {
266
+ const { execSync } = require('child_process');
267
+ execSync('which gentle-ai', { stdio: 'ignore' });
268
+ gentleAiDetected = true;
269
+ } catch {}
270
+
271
+ return {
272
+ $schema: 'https://clckernel.dev/schemas/audit-receipt.v1.json',
273
+ contract: 'clckernel.audit-receipt/v1',
274
+ timestamp: new Date().toISOString(),
275
+ commitHash,
276
+ verdict: hasFailure ? 'FAILED' : 'PASSED',
277
+ lenses: lensSummary,
278
+ generator: 'clckernel',
279
+ gentle_ai: {
280
+ compatible: true,
281
+ rdd_ready: true,
282
+ cli_installed: gentleAiDetected,
283
+ },
284
+ };
285
+ }
286
+
157
287
  // ── Console Summary ──────────────────────────────────────────────────────────
158
288
 
159
- function printSummary(results, reportPath) {
289
+ function printSummary(results, reportPath, receiptPath) {
160
290
  console.log('\n=================================================================');
161
- console.log(' CLC FORGE — EDUCATIONAL AUDIT SUMMARY');
291
+ console.log(' CLC KERNEL — 4-LENS RDD AUDIT SUMMARY');
162
292
  console.log('=================================================================\n');
163
293
 
164
- for (const result of results) {
165
- const icon = result.skipped ? '⏭️' : result.exitCode === 0 ? '✅' : '❌';
166
- const label = result.name.replace(/_/g, ' ');
167
- const msg = result.data?.message || '';
168
- console.log(` ${icon} ${label}: ${msg}`);
294
+ const lenses = ['correctness', 'security', 'architecture', 'performance'];
295
+ const lensLabels = {
296
+ correctness: '🎯 CORRECTNESS LENS',
297
+ security: '🛡️ SECURITY LENS',
298
+ architecture: '🏛️ ARCHITECTURE LENS',
299
+ performance: '⚡ PERFORMANCE LENS',
300
+ };
301
+
302
+ for (const lens of lenses) {
303
+ const lensResults = results.filter(r => r.lens === lens);
304
+ console.log(` ${lensLabels[lens]}:`);
305
+ if (lensResults.length === 0) {
306
+ console.log(' — No guards active for this lens');
307
+ } else {
308
+ for (const result of lensResults) {
309
+ const icon = result.skipped ? '⏭️' : result.exitCode === 0 ? '✅' : '❌';
310
+ const label = result.name.replace(/_/g, ' ');
311
+ const msg = result.data?.message || (result.exitCode === 0 ? 'Passed' : 'Failed');
312
+ console.log(` ${icon} ${label}: ${msg}`);
313
+ }
314
+ }
315
+ console.log('');
169
316
  }
170
317
 
171
- console.log(`\n📄 Full report: ${reportPath}`);
318
+ console.log(`📄 Full report: ${reportPath}`);
319
+ if (receiptPath) {
320
+ console.log(`🧾 Audit receipt: ${receiptPath}`);
321
+ }
172
322
  console.log('=================================================================\n');
173
323
  }
174
324
 
175
325
  // ── Main ─────────────────────────────────────────────────────────────────────
176
326
 
177
327
  async function main(targetDir) {
178
- const dir = targetDir || process.cwd();
179
- const sddDir = getActiveSddDir();
328
+ const dir = targetDir ? path.resolve(targetDir) : process.cwd();
329
+ const sddDir = getActiveSddDir(dir);
180
330
 
181
- console.log('\nRunning CLC Forge audit...\n');
331
+ console.log('\nRunning CLC Kernel audit...\n');
182
332
 
183
- const guardPaths = discoverGuards();
333
+ const targetTools = path.join(dir, 'tools');
334
+ const toolsDir = fs.existsSync(targetTools) ? targetTools : __dirname;
335
+ const guardPaths = discoverGuards(toolsDir);
184
336
 
185
337
  if (guardPaths.length === 0) {
186
338
  console.log('No guard tools found in tools/. Nothing to audit.');
@@ -200,20 +352,27 @@ async function main(targetDir) {
200
352
  const reportPath = path.join(sddDir, '05-audit-report.md');
201
353
  fs.writeFileSync(reportPath, reportContent, 'utf-8');
202
354
 
355
+ // Generate receipt
356
+ const receipt = generateReceipt(results, dir);
357
+ const receiptPath = path.join(sddDir, 'audit-receipt.json');
358
+ fs.writeFileSync(receiptPath, JSON.stringify(receipt, null, 2) + '\n', 'utf-8');
359
+
203
360
  // Print summary
204
- printSummary(results, reportPath);
361
+ printSummary(results, reportPath, receiptPath);
205
362
 
206
363
  // Exit with failure if any guard failed (not skipped)
207
364
  const hasFailure = results.some(r => !r.skipped && r.exitCode !== 0);
208
- process.exit(hasFailure ? 1 : 0);
365
+ if (hasFailure) {
366
+ process.exit(1);
367
+ }
209
368
  }
210
369
 
211
370
  // Support both require() and direct execution
212
371
  if (require.main === module) {
213
372
  main(process.argv[2]).catch(err => {
214
373
  console.error(`Audit orchestrator error: ${err.message}`);
215
- process.exit(0); // Graceful degradation
374
+ process.exit(1);
216
375
  });
217
376
  }
218
377
 
219
- module.exports = { main, getActiveSddDir, discoverGuards, runGuard };
378
+ module.exports = { main, getActiveSddDir, discoverGuards, runGuard, generateReceipt };
package/tools/audit.py CHANGED
@@ -17,6 +17,48 @@ import traceback
17
17
 
18
18
  REPO_ROOT = pathlib.Path(__file__).resolve().parent.parent
19
19
 
20
+ # ── 4 Canonical RDD Lenses Mapping ──────────────────────────────────────────
21
+
22
+ LENS_MAP = {
23
+ # Correctness
24
+ "verify_tdd": "correctness",
25
+ "check_scope": "correctness",
26
+ "check_a11y": "correctness",
27
+ "check_api_contracts": "correctness",
28
+ "check_openapi_drift": "correctness",
29
+ "pytest": "correctness",
30
+ "tsc": "correctness",
31
+ "lint": "correctness",
32
+ "ruff": "correctness",
33
+ # Security
34
+ "scan_secrets": "security",
35
+ "docker_guard": "security",
36
+ "redis_guard": "security",
37
+ "celery_guard": "security",
38
+ "postgres_guard": "security",
39
+ # Architecture
40
+ "check_architecture": "architecture",
41
+ "check_custom": "architecture",
42
+ "check_ui_reuse": "architecture",
43
+ "check_symlinks": "architecture",
44
+ "check_hitl": "architecture",
45
+ "check_domain_data": "architecture",
46
+ "check_migrations": "architecture",
47
+ "graphify": "architecture",
48
+ "gentle_ai_review": "architecture",
49
+ # Performance
50
+ "check_db_efficiency": "performance",
51
+ "check_performance": "performance",
52
+ "check_seo": "performance",
53
+ "check_responsive": "performance",
54
+ "check_storybook": "performance",
55
+ "check_test_calendar_sync": "performance",
56
+ "check_observability": "performance",
57
+ }
58
+
59
+ def get_lens(guard_name: str) -> str:
60
+ return LENS_MAP.get(guard_name, "architecture")
61
+
20
62
 
21
63
  # ── Helpers ──────────────────────────────────────────────────────────────────
22
64
 
@@ -87,12 +129,14 @@ def run_guard(guard_path: pathlib.Path, target_dir: str) -> dict:
87
129
  "exit_code": result.get("exit_code", 0),
88
130
  "skipped": bool(result.get("skipped", False)),
89
131
  "name": result.get("name", guard_name),
132
+ "lens": get_lens(guard_name),
90
133
  "data": result.get("data", result),
91
134
  }
92
135
 
93
136
  except Exception as exc:
94
137
  return {
95
138
  "exit_code": 0, "skipped": True, "name": guard_name,
139
+ "lens": get_lens(guard_name),
96
140
  "data": {"message": f"Guard unavailable: {exc}"},
97
141
  }
98
142
 
@@ -151,7 +195,7 @@ def _format_guard_section(name: str, result: dict) -> str:
151
195
 
152
196
 
153
197
  def generate_report(results: list[dict], sdd_dir: pathlib.Path) -> str:
154
- """Generate the 05-audit-report.md from aggregated guard results."""
198
+ """Generate the 05-audit-report.md from aggregated guard results grouped by 4 RDD lenses."""
155
199
  task_name = sdd_dir.name
156
200
  passed = sum(1 for r in results if not r.get("skipped") and r.get("exit_code") == 0)
157
201
  failed = sum(1 for r in results if not r.get("skipped") and r.get("exit_code") != 0)
@@ -161,8 +205,8 @@ def generate_report(results: list[dict], sdd_dir: pathlib.Path) -> str:
161
205
  sections: list[str] = []
162
206
  sections.append(f"# Code Audit Report: {task_name}")
163
207
  sections.append("")
164
- sections.append("> **Note for reviewer:** This report summarizes security, architecture,")
165
- sections.append("> scope, migration safety, and TDD coverage to facilitate code review.")
208
+ sections.append("> **Review-Driven Development (RDD) Report:**")
209
+ sections.append("> Segmented across the 4 Canonical Review Lenses (Correctness, Security, Architecture, Performance).")
166
210
  sections.append("")
167
211
  sections.append("---")
168
212
  sections.append("")
@@ -178,39 +222,116 @@ def generate_report(results: list[dict], sdd_dir: pathlib.Path) -> str:
178
222
  sections.append("---")
179
223
  sections.append("")
180
224
 
181
- for result in results:
182
- sections.append(_format_guard_section(result.get("name", "unknown"), result))
225
+ lenses = ["correctness", "security", "architecture", "performance"]
226
+ headers = {
227
+ "correctness": "## 🎯 Correctness Lens",
228
+ "security": "## 🛡️ Security Lens",
229
+ "architecture": "## 🏛️ Architecture Lens",
230
+ "performance": "## ⚡ Performance Lens",
231
+ }
232
+
233
+ for lens in lenses:
234
+ sections.append(headers[lens])
183
235
  sections.append("")
236
+ lens_results = [r for r in results if r.get("lens") == lens]
237
+ if not lens_results:
238
+ sections.append("_No guards registered for this lens._\n")
239
+ else:
240
+ for result in lens_results:
241
+ sections.append(_format_guard_section(result.get("name", "unknown"), result))
242
+ sections.append("")
184
243
  sections.append("---")
185
244
  sections.append("")
186
245
 
187
246
  return "\n".join(sections)
188
247
 
189
248
 
249
+ def generate_receipt(results: list[dict], target_dir: str) -> dict:
250
+ """Generate an immutable machine-readable audit receipt (audit-receipt.json)."""
251
+ import datetime
252
+
253
+ lenses = ["correctness", "security", "architecture", "performance"]
254
+ lens_summary = {}
255
+ has_failure = False
256
+
257
+ for lens in lenses:
258
+ lens_results = [r for r in results if r.get("lens") == lens]
259
+ passed = sum(1 for r in lens_results if not r.get("skipped") and r.get("exit_code") == 0)
260
+ failed = sum(1 for r in lens_results if not r.get("skipped") and r.get("exit_code") != 0)
261
+ skipped = sum(1 for r in lens_results if r.get("skipped"))
262
+ if failed > 0:
263
+ has_failure = True
264
+ lens_summary[lens] = {
265
+ "status": "FAILED" if failed > 0 else "PASSED",
266
+ "passed": passed,
267
+ "failed": failed,
268
+ "skipped": skipped,
269
+ }
270
+
271
+ commit_hash = "UNKNOWN"
272
+ try:
273
+ commit_hash = subprocess.check_output(
274
+ ["git", "rev-parse", "HEAD"],
275
+ cwd=target_dir,
276
+ stderr=subprocess.DEVNULL,
277
+ encoding="utf-8"
278
+ ).strip()
279
+ except Exception:
280
+ pass
281
+
282
+ import shutil
283
+ gentle_ai_detected = shutil.which("gentle-ai") is not None
284
+
285
+ return {
286
+ "$schema": "https://clckernel.dev/schemas/audit-receipt.v1.json",
287
+ "contract": "clckernel.audit-receipt/v1",
288
+ "timestamp": datetime.datetime.now(datetime.timezone.utc).isoformat(),
289
+ "commitHash": commit_hash,
290
+ "verdict": "FAILED" if has_failure else "PASSED",
291
+ "lenses": lens_summary,
292
+ "generator": "clckernel",
293
+ "gentle_ai": {
294
+ "compatible": True,
295
+ "rdd_ready": True,
296
+ "cli_installed": gentle_ai_detected,
297
+ },
298
+ }
299
+
300
+
190
301
  # ── Console Summary ──────────────────────────────────────────────────────────
191
302
 
192
- def print_summary(results: list[dict], report_path: pathlib.Path) -> None:
303
+ def print_summary(results: list[dict], report_path: pathlib.Path, receipt_path: pathlib.Path | None = None) -> None:
193
304
  """Print an educational summary to the terminal."""
194
305
  print("\n" + "=" * 65)
195
- print(" CLC FORGE \u2014 EDUCATIONAL AUDIT SUMMARY")
306
+ print(" CLC KERNEL — 4-LENS RDD AUDIT SUMMARY")
196
307
  print("=" * 65 + "\n")
197
308
 
198
- for result in results:
199
- skipped = result.get("skipped", False)
200
- exit_code = result.get("exit_code", 0)
201
- name = result.get("name", "unknown").replace("_", " ")
202
- msg = result.get("data", {}).get("message", "")
203
-
204
- if skipped:
205
- icon = "\u23ed\ufe0f"
206
- elif exit_code == 0:
207
- icon = "\u2705"
309
+ lenses = ["correctness", "security", "architecture", "performance"]
310
+ labels = {
311
+ "correctness": "🎯 CORRECTNESS LENS",
312
+ "security": "🛡️ SECURITY LENS",
313
+ "architecture": "🏛️ ARCHITECTURE LENS",
314
+ "performance": "⚡ PERFORMANCE LENS",
315
+ }
316
+
317
+ for lens in lenses:
318
+ lens_results = [r for r in results if r.get("lens") == lens]
319
+ print(f" {labels[lens]}:")
320
+ if not lens_results:
321
+ print(" — No guards active for this lens")
208
322
  else:
209
- icon = "\u274c"
210
-
211
- print(f" {icon} {name}: {msg}")
212
-
213
- print(f"\n Report: {report_path}")
323
+ for result in lens_results:
324
+ skipped = result.get("skipped", False)
325
+ exit_code = result.get("exit_code", 0)
326
+ name = result.get("name", "unknown").replace("_", " ")
327
+ msg = result.get("data", {}).get("message", "Passed" if exit_code == 0 else "Failed")
328
+ icon = "⏭️" if skipped else ("✅" if exit_code == 0 else "❌")
329
+ print(f" {icon} {name}: {msg}")
330
+ print("")
331
+
332
+ print(f"📄 Full report: {report_path}")
333
+ if receipt_path:
334
+ print(f"🧾 Audit receipt: {receipt_path}")
214
335
  print("=" * 65 + "\n")
215
336
 
216
337
 
@@ -229,7 +350,7 @@ def main(target_dir: str | None = None) -> int:
229
350
  sdd_dir = sdds_dir / "audit-run"
230
351
  sdd_dir.mkdir(parents=True, exist_ok=True)
231
352
 
232
- print(f"\nRunning CLC Forge audit for: {sdd_dir.name}\n")
353
+ print(f"\nRunning CLC Kernel audit for: {sdd_dir.name}\n")
233
354
 
234
355
  guard_paths = discover_guards(tools_dir)
235
356
 
@@ -253,8 +374,13 @@ def main(target_dir: str | None = None) -> int:
253
374
  report_path = sdd_dir / "05-audit-report.md"
254
375
  report_path.write_text(report_content, encoding="utf-8")
255
376
 
377
+ # Generate and write receipt
378
+ receipt = generate_receipt(results, dir_path)
379
+ receipt_path = sdd_dir / "audit-receipt.json"
380
+ receipt_path.write_text(json.dumps(receipt, indent=2) + "\n", encoding="utf-8")
381
+
256
382
  # Print summary
257
- print_summary(results, report_path)
383
+ print_summary(results, report_path, receipt_path)
258
384
 
259
385
  # Exit with failure if any guard failed (not skipped)
260
386
  has_failure = any(
@@ -270,4 +396,4 @@ if __name__ == "__main__":
270
396
  sys.exit(main(target))
271
397
  except Exception:
272
398
  traceback.print_exc()
273
- sys.exit(0) # Graceful degradation
399
+ sys.exit(1)