{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://logicsrc.com/schemas/opencontext/diagnostic.schema.json", "title": "OpenContext Diagnostic Report", "description": "The machine-readable output of `opencontext validate` and `opencontext doctor`: every finding, where it came from, how bad it is, and the resulting health score. Diagnostics are the contract CI depends on, so the codes are normative and stable — a pipeline that fails on duplicate-canonical must keep failing on it across implementations and versions.", "type": "object", "required": ["opencontext", "ok", "findings"], "additionalProperties": false, "properties": { "opencontext": { "type": "string", "pattern": "^\\d+\\.\\d+(\\.\\d+)?$" }, "ok": { "type": "boolean", "description": "True when no finding meets or exceeds the configured failure severity. This is what the exit code follows." }, "generated_at": { "type": "string", "format": "date-time" }, "namespace": { "type": "string", "pattern": "^[a-z0-9][a-z0-9-]*$" }, "score": { "type": "number", "minimum": 0, "maximum": 100, "description": "Context health, 0-100. Computed as 100 minus the sum of weight x affected objects for each finding, normalised by the object count and clamped at 0. The weights are documented and configurable, so a score is comparable only within a repository's own configuration." }, "counts": { "type": "object", "additionalProperties": false, "description": "Roll-up used by the human-readable report.", "properties": { "objects": { "type": "integer", "minimum": 0 }, "errors": { "type": "integer", "minimum": 0 }, "warnings": { "type": "integer", "minimum": 0 }, "info": { "type": "integer", "minimum": 0 }, "stale": { "type": "integer", "minimum": 0 }, "expired": { "type": "integer", "minimum": 0 }, "conflicting": { "type": "integer", "minimum": 0 }, "orphaned": { "type": "integer", "minimum": 0 }, "missing_owner": { "type": "integer", "minimum": 0 }, "broken_sources": { "type": "integer", "minimum": 0 } } }, "findings": { "type": "array", "description": "Every finding, ordered most severe first, then by code, then by object id, so two runs over the same repository produce byte-identical reports.", "items": { "$ref": "#/$defs/finding" } }, "extensions": { "type": "object", "propertyNames": { "type": "string", "pattern": "^[a-z0-9]+(\\.[a-z0-9-]+)+$" }, "additionalProperties": true } }, "$defs": { "severity": { "type": "string", "enum": ["info", "warning", "error"], "description": "error breaks the contract and fails a strict run; warning is context rot that needs attention but still resolves; info is advisory." }, "finding": { "type": "object", "required": ["code", "severity", "message"], "additionalProperties": false, "properties": { "code": { "type": "string", "enum": [ "schema-invalid", "manifest-invalid", "duplicate-id", "duplicate-canonical", "unknown-authority", "conflict-declared", "conflict-ambiguous", "broken-supersession", "supersession-cycle", "multiple-active-versions", "broken-reference", "orphaned", "missing-owner", "missing-provenance", "missing-digest", "stale", "expired", "not-yet-valid", "review-overdue", "unapproved", "unknown-scheme", "source-unavailable", "path-traversal", "invalid-permission", "unknown-role", "role-cycle", "empty-scope", "secret-detected", "untrusted-canonical", "unknown-extension" ], "description": "Stable diagnostic code. duplicate-canonical, conflict-ambiguous, and broken-supersession are the checks that keep the resolver from quietly guessing; secret-detected and path-traversal are security checks; unknown-extension is only ever raised in strict mode." }, "severity": { "$ref": "#/$defs/severity" }, "message": { "type": "string", "minLength": 1, "description": "What is wrong, in a sentence an author can act on." }, "id": { "type": "string", "description": "Context object id the finding concerns." }, "ids": { "type": "array", "items": { "type": "string" }, "description": "Every object involved, when a finding is about a relationship rather than one object — the two canonical policies that collide, or the chain that broke." }, "file": { "type": "string", "description": "Path the object was loaded from, relative to the manifest." }, "line": { "type": "integer", "minimum": 1, "description": "1-indexed line, when the source format carries positions." }, "column": { "type": "integer", "minimum": 1 }, "field": { "type": "string", "description": "Dotted path of the offending field, e.g. permissions.read." }, "expected": { "description": "What the field should have been." }, "actual": { "description": "What it was." }, "remediation": { "type": "string", "description": "The concrete next action, e.g. 'Add owner: support, or set health.require_owner: false'." } } } } }