Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 27 additions & 27 deletions .harness/playbooks/sdlc-deep-audit.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -191,27 +191,27 @@ function auditEvaluationEngine() {
}

// Check for SatelliteEvaluationPipeline (GT-281)
const pipelineFile = "packages/core-domain/src/application/services/satellite-evaluation-pipeline.service.ts";
const pipelineFile = "src/packages/core-domain/src/application/services/satellite-evaluation-pipeline.service.ts";
const hasPipeline = exists(pipelineFile);

// Check for SatelliteManifest type
const manifestTypeFile = "packages/core-domain/src/domain/satellite-manifest.ts";
const manifestTypeFile = "src/packages/core-domain/src/domain/satellite-manifest.ts";
const hasManifestType = exists(manifestTypeFile);

// Check for end-to-end pipeline test
const pipelineTest = "packages/core-domain/src/application/services/satellite-evaluation-pipeline.spec.ts";
const pipelineTest = "src/packages/core-domain/src/application/services/satellite-evaluation-pipeline.spec.ts";
const hasPipelineTest = exists(pipelineTest);

// Check for CLI --manifest/--phase options in validate command
const cliCommand = "sdk/cli/src/commands/validate/validate.command.ts";
const cliCommand = "src/sdk/cli/src/commands/validate/validate.command.ts";
const cliHasManifest = exists(cliCommand) ? (read(cliCommand) || "").includes("--manifest") : false;

// Check that ValidateSatelliteUseCase accepts manifest input
const useCaseFile = "packages/core-domain/src/application/use-cases/validate-satellite.use-case.ts";
const useCaseFile = "src/packages/core-domain/src/application/use-cases/validate-satellite.use-case.ts";
const useCaseAcceptsManifest = exists(useCaseFile) ? (read(useCaseFile) || "").includes("manifest?:") : false;

// Check the 3 interfaces converge on same UseCase
const mcpToolFile = "packages/mcp-server/src/tools/validate.tool.ts";
const mcpToolFile = "src/packages/mcp-server/src/tools/validate.tool.ts";
const mcpCallsPipeline = exists(mcpToolFile) ? (read(mcpToolFile) || "").includes("runPipeline") : false;

return {
Expand Down Expand Up @@ -267,43 +267,43 @@ function auditClientIngestion() {
// ── 5. LAS TRES INTERFACES ───────────────────────────────────────────

function auditThreeInterfaces() {
const cliCommands = exists("sdk/cli/src/commands") ? fs.readdirSync(path.join(root, "sdk/cli/src/commands")).filter(f => !f.startsWith(".")) : [];
const mcpTools = exists("packages/mcp-server/src/tools") ? fs.readdirSync(path.join(root, "packages/mcp-server/src/tools")).filter(f => f.endsWith(".ts") && !f.includes("spec")) : [];
const coreApiControllers = exists("apps/core-api/src/presentation/controllers") ? fs.readdirSync(path.join(root, "apps/core-api/src/presentation/controllers")).filter(f => f.endsWith(".ts") && !f.includes("spec")) : [];
const cliCommands = exists("src/sdk/cli/src/commands") ? fs.readdirSync(path.join(root, "src/sdk/cli/src/commands")).filter(f => !f.startsWith(".")) : [];
const mcpTools = exists("src/packages/mcp-server/src/tools") ? fs.readdirSync(path.join(root, "src/packages/mcp-server/src/tools")).filter(f => f.endsWith(".ts") && !f.includes("spec")) : [];
const coreApiControllers = exists("src/apps/core-api/src/presentation/controllers") ? fs.readdirSync(path.join(root, "src/apps/core-api/src/presentation/controllers")).filter(f => f.endsWith(".ts") && !f.includes("spec")) : [];

// Check if each surface exposes an EVALUATION operation
let cliHasEval = false;
let mcpHasEval = false;
let apiHasEval = false;

const cliEvalFiles = globFiles("sdk/cli/src/commands/**/*.ts").filter(f => !f.includes("spec"));
const cliEvalFiles = globFiles("src/sdk/cli/src/commands/**/*.ts").filter(f => !f.includes("spec"));
for (const f of cliEvalFiles) {
const c = read(f);
if (!c) continue;
if (c.includes("evaluate") || c.includes("validate") || c.includes("gate")) { cliHasEval = true; break; }
}

const mcpEvalFiles = globFiles("packages/mcp-server/src/tools/**/*.ts");
const mcpEvalFiles = globFiles("src/packages/mcp-server/src/tools/**/*.ts");
for (const f of mcpEvalFiles) {
const c = read(f);
if (!c) continue;
if (c.includes("evaluate") || c.includes("validate") || c.includes("gate")) { mcpHasEval = true; break; }
}

const apiEvalFiles = globFiles("apps/core-api/src/**/*.ts");
const apiEvalFiles = globFiles("src/apps/core-api/src/**/*.ts");
for (const f of apiEvalFiles) {
const c = read(f);
if (!c) continue;
if ((c.includes("evaluate") || c.includes("validate") || c.includes("gate")) && !f.includes("spec")) { apiHasEval = true; break; }
}

// Check if all three route to same underlying service
const coreDomainFiles = globFiles("packages/core-domain/src/**/*.ts").filter(f => !f.includes("spec"));
const coreDomainFiles = globFiles("src/packages/core-domain/src/**/*.ts").filter(f => !f.includes("spec"));
Comment thread
beyondnetPeru marked this conversation as resolved.
let sharedUseCase = null;
for (const f of coreDomainFiles) {
const c = read(f);
if (!c) continue;
if (c.includes("ValidateSatelliteUseCase")) {
if (c.includes("class ValidateSatelliteUseCase")) {
const name = f.split("/").pop().replace(".ts", "");
sharedUseCase = name;
break;
Expand All @@ -329,31 +329,31 @@ function auditThreeInterfaces() {

function auditActionableReports() {
// GT-282: check for structured evaluation types with actionable detail fields
const manifestType = "packages/core-domain/src/domain/satellite-manifest.ts";
const manifestType = "src/packages/core-domain/src/domain/satellite-manifest.ts";
const manifestContent = read(manifestType);

const hasRemediation = manifestContent?.includes("remediation");
const hasSeverity = manifestContent?.includes("EvaluationSeverity");
const hasGateRef = manifestContent?.includes("gateRef");

// Check for ADR-0073 output envelope in evaluation verdict
const pipelineService = "packages/core-domain/src/application/services/satellite-evaluation-pipeline.service.ts";
const pipelineService = "src/packages/core-domain/src/application/services/satellite-evaluation-pipeline.service.ts";
const pipelineContent = read(pipelineService);
const hasOutputEnvelope = pipelineContent?.includes("outputEnvelope") && pipelineContent?.includes("createSuccessEnvelope");
const hasADREnvelope = read(pipelineService)?.includes("ADR-0073") || read(manifestType)?.includes("ADR-0073");

// Check MCP includes actionable fields
const mcpTool = "packages/mcp-server/src/tools/validate.tool.ts";
const mcpTool = "src/packages/mcp-server/src/tools/validate.tool.ts";
const mcpContent = read(mcpTool);
const mcpShowsRemediation = mcpContent?.includes("remediation");

// Check CLI shows actionable details
const cliCommand = "sdk/cli/src/commands/validate/validate.command.ts";
const cliCommand = "src/sdk/cli/src/commands/validate/validate.command.ts";
const cliContent = read(cliCommand);
const cliShowsRemediation = cliContent?.includes("remediation") || cliContent?.includes("Remedio");

// Check tests verify actionable fields
const pipelineTest = "packages/core-domain/src/application/services/satellite-evaluation-pipeline.spec.ts";
const pipelineTest = "src/packages/core-domain/src/application/services/satellite-evaluation-pipeline.spec.ts";
const testContent = read(pipelineTest);
const testChecksRemediation = testContent?.includes("remediation");
const testChecksOutputEnvelope = testContent?.includes("outputEnvelope");
Expand Down Expand Up @@ -423,8 +423,8 @@ function auditGovernance() {

// GT-412: runtime policy enforcement must be mandatory before governed
// capabilities execute, and hosted defaults must use the real OPA adapter.
const runtimeService = read("packages/agent-runtime/src/application/agent-runtime.service.ts") || "";
const runtimeFactory = read("apps/agent-runtime-api/src/agent-runtime/runtime.factory.ts") || "";
const runtimeService = read("src/packages/agent-runtime/src/application/agent-runtime.service.ts") || "";
const runtimeFactory = read("src/apps/agent-runtime-api/src/agent-runtime/runtime.factory.ts") || "";
const preflightIdx = runtimeService.indexOf("steps.push('policy-preflight')");
const harnessIdx = runtimeService.indexOf("steps.push('harness-execute')");
const approvalIdx = runtimeService.indexOf("steps.push('approval')");
Expand Down Expand Up @@ -454,7 +454,7 @@ function auditGovernance() {
// ── 8. VERIFICACIONES PUNTUALES ──────────────────────────────────────

function auditPointChecks() {
const scaffoldCmdExists = exists("sdk/cli/src/commands/architecture/scaffold.command.ts");
const scaffoldCmdExists = exists("src/sdk/cli/src/commands/architecture/scaffold.command.ts");

// Check for broken ADR references
let brokenAdrRefs = 0;
Expand All @@ -472,7 +472,7 @@ function auditPointChecks() {
// Check for invented commands in docs
let inventedCommands = 0;
const realCommands = new Set(
walk("sdk/cli/src/commands").filter(f => f.endsWith(".ts") && !f.includes("spec"))
walk("src/sdk/cli/src/commands").filter(f => f.endsWith(".ts") && !f.includes("spec"))
.map(f => f.split("/").pop().replace(".command.ts", "").replace(".ts", ""))
);
for (const f of allFiles) {
Expand Down Expand Up @@ -500,14 +500,14 @@ function auditPointChecks() {
// ── 9. INTEGRACIÓN AGENT RUNTIME ─────────────────────────────────────

function auditAgentRuntimeConnectivity() {
const hasAgentRuntimeApi = exists("apps/agent-runtime-api");
const hasAgentRuntimeApi = exists("src/apps/agent-runtime-api");

const sdkAgentClient = exists("packages/sdk-client/src/rest/agent.client.ts");
const sdkAgentClient = exists("src/packages/sdk-client/src/rest/agent.client.ts");

const cliAgentCmd = "sdk/cli/src/commands/agents/agents.command.ts";
const cliAgentCmd = "src/sdk/cli/src/commands/agents/agents.command.ts";
const cliHasAgentRun = exists(cliAgentCmd) ? (read(cliAgentCmd) || "").includes("runAgent") : false;

const mcpAgentTool = "packages/mcp-server/src/tools/agent.tools.ts";
const mcpAgentTool = "src/packages/mcp-server/src/tools/agent.tools.ts";
const mcpHasAgentRun = exists(mcpAgentTool) ? (read(mcpAgentTool) || "").includes("evolith-agent-run") : false;

const connected = hasAgentRuntimeApi && sdkAgentClient && cliHasAgentRun && mcpHasAgentRun;
Expand Down
1 change: 1 addition & 0 deletions .harness/scripts/ci/03-validate-root-cleanliness.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ const allowedDirectories = new Set([
// sdk/, tests/) was relocated here, so those are no longer permitted at root.
"src",
// Product documentation corpus.
"docs",
"product",
"examples",
"wiki"
Expand Down
3 changes: 3 additions & 0 deletions README.es.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
[![License](https://img.shields.io/badge/License-MIT-informational?style=for-the-badge)]()
[![CI](https://img.shields.io/github/actions/workflow/status/beyondnetcode/evolith_arch32/docs.yml?style=for-the-badge&label=CI)](https://github.com/beyondnetcode/evolith_arch32/actions)

> **[Comenzar Aquí: Guía de Instalación Paso a Paso](./docs/guides/evolith-quickstart.es.md)**

<br/>

<a href="https://beyondnetcode.github.io/evolith_arch32/master-view.html" title="Abrir el diagrama interactivo — desplazar y hacer zoom">
Expand Down Expand Up @@ -147,6 +149,7 @@ Evolith se distribuye como una suite de productos coordinados sobre una base com
| **[MCP Services](product/products/mcp-services/README.es.md)** | Gobernanza como contexto en vivo para LLMs y agentes de IA (47 tools, 9 resources, 8 prompts) |
| **[Agent Runtime](reference/core/architecture/foundations/README.es.md)** | Capa de mediación agéntica — orquesta el Core mediante Puertos y Adaptadores; Hermes es uno de los adaptadores reemplazables |
| **[Evolith Tracker](product/products/evolith-tracker/README.es.md)** | Gobernanza del ciclo de vida del negocio — fases, propietarios, financiación y ROI |
| **[Narrativa Comercial](product/suite/vision/evolith-commercial-brochure.es.md)** | Estrategia de producto y monetización empresarial (Despliegue Hub & Spoke) |
| **[Rulesets](src/rulesets/README.es.md)** | Reglas de aplicación legibles por máquina por topología |
| **[Políticas OPA](src/rulesets/opa/README.es.md)** | Controles de política granulares integrados en el pipeline |
| **[Schemas y Manifests](src/rulesets/schema/README.es.md)** | Contratos estructurados para artefactos y definiciones de topología |
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
[![License](https://img.shields.io/badge/License-MIT-informational?style=for-the-badge)]()
[![CI](https://img.shields.io/github/actions/workflow/status/beyondnetcode/evolith_arch32/docs.yml?style=for-the-badge&label=CI)](https://github.com/beyondnetcode/evolith_arch32/actions)

> **[Start Here: Step-by-Step Quickstart Guide](./docs/guides/evolith-quickstart.md)**

<br/>

<a href="https://beyondnetcode.github.io/evolith_arch32/master-view.html" title="Open the interactive diagram — pan & zoom">
Expand Down Expand Up @@ -148,6 +150,7 @@ Evolith ships as a suite of coordinated products built on a common foundation.
| **[MCP Services](product/products/mcp-services/README.md)** | Governance as live context for LLMs and AI agents (47 tools, 9 resources, 8 prompts) |
| **[Agent Runtime](reference/core/architecture/foundations/README.md)** | Agentic mediation layer — orchestrates Core through Ports & Adapters; Hermes is one replaceable adapter |
| **[Evolith Tracker](product/products/evolith-tracker/README.md)** | Business lifecycle governance — phases, owners, funding, and ROI |
| **[Commercial Vision](product/suite/vision/evolith-commercial-brochure.md)** | Product strategy and enterprise monetization narrative (Hub & Spoke deployment) |
| **[Rulesets](src/rulesets/README.md)** | Machine-readable enforcement rules per topology |
| **[OPA Policies](src/rulesets/opa/README.md)** | Fine-grained policy checks integrated into the pipeline |
| **[Schemas & Manifests](src/rulesets/schema/README.md)** | Structured contracts for artifacts and topology definitions |
Expand Down
68 changes: 68 additions & 0 deletions docs/guides/evolith-quickstart.es.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Guía de Inicio Rápido: Evolith (Paso a Paso)

Esta guía te ayudará a instalar y poner en marcha Evolith en **menos de 5 minutos**, para que puedas comenzar a validar la arquitectura de tu código.

---

## Paso 1: Levantar el Cerebro (Evolith Core API)

El Core API es el servidor central que contiene las reglas de arquitectura de tu empresa. Debes levantarlo primero para que los clientes puedan consultarlo.

Tienes dos opciones para iniciarlo en tu máquina local:

### Opción A: Vía Docker Compose (Más Rápido)
Ideal para desarrolladores. Levanta la API y la base de datos PostgreSQL mínima necesaria.
```bash
docker-compose -f product/infra/docker-compose.yml up -d postgres
```

### Opción B: Vía Kubernetes / Helm (Entorno Completo)
Ideal para simulaciones de producción o arquitectos. Levanta el clúster local, la base de datos, el Gateway y el Core API.
```bash
./.harness/scripts/run-core-local.sh
```

Una vez que termine, el servidor estará escuchando en `http://localhost:30080`. Puedes ver la documentación de la API generada en `http://localhost:30080/api/docs`.

---

## Paso 2: Instalar el Cliente (Evolith CLI)

El CLI es la herramienta que utilizarán los desarrolladores en su día a día.

1. Instala el paquete de forma global usando npm:
```bash
npm install -g @beyondnet/evolith-cli
```

2. Configura la URL del servidor al que el CLI debe apuntar (el que levantamos en el Paso 1). Puedes hacerlo exportando una variable de entorno:
```bash
export EVOLITH_CORE_URL="http://localhost:30080/api/v1"
```

---

## Paso 3: Tu Primera Validación

Ve a la carpeta raíz de cualquier proyecto de software (satélite) que quieras validar y ejecuta el comando de validación.

```bash
cd mi-proyecto-backend
evolith validate
```

**¿Qué sucede detrás de escena?**
El CLI tomará el estado actual de tu código, se conectará al Core API central y evaluará tu proyecto contra las reglas OPA y los ADRs oficiales de la empresa. En segundos, te devolverá un reporte indicando si cumples con el estándar o si hay violaciones de arquitectura.

---

## Paso 4: (Opcional) Conectar a tu Agente de IA

Evolith no es solo para humanos. Puedes conectar tu editor de código basado en IA (Cursor, Claude Desktop, etc.) para que "entienda" tu arquitectura.

Para arrancar el servidor MCP, simplemente ejecuta:
```bash
evolith mcp start
```

Luego, en la configuración de Cursor o Claude Desktop, añade este servidor MCP local. A partir de ese momento, tu Agente de IA sabrá qué patrones usar, qué librerías están prohibidas y cómo debe estructurar el código antes de escribir una sola línea.
68 changes: 68 additions & 0 deletions docs/guides/evolith-quickstart.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Quickstart Guide: Evolith (Step by Step)

This guide will help you install and run Evolith in **less than 5 minutes**, so you can start validating your code's architecture right away.

---

## Step 1: Boot the Brain (Evolith Core API)

The Core API is the central server containing your enterprise architecture rules. You must boot it up first so that clients can query it.

You have two options to start it on your local machine:

### Option A: Via Docker Compose (Fastest)
Ideal for developers. This boots up the API and the minimum required PostgreSQL database.
```bash
docker-compose -f product/infra/docker-compose.yml up -d postgres
```

### Option B: Via Kubernetes / Helm (Full Environment)
Ideal for production simulations or architects. This spins up the local cluster, the database, the API Gateway, and the Core API.
```bash
./.harness/scripts/run-core-local.sh
```

Once finished, the server will be listening on `http://localhost:30080`. You can view the generated API documentation at `http://localhost:30080/api/docs`.

---

## Step 2: Install the Client (Evolith CLI)

The CLI is the tool developers will use in their day-to-day workflow.

1. Install the package globally using npm:
```bash
npm install -g @beyondnet/evolith-cli
```

2. Configure the server URL the CLI should point to (the one we booted in Step 1). You can do this by exporting an environment variable:
```bash
export EVOLITH_CORE_URL="http://localhost:30080/api/v1"
```

---

## Step 3: Your First Validation

Navigate to the root folder of any software project (satellite) you want to validate and run the validation command.

```bash
cd my-backend-project
evolith validate
```

**What happens behind the scenes?**
The CLI will take the current state of your code, connect to the central Core API, and evaluate your project against the official OPA rules and ADRs of the company. In seconds, it will return a report indicating whether you comply with the standard or if there are any architecture violations.

---

## Step 4: (Optional) Connect your AI Agent

Evolith isn't just for humans. You can connect your AI-powered code editor (Cursor, Claude Desktop, etc.) so it "understands" your architecture.

To start the MCP server, simply run:
```bash
evolith mcp start
```

Then, in your Cursor or Claude Desktop settings, add this local MCP server. From that moment on, your AI Agent will know which patterns to use, which libraries are forbidden, and how it should structure the code before writing a single line.
2 changes: 2 additions & 0 deletions product/infra/helm/evolith-core-api/values-local.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,5 @@ podDisruptionBudget:

networkPolicy:
enabled: false
extraEnv:
SWAGGER_ENABLED: "true"
Loading
Loading