agentnative 0.5.0

The agent-native CLI linter — audit whether your CLI follows agent-readiness principles
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://anc.dev/scorecard-v0.7.schema.json",
  "title": "agentnative scorecard",
  "description": "JSON Schema for `anc audit --output json` scorecards (schema version 0.7). Schema 0.7 introduces the 7-status taxonomy (`opt_out` and `n_a` added to `status`, with matching counters in `summary`), per-row emission (one result per requirement-row instead of per audit_id; `tier` and `audit_id` fields added to each result), and antecedent propagation for conditional requirements. See docs/plans/2026-05-21-001-feat-scorecard-fairness-taxonomy-plan.md in the agentnative-site repo for the full taxonomy rationale.",
  "type": "object",
  "required": [
    "schema_version",
    "results",
    "summary",
    "coverage_summary",
    "audience",
    "audit_profile",
    "spec_version",
    "tool",
    "anc",
    "run",
    "target",
    "badge"
  ],
  "additionalProperties": false,
  "properties": {
    "schema_version": {
      "type": "string",
      "description": "Scorecard schema version. Pre-launch additive — consumers feature-detect new fields rather than pin to an exact value.",
      "examples": ["0.7"]
    },
    "results": {
      "type": "array",
      "description": "Per-requirement-row outcomes (schema 0.7+). One entry per requirement row covered by an audit that ran in this invocation; a single probe whose `Audit::covers()` lists multiple rows produces multiple entries (each entry's `audit_id` carries the probe's id for provenance).",
      "items": { "$ref": "#/$defs/AuditResultView" }
    },
    "summary": { "$ref": "#/$defs/Summary" },
    "coverage_summary": { "$ref": "#/$defs/CoverageSummary" },
    "audience": {
      "type": ["string", "null"],
      "description": "Derived audience classification. `null` when the classifier could not produce a label (e.g., signal audit suppressed by `--audit-profile`, source-only run). Read-only over results; never gates totals or exit codes.",
      "enum": ["agent-optimized", "mixed", "human-primary", null]
    },
    "audience_reason": {
      "type": "string",
      "description": "Reason the classifier declined a label, when `audience` is null. Omitted from JSON when `audience` has a value.",
      "enum": ["suppressed", "insufficient_signal"]
    },
    "audit_profile": {
      "type": ["string", "null"],
      "description": "The `--audit-profile` value applied to this run, or null when no profile was set. Drives suppression of audits listed in the registry's SUPPRESSION_TABLE for that category.",
      "enum": ["human-tui", "file-traversal", "posix-utility", "diagnostic-only", null]
    },
    "spec_version": {
      "type": "string",
      "description": "agentnative-spec version this `anc` build was compiled against. Sourced at build time from `src/principles/spec/VERSION`. Reads `unknown` when the vendored VERSION file was missing at build time.",
      "examples": ["0.4.0"]
    },
    "tool": { "$ref": "#/$defs/ToolInfo" },
    "anc": { "$ref": "#/$defs/AncInfo" },
    "run": { "$ref": "#/$defs/RunInfo" },
    "target": { "$ref": "#/$defs/TargetInfo" },
    "badge": { "$ref": "#/$defs/BadgeInfo" }
  },
  "$defs": {
    "AuditResultView": {
      "type": "object",
      "required": ["id", "label", "group", "layer", "status", "evidence", "confidence", "tier", "audit_id"],
      "additionalProperties": false,
      "properties": {
        "id": {
          "type": "string",
          "description": "Requirement-row identifier (schema 0.7+; matches `coverage/matrix.json` row ids, e.g. `p1-must-no-interactive`). The site's `/score/<tool>` page and external leaderboards pin on these strings. Previously (≤0.5) this carried the probe id."
        },
        "label": {
          "type": "string",
          "description": "Human-readable summary of what the audit verifies."
        },
        "group": {
          "type": "string",
          "description": "Principle bucket the audit belongs to. Cross-cutting groups (`CodeQuality`, `ProjectStructure`) appear regardless of `--principle` filter.",
          "examples": ["P1", "P2", "P8", "CodeQuality", "ProjectStructure"]
        },
        "layer": {
          "type": "string",
          "description": "Where the audit ran. Serialized as snake_case.",
          "enum": ["behavioral", "source", "project"]
        },
        "status": {
          "type": "string",
          "description": "Outcome of the audit under the 7-status taxonomy (schema 0.7+). `opt_out` = deliberate non-adoption; `n_a` = conditional antecedent unmet (set by antecedent propagation); `skip` = linter probe limitation. Skips, errors, opt_outs, and n_as are all excluded from the transitional badge denominator.",
          "enum": ["pass", "warn", "fail", "opt_out", "n_a", "skip", "error"]
        },
        "evidence": {
          "type": ["string", "null"],
          "description": "Structured evidence for non-Pass statuses: the suppression-table marker, the unrecognized-flag list, the missing-file path, the antecedent propagation reason. `null` for clean Pass."
        },
        "confidence": {
          "type": "string",
          "description": "How directly the audit verifies its requirement. `high` for direct probes; `medium` for heuristics. Older consumers feature-detect.",
          "enum": ["high", "medium"]
        },
        "tier": {
          "type": ["string", "null"],
          "description": "Requirement-row RFC 2119 level (schema 0.7+). `null` only when the row id is not in the registry — an internal inconsistency that should be loud.",
          "enum": ["must", "should", "may", null]
        },
        "audit_id": {
          "type": "string",
          "description": "Probe that produced this row (schema 0.7+). One probe may produce multiple rows when its `Audit::covers()` slice names multiple requirements (e.g. `p3-version` covers both `p3-must-version` and `p3-should-version-short`)."
        }
      }
    },
    "Summary": {
      "type": "object",
      "description": "Run-level outcome counts. Schema 0.7+ adds `opt_out` and `n_a` counters alongside the historic five.",
      "required": ["total", "pass", "warn", "fail", "opt_out", "n_a", "skip", "error"],
      "additionalProperties": false,
      "properties": {
        "total": { "type": "integer", "minimum": 0 },
        "pass": { "type": "integer", "minimum": 0 },
        "warn": { "type": "integer", "minimum": 0 },
        "fail": { "type": "integer", "minimum": 0 },
        "opt_out": { "type": "integer", "minimum": 0 },
        "n_a": { "type": "integer", "minimum": 0 },
        "skip": { "type": "integer", "minimum": 0 },
        "error": { "type": "integer", "minimum": 0 }
      }
    },
    "LevelCounts": {
      "type": "object",
      "description": "Per-level verification counts. `verified` counts requirements that had at least one audit declare `covers()` against them in this run, regardless of pass/fail.",
      "required": ["total", "verified"],
      "additionalProperties": false,
      "properties": {
        "total": { "type": "integer", "minimum": 0 },
        "verified": { "type": "integer", "minimum": 0 }
      }
    },
    "CoverageSummary": {
      "type": "object",
      "description": "Three-way coverage rollup over registry requirements: how many `must` / `should` / `may` requirements were verified by this run's audits.",
      "required": ["must", "should", "may"],
      "additionalProperties": false,
      "properties": {
        "must": { "$ref": "#/$defs/LevelCounts" },
        "should": { "$ref": "#/$defs/LevelCounts" },
        "may": { "$ref": "#/$defs/LevelCounts" }
      }
    },
    "ToolInfo": {
      "type": "object",
      "description": "Identity of the scored target. `binary` is `null` for project-mode runs without a built artifact; `version` is `null` when probing failed, produced no parseable output, or was declined by the self-spawn guard.",
      "required": ["name", "binary", "version"],
      "additionalProperties": false,
      "properties": {
        "name": { "type": "string" },
        "binary": { "type": ["string", "null"] },
        "version": { "type": ["string", "null"] }
      }
    },
    "AncInfo": {
      "type": "object",
      "description": "Identity of the `anc` build that produced this scorecard.",
      "required": ["version"],
      "additionalProperties": false,
      "properties": {
        "version": { "type": "string", "examples": ["0.4.0"] }
      }
    },
    "PlatformInfo": {
      "type": "object",
      "description": "OS / architecture pair sourced from `std::env::consts::{OS, ARCH}`.",
      "required": ["os", "arch"],
      "additionalProperties": false,
      "properties": {
        "os": { "type": "string", "examples": ["linux", "macos", "windows"] },
        "arch": { "type": "string", "examples": ["x86_64", "aarch64"] }
      }
    },
    "RunInfo": {
      "type": "object",
      "description": "Run-level facts. `invocation` is argv joined with spaces, captured before `inject_default_subcommand` rewrites bare paths. `started_at` is RFC 3339 UTC. `duration_ms` is wall-clock.",
      "required": ["invocation", "started_at", "duration_ms", "platform"],
      "additionalProperties": false,
      "properties": {
        "invocation": { "type": "string", "examples": ["anc ."] },
        "started_at": { "type": "string", "format": "date-time" },
        "duration_ms": { "type": "integer", "minimum": 0 },
        "platform": { "$ref": "#/$defs/PlatformInfo" }
      }
    },
    "TargetInfo": {
      "type": "object",
      "description": "What `anc audit` was pointed at. `path` is the basename (never an absolute path — protects against home-dir PII leaks). Always-present-null keys keep consumer code simple.",
      "required": ["kind", "path", "command"],
      "additionalProperties": false,
      "properties": {
        "kind": { "type": "string", "enum": ["project", "binary", "command"] },
        "path": { "type": ["string", "null"] },
        "command": { "type": ["string", "null"] }
      }
    },
    "BadgeInfo": {
      "type": "object",
      "description": "Agent-native badge metadata derived from this run. `score_pct` is `pass / (pass + warn + fail)` rounded to an integer percent — Skips and Errors are excluded from both sides of the ratio. `eligible` is `true` iff `score_pct >= 80` and a tool slug was derivable. `embed_markdown` is populated only when `eligible` (do-not-nag contract); `scorecard_url` / `badge_url` are populated whenever a slug exists so below-floor regressions shift color rather than 404.",
      "required": ["eligible", "score_pct", "embed_markdown", "scorecard_url", "badge_url", "convention_url"],
      "additionalProperties": false,
      "properties": {
        "eligible": { "type": "boolean" },
        "score_pct": { "type": "integer", "minimum": 0, "maximum": 100 },
        "embed_markdown": { "type": ["string", "null"] },
        "scorecard_url": { "type": ["string", "null"], "format": "uri" },
        "badge_url": { "type": ["string", "null"], "format": "uri" },
        "convention_url": { "type": "string", "format": "uri", "const": "https://anc.dev/badge" }
      }
    }
  },
  "examples": [
    {
      "schema_version": "0.7",
      "results": [
        {
          "id": "p1-must-no-interactive",
          "label": "Non-interactive by default",
          "group": "P1",
          "layer": "behavioral",
          "status": "pass",
          "evidence": null,
          "confidence": "high",
          "tier": "must",
          "audit_id": "p1-non-interactive"
        }
      ],
      "summary": { "total": 1, "pass": 1, "warn": 0, "fail": 0, "opt_out": 0, "n_a": 0, "skip": 0, "error": 0 },
      "coverage_summary": {
        "must": { "total": 23, "verified": 17 },
        "should": { "total": 14, "verified": 9 },
        "may": { "total": 7, "verified": 3 }
      },
      "audience": "agent-optimized",
      "audit_profile": null,
      "spec_version": "0.4.0",
      "tool": { "name": "ripgrep", "binary": "rg", "version": "14.1.0" },
      "anc": { "version": "0.4.0" },
      "run": {
        "invocation": "anc --command ripgrep",
        "started_at": "2026-05-21T17:03:00Z",
        "duration_ms": 1240,
        "platform": { "os": "linux", "arch": "x86_64" }
      },
      "target": { "kind": "command", "path": null, "command": "ripgrep" },
      "badge": {
        "eligible": true,
        "score_pct": 100,
        "embed_markdown": "[![agent-native](https://anc.dev/badge/ripgrep.svg)](https://anc.dev/score/ripgrep)",
        "scorecard_url": "https://anc.dev/score/ripgrep",
        "badge_url": "https://anc.dev/badge/ripgrep.svg",
        "convention_url": "https://anc.dev/badge"
      }
    }
  ]
}