# Query geometry

Ask the engine what it measured and read the report without asserting anything.

Canonical page: https://www.geospec.xyz/docs/guides/query-geometry

A query reports a measurement instead of comparing it with an expectation, and it never throws: a refused query is a report with a diagnostic. Read `status` first; only `passed` carries a measurement.

**TypeScript**

Queries run on the assertion client. `createGeoSpecAssertionClient({ engine })` from `geospec/assertion-client` gives `client.query({ capability, subject, payload })`, and its subjects come from `createGeoSpecNativeModelLoader` in `geospec/runner/native` rather than the loader in `geospec/model`, which admits models for chains only. The demo's `check.ts` shows the setup.

**Python**

`query_geo(subject, capability, payload)` from `geospec` takes the model `load_model` returns, with the payload as a dict.

### 1. Query the plate [#1-query-the-plate]

```ts
await client.query({
  capability: 'analyzeBrep',
  subject: part,
});
await client.query({
  capability: 'inspectGeometry',
  subject: part,
  payload: {
    selectors: [{
      kind: 'axis',
      query: {
        axis: { direction: [0, 0, 1] },
      },
    }],
  },
});
```

`analyzeBrep` takes only the subject and reports the whole BRep inventory. `inspectGeometry` resolves selectors and reports what each one matched; this one asks for the axis along z, which is the bore. Change the selector to `{ kind: 'face', query: { surfaceType: 'plane' }, expect: 'many' }` and the report lists the plate's six planar faces with their normals and offsets.

### 2. Read a report [#2-read-a-report]

A query answers `passed` with its measurement in the evidence, or `refused` when the evidence it reads is missing or cannot decide, with a diagnostic naming the reason. It asserts nothing, so it never answers `failed`.

**TypeScript**

Read `report.status`, `report.evidence` and `report.diagnostics`.

**Python**

Read `report.result["status"]`, `report.result["evidence"]` and `report.diagnostics`; `report.passed` is the status as a boolean.

The bore selector reports:

```json
{
  "bounds": { "max": [5.0000001, 5.0000001, 20.0000001], "min": [-5.0000001, -5.0000001, -1e-7] },
  "center": [3.2862601528904634e-13, 5.731384959986079e-17, 10],
  "direction": [0, 0, 1],
  "kind": "axis",
  "name": "axis:whole#6",
  "radius": 5,
  "source": "selector"
}
```

`analyzeBrep` reports under `brep`: `boundingBox`, `circularHoles`, `circularHolePatterns`, `cylindricalFaces`, `planarFaces`, `chamferFeatures`, `filletFeatures`, `massProperties`, `topologyCounts`, `validity` and the topology the feature claims qualify. The plate's one hole reads `{ "axis": "z", "axisRange": { "max": 20, "min": 0 }, "center": [3.2862601528904634e-13, 5.731384959986079e-17, 10], "diameter": 10, "through": true }`.

### 3. Choose a query [#3-choose-a-query]

| Query                | Reads                                                                                                                                                                                  | On a mesh                                                                                                       |
| -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
| `analyzeBrep`        | The exact BRep inventory of a STEP subject.                                                                                                                                            | `refused`, `GEOSPEC_BREP_EVIDENCE_UNAVAILABLE`.                                                                 |
| `analyzeMesh`        | The triangles the engine measures: `triangleCount`, `vertexCount`, `watertight`, `boundingBox` and `meshQuality` with `signedVolume`, `surfaceArea` and per-triangle rows.             | The mesh itself; a STEP subject answers with the engine's own tessellation.                                     |
| `inspectGeometry`    | What each selector matched.                                                                                                                                                            | `body` selectors only; an `axis` or `face` selector answers `refused`, `GEOSPEC_SELECTOR_UNSUPPORTED_EVIDENCE`. |
| `analyzeMeshOverlap` | The shared volume of each pair of named components.                                                                                                                                    | Two or more named parts; a single body answers `refused`, `GEOSPEC_COMPONENT_PARTITION_INCONCLUSIVE`.           |
| `queryPmi`           | The product manufacturing information records of a STEP file; the plate's inventory has `"status": "empty"`.                                                                           | `refused`, `GEOSPEC_UNSUPPORTED_EVIDENCE`.                                                                      |
| `minimumDistance`    | The exact distance between two occurrences of an AP242 STEP assembly, a typed result in TypeScript and the report's `fact` in Python; see [Compare parts](https://www.geospec.xyz/docs/guides/compare-parts.mdx). | `refused`, `unsupported-evidence`.                                                                              |

A selector for `inspectGeometry` is an occurrence path string such as `'subject'`, or an object: `{ kind: 'occurrence', name }` takes a name or a regular expression, and `body`, `face`, `axis` and `plane` take a `query` such as `{ surfaceType: 'cylinder' }` or `{ normal: { direction: [0, 0, 1] } }`. `expect: 'many'` allows more than one match; a selector that matches nothing refuses the query with `GEOSPEC_SELECTOR_UNMATCHED`, and the report lists no matches.

## Variations [#variations]

**No negation.** A query states no expectation, so there is nothing to negate: `client.query` has no `.not` and `query_geo` no `not_`.

**A query is not a claim.** A report is a measurement to read, not a pass to count. When a spec needs the value to hold, write the matching claim, such as `toHaveCircularHole` from [Find holes and features](https://www.geospec.xyz/docs/guides/find-holes-and-features.mdx), so a wrong value fails.

**Budgets and the reference.** A query charges work units like a claim; [Set tolerances and budgets](https://www.geospec.xyz/docs/guides/set-tolerances-and-budgets.mdx) covers the accounting, and the [queries reference](https://www.geospec.xyz/docs/reference/queries.mdx#analyzebrep) lists every field.