diff --git a/.claude/rules/knowledge-plane.md b/.claude/rules/knowledge-plane.md new file mode 100644 index 0000000..cc5af07 --- /dev/null +++ b/.claude/rules/knowledge-plane.md @@ -0,0 +1,58 @@ +# Reglas — Knowledge Plane + +## Paths cubiertos + +```yaml +paths: + - "templates/vault/**" # meta-repo: archivos fuente de la capa (G2+) + - "vault/**" # proyecto generado: vault real cuando pos se usa +``` + +`templates/vault/**` aplica al meta-repo cuando se trabaja en G2+ (renderers, +templates `.hbs`). `vault/**` aplica cuando Claude Code opera dentro de un proyecto +generado por `pos` que tiene la capa activada. + +## Contrato de referencia + +Ver [docs/KNOWLEDGE_PLANE.md](../../docs/KNOWLEDGE_PLANE.md) para el contrato +completo (tres capas, principios invariantes, scope de cada rama G1–G4). + +## Qué hacer al editar archivos bajo `vault/**` + +1. **Respetar la separación raw / wiki / config.md**. No mover contenido de `raw/` + a `wiki/` sin síntesis; no modificar `raw/` in-place (son fuentes inmutables). + +2. **`vault/config.md` es la fuente de verdad local**. Antes de añadir convenciones + de nomenclatura o tags, verificar que no contradicen `vault/config.md`. + +3. **Sin dependencias de runtime**. Ningún archivo del vault debe importar, requerir + ni referenciar código ejecutable. El vault es solo Markdown. + +4. **Sin nuevos campos del questionnaire** sin rama G propia. Si una tarea requiere + ampliar el opt-in (ej. `integrations.knowledge_plane.adapter`), seguir el flujo + de rama con Fase -1 explícita. No añadir campos al schema.yaml directamente + (regla #7 CLAUDE.md — ≥2 repeticiones antes de abstraer). + +## Qué hacer al editar archivos bajo `templates/vault/**` (meta-repo, G2+) + +1. **TDD obligatorio** para cualquier nuevo renderer en `generator/renderers/`. + El pre-write-guard enforza test-pair co-located para `generator/**/*.ts`. + +2. **Registrar el renderer** en `generator/renderers/index.ts` dentro del grupo + `knowledgePlaneRenderers` (nuevo grupo, patrón `renderer-group` — sexta aplicación + del patrón; los 5 grupos existentes son core/policy/tests/cicd/skills-hooks, ver + `.claude/rules/generator.md § Renderers`). + +3. **Snapshots deterministas**: el renderer no debe usar `Date.now()` ni rutas del + host. El timestamp se inyecta vía `profile.metadata.generatedAt`. + +4. **Opt-in gate**: el renderer sólo emite archivos cuando + `answers["integrations.knowledge_plane.enabled"] === true`. Con `false` (default), + la función devuelve `[]`. + +## Qué NO hacer + +- No implementar ingest automático, daemons ni watchers dentro del vault (G3 es stub CLI manual). +- No añadir MCP específico de Obsidian como dependencia del meta-repo (es reference adapter, no contrato base). +- No crear `vault/schema.md` — el config file se llama `vault/config.md` (decisión G1, evita colisión léxica con `questionnaire/schema.yaml`). +- No mezclar renderer de vault con otros renderers en una misma rama. Scope separado (CLAUDE.md "No tocar hooks/ y generator/ en la misma rama"). diff --git a/HANDOFF.md b/HANDOFF.md index 2bb1c15..a5a52e2 100644 --- a/HANDOFF.md +++ b/HANDOFF.md @@ -5,7 +5,7 @@ ## 1. Snapshot - Repo: `project-operating-system` (plugin `pos`). -- Rama actual: **`refactor/template-policy-d5b-migration` ✅ PR pendiente** (sub-rama refactor post-F4 que cierra el drift `meta-repo ↔ template` documentado desde D5b y reforzado en F3). Anterior: **F4 ✅ PR pendiente** (`feat/f4-marketplace-public-repo`, en revisión docs-sync — última rama de Fase F propiamente dicha). Siguiente: **`feat/g1-knowledge-plane-contract`** (contrato tool-agnostic raw/wiki/schema, Fase G real) — `feat/fx-knowledge-plane-plan` ya mergeada `cc7d2c3` (#14). +- Rama actual: **`feat/g1-knowledge-plane-contract` ✅ PR pendiente** (Fase G entry-point real — contrato tool-agnostic, `docs/KNOWLEDGE_PLANE.md` standalone, `.claude/rules/knowledge-plane.md`, schema field `integrations.knowledge_plane.enabled: boolean default false`). Anterior: **`chore/roadmap-mark-fx-knowledge-plane-plan-done` ✅ #30** (docs-sync de `feat/fx-knowledge-plane-plan` mergeada como `cc7d2c3` #14). Siguiente: **`feat/g2-adapter-obsidian-reference`** (renderer Obsidian + esqueleto `vault/`). - `refactor/template-policy-d5b-migration` entregó: `templates/policy.yaml.hbs` migrado al shape contractual con loader (A1 `pre_write.enforced_patterns: []` + A2 `skills_allowed` omitido + A3 `pre_compact.persist` 3 items canónicos + A4 `post_merge.skills_conditional[0].trigger` con globs genéricos conservadores) + 3 snapshots regenerados (cli-tool, nextjs-app, agent-sdk) + cleanup de overlays D4+D5 en `bin/_selftest.py` (D3+D6 mantienen overlays mínimos por diseño explícito). Contract test Python-side `bin/tests/test_template_loader_contract.py` corre los 5 accessors reales del loader sobre el output del generator real. Suite: 671 passed + 1 skipped (vs main baseline 644 + 1 skip; +27 contract tests, sin regresión). Vitest 515/515. Selftest 5/5 escenarios verdes sin overlays para D4/D5. - F4 entregó: `.claude-plugin/marketplace.json` (manifest oficial Claude Code marketplace primitive: top-level `{name, owner, plugins, metadata}` + `owner.name="javiAI"` + `plugins[0].source.{source:github, repo:javiAI/project-operating-system, ref:v0.1.0}`) + `.github/workflows/release.yml` (5 jobs: version-match → selftest + build-bundle → publish-release → mirror-marketplace condicional via `vars.POS_MARKETPLACE_REPO`) + `docs/RELEASE.md` (runbook de versionado + bundle + flujo + recovery + activación de mirror) + bump `plugin.json.version` 0.0.1→0.1.0 (single source of truth: tag git = `v${version}`; `marketplace.json.source.ref` espeja). Bundle release curated plugin-only (excluye `generator/`, `templates/`, `questionnaire/`, `tools/`). Repo público `javiAI/pos-marketplace` **diferido** — creación manual cuando se decida ir live; mirror skippea silenciosamente si `POS_MARKETPLACE_REPO` está vacío. Suite: 665 passed + 1 skipped. - F3 entregó: `bin/pos-selftest.sh` (wrapper bash mínimo) + `bin/_selftest.py` (orquestador stdlib Python) + `bin/tests/test_selftest_smoke.py` + `bin/tests/test_selftest_scenarios.py` (5 escenarios funcionales-críticos D1/D3/D4/D5/D6 sobre proyecto sintético generado real-time por `npx tsx generator/run.ts --profile cli-tool.yaml`). CI: nuevo job `selftest` (ubuntu × py 3.11) en `.github/workflows/ci.yml`. Sin Claude Code runtime, sin invocaciones reales de skills/agents. @@ -138,7 +138,7 @@ Hasta F1 el plugin reusaba subagents built-in; desde F2 los críticos son propio Fase F + drift template **cerrados** tras F4 + `refactor/template-policy-d5b-migration`. Carry-overs abiertos: -- **`feat/fx-knowledge-plane-plan`** ✅ mergeada `cc7d2c3` (PR #14, post-D3). FASE G abierta en MASTER_PLAN + ARCHITECTURE § 1.1. Siguiente: **`feat/g1-knowledge-plane-contract`** (contrato tool-agnostic raw/wiki/schema + opt-in questionnaire). +- **`feat/g1-knowledge-plane-contract`** ✅ PR pendiente. Entregó: `docs/KNOWLEDGE_PLANE.md` (contrato standalone 3 capas + principios invariantes + scope G1-G4), `.claude/rules/knowledge-plane.md` (path-scoped `templates/vault/**` + `vault/**`), `questionnaire/schema.yaml` campo `integrations.knowledge_plane.enabled` (boolean, default false), ARCHITECTURE §1.1 resumen+puntero, 2 fixtures + 2 test cases. Suite 517 vitest. Siguiente: **`feat/g2-adapter-obsidian-reference`** (renderer reference adapter, esqueleto vault/). - **Activación del marketplace público**: cuando se decida crear `javiAI/pos-marketplace`, seguir el runbook de [docs/RELEASE.md § Mirror al marketplace público](docs/RELEASE.md) (3 pasos: crear repo + `gh variable set POS_MARKETPLACE_REPO` + `gh secret set POS_MARKETPLACE_TOKEN`). El próximo release abre PR automático contra el repo público. - **Skills `/pos:pr-description` + `/pos:release`**: diferidas por regla #7 CLAUDE.md (≥2 repeticiones documentadas). F4 entrega flow manual; cuando se observe el patrón ≥2 veces, extraer. - **`audit.yml` nightly**: declarado en `policy.yaml.ci_cd.workflows` desde Fase A; sin consumer activo. Reabrir cuando `npm audit` + `pip-audit` + `/pos:audit-plugin --self` justifiquen ejecución periódica. diff --git a/MASTER_PLAN.md b/MASTER_PLAN.md index 66238fc..5729060 100644 --- a/MASTER_PLAN.md +++ b/MASTER_PLAN.md @@ -867,23 +867,41 @@ Esperar aprobación explícita del usuario. Con OK → crear marker + rama. > > **Estado**: planificada, sin fecha de ejecución. Puede reordenarse o descartarse sin impacto sobre A..F. -### Rama G1 — `feat/g1-knowledge-plane-contract` +### Rama G1 — `feat/g1-knowledge-plane-contract` — ✅ -**Scope**: fijar el contrato tool-agnostic de la capa. Markdown file-based, tres capas separadas (raw / wiki / schema). +**Scope entregado**: contrato tool-agnostic de la capa knowledge plane. Markdown file-based, +tres capas separadas (raw / wiki / config.md). Cero código de adapter, renderer o ingest. -**Archivos (previstos)**: - -- `docs/KNOWLEDGE_PLANE.md` — especificación conceptual (shape de `schema.md`, convenciones `raw/` y `wiki/`, invariantes). -- `.claude/rules/knowledge-plane.md` — rule path-scoped cuando se editan archivos bajo `vault/**`. -- `questionnaire/schema.yaml` — añade opt-in `integrations.knowledge_plane.enabled`. **Candidate shape to be finalized in G1**: no se decide en esta rama si el opt-in es bool único o sub-objeto `{ enabled, adapter, vault_path }`. - -**NO incluye**: adapter concreto, renderer, ingest CLI, lint. - -**Cuestión abierta** (a resolver en G1): el término `schema.md` colisiona léxicamente con `questionnaire/schema.yaml` (ya canonical). G1 decide renombre (p.ej. `vault/_meta.md`, `vault/config.md`) o justifica coexistencia. - -**Contexto a leer**: [docs/ARCHITECTURE.md § 1.1](docs/ARCHITECTURE.md) (incluye link al gist de Karpathy sobre wikis LLM-friendly). +**Archivos entregados**: -**Criterio de salida**: contrato público legible sin ambigüedad sobre qué es "raw" vs "wiki" vs "schema"; opt-in testeable; cero código de adapter o ingest. +- `docs/KNOWLEDGE_PLANE.md` (NEW) — especificación standalone: tres capas, principios + invariantes (file-based, tool-agnostic, opt-in, sin runtime compartido), convenciones + raw/wiki/config.md, opt-in schema, scope G1-G4, relación con modelo de dos capas. +- `.claude/rules/knowledge-plane.md` (NEW) — rule path-scoped: cubre `templates/vault/**` + (meta-repo, activo en G2+) y `vault/**` (proyecto generado). Documenta qué hacer/no hacer + en cada contexto. +- `questionnaire/schema.yaml` (+9 líneas) — campo `integrations.knowledge_plane.enabled` + (type: boolean, default: false) en sección E Integraciones. +- `docs/ARCHITECTURE.md § 1.1` — resumen + puntero a `docs/KNOWLEDGE_PLANE.md`. Diagrama + ASCII actualizado (config.md en lugar de schema.md). Nota "no implementada todavía" reemplazada. +- `tools/validate-profile.test.ts` (+13 líneas) — 2 nuevos test cases. +- `tools/__fixtures__/profiles/valid/knowledge-plane-on.yaml` (NEW) — fixture RED/GREEN. +- `tools/__fixtures__/profiles/invalid/knowledge-plane-type-mismatch.yaml` (NEW). + +**Decisiones cerradas en Fase -1**: + +- **A1 — Opt-in bool único**. `integrations.knowledge_plane.enabled: boolean, default: false`. + `adapter` y `vault_path` diferidos a G2+ (regla #7 — sin consumer real hoy). +- **A2 — Config file = `vault/config.md`**. `vault/schema.md` descartado por colisión léxica + con `questionnaire/schema.yaml` (canónico). Decisión permanente: no usar `schema.md` en vault. +- **A3 — Path-scope dual**. `.claude/rules/knowledge-plane.md` cubre `templates/vault/**` + (meta-repo) y `vault/**` (proyecto generado). Ambos documentados con contexto explícito. +- **A4 — Standalone**. `docs/KNOWLEDGE_PLANE.md` independiente; ARCHITECTURE §1.1 = resumen + y puntero. Consistente con `docs/RELEASE.md` en F4. + +**Criterio de salida cumplido**: contrato público legible sin ambigüedad (raw/wiki/config.md); +opt-in testeable (517 vitest, validate:profiles 3 canónicos OK, type-mismatch validado); +cero código de adapter o ingest. ### Rama G2 — `feat/g2-adapter-obsidian-reference` diff --git a/ROADMAP.md b/ROADMAP.md index fd939ba..7020513 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -48,7 +48,7 @@ Estado vivo. Cada fila refleja una rama de [MASTER_PLAN.md](MASTER_PLAN.md). | `refactor/template-policy-d5b-migration` | Migrar `templates/policy.yaml.hbs` al shape contractual con loader (`enforced_patterns: []`, `skills_allowed` omitido, `pre_compact.persist` 3 items, `post_merge.trigger` genérico); cierra drift D5b/F3; contract test Python-side; overlays D4/D5 removidos | ✅ | — | | `feat/f4-marketplace-public-repo` | `marketplace.json` + `release.yml` (5 jobs: version-match, selftest, build-bundle, publish-release, mirror-marketplace condicional) + `docs/RELEASE.md` runbook + bump 0.0.1→0.1.0; repo público diferido | ✅ | — (PR pendiente) | | `feat/fx-knowledge-plane-plan` | Docs-only: abre FASE G en MASTER_PLAN (capa opcional knowledge plane) | ✅ | cc7d2c3 (#14) | -| `feat/g1-knowledge-plane-contract` | Contrato tool-agnostic (raw/wiki/schema) + opt-in questionnaire | ⏳ | — | +| `feat/g1-knowledge-plane-contract` | Contrato tool-agnostic (vault/raw, vault/wiki, vault/config.md) + opt-in questionnaire + `docs/KNOWLEDGE_PLANE.md` + `.claude/rules/knowledge-plane.md` + schema field boolean | ✅ | — (PR pendiente) | | `feat/g2-adapter-obsidian-reference` | Primer reference adapter: esqueleto `vault/` + Obsidian Web Clipper | ⏳ | — | | `feat/g3-ingest-cli` | Stub CLI `pos knowledge ingest` (diferida) | ⏳ | — | | `feat/g4-wiki-lint` | Skill `/pos:knowledge-lint` (diferida) | ⏳ | — | diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index d359754..ecde138 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -30,7 +30,9 @@ El meta-repo nunca ejecuta código del proyecto destino. El proyecto destino nun ### 1.1. Knowledge plane (opcional) -> **Opcional.** Capa extra mountable *dentro* del repo generado, adoptable vía opt-in del questionnaire. Introducida como roadmap en [MASTER_PLAN.md § FASE G](../MASTER_PLAN.md); no implementada todavía. +> **Opcional.** Capa extra mountable *dentro* del repo generado, adoptable vía opt-in del questionnaire. +> Contrato fijado en G1 — ver especificación completa en [docs/KNOWLEDGE_PLANE.md](KNOWLEDGE_PLANE.md). +> Renderer y esqueleto `vault/` en G2 (no implementados todavía). ``` ┌────────────────────────────────────────┐ @@ -41,25 +43,19 @@ El meta-repo nunca ejecuta código del proyecto destino. El proyecto destino nun ┌────────────────────────────────────────┐ │ REPO GENERADO (runtime plane) │ │ │ -│ [opcional] vault/ (knowledge plane): │ -│ raw/ fuentes inmutables │ -│ wiki/ síntesis (LLM + humano) │ -│ schema.md configuración │ +│ [opt-in] vault/ (knowledge plane): │ +│ raw/ fuentes inmutables │ +│ wiki/ síntesis │ +│ config.md configuración │ └────────────────────────────────────────┘ ``` -**Tres capas separadas** (terminología adaptada del [gist de Karpathy sobre wikis LLM-friendly](https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f)): +**Tres capas** (terminología del [gist de Karpathy](https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f)): +`vault/raw/` (fuentes) · `vault/wiki/` (síntesis) · `vault/config.md` (configuración de instancia). -- `vault/raw/` — fuentes inmutables (artículos, papers, notas importadas, clippings). No se reescriben; se añaden. -- `vault/wiki/` — síntesis mantenida por LLM o humano. Cross-referenced, git-diffable. -- `vault/schema.md` — documento de configuración de la instancia: convenciones, reglas de síntesis, mapa de categorías. +**Principios**: file-based · tool-agnostic · opt-in (`integrations.knowledge_plane.enabled: boolean, default false`) · sin runtime compartido. -**Principios invariantes**: - -- **File-based**: todo es Markdown plano. Sin DB, sin formato propietario. Compatible con cualquier editor Markdown. -- **Tool-agnostic**: no impone cliente editor. Obsidian + Web Clipper es el **primer reference adapter** previsto — ver [MASTER_PLAN.md § Rama G2](../MASTER_PLAN.md). Logseq, Foam y plain-text son compatibles por construcción. -- **Opt-in**: el questionnaire añadirá `integrations.knowledge_plane.enabled` cuando G1 se cierre — shape candidato (bool único o sub-objeto `{ enabled, adapter, vault_path }`) a decidir en G1. Con flag off, `vault/` no se emite. -- **Sin runtime compartido**: el knowledge plane vive en el repo generado, no en el meta-repo. El generador sólo emite el esqueleto; el mantenimiento es local al proyecto destino. +Obsidian + Web Clipper = primer reference adapter previsto (G2), no contrato base. ## 2. Cuestionario → profile → generación diff --git a/docs/KNOWLEDGE_PLANE.md b/docs/KNOWLEDGE_PLANE.md new file mode 100644 index 0000000..bbe55e7 --- /dev/null +++ b/docs/KNOWLEDGE_PLANE.md @@ -0,0 +1,126 @@ +# KNOWLEDGE_PLANE — Especificación del contrato + +> Contrato tool-agnostic de la capa knowledge plane opcional del plugin `pos`. +> Para contexto arquitectónico y posición en el modelo de dos capas del meta-repo, +> ver [docs/ARCHITECTURE.md § 1.1](ARCHITECTURE.md#11-knowledge-plane-opcional). + +## 1. Qué es el knowledge plane + +El knowledge plane es una capa opcional que puede activarse en cualquier repo generado +por `pos` vía el opt-in del questionnaire. No forma parte del control plane (meta-repo) +ni del runtime plane (proyecto generado base): es una extensión mountable que provee +estructura para gestionar conocimiento de proyecto en Markdown plano. + +**Opt-in**: `integrations.knowledge_plane.enabled: true` en el profile del proyecto. +Con el flag en `false` (default), el generador no emite nada de esta capa. + +## 2. Las tres capas + +``` +vault/ +├── raw/ fuentes inmutables +├── wiki/ síntesis +└── config.md configuración de la instancia +``` + +### 2.1 `vault/raw/` — fuentes inmutables + +Contiene material de referencia que no se reescribe: artículos, papers, transcripciones, +notas importadas, clippings web. Las entradas se añaden, nunca se modifican en el lugar. + +**Convenciones**: +- Un archivo por fuente. Nombre descriptivo en kebab-case (`2024-attention-is-all-you-need.md`). +- Incluir metadatos mínimos al inicio del archivo: `source:`, `date:`, `tags:` (sin schema forzado). +- No crear subdirectorios sin criterio establecido en `vault/config.md`. + +### 2.2 `vault/wiki/` — síntesis + +Contiene conocimiento procesado: resúmenes, decisiones de diseño, conceptos clave, +glosarios, relaciones entre fuentes. Mantenida por el LLM o por el humano; puede +reescribirse cuando el conocimiento evolucione. + +**Convenciones**: +- Páginas en kebab-case (`arquitectura-hooks.md`, `decisiones-auth.md`). +- Cross-references con enlaces relativos (`[ver raw](../raw/fuente.md)`). +- Cada página debe tener al menos un párrafo de contexto antes de listas o tablas. +- Las páginas sin raw correspondiente son válidas (conocimiento sintetizado ad hoc). + +### 2.3 `vault/config.md` — configuración de la instancia + +Documento de configuración de este vault concreto. No es un README de uso general: +es la fuente de verdad de las convenciones adoptadas por este proyecto en particular. + +**Contenido mínimo esperado**: +- Propósito del vault (en qué contexto se usa esta capa de conocimiento). +- Convenciones de nomenclatura de `raw/` y `wiki/` para este proyecto. +- Mapa de categorías o tags si se adoptan. +- Reglas de síntesis: qué convierte un raw en wiki (threshold de relevancia, etc.). + +**Nota de naming**: el archivo se llama `config.md`, no `schema.md`, para evitar +confusión léxica con `questionnaire/schema.yaml` que es el schema del cuestionario +del generador. + +## 3. Principios invariantes + +Estos principios no pueden violarse al añadir adapters, renderers o herramientas +en fases posteriores (G2, G3, G4): + +1. **File-based**: todo es Markdown plano. Sin base de datos, sin formato propietario, + sin dependencia de un servidor. El vault puede leerse con cualquier editor de texto. + +2. **Tool-agnostic**: ningún adapter es canónico. Obsidian + Web Clipper es el + primer reference adapter previsto (G2), pero Logseq, Foam, Zettlr y plain-text + son igualmente compatibles por construcción del contrato. + +3. **Opt-in**: el questionnaire controla si el vault se emite. Un proyecto que no activa + la capa no debe tener ningún directorio `vault/` ni referencia a él en sus templates. + +4. **Sin runtime compartido**: el vault vive en el repo generado, no en el meta-repo. + El generador emite el esqueleto; el mantenimiento es responsabilidad del proyecto destino. + +5. **Sin ingest automático en G1**: la capa no implica ningún daemon, watcher ni + llamada LLM automática. Ingest manual (G3) y lint (G4) son extensiones futuras opcionales. + +## 4. Opt-in en el questionnaire + +Campo: `integrations.knowledge_plane.enabled` (sección E, Integraciones). + +```yaml +"integrations.knowledge_plane.enabled": true +``` + +Tipo: `boolean`. Default: `false`. + +El generador evalúa este campo en G2 para ramificar la emisión del esqueleto `vault/`. +En G1 el campo es declarable y validable pero el renderer no existe todavía. + +**Campos diferidos** (no en G1, regla #7 CLAUDE.md): +- `integrations.knowledge_plane.adapter` — diferido a G2+ cuando haya más de un adapter + con semántica distinta. +- `integrations.knowledge_plane.vault_path` — diferido hasta que un caso real requiera + un path personalizado (default sería `vault/`). + +## 5. Scope de cada rama de Fase G + +| Rama | Entrega | Depende de | +|---|---|---| +| G1 (esta rama) | Contrato + campo schema + regla path-scoped | — | +| G2 | Renderer Obsidian reference adapter, esqueleto `vault/` | G1 | +| G3 | Stub CLI `pos knowledge ingest` | G1 + G2 | +| G4 | Skill `/pos:knowledge-lint` | G1 + G2 + ≥2 proyectos reales | + +## 6. Relación con el modelo de dos capas + +El knowledge plane no altera el modelo de dos capas existente: + +``` +META-REPO (control plane) + │ genera + ▼ +REPO GENERADO (runtime plane) + │ + └── [opt-in] vault/ ← knowledge plane +``` + +El generador sólo emite el esqueleto. El control de contenido del vault +es local al proyecto destino y no depende del meta-repo en runtime. diff --git a/questionnaire/schema.yaml b/questionnaire/schema.yaml index edc8468..346c3e3 100644 --- a/questionnaire/schema.yaml +++ b/questionnaire/schema.yaml @@ -104,6 +104,15 @@ sections: values: ["none", "sentry", "datadog", "opentelemetry"] default: "none" + - path: integrations.knowledge_plane.enabled + type: boolean + default: false + description: > + Activa la capa knowledge plane opt-in en el repo generado (vault/raw + vault/wiki + + vault/config.md). Contrato tool-agnostic: cualquier editor Markdown es compatible. + Con este campo en true, el generador emitirá el esqueleto vault/ a partir de G2. + Ver docs/KNOWLEDGE_PLANE.md para el contrato completo. + # ───────────────────────────────────────────── - id: F name: Workflow diff --git a/tools/__fixtures__/profiles/invalid/knowledge-plane-type-mismatch.yaml b/tools/__fixtures__/profiles/invalid/knowledge-plane-type-mismatch.yaml new file mode 100644 index 0000000..32c397e --- /dev/null +++ b/tools/__fixtures__/profiles/invalid/knowledge-plane-type-mismatch.yaml @@ -0,0 +1,9 @@ +version: "0.1.0" + +profile: + name: "cli-tool" + description: "Profile with knowledge_plane.enabled as a string instead of boolean." + +answers: + "stack.language": "typescript" + "integrations.knowledge_plane.enabled": "yes" diff --git a/tools/__fixtures__/profiles/valid/knowledge-plane-on.yaml b/tools/__fixtures__/profiles/valid/knowledge-plane-on.yaml new file mode 100644 index 0000000..1881468 --- /dev/null +++ b/tools/__fixtures__/profiles/valid/knowledge-plane-on.yaml @@ -0,0 +1,25 @@ +# tools/__fixtures__/profiles/valid/knowledge-plane-on.yaml +# +# Profile que activa el knowledge plane opt-in. +# RED: produce answer-unknown-path hasta que schema.yaml declare el campo. +# GREEN: exits 0 tras añadir integrations.knowledge_plane.enabled a schema.yaml. + +version: "0.1.0" + +profile: + name: "cli-tool" + description: "TypeScript CLI with knowledge plane enabled." + +answers: + "domain.type": "cli" + "stack.language": "typescript" + "stack.database": "none" + "testing.unit_framework": "vitest" + "testing.coverage_threshold": 85 + "testing.e2e_framework": "none" + "workflow.ci_host": "github" + "workflow.release_strategy": "semantic-release" + "workflow.branch_protection": true + "claude_code.default_model": "claude-sonnet-4-6" + "claude_code.team_size": "solo" + "integrations.knowledge_plane.enabled": true diff --git a/tools/validate-profile.test.ts b/tools/validate-profile.test.ts index ca021a8..92d4834 100644 --- a/tools/validate-profile.test.ts +++ b/tools/validate-profile.test.ts @@ -62,6 +62,19 @@ describe("validateProfileFile (unit)", () => { expect(report).toMatch(/status: FAIL/); expect(report).toMatch(/answer-value-not-in-enum/); }); + + it("exits 0 for knowledge-plane-on fixture (integrations.knowledge_plane.enabled: true)", async () => { + const result = await validateProfileFile(SCHEMA, "tools/__fixtures__/profiles/valid/knowledge-plane-on.yaml"); + expect(result.issues).toEqual([]); + expect(result.exitCode).toBe(0); + }); + + it("reports answer-type-mismatch for integrations.knowledge_plane.enabled: 'yes'", async () => { + const result = await validateProfileFile(SCHEMA, "tools/__fixtures__/profiles/invalid/knowledge-plane-type-mismatch.yaml"); + expect(result.exitCode).toBe(1); + const kinds = result.issues.map((i) => i.kind); + expect(kinds).toContain("answer-type-mismatch"); + }); }); describe("validate-profile CLI (integration)", () => {