f8616b806e
P1 (Wave 1, feat) — REQ-187, REQ-188, REQ-205 (emitter), REQ-206 (emitter) New components: - core/metrics/event_envelope.py — CloudEvents 1.0 envelope + platform.* conventions - core/metrics/run_manifest.py — per-run manifest writer (nova.run.started/completed/failed) - core/metrics/decision_ledger.py — SQLite append-only hash-chain (ai.decision.made + attestation.recorded) - core/metrics/infracost_adapter.py — Infracost post-processor (degraded mode when CLI absent, A6) - schemas/metrics_event.schema.json — CloudEvents envelope schema - schemas/metrics_run_manifest.schema.json — per-run manifest schema - metrics/README.md — backup/restore doc (REQ-201) - tests/test_metrics_emitters.py — 16 tests (all pass) Modified components: - core/confidence_signal.py — emits nova.confidence.computed + nova.ai.decision.made (D-122) - core/hitl_gates.py — emits nova.attestation.recorded on qa/prod/dr gates (D-132) - adapters/terraform/policy/checkov_adapter.py — emits nova.policy.evaluated - pyproject.toml — addopts gains --junitxml + --json-report + --cov (REQ-206) - .gitignore — metrics runtime artifacts ignored D-120: Nova-native (JSONL + SQLite, no Kafka/OTel) D-121: Decision Ledger = outbox_writer extension → SQLite hash-chain D-122: AI decision = confidence_signal + HITL gate (not LLM) D-128: metrics/ at repo root D-132: Attestation instrumentation ---ci--- project: acdl phase: 1 milestone: v1.17 status: execute ---/ci---
56 lines
1.8 KiB
JSON
56 lines
1.8 KiB
JSON
{
|
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
"title": "Nova Per-Run Manifest",
|
|
"description": "Per-run manifest written to metrics/runs/<run_id>.json (REQ-187). Captures the full run lifecycle.",
|
|
"type": "object",
|
|
"required": ["run_id", "contract_id", "environment", "started_at", "completed_at", "exit_code", "stages"],
|
|
"properties": {
|
|
"run_id": {"type": "string", "minLength": 1},
|
|
"contract_id": {"type": "string"},
|
|
"environment": {"type": "string", "enum": ["dev", "qa", "prod", "dr"]},
|
|
"started_at": {"type": "string", "format": "date-time"},
|
|
"completed_at": {"type": "string", "format": "date-time"},
|
|
"exit_code": {"type": "integer"},
|
|
"stages": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "object",
|
|
"required": ["name", "duration_ms", "exit_code"],
|
|
"properties": {
|
|
"name": {"type": "string"},
|
|
"duration_ms": {"type": "number"},
|
|
"exit_code": {"type": "integer"},
|
|
"error": {"type": "string"}
|
|
}
|
|
}
|
|
},
|
|
"confidence": {
|
|
"type": "object",
|
|
"properties": {
|
|
"score": {"type": "number"},
|
|
"band": {"type": "string", "enum": ["pass", "warn", "block"]},
|
|
"perInput": {"type": "object"}
|
|
}
|
|
},
|
|
"hitl": {
|
|
"type": "object",
|
|
"properties": {
|
|
"gate": {"type": "string"},
|
|
"result": {"type": "string"},
|
|
"block": {"type": "boolean"}
|
|
}
|
|
},
|
|
"policy": {
|
|
"type": "object",
|
|
"properties": {
|
|
"passed": {"type": "integer"},
|
|
"failed": {"type": "integer"},
|
|
"skipped": {"type": "integer"}
|
|
}
|
|
},
|
|
"cost_estimate_usd": {"type": "number"},
|
|
"decision_id": {"type": "string"},
|
|
"outcome": {"type": "string", "enum": ["succeeded", "failed", "pending"]}
|
|
},
|
|
"additionalProperties": true
|
|
} |