7913116a8e
- .claude/agents/fn-analizador/SKILL.md - .claude/agents/fn-constructor/SKILL.md - .claude/agents/fn-executor/SKILL.md - .claude/agents/fn-mejorador/SKILL.md - .claude/agents/fn-orquestador/SKILL.md - .claude/agents/fn-recopilador/SKILL.md - .claude/commands/app.md - .claude/commands/compile.md - .claude/commands/cpp-app.md - .claude/commands/create_functions.md - ... Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
61 lines
2.3 KiB
Markdown
61 lines
2.3 KiB
Markdown
---
|
|
name: audit_services_spec
|
|
kind: function
|
|
lang: go
|
|
domain: infra
|
|
version: "1.0.0"
|
|
purity: impure
|
|
signature: "func AuditServicesSpec(registryRoot string) ([]ServiceSpecAudit, error)"
|
|
description: "Audita apps con tag 'service': reporta drift entre el bloque service: del app.md y los datos requeridos por el monitor (port, health_endpoint, systemd_unit, pc_targets). Lee registry.db read-only via sql.Open. Issue 0105."
|
|
tags: [audit, services, doctor, registry, sqlite, issue-0105]
|
|
uses_functions: []
|
|
uses_types: []
|
|
returns: []
|
|
returns_optional: false
|
|
error_type: error_go_core
|
|
imports:
|
|
- database/sql
|
|
- github.com/mattn/go-sqlite3
|
|
tested: false
|
|
file_path: functions/infra/audit_services_spec.go
|
|
params:
|
|
- name: registryRoot
|
|
desc: "Ruta absoluta a la raiz del fn_registry (donde vive registry.db)."
|
|
output: "Slice de ServiceSpecAudit (uno por app con tag service). OK=false si Issues no esta vacio."
|
|
---
|
|
|
|
# audit_services_spec
|
|
|
|
Reporta apps con tag `service` cuya `service:` block esta incompleta.
|
|
|
|
## Cuando usarla
|
|
|
|
- Subcomando `fn doctor services-spec` (este es su unico consumer hoy).
|
|
- Antes de desplegar `services_monitor` (issue 0106) — si esta funcion devuelve `OK=false` para alguna app, el monitor no puede reconciliar estado.
|
|
- En CI/cron para detectar regresiones cuando alguien crea app `tag: service` sin bloque.
|
|
|
|
## Ejemplo
|
|
|
|
```go
|
|
audits, err := infra.AuditServicesSpec("$HOME/fn_registry")
|
|
for _, a := range audits {
|
|
if !a.OK {
|
|
fmt.Println(a.AppID, "issues:", a.Issues)
|
|
}
|
|
}
|
|
```
|
|
|
|
## Reglas que valida
|
|
|
|
- bloque presente (alguno de runtime/systemd_unit/port/health_endpoint != default).
|
|
- `runtime` declarado y en allowlist (`systemd-user`, `systemd-system`, `docker-compose`, `stdio`, `manual`).
|
|
- `pc_targets` con al menos 1 pc_id (cruzado contra tabla `service_targets`).
|
|
- `runtime` empieza con `systemd-` ⇒ `systemd_unit` obligatorio.
|
|
- `restart_policy` (si declarada) en `always`, `on-failure`, `none`.
|
|
|
|
## Gotchas
|
|
|
|
- Lee `registry.db` en modo `?mode=ro`; si la base no existe o esta locked retorna error.
|
|
- `service:` bloque parcial pasa el check `HasBlock=true` pero falla validaciones especificas — ver `Issues[]` para detalles.
|
|
- No valida que el `port` este libre o el `systemd_unit` exista en disco; eso lo hace `services_status_go_infra` (runtime check).
|