{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "manni:ai-context:1.0.0",
  "title": "manni ai-context vocabulary v1.0.0",
  "description": "How machines made and may use this page: production provenance (`provenance`, `meta-provenance`) and consumption guidance (`risks`, `sample-questions`). `provenance` pins the body lines a machine wrote, and is managed by `manni meta derive`. `meta-provenance` is the family's human-review loop for metadata: machines propose fields and evals, and entries retire as humans review them. `risks` uses the open-enum idiom: recommended flags anchored in published prior art, any string legal, unknown values read as caution rather than absence. The machines that wrote a page are the distinct `generated-by` values across its `provenance` entries.",
  "type": "object",
  "additionalProperties": true,
  "properties": {
    "provenance": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/provenanceEntry"
      },
      "description": "Which body lines a machine wrote: one entry per range, each naming the machine, the lines, and a pin over them. Lines are body lines, counted after the frontmatter as for a citation's claim. `lines` is where the pin was last seen and `integrity` is its identity, so a range that moves keeps its entry and a range whose text changes loses it. The field is managed by `manni meta derive`, which reads the evidence from git; `fill` never proposes it. Humans never appear here, because `authors` carries them. The machines that wrote the page are the distinct `generated-by` values across its entries, and a page no machine wrote has no `provenance`. They are what the self-preference-bias check reads: a judge is grading its own author when its model is among the machines attributed for what it grades. By the eval's `target`, that is the machines here for `body` (the default), the machines in `meta-provenance` for `frontmatter`, both for `raw`, and none for a companion file (`{source: file, path}`), which carries its own record if it is a page. The check covers the whole body, because `target` has no lines form. A knowledge-graph harvest reads the page's machines from here too. Complementary to `meta-provenance`, which attributes the page's metadata.",
      "minItems": 1,
      "uniqueItems": true,
      "x-manni-location": "external"
    },
    "meta-provenance": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/metaProvenanceEntry"
      },
      "description": "Attribution for machine-proposed metadata, one entry per model (consumers merge by generated-by; the schema dedupes identical entries): which fields and which evals it proposed, at what confidence. The human-review trail for enrichment — a human deletes an entry once its fields and evals are reviewed, so a surviving entry means unreviewed machine metadata. Not managed and not derived: whoever proposes the values writes the entry. `manni meta fill` writes it for the fields it writes, in the same write: it merges into the entry whose `generated-by` is the run's model (the first such entry, if a person has made two), appending the written fields' JSON Pointers, escaped per RFC 6901 so a key `a/b` is `/a~1b`, after the entry's existing ones and setting their `confidence`; when the run's model has no entry, it appends one. Re-encrypting an existing value in place proposes nothing and is not recorded. `meta-provenance` is never proposed to a model: `fill` skips it as a candidate and leaves it out of the metadata it sends. One key serves the whole family, from page fields to proposed evals and the `graph` block. Complementary to `provenance`, which attributes the page's prose line by line.",
      "minItems": 1,
      "uniqueItems": true,
      "x-manni-location": "external"
    },
    "risks": {
      "if": {
        "type": "array"
      },
      "then": {
        "type": "array",
        "minItems": 1,
        "uniqueItems": true,
        "items": {
          "$ref": "#/$defs/riskFlag"
        }
      },
      "else": {
        "$ref": "#/$defs/riskFlag"
      },
      "description": "Flags for what following this page does, each a pre-flight question for an agent or reviewer. Cautions: `cost-incurring` (spends money), `destructive` (changes or deletes existing state), `irreversible` (cannot be undone), `privileged` (needs elevated permissions), `open-world` (reaches external systems beyond your control). Assurances: `read-only` (changes nothing) and `idempotent` (safe to repeat) — worth stating explicitly, because an unannotated page is unassessed, not safe. The last three mirror MCP's tool annotations (readOnlyHint, destructiveHint, idempotentHint, openWorldHint), the published prior art for agent-facing hints. All seven are recommendations, not a closed list: any non-empty string is legal, and a consumer switching on a flag should treat an unknown value as caution rather than absence.",
      "x-manni-location": "page"
    },
    "sample-questions": {
      "if": {
        "type": "array"
      },
      "then": {
        "type": "array",
        "minItems": 1,
        "uniqueItems": true,
        "items": {
          "type": "string",
          "minLength": 1
        }
      },
      "else": {
        "type": "string",
        "minLength": 1
      },
      "description": "One question, or a list of them, that a reader would ask that this page should answer — `How do I install the operator on EKS?`. The retrieval-eval hook: ask them against the corpus and measure whether this page carries the answer. Assertion-style per-page evals belong to manni:evals:1.0.0, not here.",
      "x-manni-location": "page"
    }
  },
  "$defs": {
    "provenanceEntry": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "generated-by",
        "lines",
        "integrity"
      ],
      "description": "One machine-written range of the body: who wrote it, where it was last seen, and the pin that identifies it.",
      "properties": {
        "generated-by": {
          "type": "string",
          "minLength": 1,
          "description": "The model, agent, or tool that wrote these lines."
        },
        "lines": {
          "$ref": "#/$defs/lines",
          "description": "Lines of the page body, counted after the frontmatter as for a citation's claim: the body starts on the first line after the closing frontmatter fence, or on line 1 with no frontmatter. This is where the pin was last seen, not the entry's identity; `derive` rewrites it when the text moves."
        },
        "integrity": {
          "type": "string",
          "pattern": "^sha256-[0-9a-f]{64}$",
          "description": "`sha256-` and sixty-four lowercase hex digits over the lines, under the hashing rule manni:citations:1.0.0 states. The pin, and the entry's identity. Always plain sha256, never keyed: the page is public, so there is nothing to hide."
        }
      }
    },
    "metaProvenanceEntry": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "generated-by"
      ],
      "anyOf": [
        {
          "required": [
            "fields"
          ]
        },
        {
          "required": [
            "evals"
          ]
        }
      ],
      "description": "One model's proposals: which metadata values and which evals it proposed, at what confidence. At least one of `fields` or `evals` is required, because an entry naming neither says nothing.",
      "properties": {
        "generated-by": {
          "type": "string",
          "minLength": 1,
          "description": "Model or agent that proposed the fields or evals."
        },
        "fields": {
          "type": "array",
          "minItems": 1,
          "items": {
            "type": "string",
            "pattern": "^/"
          },
          "uniqueItems": true,
          "description": "The metadata values it proposed, as JSON Pointers: the same form `validate` reports. `/intent` names a top-level key and `/graph/label` reaches into a block. Pointers let one entry shape cover every vocabulary stacked on the document."
        },
        "evals": {
          "type": "array",
          "minItems": 1,
          "items": {
            "type": "string",
            "pattern": "^[a-z0-9][a-z0-9-]*$"
          },
          "uniqueItems": true,
          "description": "The evals it proposed, by kebab id, so a reordered eval list does not orphan them."
        },
        "confidence": {
          "type": "object",
          "propertyNames": {
            "pattern": "^(?:/.*|[a-z0-9][a-z0-9-]*)$"
          },
          "additionalProperties": {
            "type": "number",
            "minimum": 0,
            "maximum": 1
          },
          "description": "Model confidence, 0..1, keyed by a pointer from `fields` or an id from `evals`. The two key forms cannot collide: a pointer starts with `/` and an id cannot. A confidence attached to a malformed key fails here instead of dangling."
        }
      }
    },
    "lines": {
      "oneOf": [
        {
          "type": "integer",
          "minimum": 1
        },
        {
          "type": "string",
          "pattern": "^[1-9][0-9]*-[1-9][0-9]*$"
        }
      ],
      "description": "A line range, 1-based and inclusive: an integer for one line, or `\"L1-L2\"` for several. `L1 <= L2` is a rule on implementations, since a pattern cannot compare two numbers. There is no line 0 to cite."
    },
    "riskFlag": {
      "anyOf": [
        {
          "type": "string",
          "minLength": 1
        },
        {
          "enum": [
            "cost-incurring",
            "destructive",
            "irreversible",
            "privileged",
            "open-world",
            "read-only",
            "idempotent"
          ]
        }
      ],
      "description": "One risk flag: a recommended value, or any non-empty string. The enum branch is advisory — it feeds editor completion, docs, and fill proposals; the open string branch keeps an org-specific flag a correct document rather than a violation."
    }
  }
}
