{
  "lexicon": 1,
  "id": "sh.tangled.query.enrichResponse",
  "defs": {
    "main": {
      "type": "procedure",
      "description": "like calling an xrpc query directly, but the response comes back with a stats sidecar: aggregate counts (stars, follows, issues...) for every did / at-uri / strong-ref found in the response. counts are computed synchronously from the server's local index, so there are no pending states to resolve later. any GET query the server implements can be hydrated, including queries it proxies elsewhere.",
      "input": {
        "encoding": "application/json",
        "schema": {
          "type": "object",
          "required": [
            "xrpc",
            "enrich"
          ],
          "properties": {
            "xrpc": {
              "type": "string",
              "format": "nsid",
              "description": "NSID of the inner query to run, e.g. sh.tangled.repo.listRepos."
            },
            "params": {
              "type": "unknown",
              "description": "Parameters for the inner query, exactly as it declares them."
            },
            "enrich": {
              "type": "array",
              "items": {
                "type": "ref",
                "ref": "#linkDescriptor"
              },
              "description": "Counts to compute for each found reference. A descriptor only applies to references it can meaningfully point at: a did can carry author-side counts (.repo), an at-uri can carry subject-side counts."
            },
            "sources": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "description": "RecordPaths into the inner response restricting which references get counted. When omitted, every did / at-uri / strong-ref in the response is counted. Paths that match nothing yield empty stats rather than an error."
            },
            "viewer": {
              "type": "string",
              "format": "did",
              "description": "DID whose own relation to each reference is looked up for viewer-type descriptors, e.g. whether this did starred the found repo and with which record. Required when any enrich descriptor uses type viewer."
            }
          }
        }
      },
      "output": {
        "encoding": "application/json",
        "schema": {
          "type": "object",
          "required": [
            "output",
            "stats"
          ],
          "properties": {
            "output": {
              "type": "unknown",
              "description": "The inner query's response, unmodified."
            },
            "stats": {
              "type": "unknown",
              "description": "Reference value (did or at-uri) -> link source (echoed verbatim from the request) -> aggregation results. Example: stats[\"did:plc:...\"][\"sh.tangled.graph.follow:subject\"] = {\"count\": 12, \"distinctAuthors\": 11}."
            }
          }
        }
      },
      "errors": [
        {
          "name": "UnknownQuery",
          "description": "The xrpc parameter does not name a query this server can execute."
        },
        {
          "name": "InvalidSourcePath",
          "description": "A sources entry is not valid RecordPath syntax."
        },
        {
          "name": "InvalidLinkDescriptor",
          "description": "An enrich entry names an unknown collection, or a path the server's index does not support."
        }
      ]
    },
    "linkDescriptor": {
      "type": "object",
      "required": [
        "source",
        "type"
      ],
      "description": "one aggregate count: records whose reference field equals the found reference, addressed by a constellation-style link source (\"collection:recordpath\"). envelope paths (.repo etc.) address the record's own metadata instead of its contents.",
      "properties": {
        "source": {
          "type": "string",
          "description": "Link source: the collection whose records are counted, a colon, then a RecordPath naming the reference field (e.g. sh.tangled.feed.star:subject, sh.tangled.feed.star:subject.uri), or an envelope field: .repo (authoring repo), .collection, .rkey, or bare . (the record's own at-uri)."
        },
        "type": {
          "type": "string",
          "knownValues": ["count", "distinctAuthors", "viewer"],
          "description": "What to compute over matching records: how many records (count), how many distinct authors (distinctAuthors), or the viewer's own record among the matches (viewer, requires the top-level viewer param). Results land in the stats sidecar at stats[ref][source][type]."
        }
      }
    }
  }
}
