changedOutput schema / properties / result / anyOf
Previous value: -[
- {
- "additionalProperties": false,
- "properties": {
- "_meta": {
- "additionalProperties": false,
- "description": "Canonical schema § 0.2 — present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == \"free\"`; absent on paid-tier responses.",
- "properties": {
- "deliverables": {
- "anyOf": [
- {
- "additionalProperties": false,
- "description": "Canonical schema § 0.3 — R2 signed URLs (24h TTL).",
- "properties": {
- "docx_url": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- },
- "dxf_url": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- },
- "expires_at": {
- "minLength": 1,
- "type": "string"
- },
- "pdf_url": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- },
- "xlsx_url": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- }
- },
- "required": [
- "expires_at"
- ],
- "type": "object"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- },
- "document_id": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- },
- "hint": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- },
- "issued_at": {
- "minLength": 1,
- "type": "string"
- },
- "output_mode": {
- "anyOf": [
- {
- "additionalProperties": false,
- "description": "Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``boq`` / ``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as \"capability missing\" (the box-culvert \"geometry\nbuilder isn't firing\" scare) rather than \"pared for size\": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) — both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\n— nothing is withheld, nothing to point at.",
- "properties": {
- "mode": {
- "enum": [
- "summary",
- "boq",
- "boq_with_backup"
- ],
- "type": "string"
- },
- "omitted_fields": {
- "items": {
- "type": "string"
- },
- "minItems": 1,
- "type": "array"
- },
- "retrieve_with": {
- "minLength": 1,
- "type": "string"
- }
- },
- "required": [
- "mode",
- "omitted_fields",
- "retrieve_with"
- ],
- "type": "object"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- },
- "rate_limit_remaining": {
- "anyOf": [
- {
- "minimum": 0,
- "type": "integer"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- },
- "request_id": {
- "minLength": 1,
- "type": "string"
- },
- "schema_version": {
- "const": "1.0.0",
- "default": "1.0.0",
- "type": "string"
- },
- "scope_boundary": {
- "anyOf": [
- {
- "additionalProperties": false,
- "description": "Canonical schema § 0.6 — surfaces what this assembly produces vs not.",
- "properties": {
- "not_in_scope": {
- "items": {
- "type": "string"
- },
- "type": "array"
- },
- "produced": {
- "items": {
- "type": "string"
- },
- "type": "array"
- },
- "recommended_companions": {
- "anyOf": [
- {
- "items": {
- "type": "string"
- },
- "type": "array"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- }
- },
- "required": [
- "produced",
- "not_in_scope"
- ],
- "type": "object"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- },
- "tier": {
- "enum": [
- "free",
- "paid"
- ],
- "type": "string"
- },
- "tier_upgrade": {
- "anyOf": [
- {
- "additionalProperties": false,
- "description": "Canonical schema § 0.7 — present on free-tier responses only.",
- "properties": {
- "available_tiers": {
- "items": {
- "additionalProperties": false,
- "description": "Canonical schema § 0.7 — single tier in the upgrade carousel.",
- "properties": {
- "billing": {
- "enum": [
- "one_off",
- "monthly",
- "annual"
- ],
- "type": "string"
- },
- "currency": {
- "enum": [
- "GBP",
- "SGD",
- "EUR",
- "USD",
- "CAD",
- "AUD",
- "NZD",
- "MYR"
- ],
- "type": "string"
- },
- "display_name": {
- "type": "string"
- },
- "price_local": {
- "type": "number"
- },
- "tier_slug": {
- "enum": [
- "7_day_pass",
- "solo",
- "studio",
- "practice"
- ],
- "type": "string"
- },
- "unlock_summary": {
- "minLength": 1,
- "type": "string"
- }
- },
- "required": [
- "tier_slug",
- "display_name",
- "price_local",
- "currency",
- "billing",
- "unlock_summary"
- ],
- "type": "object"
- },
- "type": "array"
- },
- "current_tier": {
- "const": "free",
- "default": "free",
- "type": "string"
- },
- "pass_credit": {
- "anyOf": [
- {
- "additionalProperties": false,
- "description": "Canonical schema § 0.7 — pass-credit upgrade hook.",
- "properties": {
- "amount_local": {
- "type": "number"
- },
- "applies_to": {
- "const": "solo_first_month",
- "default": "solo_first_month",
- "type": "string"
- },
- "currency": {
- "type": "string"
- },
- "redeemable_until": {
- "type": "string"
- }
- },
- "required": [
- "amount_local",
- "currency",
- "redeemable_until"
- ],
- "type": "object"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- },
- "pricing_url": {
- "default": "https://civilquants.com/pricing",
- "type": "string"
- }
- },
- "required": [
- "available_tiers"
- ],
- "type": "object"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- },
- "tos_url": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- },
- "upgrade_hint": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- },
- "warranty_disclaimer": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- }
- },
- "required": [
- "request_id",
- "issued_at",
- "tier"
- ],
- "type": "object"
- },
- "data": {
- "anyOf": [
- {
- "additionalProperties": false,
- "description": "Aggregated + per-section result for a sectioned assembly run.",
- "properties": {
- "aggregated_boq_rows": {
- "items": {
- "additionalProperties": false,
- "description": "Schema § 1.3 — a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant — NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.",
- "properties": {
- "amount": {
- "anyOf": [
- {
- "type": "number"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- },
- "attribution": {
- "minLength": 1,
- "type": "string"
- },
- "audit_id": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- },
- "description": {
- "minLength": 1,
- "type": "string"
- },
- "quantity": {
- "minimum": 0,
- "type": "number"
- },
- "rate": {
- "anyOf": [
- {
- "type": "number"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- },
- "unit": {
- "minLength": 1,
- "type": "string"
- },
- "work_section": {
- "minLength": 1,
- "type": "string"
- }
- },
- "required": [
- "work_section",
- "description",
- "quantity",
- "unit",
- "attribution"
- ],
- "type": "object"
- },
- "type": "array"
- },
- "assembly_slug": {
- "minLength": 1,
- "type": "string"
- },
- "parameters_used": {
- "additionalProperties": true,
- "type": "object"
- },
- "section_count": {
- "minimum": 1,
- "type": "integer"
- },
- "section_results": {
- "anyOf": [
- {
- "items": {
- "additionalProperties": false,
- "description": "Schema § 1.1 — the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers — the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars —\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).",
- "properties": {
- "assembly_slug": {
- "minLength": 1,
- "type": "string"
- },
- "audit_trail": {
- "anyOf": [
- {
- "items": {
- "additionalProperties": false,
- "description": "Schema § 1.7 — paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.",
- "properties": {
- "boq_row_index": {
- "minimum": 0,
- "type": "integer"
- },
- "derivation": {
- "minLength": 1,
- "type": "string"
- },
- "formula": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- },
- "id": {
- "minLength": 1,
- "type": "string"
- },
- "parameters_referenced": {
- "items": {
- "type": "string"
- },
- "type": "array"
- }
- },
- "required": [
- "id",
- "boq_row_index",
- "derivation"
- ],
- "type": "object"
- },
- "type": "array"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- },
- "boq_rows": {
- "items": {
- "additionalProperties": false,
- "description": "Schema § 1.3 — a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant — NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.",
- "properties": {
- "amount": {
- "anyOf": [
- {
- "type": "number"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- },
- "attribution": {
- "minLength": 1,
- "type": "string"
- },
- "audit_id": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- },
- "description": {
- "minLength": 1,
- "type": "string"
- },
- "quantity": {
- "minimum": 0,
- "type": "number"
- },
- "rate": {
- "anyOf": [
- {
- "type": "number"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- },
- "unit": {
- "minLength": 1,
- "type": "string"
- },
- "work_section": {
- "minLength": 1,
- "type": "string"
- }
- },
- "required": [
- "work_section",
- "description",
- "quantity",
- "unit",
- "attribution"
- ],
- "type": "object"
- },
- "type": "array"
- },
- "drawing": {
- "anyOf": [
- {
- "additionalProperties": false,
- "description": "Schema § 1.6a — inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview — present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle — the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.",
- "properties": {
- "entity_count": {
- "minimum": 0,
- "type": "integer"
- },
- "svg_b64": {
- "minLength": 1,
- "type": "string"
- },
- "unit_of_drawing": {
- "const": "m",
- "default": "m",
- "type": "string"
- },
- "viewbox_height": {
- "exclusiveMinimum": 0,
- "type": "number"
- },
- "viewbox_width": {
- "exclusiveMinimum": 0,
- "type": "number"
- },
- "viewbox_x": {
- "type": "number"
- },
- "viewbox_y": {
- "type": "number"
- }
- },
- "required": [
- "svg_b64",
- "viewbox_x",
- "viewbox_y",
- "viewbox_width",
- "viewbox_height",
- "entity_count"
- ],
- "type": "object"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- },
- "drawings": {
- "anyOf": [
- {
- "items": {
- "additionalProperties": false,
- "description": "Schema § 1.6 — paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.",
- "properties": {
- "drawing_type": {
- "enum": [
- "section",
- "plan",
- "elevation",
- "isometric",
- "detail"
- ],
- "type": "string"
- },
- "format": {
- "enum": [
- "DXF",
- "PDF",
- "SVG"
- ],
- "type": "string"
- },
- "layers": {
- "anyOf": [
- {
- "items": {
- "type": "string"
- },
- "type": "array"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- },
- "scale": {
- "minLength": 1,
- "type": "string"
- },
- "sheet_size": {
- "enum": [
- "A1",
- "A2",
- "A3",
- "A4"
- ],
- "type": "string"
- },
- "url": {
- "minLength": 1,
- "type": "string"
- }
- },
- "required": [
- "drawing_type",
- "format",
- "url",
- "sheet_size",
- "scale"
- ],
- "type": "object"
- },
- "type": "array"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- },
- "parameters_used": {
- "additionalProperties": false,
- "description": "Schema § 1.2 — the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\n— the bridge layer enforces this when wrapping engine output.",
- "properties": {
- "assumptions": {
- "items": {
- "type": "string"
- },
- "type": "array"
- },
- "engine_defaults": {
- "additionalProperties": true,
- "type": "object"
- },
- "user_supplied": {
- "additionalProperties": true,
- "type": "object"
- }
- },
- "type": "object"
- },
- "standard": {
- "enum": [
- "CESMM4",
- "NRM2",
- "SMM7",
- "MMHW"
- ],
- "type": "string"
- },
- "text_summary": {
- "maxLength": 2000,
- "minLength": 1,
- "type": "string"
- },
- "totals_summary": {
- "additionalProperties": false,
- "description": "Schema § 1.4 — totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{\"concrete_m3\": {...}, \"rebar_t\": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra=\"allow\")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.",
- "properties": {
- "entries": {
- "additionalProperties": {
- "additionalProperties": false,
- "description": "Schema § 1.4 — single material/work-class total entry.",
- "properties": {
- "quantity": {
- "minimum": 0,
- "type": "number"
- },
- "unit": {
- "minLength": 1,
- "type": "string"
- }
- },
- "required": [
- "quantity",
- "unit"
- ],
- "type": "object"
- },
- "type": "object"
- }
- },
- "type": "object"
- },
- "warnings": {
- "items": {
- "additionalProperties": false,
- "description": "Schema § 1.8 — a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity — it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers — a correctness/safety signal, not a paid feature.",
- "properties": {
- "affected_params": {
- "items": {
- "type": "string"
- },
- "type": "array"
- },
- "code": {
- "minLength": 1,
- "type": "string"
- },
- "detail": {
- "additionalProperties": {
- "type": "number"
- },
- "type": "object"
- },
- "message": {
- "minLength": 1,
- "type": "string"
- },
- "severity": {
- "enum": [
- "info",
- "advisory",
- "caution"
- ],
- "type": "string"
- }
- },
- "required": [
- "code",
- "severity",
- "message"
- ],
- "type": "object"
- },
- "type": "array"
- }
- },
- "required": [
- "assembly_slug",
- "standard",
- "parameters_used",
- "boq_rows",
- "totals_summary",
- "text_summary"
- ],
- "type": "object"
- },
- "type": "array"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- },
- "section_summary": {
- "items": {
- "additionalProperties": false,
- "description": "Cheap always-on per-section line: label + run length + totals.",
- "properties": {
- "label": {
- "minLength": 1,
- "type": "string"
- },
- "run_length": {
- "anyOf": [
- {
- "type": "number"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- },
- "totals_summary": {
- "additionalProperties": false,
- "description": "Schema § 1.4 — totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{\"concrete_m3\": {...}, \"rebar_t\": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra=\"allow\")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.",
- "properties": {
- "entries": {
- "additionalProperties": {
- "additionalProperties": false,
- "description": "Schema § 1.4 — single material/work-class total entry.",
- "properties": {
- "quantity": {
- "minimum": 0,
- "type": "number"
- },
- "unit": {
- "minLength": 1,
- "type": "string"
- }
- },
- "required": [
- "quantity",
- "unit"
- ],
- "type": "object"
- },
- "type": "object"
- }
- },
- "type": "object"
- }
- },
- "required": [
- "label",
- "totals_summary"
- ],
- "type": "object"
- },
- "type": "array"
- },
- "standard": {
- "enum": [
- "CESMM4",
- "NRM2",
- "SMM7",
- "MMHW"
- ],
- "type": "string"
- },
- "warnings": {
- "items": {
- "additionalProperties": false,
- "description": "A section-labelled geometry/advisory warning.",
- "properties": {
- "section_label": {
- "minLength": 1,
- "type": "string"
- },
- "warning": {
- "additionalProperties": false,
- "description": "Schema § 1.8 — a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity — it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers — a correctness/safety signal, not a paid feature.",
- "properties": {
- "affected_params": {
- "items": {
- "type": "string"
- },
- "type": "array"
- },
- "code": {
- "minLength": 1,
- "type": "string"
- },
- "detail": {
- "additionalProperties": {
- "type": "number"
- },
- "type": "object"
- },
- "message": {
- "minLength": 1,
- "type": "string"
- },
- "severity": {
- "enum": [
- "info",
- "advisory",
- "caution"
- ],
- "type": "string"
- }
- },
- "required": [
- "code",
- "severity",
- "message"
- ],
- "type": "object"
- }
- },
- "required": [
- "section_label",
- "warning"
- ],
- "type": "object"
- },
- "type": "array"
- }
- },
- "required": [
- "assembly_slug",
- "standard",
- "section_count",
- "section_summary",
- "aggregated_boq_rows"
- ],
- "type": "object"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- },
- "error": {
- "anyOf": [
- {
- "additionalProperties": false,
- "description": "Canonical schema § 0.4 — error payload returned in `MCPResponse.error`.",
- "properties": {
- "code": {
- "description": "Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) — clients use the flag to decide retry vs surface.",
- "enum": [
- "RATE_LIMIT_EXCEEDED",
- "TIER_INSUFFICIENT",
- "INVALID_INPUT",
- "SCHEMA_VERSION_MISMATCH",
- "SCHEMA_INVARIANT_VIOLATION",
- "UPSTREAM_TIMEOUT",
- "BACKEND_FAILURE",
- "IP_BLOCKED",
- "RESOURCE_NOT_FOUND",
- "RENDER_FAILURE",
- "OCR_LOW_CONFIDENCE",
- "MANUAL_REVIEW_REQUIRED",
- "ACCEPTANCE_REQUIRED",
- "INVALID_TOKEN"
- ],
- "type": "string"
- },
- "details": {
- "anyOf": [
- {
- "additionalProperties": true,
- "type": "object"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- },
- "message": {
- "minLength": 1,
- "type": "string"
- },
- "recoverable": {
- "type": "boolean"
- },
- "retry_after_seconds": {
- "anyOf": [
- {
- "minimum": 0,
- "type": "integer"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- }
- },
- "required": [
- "code",
- "message",
- "recoverable"
- ],
- "type": "object"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- }
- },
- "required": [
- "_meta"
- ],
- "type": "object"
- },
- {
- "additionalProperties": false,
- "properties": {
- "_meta": {
- "additionalProperties": false,
- "description": "Canonical schema § 0.2 — present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == \"free\"`; absent on paid-tier responses.",
- "properties": {
- "deliverables": {
- "anyOf": [
- {
- "additionalProperties": false,
- "description": "Canonical schema § 0.3 — R2 signed URLs (24h TTL).",
- "properties": {
- "docx_url": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- },
- "dxf_url": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- },
- "expires_at": {
- "minLength": 1,
- "type": "string"
- },
- "pdf_url": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- },
- "xlsx_url": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- }
- },
- "required": [
- "expires_at"
- ],
- "type": "object"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- },
- "document_id": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- },
- "hint": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- },
- "issued_at": {
- "minLength": 1,
- "type": "string"
- },
- "output_mode": {
- "anyOf": [
- {
- "additionalProperties": false,
- "description": "Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``boq`` / ``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as \"capability missing\" (the box-culvert \"geometry\nbuilder isn't firing\" scare) rather than \"pared for size\": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) — both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\n— nothing is withheld, nothing to point at.",
- "properties": {
- "mode": {
- "enum": [
- "summary",
- "boq",
- "boq_with_backup"
- ],
- "type": "string"
- },
- "omitted_fields": {
- "items": {
- "type": "string"
- },
- "minItems": 1,
- "type": "array"
- },
- "retrieve_with": {
- "minLength": 1,
- "type": "string"
- }
- },
- "required": [
- "mode",
- "omitted_fields",
- "retrieve_with"
- ],
- "type": "object"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- },
- "rate_limit_remaining": {
- "anyOf": [
- {
- "minimum": 0,
- "type": "integer"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- },
- "request_id": {
- "minLength": 1,
- "type": "string"
- },
- "schema_version": {
- "const": "1.0.0",
- "default": "1.0.0",
- "type": "string"
- },
- "scope_boundary": {
- "anyOf": [
- {
- "additionalProperties": false,
- "description": "Canonical schema § 0.6 — surfaces what this assembly produces vs not.",
- "properties": {
- "not_in_scope": {
- "items": {
- "type": "string"
- },
- "type": "array"
- },
- "produced": {
- "items": {
- "type": "string"
- },
- "type": "array"
- },
- "recommended_companions": {
- "anyOf": [
- {
- "items": {
- "type": "string"
- },
- "type": "array"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- }
- },
- "required": [
- "produced",
- "not_in_scope"
- ],
- "type": "object"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- },
- "tier": {
- "enum": [
- "free",
- "paid"
- ],
- "type": "string"
- },
- "tier_upgrade": {
- "anyOf": [
- {
- "additionalProperties": false,
- "description": "Canonical schema § 0.7 — present on free-tier responses only.",
- "properties": {
- "available_tiers": {
- "items": {
- "additionalProperties": false,
- "description": "Canonical schema § 0.7 — single tier in the upgrade carousel.",
- "properties": {
- "billing": {
- "enum": [
- "one_off",
- "monthly",
- "annual"
- ],
- "type": "string"
- },
- "currency": {
- "enum": [
- "GBP",
- "SGD",
- "EUR",
- "USD",
- "CAD",
- "AUD",
- "NZD",
- "MYR"
- ],
- "type": "string"
- },
- "display_name": {
- "type": "string"
- },
- "price_local": {
- "type": "number"
- },
- "tier_slug": {
- "enum": [
- "7_day_pass",
- "solo",
- "studio",
- "practice"
- ],
- "type": "string"
- },
- "unlock_summary": {
- "minLength": 1,
- "type": "string"
- }
- },
- "required": [
- "tier_slug",
- "display_name",
- "price_local",
- "currency",
- "billing",
- "unlock_summary"
- ],
- "type": "object"
- },
- "type": "array"
- },
- "current_tier": {
- "const": "free",
- "default": "free",
- "type": "string"
- },
- "pass_credit": {
- "anyOf": [
- {
- "additionalProperties": false,
- "description": "Canonical schema § 0.7 — pass-credit upgrade hook.",
- "properties": {
- "amount_local": {
- "type": "number"
- },
- "applies_to": {
- "const": "solo_first_month",
- "default": "solo_first_month",
- "type": "string"
- },
- "currency": {
- "type": "string"
- },
- "redeemable_until": {
- "type": "string"
- }
- },
- "required": [
- "amount_local",
- "currency",
- "redeemable_until"
- ],
- "type": "object"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- },
- "pricing_url": {
- "default": "https://civilquants.com/pricing",
- "type": "string"
- }
- },
- "required": [
- "available_tiers"
- ],
- "type": "object"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- },
- "tos_url": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- },
- "upgrade_hint": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- },
- "warranty_disclaimer": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- }
- },
- "required": [
- "request_id",
- "issued_at",
- "tier"
- ],
- "type": "object"
- },
- "data": {
- "default": null,
- "title": "Data"
- },
- "error": {
- "anyOf": [
- {
- "additionalProperties": false,
- "description": "Canonical schema § 0.4 — error payload returned in `MCPResponse.error`.",
- "properties": {
- "code": {
- "description": "Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) — clients use the flag to decide retry vs surface.",
- "enum": [
- "RATE_LIMIT_EXCEEDED",
- "TIER_INSUFFICIENT",
- "INVALID_INPUT",
- "SCHEMA_VERSION_MISMATCH",
- "SCHEMA_INVARIANT_VIOLATION",
- "UPSTREAM_TIMEOUT",
- "BACKEND_FAILURE",
- "IP_BLOCKED",
- "RESOURCE_NOT_FOUND",
- "RENDER_FAILURE",
- "OCR_LOW_CONFIDENCE",
- "MANUAL_REVIEW_REQUIRED",
- "ACCEPTANCE_REQUIRED",
- "INVALID_TOKEN"
- ],
- "type": "string"
- },
- "details": {
- "anyOf": [
- {
- "additionalProperties": true,
- "type": "object"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- },
- "message": {
- "minLength": 1,
- "type": "string"
- },
- "recoverable": {
- "type": "boolean"
- },
- "retry_after_seconds": {
- "anyOf": [
- {
- "minimum": 0,
- "type": "integer"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- }
- },
- "required": [
- "code",
- "message",
- "recoverable"
- ],
- "type": "object"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- }
- },
- "required": [
- "_meta"
- ],
- "type": "object"
- }
-]New value: +[
+ {
+ "additionalProperties": false,
+ "properties": {
+ "_meta": {
+ "additionalProperties": false,
+ "description": "Canonical schema § 0.2 — present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == \"free\"`; absent on paid-tier responses.",
+ "properties": {
+ "deliverables": {
+ "anyOf": [
+ {
+ "additionalProperties": false,
+ "description": "Canonical schema § 0.3 — R2 signed URLs (24h TTL).",
+ "properties": {
+ "docx_url": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ },
+ "dxf_url": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ },
+ "expires_at": {
+ "minLength": 1,
+ "type": "string"
+ },
+ "pdf_url": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ },
+ "xlsx_url": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ }
+ },
+ "required": [
+ "expires_at"
+ ],
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ },
+ "document_id": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ },
+ "hint": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ },
+ "issued_at": {
+ "minLength": 1,
+ "type": "string"
+ },
+ "output_mode": {
+ "anyOf": [
+ {
+ "additionalProperties": false,
+ "description": "Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as \"capability missing\" (the box-culvert \"geometry\nbuilder isn't firing\" scare) rather than \"pared for size\": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) — both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\n— nothing is withheld, nothing to point at.",
+ "properties": {
+ "mode": {
+ "enum": [
+ "summary",
+ "material_schedule",
+ "boq",
+ "boq_with_backup"
+ ],
+ "type": "string"
+ },
+ "omitted_fields": {
+ "items": {
+ "type": "string"
+ },
+ "minItems": 1,
+ "type": "array"
+ },
+ "retrieve_with": {
+ "minLength": 1,
+ "type": "string"
+ }
+ },
+ "required": [
+ "mode",
+ "omitted_fields",
+ "retrieve_with"
+ ],
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ },
+ "rate_limit_remaining": {
+ "anyOf": [
+ {
+ "minimum": 0,
+ "type": "integer"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ },
+ "request_id": {
+ "minLength": 1,
+ "type": "string"
+ },
+ "schema_version": {
+ "const": "1.0.0",
+ "default": "1.0.0",
+ "type": "string"
+ },
+ "scope_boundary": {
+ "anyOf": [
+ {
+ "additionalProperties": false,
+ "description": "Canonical schema § 0.6 — surfaces what this assembly produces vs not.",
+ "properties": {
+ "not_in_scope": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ "produced": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ "recommended_companions": {
+ "anyOf": [
+ {
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ }
+ },
+ "required": [
+ "produced",
+ "not_in_scope"
+ ],
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ },
+ "tier": {
+ "enum": [
+ "free",
+ "paid"
+ ],
+ "type": "string"
+ },
+ "tier_upgrade": {
+ "anyOf": [
+ {
+ "additionalProperties": false,
+ "description": "Canonical schema § 0.7 — present on free-tier responses only.",
+ "properties": {
+ "available_tiers": {
+ "items": {
+ "additionalProperties": false,
+ "description": "Canonical schema § 0.7 — single tier in the upgrade carousel.",
+ "properties": {
+ "billing": {
+ "enum": [
+ "one_off",
+ "monthly",
+ "annual"
+ ],
+ "type": "string"
+ },
+ "currency": {
+ "enum": [
+ "GBP",
+ "SGD",
+ "EUR",
+ "USD",
+ "CAD",
+ "AUD",
+ "NZD",
+ "MYR"
+ ],
+ "type": "string"
+ },
+ "display_name": {
+ "type": "string"
+ },
+ "price_local": {
+ "type": "number"
+ },
+ "tier_slug": {
+ "enum": [
+ "7_day_pass",
+ "solo",
+ "studio",
+ "practice"
+ ],
+ "type": "string"
+ },
+ "unlock_summary": {
+ "minLength": 1,
+ "type": "string"
+ }
+ },
+ "required": [
+ "tier_slug",
+ "display_name",
+ "price_local",
+ "currency",
+ "billing",
+ "unlock_summary"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "current_tier": {
+ "const": "free",
+ "default": "free",
+ "type": "string"
+ },
+ "pass_credit": {
+ "anyOf": [
+ {
+ "additionalProperties": false,
+ "description": "Canonical schema § 0.7 — pass-credit upgrade hook.",
+ "properties": {
+ "amount_local": {
+ "type": "number"
+ },
+ "applies_to": {
+ "const": "solo_first_month",
+ "default": "solo_first_month",
+ "type": "string"
+ },
+ "currency": {
+ "type": "string"
+ },
+ "redeemable_until": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "amount_local",
+ "currency",
+ "redeemable_until"
+ ],
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ },
+ "pricing_url": {
+ "default": "https://civilquants.com/pricing",
+ "type": "string"
+ }
+ },
+ "required": [
+ "available_tiers"
+ ],
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ },
+ "tos_url": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ },
+ "upgrade_hint": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ },
+ "warranty_disclaimer": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ }
+ },
+ "required": [
+ "request_id",
+ "issued_at",
+ "tier"
+ ],
+ "type": "object"
+ },
+ "data": {
+ "anyOf": [
+ {
+ "additionalProperties": false,
+ "description": "Aggregated + per-section result for a sectioned assembly run.",
+ "properties": {
+ "aggregated_boq_rows": {
+ "items": {
+ "additionalProperties": false,
+ "description": "Schema § 1.3 — a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant — NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.",
+ "properties": {
+ "amount": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ },
+ "attribution": {
+ "minLength": 1,
+ "type": "string"
+ },
+ "audit_id": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ },
+ "description": {
+ "minLength": 1,
+ "type": "string"
+ },
+ "quantity": {
+ "minimum": 0,
+ "type": "number"
+ },
+ "rate": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ },
+ "unit": {
+ "minLength": 1,
+ "type": "string"
+ },
+ "work_section": {
+ "minLength": 1,
+ "type": "string"
+ }
+ },
+ "required": [
+ "work_section",
+ "description",
+ "quantity",
+ "unit",
+ "attribution"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "assembly_slug": {
+ "minLength": 1,
+ "type": "string"
+ },
+ "parameters_used": {
+ "additionalProperties": true,
+ "type": "object"
+ },
+ "section_count": {
+ "minimum": 1,
+ "type": "integer"
+ },
+ "section_results": {
+ "anyOf": [
+ {
+ "items": {
+ "additionalProperties": false,
+ "description": "Schema § 1.1 — the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers — the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars —\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).",
+ "properties": {
+ "assembly_slug": {
+ "minLength": 1,
+ "type": "string"
+ },
+ "audit_trail": {
+ "anyOf": [
+ {
+ "items": {
+ "additionalProperties": false,
+ "description": "Schema § 1.7 — paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.",
+ "properties": {
+ "boq_row_index": {
+ "minimum": 0,
+ "type": "integer"
+ },
+ "derivation": {
+ "minLength": 1,
+ "type": "string"
+ },
+ "formula": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ },
+ "id": {
+ "minLength": 1,
+ "type": "string"
+ },
+ "parameters_referenced": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ }
+ },
+ "required": [
+ "id",
+ "boq_row_index",
+ "derivation"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ },
+ "boq_rows": {
+ "items": {
+ "additionalProperties": false,
+ "description": "Schema § 1.3 — a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant — NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.",
+ "properties": {
+ "amount": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ },
+ "attribution": {
+ "minLength": 1,
+ "type": "string"
+ },
+ "audit_id": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ },
+ "description": {
+ "minLength": 1,
+ "type": "string"
+ },
+ "quantity": {
+ "minimum": 0,
+ "type": "number"
+ },
+ "rate": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ },
+ "unit": {
+ "minLength": 1,
+ "type": "string"
+ },
+ "work_section": {
+ "minLength": 1,
+ "type": "string"
+ }
+ },
+ "required": [
+ "work_section",
+ "description",
+ "quantity",
+ "unit",
+ "attribution"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "drawing": {
+ "anyOf": [
+ {
+ "additionalProperties": false,
+ "description": "Schema § 1.6a — inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview — present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle — the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.",
+ "properties": {
+ "entity_count": {
+ "minimum": 0,
+ "type": "integer"
+ },
+ "svg_b64": {
+ "minLength": 1,
+ "type": "string"
+ },
+ "unit_of_drawing": {
+ "const": "m",
+ "default": "m",
+ "type": "string"
+ },
+ "viewbox_height": {
+ "exclusiveMinimum": 0,
+ "type": "number"
+ },
+ "viewbox_width": {
+ "exclusiveMinimum": 0,
+ "type": "number"
+ },
+ "viewbox_x": {
+ "type": "number"
+ },
+ "viewbox_y": {
+ "type": "number"
+ }
+ },
+ "required": [
+ "svg_b64",
+ "viewbox_x",
+ "viewbox_y",
+ "viewbox_width",
+ "viewbox_height",
+ "entity_count"
+ ],
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ },
+ "drawings": {
+ "anyOf": [
+ {
+ "items": {
+ "additionalProperties": false,
+ "description": "Schema § 1.6 — paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.",
+ "properties": {
+ "drawing_type": {
+ "enum": [
+ "section",
+ "plan",
+ "elevation",
+ "isometric",
+ "detail"
+ ],
+ "type": "string"
+ },
+ "format": {
+ "enum": [
+ "DXF",
+ "PDF",
+ "SVG"
+ ],
+ "type": "string"
+ },
+ "layers": {
+ "anyOf": [
+ {
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ },
+ "scale": {
+ "minLength": 1,
+ "type": "string"
+ },
+ "sheet_size": {
+ "enum": [
+ "A1",
+ "A2",
+ "A3",
+ "A4"
+ ],
+ "type": "string"
+ },
+ "url": {
+ "minLength": 1,
+ "type": "string"
+ }
+ },
+ "required": [
+ "drawing_type",
+ "format",
+ "url",
+ "sheet_size",
+ "scale"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ },
+ "parameters_used": {
+ "additionalProperties": false,
+ "description": "Schema § 1.2 — the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\n— the bridge layer enforces this when wrapping engine output.",
+ "properties": {
+ "assumptions": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ "engine_defaults": {
+ "additionalProperties": true,
+ "type": "object"
+ },
+ "user_supplied": {
+ "additionalProperties": true,
+ "type": "object"
+ }
+ },
+ "type": "object"
+ },
+ "standard": {
+ "enum": [
+ "CESMM4",
+ "NRM2",
+ "SMM7",
+ "MMHW"
+ ],
+ "type": "string"
+ },
+ "text_summary": {
+ "maxLength": 2000,
+ "minLength": 1,
+ "type": "string"
+ },
+ "totals_summary": {
+ "additionalProperties": false,
+ "description": "Schema § 1.4 — totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{\"concrete_m3\": {...}, \"rebar_t\": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra=\"allow\")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.",
+ "properties": {
+ "entries": {
+ "additionalProperties": {
+ "additionalProperties": false,
+ "description": "Schema § 1.4 — single material/work-class total entry.",
+ "properties": {
+ "quantity": {
+ "minimum": 0,
+ "type": "number"
+ },
+ "unit": {
+ "minLength": 1,
+ "type": "string"
+ }
+ },
+ "required": [
+ "quantity",
+ "unit"
+ ],
+ "type": "object"
+ },
+ "type": "object"
+ }
+ },
+ "type": "object"
+ },
+ "warnings": {
+ "items": {
+ "additionalProperties": false,
+ "description": "Schema § 1.8 — a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity — it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers — a correctness/safety signal, not a paid feature.",
+ "properties": {
+ "affected_params": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ "code": {
+ "minLength": 1,
+ "type": "string"
+ },
+ "detail": {
+ "additionalProperties": {
+ "type": "number"
+ },
+ "type": "object"
+ },
+ "message": {
+ "minLength": 1,
+ "type": "string"
+ },
+ "severity": {
+ "enum": [
+ "info",
+ "advisory",
+ "caution"
+ ],
+ "type": "string"
+ }
+ },
+ "required": [
+ "code",
+ "severity",
+ "message"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ }
+ },
+ "required": [
+ "assembly_slug",
+ "standard",
+ "parameters_used",
+ "boq_rows",
+ "totals_summary",
+ "text_summary"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ },
+ "section_summary": {
+ "items": {
+ "additionalProperties": false,
+ "description": "Cheap always-on per-section line: label + run length + totals.",
+ "properties": {
+ "label": {
+ "minLength": 1,
+ "type": "string"
+ },
+ "run_length": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ },
+ "totals_summary": {
+ "additionalProperties": false,
+ "description": "Schema § 1.4 — totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{\"concrete_m3\": {...}, \"rebar_t\": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra=\"allow\")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.",
+ "properties": {
+ "entries": {
+ "additionalProperties": {
+ "additionalProperties": false,
+ "description": "Schema § 1.4 — single material/work-class total entry.",
+ "properties": {
+ "quantity": {
+ "minimum": 0,
+ "type": "number"
+ },
+ "unit": {
+ "minLength": 1,
+ "type": "string"
+ }
+ },
+ "required": [
+ "quantity",
+ "unit"
+ ],
+ "type": "object"
+ },
+ "type": "object"
+ }
+ },
+ "type": "object"
+ }
+ },
+ "required": [
+ "label",
+ "totals_summary"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "standard": {
+ "enum": [
+ "CESMM4",
+ "NRM2",
+ "SMM7",
+ "MMHW"
+ ],
+ "type": "string"
+ },
+ "warnings": {
+ "items": {
+ "additionalProperties": false,
+ "description": "A section-labelled geometry/advisory warning.",
+ "properties": {
+ "section_label": {
+ "minLength": 1,
+ "type": "string"
+ },
+ "warning": {
+ "additionalProperties": false,
+ "description": "Schema § 1.8 — a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity — it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers — a correctness/safety signal, not a paid feature.",
+ "properties": {
+ "affected_params": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ "code": {
+ "minLength": 1,
+ "type": "string"
+ },
+ "detail": {
+ "additionalProperties": {
+ "type": "number"
+ },
+ "type": "object"
+ },
+ "message": {
+ "minLength": 1,
+ "type": "string"
+ },
+ "severity": {
+ "enum": [
+ "info",
+ "advisory",
+ "caution"
+ ],
+ "type": "string"
+ }
+ },
+ "required": [
+ "code",
+ "severity",
+ "message"
+ ],
+ "type": "object"
+ }
+ },
+ "required": [
+ "section_label",
+ "warning"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ }
+ },
+ "required": [
+ "assembly_slug",
+ "standard",
+ "section_count",
+ "section_summary",
+ "aggregated_boq_rows"
+ ],
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ },
+ "error": {
+ "anyOf": [
+ {
+ "additionalProperties": false,
+ "description": "Canonical schema § 0.4 — error payload returned in `MCPResponse.error`.",
+ "properties": {
+ "code": {
+ "description": "Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) — clients use the flag to decide retry vs surface.",
+ "enum": [
+ "RATE_LIMIT_EXCEEDED",
+ "TIER_INSUFFICIENT",
+ "INVALID_INPUT",
+ "SCHEMA_VERSION_MISMATCH",
+ "SCHEMA_INVARIANT_VIOLATION",
+ "UPSTREAM_TIMEOUT",
+ "BACKEND_FAILURE",
+ "IP_BLOCKED",
+ "RESOURCE_NOT_FOUND",
+ "RENDER_FAILURE",
+ "OCR_LOW_CONFIDENCE",
+ "MANUAL_REVIEW_REQUIRED",
+ "ACCEPTANCE_REQUIRED",
+ "INVALID_TOKEN"
+ ],
+ "type": "string"
+ },
+ "details": {
+ "anyOf": [
+ {
+ "additionalProperties": true,
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ },
+ "message": {
+ "minLength": 1,
+ "type": "string"
+ },
+ "recoverable": {
+ "type": "boolean"
+ },
+ "retry_after_seconds": {
+ "anyOf": [
+ {
+ "minimum": 0,
+ "type": "integer"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ }
+ },
+ "required": [
+ "code",
+ "message",
+ "recoverable"
+ ],
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ }
+ },
+ "required": [
+ "_meta"
+ ],
+ "type": "object"
+ },
+ {
+ "additionalProperties": false,
+ "properties": {
+ "_meta": {
+ "additionalProperties": false,
+ "description": "Canonical schema § 0.2 — present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == \"free\"`; absent on paid-tier responses.",
+ "properties": {
+ "deliverables": {
+ "anyOf": [
+ {
+ "additionalProperties": false,
+ "description": "Canonical schema § 0.3 — R2 signed URLs (24h TTL).",
+ "properties": {
+ "docx_url": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ },
+ "dxf_url": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ },
+ "expires_at": {
+ "minLength": 1,
+ "type": "string"
+ },
+ "pdf_url": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ },
+ "xlsx_url": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ }
+ },
+ "required": [
+ "expires_at"
+ ],
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ },
+ "document_id": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ },
+ "hint": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ },
+ "issued_at": {
+ "minLength": 1,
+ "type": "string"
+ },
+ "output_mode": {
+ "anyOf": [
+ {
+ "additionalProperties": false,
+ "description": "Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as \"capability missing\" (the box-culvert \"geometry\nbuilder isn't firing\" scare) rather than \"pared for size\": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) — both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\n— nothing is withheld, nothing to point at.",
+ "properties": {
+ "mode": {
+ "enum": [
+ "summary",
+ "material_schedule",
+ "boq",
+ "boq_with_backup"
+ ],
+ "type": "string"
+ },
+ "omitted_fields": {
+ "items": {
+ "type": "string"
+ },
+ "minItems": 1,
+ "type": "array"
+ },
+ "retrieve_with": {
+ "minLength": 1,
+ "type": "string"
+ }
+ },
+ "required": [
+ "mode",
+ "omitted_fields",
+ "retrieve_with"
+ ],
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ },
+ "rate_limit_remaining": {
+ "anyOf": [
+ {
+ "minimum": 0,
+ "type": "integer"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ },
+ "request_id": {
+ "minLength": 1,
+ "type": "string"
+ },
+ "schema_version": {
+ "const": "1.0.0",
+ "default": "1.0.0",
+ "type": "string"
+ },
+ "scope_boundary": {
+ "anyOf": [
+ {
+ "additionalProperties": false,
+ "description": "Canonical schema § 0.6 — surfaces what this assembly produces vs not.",
+ "properties": {
+ "not_in_scope": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ "produced": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ "recommended_companions": {
+ "anyOf": [
+ {
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ }
+ },
+ "required": [
+ "produced",
+ "not_in_scope"
+ ],
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ },
+ "tier": {
+ "enum": [
+ "free",
+ "paid"
+ ],
+ "type": "string"
+ },
+ "tier_upgrade": {
+ "anyOf": [
+ {
+ "additionalProperties": false,
+ "description": "Canonical schema § 0.7 — present on free-tier responses only.",
+ "properties": {
+ "available_tiers": {
+ "items": {
+ "additionalProperties": false,
+ "description": "Canonical schema § 0.7 — single tier in the upgrade carousel.",
+ "properties": {
+ "billing": {
+ "enum": [
+ "one_off",
+ "monthly",
+ "annual"
+ ],
+ "type": "string"
+ },
+ "currency": {
+ "enum": [
+ "GBP",
+ "SGD",
+ "EUR",
+ "USD",
+ "CAD",
+ "AUD",
+ "NZD",
+ "MYR"
+ ],
+ "type": "string"
+ },
+ "display_name": {
+ "type": "string"
+ },
+ "price_local": {
+ "type": "number"
+ },
+ "tier_slug": {
+ "enum": [
+ "7_day_pass",
+ "solo",
+ "studio",
+ "practice"
+ ],
+ "type": "string"
+ },
+ "unlock_summary": {
+ "minLength": 1,
+ "type": "string"
+ }
+ },
+ "required": [
+ "tier_slug",
+ "display_name",
+ "price_local",
+ "currency",
+ "billing",
+ "unlock_summary"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "current_tier": {
+ "const": "free",
+ "default": "free",
+ "type": "string"
+ },
+ "pass_credit": {
+ "anyOf": [
+ {
+ "additionalProperties": false,
+ "description": "Canonical schema § 0.7 — pass-credit upgrade hook.",
+ "properties": {
+ "amount_local": {
+ "type": "number"
+ },
+ "applies_to": {
+ "const": "solo_first_month",
+ "default": "solo_first_month",
+ "type": "string"
+ },
+ "currency": {
+ "type": "string"
+ },
+ "redeemable_until": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "amount_local",
+ "currency",
+ "redeemable_until"
+ ],
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ },
+ "pricing_url": {
+ "default": "https://civilquants.com/pricing",
+ "type": "string"
+ }
+ },
+ "required": [
+ "available_tiers"
+ ],
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ },
+ "tos_url": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ },
+ "upgrade_hint": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ },
+ "warranty_disclaimer": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ }
+ },
+ "required": [
+ "request_id",
+ "issued_at",
+ "tier"
+ ],
+ "type": "object"
+ },
+ "data": {
+ "default": null,
+ "title": "Data"
+ },
+ "error": {
+ "anyOf": [
+ {
+ "additionalProperties": false,
+ "description": "Canonical schema § 0.4 — error payload returned in `MCPResponse.error`.",
+ "properties": {
+ "code": {
+ "description": "Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) — clients use the flag to decide retry vs surface.",
+ "enum": [
+ "RATE_LIMIT_EXCEEDED",
+ "TIER_INSUFFICIENT",
+ "INVALID_INPUT",
+ "SCHEMA_VERSION_MISMATCH",
+ "SCHEMA_INVARIANT_VIOLATION",
+ "UPSTREAM_TIMEOUT",
+ "BACKEND_FAILURE",
+ "IP_BLOCKED",
+ "RESOURCE_NOT_FOUND",
+ "RENDER_FAILURE",
+ "OCR_LOW_CONFIDENCE",
+ "MANUAL_REVIEW_REQUIRED",
+ "ACCEPTANCE_REQUIRED",
+ "INVALID_TOKEN"
+ ],
+ "type": "string"
+ },
+ "details": {
+ "anyOf": [
+ {
+ "additionalProperties": true,
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ },
+ "message": {
+ "minLength": 1,
+ "type": "string"
+ },
+ "recoverable": {
+ "type": "boolean"
+ },
+ "retry_after_seconds": {
+ "anyOf": [
+ {
+ "minimum": 0,
+ "type": "integer"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ }
+ },
+ "required": [
+ "code",
+ "message",
+ "recoverable"
+ ],
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ }
+ },
+ "required": [
+ "_meta"
+ ],
+ "type": "object"
+ }
+]