{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "https://aidid.im/schemas/did/canonical-resolve.schema.json",
  "title": "AIDID canonical resolve HTTP envelope",
  "description": "JSON body of the canonical AIDID resolve endpoint. Request: `GET {agent_api}/agent/v1/aidid/resolve?did=<did>` (equivalently `/agent/v1/aidid/resolve/{did}`) with `accept: application/json`; the client aborts after 8000 ms by default. Success is `{\"data\": <record>}`; a did-not-found / invalid-DID / registry-unavailable failure is `{\"error_code\": <number>}`. A **deactivated** DID still answers with HTTP 200 and `data.deactivated=true`. `data.record_state` MUST equal `deactivated ? \"deactivated\" : \"active\"`; any disagreement makes the answer `invalid_response`. The registry also fails closed: HTTP 200 with `data.status=\"blocked\"` (equivalently error_code 3001) means the canonical mapping is unavailable — that is a third real wire variant and is modelled explicitly as `#/$defs/blocked` (it is NOT a DID record).",
  "type": "object",
  "properties": {
    "data": {
      "oneOf": [
        {
          "$ref": "#/$defs/canonicalRecord"
        },
        {
          "$ref": "#/$defs/blocked"
        }
      ]
    },
    "error_code": {
      "type": "number",
      "enum": [
        1001,
        3001,
        3002,
        6001
      ],
      "description": "Agent API error code: 1001 invalid DID, 3001 canonical mapping unavailable (fail-closed), 3002 on-chain record invalid, 6001 DID not found."
    }
  },
  "oneOf": [
    {
      "required": [
        "data"
      ]
    },
    {
      "required": [
        "error_code"
      ]
    }
  ],
  "$defs": {
    "canonicalRecord": {
      "title": "Canonical AIDID record",
      "description": "The flat canonical record carried in `data` for an active or deactivated DID.",
      "type": "object",
      "required": [
        "did",
        "document",
        "owner",
        "version_id",
        "created",
        "updated",
        "deactivated"
      ],
      "properties": {
        "did": {
          "type": "string",
          "pattern": "^did:msg:[A-Za-z0-9._-]+$"
        },
        "document": {
          "$ref": "#/$defs/didDocument"
        },
        "owner": {
          "type": "string",
          "pattern": "^msg[0-9a-f]{40}[0-9a-f]$",
          "description": "On-chain owner (the registering transaction sender).",
          "x-aidid": {
            "note": "44 字符**账户**地址，绝不是 bech32：`msg` + 40 hex payload + 1 位节点校验 hex。合约地址是 42 字符标准 bech32，二者不可混用（SPEC-DID v1.6 §1/§5，MSGChain H-2）。"
          }
        },
        "version_id": {
          "type": "number",
          "minimum": 0,
          "description": "Monotonic version, +1 on every update."
        },
        "created": {
          "type": "number",
          "minimum": 0,
          "description": "Block time (seconds) when the DID was created."
        },
        "updated": {
          "type": "number",
          "minimum": 0,
          "description": "Block time (seconds) of the last update."
        },
        "deactivated": {
          "type": "boolean",
          "description": "Lifecycle flag. Emitted explicitly as `false` for an active record."
        },
        "record_state": {
          "enum": [
            "active",
            "deactivated"
          ],
          "description": "Canonical record lifecycle state. Must equal `deactivated ? \"deactivated\" : \"active\"`, else the answer is treated as `invalid_response`."
        },
        "status": {
          "const": "resolved"
        },
        "height": {
          "type": [
            "number",
            "null"
          ],
          "description": "Committed height at resolve time (not the write height), or `null`."
        }
      }
    },
    "didDocument": {
      "title": "DID Document",
      "type": "object",
      "additionalProperties": false,
      "required": [
        "id",
        "verification_method"
      ],
      "properties": {
        "id": {
          "type": "string",
          "pattern": "^did:msg:[A-Za-z0-9._-]+$",
          "description": "The DID this document belongs to. Must equal the record `did`."
        },
        "controller": {
          "type": [
            "array",
            "null"
          ],
          "items": {
            "type": "string",
            "pattern": "^did:msg:[A-Za-z0-9._-]+$"
          },
          "description": "Controller DIDs, or `null`. `[local.id]` is what the current implementation writes."
        },
        "verification_method": {
          "type": "array",
          "minItems": 1,
          "items": {
            "$ref": "#/$defs/verificationMethod"
          },
          "description": "At least one verification method is required (chain rejects an empty list)."
        },
        "authentication": {
          "type": [
            "array",
            "null"
          ],
          "items": {
            "type": "string"
          },
          "description": "Verification method references, or `null`. Chain does not validate them."
        },
        "assertion_method": {
          "type": [
            "array",
            "null"
          ],
          "items": {
            "type": "string"
          },
          "description": "Verification method references, or `null`. Chain does not validate them."
        },
        "service": {
          "type": [
            "array",
            "null"
          ],
          "items": {
            "$ref": "#/$defs/serviceEndpoint"
          },
          "description": "Service endpoints, or `null`. Chain does not validate service fields."
        }
      }
    },
    "verificationMethod": {
      "title": "Verification Method",
      "description": "One verification method of a DID document. Field names are the CosmWasm snake_case contract names.",
      "type": "object",
      "additionalProperties": false,
      "required": [
        "id",
        "controller",
        "verification_method_type",
        "public_key_multibase"
      ],
      "properties": {
        "id": {
          "type": "string",
          "minLength": 1,
          "description": "`<did>#key-1` in the current implementation. The contract only requires the id to exist inside the document."
        },
        "controller": {
          "type": "string",
          "minLength": 1,
          "description": "Controller DID. Equal to the owning DID in the current implementation."
        },
        "verification_method_type": {
          "type": "string",
          "minLength": 1,
          "description": "Verification method type string. Stored verbatim by the chain; NOT validated there.",
          "x-aidid": {
            "note": "自由字符串：链侧（contracts/did-contract/src/state.rs）仅存储、不校验（SPEC-DID v1.6 §3 / H-7）。本仓生产 signer 值 = `Dilithium5VerificationKey2025`，浏览器 bridge 值 = `EcdsaP384BridgeVerificationKey2025`；任何非空字符串都能通过链侧。若未来链侧开始校验，官方称会提前通知。"
          }
        },
        "public_key_multibase": {
          "type": "string",
          "pattern": "^z[A-Za-z0-9+/]+={0,2}$",
          "description": "Multibase-encoded public key: `z` + base64. The `z` prefix is mandatory (SPEC-DID v1.6 §3).",
          "x-aidid": {
            "note": "`z` + base64。Dilithium-5 公钥 2592 字节 ⇒ base64 3456 字符 ⇒ 该字符串 `z` + 3456 = 3457 字符（无 padding）。bridge 路径是 `z` + SPKI(base64)。"
          }
        }
      }
    },
    "serviceEndpoint": {
      "title": "Service Endpoint",
      "description": "One service entry of a DID document (`ServiceEndpoint` in the contract state).",
      "type": "object",
      "additionalProperties": false,
      "required": [
        "id",
        "service_type",
        "service_endpoint"
      ],
      "properties": {
        "id": {
          "type": "string",
          "minLength": 1
        },
        "service_type": {
          "type": "string",
          "minLength": 1
        },
        "service_endpoint": {
          "type": "string",
          "minLength": 1
        }
      }
    },
    "blocked": {
      "title": "Canonical registry unavailable (fail-closed)",
      "description": "HTTP 200 with `data.status=\"blocked\"` — the canonical AIDID mapping is unavailable. This is NOT a DID record and the client must fail closed (equivalent to error_code 3001).",
      "type": "object",
      "required": [
        "status"
      ],
      "properties": {
        "status": {
          "const": "blocked"
        }
      },
      "x-aidid": {
        "note": "Third real wire variant from `classifyCanonicalResolveResponse` (frontend/lib/msgCanonicalRegistry.ts): HTTP 200 + data.status==='blocked' ⇒ endpoint_unavailable."
      }
    }
  },
  "examples": [
    {
      "data": {
        "did": "did:msg:qJoURrDO2wbAgVqLlc9jEw",
        "document": {
          "id": "did:msg:qJoURrDO2wbAgVqLlc9jEw",
          "controller": null,
          "verification_method": [
            {
              "id": "did:msg:qJoURrDO2wbAgVqLlc9jEw#key-1",
              "controller": "did:msg:qJoURrDO2wbAgVqLlc9jEw",
              "verification_method_type": "Dilithium5VerificationKey2025",
              "public_key_multibase": "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"
            }
          ],
          "authentication": [
            "did:msg:qJoURrDO2wbAgVqLlc9jEw#key-1"
          ],
          "assertion_method": null,
          "service": null
        },
        "owner": "msg255f8e675fd764ce2a3d26b824184eddb63641462",
        "version_id": 1,
        "created": 1789000000,
        "updated": 1789000000,
        "deactivated": false,
        "record_state": "active",
        "status": "resolved",
        "height": 1
      }
    },
    {
      "error_code": 6001
    }
  ],
  "x-aidid": {
    "spec": {
      "doc": "AIDID_DID规范_v1.md",
      "section": "§8.4",
      "version": "v1.6"
    },
    "status": "external-pending",
    "source": [
      "frontend/lib/msgCanonicalRegistry.ts#classifyCanonicalResolveResponse",
      "frontend/lib/msgCanonicalRegistry.ts#AIDID_RESOLVE_ERROR_CODES",
      "frontend/lib/msgCanonicalRegistry.ts#buildCanonicalResolveUrl",
      "frontend/lib/msgResolver.ts#CanonicalAididRecord"
    ],
    "note": "公网 Agent API endpoint 尚未授权（AIDID 侧被 13197 无 CORS / 《窗口参数》阻塞），故整体 status = `external-pending`；字段形状本身按 devnet 实测的 A7 wire 契约（SPEC-DID §8.4）书写。响应来自链侧，因此本 schema **不设 `additionalProperties:false`**：`reason_code`/`error`/`message`/`blocker` 等额外字段一律忽略。deactivated 记录返回 HTTP 200 且 `deactivated=true`；`status=\"resolved\"` 永远不能单独当作 active 的证据。",
    "enumBindings": [
      {
        "pointer": "/properties/error_code/enum",
        "source": "AIDID_RESOLVE_ERROR_CODES"
      }
    ],
    "honestLimit": "真实网络调用尚未取得授权；示例由仓内 fixture 构造（active 记录），deactivated/404/3001 分支目前只有单测与录制形状，没有公网实测。"
  }
}
