{
  "openapi": "3.1.0",
  "info": {
    "title": "ICM Brihaddesi Grammar API",
    "version": "v1",
    "description": "REST API exposing the structured grammar extracted from the Brihaddesi (Mātaṅga ~750 CE, ed. Sharma 1992 IGNCA). Every response is materialized on-the-fly from the pipeline SQLite DB — DB is the single source of truth. JSON contract for machine consumption, with DSL v1.1 text view for editorial use."
  },
  "servers": [
    {
      "url": "/api/v1"
    }
  ],
  "tags": [
    {
      "name": "Sources",
      "description": "Books and their metadata"
    },
    {
      "name": "Concepts",
      "description": "Concept-clusters extracted across the corpus"
    },
    {
      "name": "Families",
      "description": "Grammar families (jati, svara_role, etc.) with schemas + records"
    },
    {
      "name": "Pages",
      "description": "Source pages and their content"
    },
    {
      "name": "Structures",
      "description": "Vision-extracted structural content (tables, diagrams, sequences)"
    },
    {
      "name": "Rules",
      "description": "Generative rules — operations/procedures extracted from the corpus (step 7c)"
    },
    {
      "name": "Search",
      "description": "Full-text search"
    }
  ],
  "paths": {
    "/rules": {
      "get": {
        "tags": [
          "Rules"
        ],
        "summary": "Generative rules (step 7c)",
        "parameters": [
          {
            "name": "family",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "category",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "construction",
                "transformation",
                "derivation",
                "validation",
                "position",
                "classification"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Rules list"
          }
        }
      }
    },
    "/rules/{rule_id}": {
      "get": {
        "tags": [
          "Rules"
        ],
        "summary": "Single generative rule",
        "parameters": [
          {
            "name": "rule_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Rule with inputs/output/body/evidence"
          },
          "404": {
            "description": "Not found"
          }
        }
      }
    },
    "/sources": {
      "get": {
        "tags": [
          "Sources"
        ],
        "summary": "List sources",
        "responses": {
          "200": {
            "description": "List of books in the corpus"
          }
        }
      }
    },
    "/sources/{source_id}": {
      "get": {
        "tags": [
          "Sources"
        ],
        "summary": "Source metadata + stats",
        "parameters": [
          {
            "name": "source_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Source details"
          },
          "404": {
            "description": "Not found"
          }
        }
      }
    },
    "/concepts": {
      "get": {
        "tags": [
          "Concepts"
        ],
        "summary": "Paginated concept list",
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 1
            }
          },
          {
            "name": "per_page",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50
            }
          },
          {
            "name": "type",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "majority_type filter"
          },
          {
            "name": "dico",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "yes",
                "no",
                ""
              ]
            }
          },
          {
            "name": "family",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "dico_category filter"
          },
          {
            "name": "q",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "search in canonical/key"
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "pages",
                "occurrences",
                "affirmations",
                "degree",
                "alpha"
              ],
              "default": "pages"
            }
          },
          {
            "name": "order",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ],
              "default": "desc"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated list with total + concepts array"
          }
        }
      }
    },
    "/concepts/{cluster_id}": {
      "get": {
        "tags": [
          "Concepts"
        ],
        "summary": "Full concept (variants + record + affirmations)",
        "parameters": [
          {
            "name": "cluster_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Concept object"
          },
          "404": {
            "description": "Not found"
          }
        }
      }
    },
    "/concepts/{cluster_id}/relations": {
      "get": {
        "tags": [
          "Concepts"
        ],
        "summary": "Concept's in+out edges from the graph",
        "parameters": [
          {
            "name": "cluster_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{out: [...], in: [...]}"
          }
        }
      }
    },
    "/concepts/{cluster_id}/rules": {
      "get": {
        "tags": [
          "Concepts"
        ],
        "summary": "Generative rules attached to a concept",
        "parameters": [
          {
            "name": "cluster_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of rules for that concept"
          },
          "404": {
            "description": "Concept not found"
          }
        }
      }
    },
    "/concepts/{cluster_id}/dsl": {
      "get": {
        "tags": [
          "Concepts"
        ],
        "summary": "DSL v1.1 pseudocode text",
        "parameters": [
          {
            "name": "cluster_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Plain text DSL",
            "content": {
              "text/plain": {}
            }
          }
        }
      }
    },
    "/families": {
      "get": {
        "tags": [
          "Families"
        ],
        "summary": "List grammar families",
        "responses": {
          "200": {
            "description": "Families summary"
          }
        }
      }
    },
    "/families/{name}": {
      "get": {
        "tags": [
          "Families"
        ],
        "summary": "Family schema + instances",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Family object"
          },
          "404": {
            "description": "Not found"
          }
        }
      }
    },
    "/pages": {
      "get": {
        "tags": [
          "Pages"
        ],
        "summary": "List pages",
        "responses": {
          "200": {
            "description": "Pages list"
          }
        }
      }
    },
    "/pages/{page_id}": {
      "get": {
        "tags": [
          "Pages"
        ],
        "summary": "Page text + its affirmations",
        "parameters": [
          {
            "name": "page_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Page object"
          },
          "404": {
            "description": "Not found"
          }
        }
      }
    },
    "/structures": {
      "get": {
        "tags": [
          "Structures"
        ],
        "summary": "Structural extracts (step 6c)",
        "responses": {
          "200": {
            "description": "Per-page structural data"
          }
        }
      }
    },
    "/search": {
      "get": {
        "tags": [
          "Search"
        ],
        "summary": "Search concepts + affirmations",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 30
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Search results"
          }
        }
      }
    }
  }
}