chore: snapshot WIP previo + flow 0008 + 7 sub-issues (0112-0119)
Snapshot de WIP acumulado de sesiones previas antes de merge wave 1 del flow 0008 (kanban_cpp + agent_runner_api + DoD schema). Incluye: - dev/flows/0008-kanban-cpp-and-agent-workflows.md - dev/issues/0112-0119*.md (7 sub-issues) - WIP previo en cmd/fn/doctor.go, registry/*, modules/, cpp/, etc. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,131 @@
|
||||
package infra
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
// ServiceSpecAudit reports drift between an app tagged `service` and the
|
||||
// `service:` frontmatter block populated by the indexer (issue 0105).
|
||||
type ServiceSpecAudit struct {
|
||||
AppID string `json:"app_id"`
|
||||
Name string `json:"name"`
|
||||
HasBlock bool `json:"has_block"`
|
||||
Runtime string `json:"runtime"`
|
||||
Port int `json:"port"`
|
||||
HealthPath string `json:"health_endpoint"`
|
||||
SystemdUnit string `json:"systemd_unit"`
|
||||
PCTargets []string `json:"pc_targets"`
|
||||
IsLocalOnly bool `json:"is_local_only"`
|
||||
RestartPolicy string `json:"restart_policy"`
|
||||
Issues []string `json:"issues"`
|
||||
OK bool `json:"ok"`
|
||||
}
|
||||
|
||||
// AuditServicesSpec lists every app with tag `service` and reports whether its
|
||||
// `service:` frontmatter is complete enough for downstream monitoring
|
||||
// (services_monitor app, issue 0106).
|
||||
//
|
||||
// Rules:
|
||||
// - block must exist (otherwise IsLocalOnly/runtime are all defaults).
|
||||
// - runtime is required (one of: systemd-user, systemd-system, docker-compose, stdio, manual).
|
||||
// - pc_targets must declare >= 1 pc_id.
|
||||
// - if runtime starts with `systemd-`, systemd_unit is required.
|
||||
// - if runtime in {systemd-*, docker-compose} and port > 0, health_endpoint is recommended (warning, not failure).
|
||||
func AuditServicesSpec(registryRoot string) ([]ServiceSpecAudit, error) {
|
||||
dbPath := registryRoot + "/registry.db"
|
||||
db, err := sql.Open("sqlite3", dbPath+"?_journal_mode=WAL&mode=ro")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("audit_services_spec: open db: %w", err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
rows, err := db.Query(`
|
||||
SELECT id, name,
|
||||
COALESCE(service_runtime,''),
|
||||
COALESCE(service_port,0),
|
||||
COALESCE(service_health_endpoint,''),
|
||||
COALESCE(service_systemd_unit,''),
|
||||
COALESCE(service_restart_policy,''),
|
||||
COALESCE(service_is_local_only,0)
|
||||
FROM apps
|
||||
WHERE tags LIKE '%service%'
|
||||
ORDER BY id
|
||||
`)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("audit_services_spec: query: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var out []ServiceSpecAudit
|
||||
for rows.Next() {
|
||||
var a ServiceSpecAudit
|
||||
var localOnly int
|
||||
if err := rows.Scan(
|
||||
&a.AppID, &a.Name,
|
||||
&a.Runtime, &a.Port, &a.HealthPath, &a.SystemdUnit, &a.RestartPolicy, &localOnly,
|
||||
); err != nil {
|
||||
return nil, fmt.Errorf("audit_services_spec: scan: %w", err)
|
||||
}
|
||||
a.IsLocalOnly = localOnly != 0
|
||||
a.HasBlock = a.Runtime != "" || a.SystemdUnit != "" || a.Port != 0 || a.HealthPath != ""
|
||||
|
||||
// pc_targets from service_targets table.
|
||||
tRows, err := db.Query(
|
||||
"SELECT pc_id FROM service_targets WHERE app_id = ? ORDER BY pc_id",
|
||||
a.AppID,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("audit_services_spec: service_targets query: %w", err)
|
||||
}
|
||||
for tRows.Next() {
|
||||
var pc string
|
||||
if err := tRows.Scan(&pc); err != nil {
|
||||
tRows.Close()
|
||||
return nil, err
|
||||
}
|
||||
a.PCTargets = append(a.PCTargets, pc)
|
||||
}
|
||||
tRows.Close()
|
||||
|
||||
// Validate.
|
||||
if !a.HasBlock {
|
||||
a.Issues = append(a.Issues, "missing service: block in app.md")
|
||||
}
|
||||
if a.Runtime == "" {
|
||||
a.Issues = append(a.Issues, "missing service.runtime")
|
||||
} else if !validRuntimes[a.Runtime] {
|
||||
a.Issues = append(a.Issues, "invalid service.runtime: "+a.Runtime)
|
||||
}
|
||||
if len(a.PCTargets) == 0 {
|
||||
a.Issues = append(a.Issues, "missing service.pc_targets (>= 1 required)")
|
||||
}
|
||||
if strings.HasPrefix(a.Runtime, "systemd-") && a.SystemdUnit == "" {
|
||||
a.Issues = append(a.Issues, "runtime systemd-* requires service.systemd_unit")
|
||||
}
|
||||
if a.RestartPolicy != "" && !validRestart[a.RestartPolicy] {
|
||||
a.Issues = append(a.Issues, "invalid service.restart_policy: "+a.RestartPolicy)
|
||||
}
|
||||
|
||||
a.OK = len(a.Issues) == 0
|
||||
out = append(out, a)
|
||||
}
|
||||
return out, rows.Err()
|
||||
}
|
||||
|
||||
var validRuntimes = map[string]bool{
|
||||
"systemd-user": true,
|
||||
"systemd-system": true,
|
||||
"docker-compose": true,
|
||||
"stdio": true,
|
||||
"manual": true,
|
||||
}
|
||||
|
||||
var validRestart = map[string]bool{
|
||||
"always": true,
|
||||
"on-failure": true,
|
||||
"none": true,
|
||||
}
|
||||
Reference in New Issue
Block a user