{"openapi":"3.1.0","info":{"title":"ARCNM","version":"0.1.0"},"paths":{"/api/v1/uploads/presign":{"post":{"tags":["uploads"],"summary":"Presign","operationId":"uploads-presign","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PresignRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PresignResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/uploads/confirm":{"post":{"tags":["uploads"],"summary":"Confirm","operationId":"uploads-confirm","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/uploads/":{"get":{"tags":["uploads"],"summary":"List Uploads","description":"List the org's uploads, hiding cancelled rows by default.\n\nCancelled uploads are useless — the file may have been written to\nstorage but the download endpoint refuses to serve it (status gate\nis ``confirmed`` only). They just clutter the picker, so the UI gets\nthem filtered out unless an admin explicitly opts in via\n``?include_cancelled=true`` (e.g. for an audit view).","operationId":"uploads-list_uploads","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"include_cancelled","in":"query","required":false,"schema":{"type":"boolean","description":"Include cancelled uploads in the list (hidden by default).","default":false,"title":"Include Cancelled"},"description":"Include cancelled uploads in the list (hidden by default)."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/DataSourcePublic"},"title":"Response Uploads-List Uploads"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/uploads/{data_source_id}/cancel":{"post":{"tags":["uploads"],"summary":"Cancel Upload","description":"Mark a pending upload as ``cancelled``.\n\nIdempotent for already-cancelled rows; rejects rows that have moved\npast ``pending`` since cancelling a confirmed file would silently\ndelete a valid artefact.","operationId":"uploads-cancel_upload","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"data_source_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Data Source Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DataSourcePublic"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/uploads/{data_source_id}/retry":{"post":{"tags":["uploads"],"summary":"Retry Upload","description":"Re-queue the confirm worker for a non-confirmed upload.","operationId":"uploads-retry_upload","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"data_source_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Data Source Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DataSourcePublic"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/uploads/bulk-cancel":{"post":{"tags":["uploads"],"summary":"Bulk Cancel Uploads","description":"Cancel many pending uploads at once.\n\nPer-row failures are reported in ``skipped`` so the UI can render a\nsummary toast — the whole batch isn't rolled back if a single id is\nalready confirmed. We cap the batch size to keep a single request\nbounded.","operationId":"uploads-bulk_cancel_uploads","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkUploadIds"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkUploadResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/uploads/bulk-retry":{"post":{"tags":["uploads"],"summary":"Bulk Retry Uploads","description":"Re-queue many uploads at once.","operationId":"uploads-bulk_retry_uploads","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkUploadIds"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkUploadResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/uploads/{data_source_id}/download-url":{"get":{"tags":["uploads"],"summary":"Download Url","operationId":"uploads-download_url","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"data_source_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Data Source Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DownloadUrlResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/materials/standards":{"get":{"tags":["parts"],"summary":"List Standards","operationId":"parts-list_standards","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MaterialStandardPublic"},"title":"Response Parts-List Standards"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/materials/grades":{"get":{"tags":["parts"],"summary":"List Grades","description":"List canonical grades.\n\n``q`` searches across ``primary_code``, ``display_code``, ``name``,\n``urn`` AND every alias's ``code``/``display_code``. A user typing\n\"AISI 304\", \"SUS304\" or \"S30400\" therefore finds 1.4301 from this\nsingle endpoint — no need to fall back to POST ``/lookup``.\n\nReturns the **total** matching row count (not page size) so the\nfrontend can paginate properly.","operationId":"parts-list_grades","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"category","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/MaterialCategory"},{"type":"null"}],"description":"Filter by material category (e.g. stainless_steel, aluminium).","title":"Category"},"description":"Filter by material category (e.g. stainless_steel, aluminium)."},{"name":"iso_group","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/IsoMachiningGroup"},{"type":"null"}],"description":"Filter by ISO 513 machining group (P, M, K, N, S, H).","title":"Iso Group"},"description":"Filter by ISO 513 machining group (P, M, K, N, S, H)."},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string","minLength":1,"maxLength":128},{"type":"null"}],"description":"Free-text search across grade codes, names, URNs, and aliases.","title":"Q"},"description":"Free-text search across grade codes, names, URNs, and aliases."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":100,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MaterialGradesPublic"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/materials/grades/{grade_id}":{"get":{"tags":["parts"],"summary":"Get Grade","operationId":"parts-get_grade","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"grade_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Grade Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MaterialGradePublic"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/materials/grades/by-urn/{urn}":{"get":{"tags":["parts"],"summary":"Get Grade By Urn","operationId":"parts-get_grade_by_urn","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"urn","in":"path","required":true,"schema":{"type":"string","description":"Material grade URN to resolve (e.g. urn:material:cen:1.4301).","title":"Urn"},"description":"Material grade URN to resolve (e.g. urn:material:cen:1.4301)."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MaterialGradePublic"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/materials/lookup":{"post":{"tags":["parts"],"summary":"Lookup","operationId":"parts-lookup","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MaterialLookupRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MaterialLookupResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/materials/lookup/batch":{"post":{"tags":["parts"],"summary":"Lookup Batch","description":"Bulk-resolve up to 100 queries in one round-trip.\n\nDrawing extractors emit N candidate strings per part; the worker\nand the frontend typeahead both call this endpoint instead of N\nindividual ``/lookup`` requests. Misses are returned in-band with\n``result=null`` so callers can correlate hits/misses by position.","operationId":"parts-lookup_batch","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MaterialLookupBatchRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MaterialLookupBatchResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/materials/overrides":{"get":{"tags":["parts"],"summary":"List Overrides","operationId":"parts-list_overrides","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OrgMaterialOverridePublic"},"title":"Response Parts-List Overrides"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["parts"],"summary":"Create Override","operationId":"parts-create_override","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgMaterialOverrideCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgMaterialOverridePublic"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/materials/overrides/{override_id}":{"patch":{"tags":["parts"],"summary":"Update Override","description":"Partial update. Only fields explicitly present in the body are\napplied — pass ``null`` to clear a field, omit to leave unchanged.","operationId":"parts-update_override","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"override_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Override Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgMaterialOverrideUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgMaterialOverridePublic"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["parts"],"summary":"Delete Override","operationId":"parts-delete_override","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"override_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Override Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/app__modules__parts__routes__materials__DeleteMessage"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/environments/":{"get":{"tags":["parts","parts"],"summary":"List Environments","operationId":"parts-list_environments","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":200,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentPublic"},"title":"Response Parts-List Environments"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/environments/{env_id}":{"get":{"tags":["parts","parts"],"summary":"Get Environment","operationId":"parts-get_environment","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"env_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Env Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentDetail"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["parts","parts"],"summary":"Update Environment","description":"Update the tenant-controllable extractor list on an environment.\n\nThe canonical geometry source (`arcnm`) is always retained.\n\nTenant-scoped: a 404 is returned for env ids belonging to other\norgs so we never confirm cross-tenant existence.","operationId":"parts-update_environment","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"env_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Env Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentExtractorUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentPublic"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["parts","parts"],"summary":"Delete Environment","description":"Delete an environment. ON DELETE CASCADE on the rate + machine-\nmembership tables means the rates + memberships disappear with it;\nthe underlying ``MachineDefinition`` rows survive (they're org-\nscoped, not env-scoped, and may be reused by sibling envs).","operationId":"parts-delete_environment","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"env_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Env Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/environments":{"post":{"tags":["parts","parts"],"summary":"Create Environment","operationId":"parts-create_environment","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentPublic"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/environments/{env_id}/identity":{"put":{"tags":["parts","parts"],"summary":"Update Environment Identity","operationId":"parts-update_environment_identity","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"env_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Env Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentIdentityUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentPublic"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/environments/{env_id}/machines":{"get":{"tags":["parts","parts"],"summary":"List Env Machines","description":"Machines wired to this env, ordered by `fleet_priority` (lower =\nearlier candidate). Engine-agnostic — the same fleet feeds ARCNM\ntoday and is reused as-is by any future engine via a shared\nresolver.","operationId":"parts-list_env_machines","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"env_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Env Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EnvMachineRowPublic"},"title":"Response Parts-List Env Machines"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["parts","parts"],"summary":"Attach Machine","operationId":"parts-attach_machine","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"env_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Env Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttachMachineRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvMachineRowPublic"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/environments/{env_id}/machines/{membership_id}":{"patch":{"tags":["parts","parts"],"summary":"Update Membership","operationId":"parts-update_membership","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"env_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Env Id"}},{"name":"membership_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Membership Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MembershipUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvMachineRowPublic"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["parts","parts"],"summary":"Detach Machine","operationId":"parts-detach_machine","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"env_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Env Id"}},{"name":"membership_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Membership Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/environments/{env_id}/rates":{"get":{"tags":["parts","parts"],"summary":"List Rates","description":"List all rates for an env, uniformly shaped so the rate editor\ncan render every kind side by side. Optional `?kind=` filter.","operationId":"parts-list_rates","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"env_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Env Id"}},{"name":"kind","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter to a single rate kind (labour, overhead, material, or fx).","title":"Kind"},"description":"Filter to a single rate kind (labour, overhead, material, or fx)."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RateRowPublicOut"},"title":"Response Parts-List Rates"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["parts","parts"],"summary":"Upsert Rate","description":"Create a rate row of the requested kind. Effective-dated: the new\nrow's `valid_from` opens a window; the previous active row's\n`valid_to` should be capped by the caller.","operationId":"parts-upsert_rate","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"env_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Env Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateUpsert"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateRowPublicOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/environments/{env_id}/rates/{kind}/{rate_id}":{"delete":{"tags":["parts","parts"],"summary":"Delete Rate","operationId":"parts-delete_rate","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"env_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Env Id"}},{"name":"kind","in":"path","required":true,"schema":{"type":"string","description":"Rate kind to delete (labour, overhead, material, or fx).","title":"Kind"},"description":"Rate kind to delete (labour, overhead, material, or fx)."},{"name":"rate_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Rate Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/calibration/outcomes":{"post":{"tags":["parts","parts"],"summary":"Submit calibration observations for an environment.","description":"Submit a batch of observations (predicted vs. actual outcomes) for an environment so it can be calibrated. Tenant-bound; ``scope='environment'`` only. Safe for AI agent use: idempotent on each observation's natural key and rate-limited by the global tenant policy. Recalibrate the environment afterwards to apply the accumulated observations.","operationId":"parts-calibration-ingest-environment-outcomes","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OutcomeIngestPayload"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalibrationResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/calibration/environments/{env_id}/finalize":{"post":{"tags":["parts","parts"],"summary":"Recalibrate an environment from its accumulated observations.","description":"Recalibrate this environment for the selected target metric using every observation submitted for it so far, then activate the result. Use after submitting observations. To start from raw ERP actuals without submitting observations first, use the one-click auto-calibrate endpoint instead.","operationId":"parts-calibration-finalize-environment","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"env_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Env Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FinalizeRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalibrationResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/calibration/environments/{env_id}/teach":{"post":{"tags":["parts","parts"],"summary":"Calibrate an environment from (predicted, actual) pairs.","description":"Calibrate an environment from caller-supplied (predicted, actual) rows. Each ``predicted`` value must come from a current quote for the part. If you only have actuals, use the one-click auto-calibrate endpoint, which re-quotes each part server-side.","operationId":"parts-calibration-teach-environment","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"env_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Env Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeachRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalibrationResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/calibration/environments/{env_id}/auto-calibrate":{"post":{"tags":["parts","parts"],"summary":"One-click environment calibration from (part_revision_id, actual_unit_cost) rows.","description":"The headline customer-facing endpoint — turn a list of ERP actual unit costs into a calibrated environment in one call. The server re-quotes every part with the environment's current pricing so the result reflects your true cost delta. Parts with no prior successful quote are returned in ``unmatched_part_ids`` so you can quote them and retry. Safe for AI-agent use over MCP and idempotent: the same set of actuals yields the same result.","operationId":"parts-calibration-auto-calibrate-environment","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"env_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Env Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutoCalibrateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalibrationResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/calibration/environments/{env_id}/auto-calibrate-from-erp":{"post":{"tags":["parts","parts"],"summary":"Calibrate an env from raw ERP work-order rows.","description":"ERP-native variant of ``auto-calibrate``: accepts the raw columns most ERPs export (part_number, work_order_id, quantity, total_cost) and handles part-number resolution + unit-cost derivation server-side. Idempotent on work_order_id.","operationId":"parts-calibration-auto-calibrate-from-erp","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"env_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Env Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErpAutoCalibrateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalibrationResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/calibration/environments/{env_id}/learning-curve-fit":{"post":{"tags":["parts","parts"],"summary":"Calibrate cost-down-with-volume from lot-progression actuals.","description":"Calibrate how this environment's per-unit cost falls as cumulative production grows, using a sequence of production-lot actuals for one part. Choose the cumulative model (the safer default, observed directly) or the per-unit model. Submit at least three lots.","operationId":"parts-calibration-fit-learning-curve","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"env_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Env Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LearningCurveFitRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalibrationResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/calibration/conformal-recalibrate":{"post":{"tags":["parts","parts"],"summary":"Recalibrate an environment's prediction interval from recent samples.","description":"Recalibrate the prediction interval applied to priced quotes from a fresh set of (predicted, actual) samples. Once updated, subsequent quotes use the new interval. A monthly cadence is the recommended default; submit fresh samples whenever your recent outcomes have shifted.","operationId":"parts-calibration-conformal-recalibrate","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConformalRecalibrateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalibrationResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/calibration/environments/{env_id}/policy/calibrate":{"post":{"tags":["parts","parts"],"summary":"Calibrate which machine an environment recommends from past choices.","description":"Calibrate how this environment chooses a machine, using a list of historical 'the shop actually picked machine X' decisions. Once calibrated, the environment's machine recommendations better match your shop's real choices.","operationId":"parts-calibration-calibrate-selection-policy","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"env_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Env Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PolicyCalibrateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalibrationResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/calibration/environments/{env_id}/status":{"get":{"tags":["parts","parts"],"summary":"Calibration health summary for one environment.","description":"Read view of an environment's calibration health: whether it is calibrated, when it was last calibrated, and how many submitted observations are waiting to be applied. Designed as the AI agent's discovery endpoint — call this first to decide whether to submit fresh observations or recalibrate.","operationId":"parts-calibration-environment-status","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"env_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Env Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalibrationStatusResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/calculations":{"post":{"tags":["parts","parts"],"summary":"Create a calculation (queued)","description":"Create a new Calculation row tied to (revision × env × dataset). Does NOT enqueue — call ``POST /parts/calculations/{id}/run`` to schedule.\n\nOne engine (**ARCNM**), one endpoint. The platform chooses the right drawing-understanding depth per calculation automatically. The optional ``extraction_tier`` field lets you override that depth — ``auto`` (default), ``lite`` (faster), or ``full`` (deepest); most callers should leave it unset.","operationId":"parts-create_calculation","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalculationCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalculationStatus"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["parts","parts"],"summary":"List Calculations","description":"List recent calculations for the tenant.\n\nReturns the most recent ``limit`` rows ordered by ``created_at``\ndescending with a slim projection — no analytics blob, to keep the\nlist response cheap.\n\nOptional ``part_id`` narrows the result to a single part.","operationId":"parts-list_calculations","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Limit"}},{"name":"status_filter","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by lifecycle status (e.g. queued, running, succeeded, failed, cancelled).","title":"Status Filter"},"description":"Filter by lifecycle status (e.g. queued, running, succeeded, failed, cancelled)."},{"name":"part_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Part Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalculationListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/calculations/{calculation_id}/run":{"post":{"tags":["parts","parts"],"summary":"Run Calculation","description":"Enqueue the calculation onto the worker queue.\n\nIdempotent: a row in a non-terminal state (queued/running/polling)\nis not re-enqueued; a row in ``succeeded`` is returned untouched;\na row in ``failed``/``cancelled``/``timed_out`` is reset to\n``queued`` and re-enqueued so the user can retry.","operationId":"parts-run_calculation","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"calculation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Calculation Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalculationStatus"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/calculations/{calculation_id}/inputs":{"post":{"tags":["parts","parts"],"summary":"Upload Inputs","description":"Attach a 2D drawing PDF / STL mesh / RFQ text file to the calculation.\n\nThe file is stored against the calculation's part revision under the\nrequested ``role``. Subsequent ``POST /run`` calls auto-discover it\nby role so the pipeline can fan out additional extractors (drawing,\nmesh fallback, RFQ text) alongside the primary geometry pass.","operationId":"parts-upload_inputs","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"calculation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Calculation Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_parts-upload_inputs"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadInputsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/calculations/{calculation_id}":{"get":{"tags":["parts","parts"],"summary":"Get Calculation","operationId":"parts-get_calculation","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"calculation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Calculation Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalculationDetailResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["parts","parts"],"summary":"Delete Calculation","description":"Hard-delete a calculation row.\n\nA non-terminal row is first cancelled (which releases the wallet\nhold) so the worker can no longer transition it; the row itself is\nthen removed. Use Cancel if you want the audit trail to persist.","operationId":"parts-delete_calculation","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"calculation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Calculation Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalculationDeleteResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/calculations/{calculation_id}/material":{"patch":{"tags":["parts","parts"],"summary":"Patch Calculation Material","description":"Override the material on an existing calculation.\n\nThe new ``material_grade_id`` is resolved exactly the same way\n``POST /parts/calculations`` resolves it on create, so the result is\nconsistent with the create-time logic.\n\nThe calculation isn't re-priced here — follow up with ``POST /run``\nif a re-quote is desired. The explicit two-step flow lets you review\nthe override before paying for another pipeline pass.","operationId":"parts-patch_calculation_material","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"calculation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Calculation Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalculationMaterialPatch"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalculationMaterialPatchResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/calculations/quote":{"post":{"tags":["parts","parts"],"summary":"Quote","description":"Convenience: create + enqueue in one round-trip.\n\nEquivalent to ``POST / + POST /{id}/run``.","operationId":"parts-quote","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalculationCreate"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalculationStatus"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/calculations/upload-and-quote":{"post":{"tags":["parts","parts"],"summary":"Upload And Quote","description":"One-shot upload + new-calculation flow.\n\nTakes a STEP file (+ optional 2D drawing PDF + RFQ text), creates\nthe underlying Part / PartRevision / dataset rows, and enqueues\nthe calculation. This is the simplest end-to-end UX — the user\ngoes from \"I have a CAD file\" to \"I'll see a quote in 30 s\"\nwith one HTTP call.\n\nIdempotency: ``part_number`` is the natural key — if a Part with\nthe same number already exists for this tenant, we attach a new\nrevision rather than re-creating the Part.","operationId":"parts-upload_and_quote","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_parts-upload_and_quote"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalculationStatus"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/calculations/{calculation_id}/cancel":{"post":{"tags":["parts","parts"],"summary":"Cancel Calculation","description":"Cancel a queued / running / polling calculation.\n\nIdempotent: a terminal row is returned untouched. The wallet hold\nis released as part of the transition so a cancelled calc never\ndebits the org's balance.","operationId":"parts-cancel_calculation","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"calculation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Calculation Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalculationStatus"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/calculations/bulk-cancel":{"post":{"tags":["parts","parts"],"summary":"Bulk Cancel Calculations","operationId":"parts-bulk_cancel_calculations","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkCalculationRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkCalculationResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/calculations/bulk-retry":{"post":{"tags":["parts","parts"],"summary":"Bulk Retry Calculations","description":"Re-enqueue eligible failed/cancelled/timed_out rows.\n\nEach row goes through the same place-hold + enqueue path as a\ndirect `POST /run` so wallet semantics and attempt budgets are\nenforced identically. A row that's already running, succeeded,\nor out of attempt budget lands in `skipped`.","operationId":"parts-bulk_retry_calculations","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkCalculationRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkCalculationResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/calculations/bulk-delete":{"post":{"tags":["parts","parts"],"summary":"Bulk Delete Calculations","operationId":"parts-bulk_delete_calculations","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkCalculationRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkCalculationResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/calculations/{calculation_id}/select-machine":{"post":{"tags":["parts","parts"],"summary":"Select Machine","description":"Run geometry extraction and machine selection only, returning the rationale.\n\nCheaper than a full calculation (skips planning, physics, and\neconomics); typical latency 200–800 ms for a 10-machine fleet.","operationId":"parts-select_machine","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"calculation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Calculation Id"}},{"name":"X-Request-ID","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Optional client-supplied request ID; reused as an idempotency key for the metered charge.","title":"X-Request-Id"},"description":"Optional client-supplied request ID; reused as an idempotency key for the metered charge."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Idempotency-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SelectionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/{part_id}/revisions/{revision_id}/datasets":{"get":{"tags":["parts"],"summary":"List Datasets","operationId":"parts-list_datasets","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}},{"name":"revision_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Revision Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PartRevisionDatasetPublic"},"title":"Response Parts-List Datasets"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["parts"],"summary":"Attach Dataset","description":"Attach an existing DataSource row to a revision.\n\nFor a fresh file upload, prefer ``POST .../datasets/upload`` which\ncreates the DataSource + link in one shot.","operationId":"parts-attach_dataset","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}},{"name":"revision_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Revision Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DatasetAttach"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartRevisionDatasetPublic"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/{part_id}/revisions/{revision_id}/datasets/upload":{"post":{"tags":["parts"],"summary":"Upload Dataset","description":"Upload a file directly onto a revision, in one shot.\n\nStores the file and links it to the revision. No calculation is\nenqueued — use ``/parts/calculations/upload`` for the\ncalculate-on-upload flow.","operationId":"parts-upload_dataset","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}},{"name":"revision_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Revision Id"}},{"name":"role","in":"query","required":false,"schema":{"type":"string","description":"Role of the file on the revision (e.g. cad_3d for a 3D model, drawing_2d for a 2D drawing).","default":"cad_3d","title":"Role"},"description":"Role of the file on the revision (e.g. cad_3d for a 3D model, drawing_2d for a 2D drawing)."},{"name":"is_primary","in":"query","required":false,"schema":{"type":"boolean","description":"Whether this dataset becomes the primary one for its role on the revision.","default":true,"title":"Is Primary"},"description":"Whether this dataset becomes the primary one for its role on the revision."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_parts-upload_dataset"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartRevisionDatasetPublic"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/{part_id}/revisions/{revision_id}/datasets/{dataset_link_id}":{"patch":{"tags":["parts"],"summary":"Update Dataset","description":"Edit a dataset link.\n\nCurrently supports two fields:\n  - ``filename``: rename the underlying ``DataSource``.\n  - ``is_primary``: promote/demote within the parent revision. The\n    \"exactly one primary\" invariant is maintained server-side: when\n    promoting, every other link on the same revision is demoted in\n    the same transaction so concurrent primaries can't co-exist.","operationId":"parts-update_dataset","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}},{"name":"revision_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Revision Id"}},{"name":"dataset_link_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Dataset Link Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartRevisionDatasetUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartRevisionDatasetPublic"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["parts"],"summary":"Detach Dataset","operationId":"parts-detach_dataset","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}},{"name":"revision_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Revision Id"}},{"name":"dataset_link_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Dataset Link Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DetachMessage"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/":{"get":{"tags":["parts"],"summary":"List Parts","operationId":"parts-list_parts","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Substring match","title":"Q"},"description":"Substring match"},{"name":"classification_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Classification Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":100,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartsPublic"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["parts"],"summary":"Create Part","operationId":"parts-create_part","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartPublic"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/{part_id}":{"get":{"tags":["parts"],"summary":"Get Part","operationId":"parts-get_part","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartPublic"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["parts"],"summary":"Update Part","operationId":"parts-update_part","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartPublic"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["parts"],"summary":"Delete Part","operationId":"parts-delete_part","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/app__modules__parts__routes__parts__DeleteMessage"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/{part_id}/preview-url":{"get":{"tags":["parts"],"summary":"Part Preview Url","description":"Engine-agnostic GLB preview for a Part.\n\nResolves the part's most-recent revision's primary CAD dataset and\nhands back a presigned URL for its glTF/GLB. The frontend uses this\non the parts overview and part detail pages so the 3D model is\nsurfaced before any calculation has run.\n\nReturns ``{url, status}`` (status semantics match\n``/parts/datasets/{ds_id}/preview-url``). The frontend treats the\nsame payload identically across all surfaces — that is the\n\"globally unified\" 3D preview contract.","operationId":"parts-part_preview_url","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartPreviewUrl"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/{part_id}/revisions":{"get":{"tags":["parts"],"summary":"List Revisions","operationId":"parts-list_revisions","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartRevisionsPublic"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["parts"],"summary":"Create Revision","operationId":"parts-create_revision","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartRevisionCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartRevisionPublic"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/{part_id}/revisions/{revision_id}":{"get":{"tags":["parts"],"summary":"Get Revision","operationId":"parts-get_revision","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}},{"name":"revision_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Revision Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartRevisionPublic"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["parts"],"summary":"Update Revision","operationId":"parts-update_revision","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}},{"name":"revision_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Revision Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartRevisionUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartRevisionPublic"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["parts"],"summary":"Delete Revision","operationId":"parts-delete_revision","security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}},{"name":"revision_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Revision Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"X-Org-Slug","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Org-Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/app__modules__parts__routes__parts__DeleteMessage"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"AttachMachineRequest":{"properties":{"machine_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Machine Id","description":"Identifier of an existing machine to attach; mutually exclusive with new_machine."},"new_machine":{"anyOf":[{"$ref":"#/components/schemas/MachineDefinitionCreate"},{"type":"null"}],"description":"Inline definition of a new machine to create and attach; mutually exclusive with machine_id."},"fleet_priority":{"type":"integer","title":"Fleet Priority","description":"Orders machines within the environment; lower values are tried first.","default":100},"is_enabled":{"type":"boolean","title":"Is Enabled","description":"Whether the machine is active in the environment's fleet on attach.","default":true},"valid_from":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Valid From","description":"ISO date (YYYY-MM-DD) the membership starts; defaults to the machine's own valid_from."},"valid_to":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Valid To","description":"ISO date (YYYY-MM-DD) the membership ends; defaults to the machine's own valid_to."}},"type":"object","title":"AttachMachineRequest","description":"Attach either an existing machine (by `machine_id`) or define a\nnew one inline. Inline is the common UX path (env editor \"Add\nmachine\"); the `machine_id` path lets one definition be shared\nacross multiple sibling envs."},"AutoCalibrateActualRow":{"properties":{"part_revision_id":{"type":"string","format":"uuid","title":"Part Revision Id","description":"The part revision the actual was observed on."},"actual_unit_cost":{"type":"number","exclusiveMinimum":0.0,"title":"Actual Unit Cost","description":"Observed unit cost in the tenant's currency. The service pairs it with the most recent successful quote for this part in this environment, so you never need to supply a predicted value yourself."},"bin":{"anyOf":[{"type":"string","maxLength":128},{"type":"null"}],"title":"Bin","description":"Optional bin label (e.g. 'milling.steel_C45')."},"lot_size":{"anyOf":[{"type":"integer","maximum":1000000.0,"minimum":1.0},{"type":"null"}],"title":"Lot Size","description":"**Strongly recommended.** The production lot the actual cost was incurred over. ERP exports usually include this (work-order quantity / batch size). Without it, calibration cannot separate one-time setup cost from per-unit cost and the result is only accurate near the lot size that dominated your data."},"annual_volume":{"anyOf":[{"type":"integer","maximum":100000000.0,"minimum":1.0},{"type":"null"}],"title":"Annual Volume","description":"12-month forecast volume for this part. Tooling-amortization denominator when no tooling-lifetime override is supplied."},"tooling_lifetime_units":{"anyOf":[{"type":"integer","maximum":1000000000.0,"minimum":1.0},{"type":"null"}],"title":"Tooling Lifetime Units","description":"Overrides ``annual_volume`` for the tooling amortization slot when fixture lifetime is tracked separately."}},"type":"object","required":["part_revision_id","actual_unit_cost"],"title":"AutoCalibrateActualRow"},"AutoCalibrateRequest":{"properties":{"actuals":{"items":{"$ref":"#/components/schemas/AutoCalibrateActualRow"},"type":"array","maxItems":20000,"minItems":1,"title":"Actuals","description":"Up to 20,000 (part_revision_id, actual_unit_cost) rows. Designed for ERP exports: an AI agent or a CSV uploader can stream a tenant's history in one call."},"target_alpha":{"type":"number","maximum":0.5,"minimum":0.01,"title":"Target Alpha","description":"Target miss rate for the prediction interval (default 0.10 → a 90% interval).","default":0.1},"holdout_pct":{"type":"number","maximum":0.5,"minimum":0.05,"title":"Holdout Pct","description":"Fraction of rows held out to size the prediction interval.","default":0.15}},"type":"object","required":["actuals"],"title":"AutoCalibrateRequest"},"Body_parts-upload_and_quote":{"properties":{"costing_environment_id":{"type":"string","format":"uuid","title":"Costing Environment Id","description":"UUID of the costing environment (machine rates, region) to price against."},"part_number":{"type":"string","maxLength":128,"minLength":1,"title":"Part Number","description":"Natural-key part number; reused to attach a new revision if the part already exists."},"lot_size":{"type":"integer","maximum":1000000000.0,"minimum":1.0,"title":"Lot Size","description":"Number of identical parts produced per batch (1 to 1,000,000,000).","default":1},"annual_volume":{"type":"integer","maximum":1000000000.0,"minimum":1.0,"title":"Annual Volume","description":"Expected yearly quantity used to amortize setup cost (1 to 1,000,000,000).","default":1},"material_ref":{"anyOf":[{"type":"string","maxLength":256},{"type":"null"}],"title":"Material Ref","description":"Free-form material reference (URN, Werkstoffnummer, AISI/SAE code, trade name, or your SKU)."},"material_grade_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Material Grade Id","description":"UUID of a resolved material grade; takes precedence over material_ref when both are supplied."},"engine":{"type":"string","maxLength":64,"title":"Engine","description":"Pricing engine selector; retained for back-compat and always normalized to the sole engine.","default":"arcanum"},"extraction_tier":{"type":"string","maxLength":32,"title":"Extraction Tier","description":"Drawing-understanding depth override: auto (default), lite (faster), or full (deepest). Most callers should leave this unset.","default":"arcnm"},"cad_file":{"type":"string","contentMediaType":"application/octet-stream","title":"Cad File","description":"3D CAD file (e.g. STEP) to price; required."},"drawing_file":{"anyOf":[{"type":"string","contentMediaType":"application/octet-stream"},{"type":"null"}],"title":"Drawing File","description":"Optional 2D drawing (PDF/PNG/JPEG) for the part."},"rfq_file":{"anyOf":[{"type":"string","contentMediaType":"application/octet-stream"},{"type":"null"}],"title":"Rfq File","description":"Optional RFQ text file with requirements for the part."}},"type":"object","required":["costing_environment_id","part_number","cad_file"],"title":"Body_parts-upload_and_quote"},"Body_parts-upload_dataset":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File","description":"The CAD model or drawing file to attach to the revision."}},"type":"object","required":["file"],"title":"Body_parts-upload_dataset"},"Body_parts-upload_inputs":{"properties":{"role":{"type":"string","title":"Role","description":"Role the file plays on the calculation's revision (e.g. drawing_2d, mesh_3d, rfq_text)."},"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File","description":"The file to attach (2D drawing PDF, STL mesh, or RFQ text)."}},"type":"object","required":["role","file"],"title":"Body_parts-upload_inputs"},"BulkCalculationRequest":{"properties":{"ids":{"items":{"type":"string","format":"uuid"},"type":"array","maxItems":200,"minItems":1,"title":"Ids","description":"Calculation IDs to act on (1–200). Duplicates collapse silently."}},"type":"object","required":["ids"],"title":"BulkCalculationRequest","description":"Payload for bulk-cancel / bulk-retry / bulk-delete.\n\n`ids` is treated as a set — duplicates collapse silently. The cap\nmatches the frontend's table page size (50) so a malicious client\ncan't fan out an unbounded delete from a single request."},"BulkCalculationResult":{"properties":{"succeeded":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Succeeded","description":"IDs of calculations the bulk action applied to successfully."},"skipped":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Skipped","description":"IDs skipped because their state didn't allow the action."},"not_found":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Not Found","description":"IDs that did not match a calculation for this tenant."}},"type":"object","title":"BulkCalculationResult"},"BulkUploadIds":{"properties":{"ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Ids","description":"Upload (data source) IDs to cancel or retry in bulk."}},"type":"object","required":["ids"],"title":"BulkUploadIds"},"BulkUploadResult":{"properties":{"cancelled":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Cancelled","description":"Upload IDs that were successfully cancelled."},"retried":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Retried","description":"Upload IDs that were successfully re-queued for confirmation."},"skipped":{"items":{"additionalProperties":{"type":"string"},"type":"object"},"type":"array","title":"Skipped","description":"Uploads that were skipped, each as ``{id, reason}``."}},"type":"object","title":"BulkUploadResult"},"CalculationCreate":{"properties":{"part_revision_id":{"type":"string","format":"uuid","title":"Part Revision Id","description":"UUID of the part revision to price."},"dataset_link_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Dataset Link Id","description":"UUID of a specific dataset link to use; omit to use the revision's active primary CAD."},"costing_environment_id":{"type":"string","format":"uuid","title":"Costing Environment Id","description":"UUID of the costing environment (machine rates, region) to price against."},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Optional human-readable label; defaults to a timestamped name when omitted."},"lot_size":{"type":"integer","minimum":1.0,"title":"Lot Size","description":"Number of identical parts produced per batch (>= 1).","default":1},"annual_volume":{"type":"integer","minimum":1.0,"title":"Annual Volume","description":"Expected yearly quantity, used for amortizing setup over the run (>= 1).","default":1},"material_ref":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Material Ref","description":"Free-form material reference (URN, Werkstoffnummer, AISI/SAE code, trade name, or your SKU); resolved to a material grade."},"material_grade_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Material Grade Id","description":"UUID of a resolved material grade; takes precedence over material_ref when both are supplied."},"region":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Region","description":"Pricing region override; defaults to the costing environment's region when omitted."},"currency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Currency","description":"ISO 4217 currency code for the quote; defaults to the costing environment's currency when omitted."},"engine":{"type":"string","title":"Engine","description":"Pricing engine selector; retained for back-compat and always normalized to the sole engine.","default":"arcanum"},"extraction_tier":{"type":"string","enum":["auto","lite","full"],"title":"Extraction Tier","description":"Drawing-understanding depth. ``auto`` (default) lets the platform choose the right depth per drawing; ``lite`` is faster and lighter; ``full`` is the deepest. Most callers should leave this unset.","default":"auto","examples":["auto","lite","full"]}},"type":"object","required":["part_revision_id","costing_environment_id"],"title":"CalculationCreate"},"CalculationDeleteResponse":{"properties":{"message":{"type":"string","title":"Message","description":"Human-readable confirmation that the calculation was deleted."}},"additionalProperties":true,"type":"object","required":["message"],"title":"CalculationDeleteResponse","description":"Body for ``DELETE /parts/calculations/{id}`` — ``{\"message\": ...}``."},"CalculationDetailResponse":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the calculation."},"part_id":{"type":"string","title":"Part Id","description":"UUID of the part this calculation belongs to."},"part_revision_id":{"type":"string","title":"Part Revision Id","description":"UUID of the part revision that was priced."},"costing_environment_id":{"type":"string","title":"Costing Environment Id","description":"UUID of the costing environment used for pricing."},"status":{"type":"string","title":"Status","description":"Current lifecycle state (e.g. queued, running, succeeded, failed, cancelled)."},"engine":{"type":"string","title":"Engine","description":"Pricing engine used for this calculation."},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Human-readable label for the calculation."},"lot_size":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Lot Size","description":"Number of identical parts produced per batch."},"annual_volume":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Annual Volume","description":"Expected yearly quantity used to amortize setup cost."},"currency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Currency","description":"ISO 4217 currency code for the cost figures."},"material_grade_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Material Grade Id","description":"UUID of the linked material grade; null when no grade is set."},"material_ref":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Material Ref","description":"Material reference (URN) of the linked grade; null when no grade is set."},"unit_cost":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Unit Cost","description":"Cost per part in the quote's currency; null until pricing completes."},"total_cost":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Total Cost","description":"Total cost for the full lot in the quote's currency; null until pricing completes."},"setup_cost":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Setup Cost","description":"One-time setup cost in the quote's currency; null until pricing completes."},"unit_time_s":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Unit Time S","description":"Production time per part in seconds; null until pricing completes."},"total_time_s":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Total Time S","description":"Total production time for the lot in seconds; null until pricing completes."},"analytics":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Analytics","description":"Free-form engine-output object carrying the cost breakdown and audit detail; its internal keys may evolve."},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error","description":"Failure message; null unless the run failed."},"started_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Started At","description":"ISO 8601 timestamp when the run started; null before it begins."},"finished_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Finished At","description":"ISO 8601 timestamp when the run finished; null before it completes."},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At","description":"ISO 8601 timestamp when the calculation was created."}},"additionalProperties":true,"type":"object","required":["id","part_id","part_revision_id","costing_environment_id","status","engine"],"title":"CalculationDetailResponse","description":"Full single-calculation view for ``GET /parts/calculations/{id}``.\n\n``analytics`` is the free-form engine-output JSONB blob, typed as an\nopen dict. Cost/time outputs are ``None`` until the calc succeeds;\n``error`` is ``None`` unless the run failed."},"CalculationListItem":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the calculation."},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Human-readable label for the calculation."},"status":{"type":"string","title":"Status","description":"Current lifecycle state (e.g. queued, running, succeeded, failed, cancelled)."},"engine":{"type":"string","title":"Engine","description":"Pricing engine used for this calculation."},"lot_size":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Lot Size","description":"Number of identical parts produced per batch."},"unit_cost":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Unit Cost","description":"Cost per part in the quote's currency; null until pricing completes."},"currency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Currency","description":"ISO 4217 currency code for the cost figures."},"material_grade_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Material Grade Id","description":"UUID of the linked material grade; null when no grade is set."},"material_ref":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Material Ref","description":"Material reference (URN) of the linked grade; null when no grade is set."},"started_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Started At","description":"ISO 8601 timestamp when the run started; null before it begins."},"finished_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Finished At","description":"ISO 8601 timestamp when the run finished; null before it completes."},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At","description":"ISO 8601 timestamp when the calculation was created."}},"additionalProperties":true,"type":"object","required":["id","status","engine"],"title":"CalculationListItem","description":"One row in ``GET /parts/calculations``.\n\nThe handler always emits every key, but several are ``None`` when the\nunderlying column is unset (``unit_cost`` before pricing,\n``material_*`` when no grade is linked, timestamps before the run\nstarts/finishes). IDs and timestamps are serialised as strings."},"CalculationListResponse":{"properties":{"items":{"items":{"$ref":"#/components/schemas/CalculationListItem"},"type":"array","title":"Items","description":"The calculations on this page, newest first."},"count":{"type":"integer","title":"Count","description":"Number of calculations returned in ``items`` (this page's size)."}},"additionalProperties":true,"type":"object","required":["items","count"],"title":"CalculationListResponse","description":"Envelope for ``GET /parts/calculations`` — ``{items, count}``."},"CalculationMaterialPatch":{"properties":{"material_grade_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Material Grade Id","description":"UUID of the material grade to link. Provide this or ``material_ref``."},"material_ref":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Material Ref","description":"Material reference (URN, Werkstoffnummer, or trade name) to resolve and link. Provide this or ``material_grade_id``."}},"type":"object","title":"CalculationMaterialPatch","description":"Body for ``PATCH /parts/calculations/{id}/material``.\n\nExactly one of ``material_grade_id`` / ``material_ref`` is required.\n``material_grade_id`` is the direct FK (what the\n``<MaterialPicker/>`` component submits); ``material_ref`` is the\nfree-text URN / Werkstoffnummer / trade name path that goes through\n``material_service.resolve`` (kept for AI-agent + ERP ingestion)."},"CalculationMaterialPatchResponse":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the calculation that was updated."},"material_grade_id":{"type":"string","title":"Material Grade Id","description":"UUID of the newly assigned material grade."},"material_ref":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Material Ref","description":"Material reference (URN) of the newly assigned grade; null when unavailable."},"previous_material_grade_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Previous Material Grade Id","description":"UUID of the material grade before this change; null if none was set."},"resolved_via":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Resolved Via","description":"How the grade was resolved: a directly supplied grade id, or a free-form reference lookup."}},"additionalProperties":true,"type":"object","required":["id","material_grade_id"],"title":"CalculationMaterialPatchResponse","description":"Body for ``PATCH /parts/calculations/{id}/material``."},"CalculationStatus":{"properties":{"id":{"type":"string","format":"uuid","title":"Id","description":"UUID of the calculation."},"status":{"type":"string","title":"Status","description":"Current lifecycle state (e.g. queued, running, succeeded, failed, cancelled)."},"enqueued_task":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Enqueued Task","description":"Name of the background task enqueued for this run; null if nothing was scheduled."},"job_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Job Id","description":"Identifier of the queued background job; null when no job was enqueued."}},"type":"object","required":["id","status"],"title":"CalculationStatus"},"CalibrationResult":{"properties":{"run_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Run Id","description":"Identifier of the calibration run, when one was created."},"id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id","description":"Identifier of the resulting record, when applicable."},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status","description":"Outcome status of the calibration run."},"scope":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Scope","description":"Scope the run applied to: 'platform' or 'environment'."},"ingested":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Ingested","description":"Number of observations persisted by an ingest call."},"samples":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Samples","description":"Number of samples considered by the run."},"samples_applied":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Samples Applied","description":"Number of samples actually applied to the fit."},"unmatched_part_ids":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Unmatched Part Ids","description":"Part revision IDs with no prior quote, so they were skipped."},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message","description":"Human-readable note about the run, when present."},"env_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Env Id","description":"Identifier of the calibrated environment."},"matched":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Matched","description":"Number of supplied rows matched to an existing quote."},"n_train":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"N Train","description":"Number of rows used to fit the calibration."},"n_holdout":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"N Holdout","description":"Number of rows held out to size the prediction interval."},"holdout_mape":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Holdout Mape","description":"Mean absolute percentage error on the held-out rows."},"holdout_coverage":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Holdout Coverage","description":"Fraction (0–1) of held-out actuals falling inside the interval."},"fit":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Fit","description":"Structured object with the fitted parameters and fit diagnostics."},"work_orders_received":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Work Orders Received","description":"Number of ERP work-order rows received."},"work_orders_resolved":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Work Orders Resolved","description":"Number of work orders resolved to a known part revision."},"unknown_part_numbers":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Unknown Part Numbers","description":"Part numbers that could not be resolved to a known part."},"target_metric":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Target Metric","description":"Metric the calibration targeted (e.g. 'unit_cost')."},"alpha":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Alpha","description":"Target miss rate of the prediction interval (e.g. 0.10 → 90%)."},"q_alpha":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Q Alpha","description":"Fitted conformal quantile that sets the interval half-width."},"n_calibration":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"N Calibration","description":"Number of samples used to fit the conformal interval."},"observed_coverage":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Observed Coverage","description":"Empirical coverage (0–1) of the fitted interval on its samples."},"part_revision_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Part Revision Id","description":"Identifier of the part revision that was fit."},"a":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"A","description":"Fitted first-unit cost coefficient of the curve."},"b":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"B","description":"Fitted log-log slope exponent of the learning curve."},"learning_rate":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Learning Rate","description":"Learning rate (0–1): cost retained each time output doubles."},"r_squared":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"R Squared","description":"Coefficient of determination (0–1) of the curve fit."},"residual_sigma_log":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Residual Sigma Log","description":"Standard deviation of the fit residuals in log space."},"n_lots":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"N Lots","description":"Number of production lots used in the curve fit."},"n_iterations":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"N Iterations","description":"Iterations the midpoint solver ran before converging."},"policy_history_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Policy History Id","description":"Identifier of the newly written selection-policy row."},"seed_accuracy":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Seed Accuracy","description":"Accuracy (0–1) of the seed policy before calibration."},"fitted_accuracy":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Fitted Accuracy","description":"Accuracy (0–1) of the fitted policy on the training rows."},"holdout_accuracy":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Holdout Accuracy","description":"Accuracy (0–1) of the fitted policy on held-out rows."},"grid_size":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Grid Size","description":"Number of policy candidates evaluated during the fit."},"fitted_policy":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Fitted Policy","description":"Structured object describing the fitted selection policy."}},"additionalProperties":true,"type":"object","title":"CalibrationResult","description":"Result of a calibration *write* run (ingest, finalize, teach,\nauto-calibrate, ERP auto-calibrate, learning-curve fit, conformal\nrecalibrate, policy calibrate).\n\nA single permissive envelope shared by every write route: each route\npopulates the subset relevant to it, and ``extra=\"allow\"`` carries any\nfurther handler keys through untouched. Nested payloads (``fit``,\n``fitted_policy``) are passed through as objects rather than re-validated\nso their numeric internals are never coerced or dropped."},"CalibrationStatusResult":{"properties":{"env_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Env Id","description":"Identifier of the environment this status describes."},"active_posterior_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Active Posterior Count","description":"Number of active calibrated parameters; 0 means uncalibrated."},"last_fit_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Fit At","description":"ISO 8601 timestamp of the last calibration; null if never run."},"observations":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Observations","description":"Per-source counts of submitted observations awaiting application."},"conformal":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Conformal","description":"Recent prediction-interval calibrations, each a structured object."},"drift_alerts":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Drift Alerts","description":"Recent drift alerts, each a structured object with signal and severity."}},"additionalProperties":true,"type":"object","title":"CalibrationStatusResult","description":"Read-only environment calibration status (also exposed to AI agents and\nops dashboards). Mirrors the handler exactly; ``extra=\"allow\"`` keeps it\nforward-compatible. List payloads are passed through as objects so their\nnumeric internals are never coerced or dropped."},"ConfirmRequest":{"properties":{"data_source_id":{"type":"string","format":"uuid","title":"Data Source Id","description":"UUID of the presigned upload to validate and ingest."}},"type":"object","required":["data_source_id"],"title":"ConfirmRequest"},"ConfirmResponse":{"properties":{"job_id":{"type":"string","title":"Job Id","description":"Identifier of the background job validating and ingesting the file."}},"additionalProperties":true,"type":"object","required":["job_id"],"title":"ConfirmResponse"},"ConformalRecalibrateRequest":{"properties":{"scope":{"type":"string","enum":["platform","environment"],"title":"Scope","description":"Scope to recalibrate; tenant tokens may use 'environment' only."},"env_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Env Id","description":"Target environment; required when scope is 'environment'."},"target_metric":{"type":"string","enum":["cycle_time_s","setup_time_s","unit_cost"],"title":"Target Metric","description":"Metric whose prediction interval is recalibrated.","default":"unit_cost"},"target_alpha":{"type":"number","maximum":0.5,"minimum":0.01,"title":"Target Alpha","description":"Target miss rate for the prediction interval (0.10 → a 90% interval).","default":0.1},"samples":{"items":{"additionalProperties":true,"type":"object"},"type":"array","maxItems":20000,"title":"Samples","description":"Up to 20,000 (predicted, actual) samples; both values must be greater than 0."}},"type":"object","required":["scope"],"title":"ConformalRecalibrateRequest"},"CoolantType":{"type":"string","enum":["flood","through_spindle","air_blast","mql","none"],"title":"CoolantType"},"DataSourcePublic":{"properties":{"id":{"type":"string","format":"uuid","title":"Id","description":"Unique identifier of the uploaded data source."},"name":{"type":"string","title":"Name","description":"Original filename of the uploaded file."},"content_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content Type","description":"MIME type of the file (e.g. 'application/pdf'); null if unknown."},"size_bytes":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Size Bytes","description":"Size of the file in bytes; null until the upload is confirmed."},"sha256":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sha256","description":"Hex-encoded SHA-256 checksum of the file; null until confirmed."},"status":{"type":"string","title":"Status","description":"Upload lifecycle state: pending, confirmed, failed, or cancelled."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"ISO 8601 timestamp when the upload record was created."}},"type":"object","required":["id","name","status","created_at"],"title":"DataSourcePublic"},"DatasetAttach":{"properties":{"data_source_id":{"type":"string","format":"uuid","title":"Data Source Id","description":"Identifier of the uploaded data source to attach to the revision."},"role":{"type":"string","title":"Role","description":"Role of the file on the revision (e.g. cad_3d for a 3D CAD model, drawing_2d for a 2D drawing).","default":"other"},"is_primary":{"type":"boolean","title":"Is Primary","description":"Whether this dataset is the primary one for the revision.","default":false},"attributes":{"additionalProperties":true,"type":"object","title":"Attributes","description":"Free-form metadata for the attachment, as a JSON object.","default":{}}},"type":"object","required":["data_source_id"],"title":"DatasetAttach"},"DetachMessage":{"properties":{"message":{"type":"string","title":"Message","description":"Human-readable confirmation that the dataset was detached."}},"additionalProperties":true,"type":"object","required":["message"],"title":"DetachMessage","description":"``{\"message\": \"...\"}`` envelope for the detach endpoint."},"DownloadUrlResponse":{"properties":{"url":{"type":"string","title":"Url","description":"Short-lived presigned URL to download the confirmed file."}},"additionalProperties":true,"type":"object","required":["url"],"title":"DownloadUrlResponse"},"EnvMachineRowPublic":{"properties":{"membership_id":{"type":"string","title":"Membership Id","description":"Unique identifier of the environment-machine membership."},"machine":{"anyOf":[{"$ref":"#/components/schemas/MachinePublic"},{"type":"null"}],"description":"The attached machine definition; null only when it cannot be re-read."},"fleet_priority":{"type":"integer","title":"Fleet Priority","description":"Orders machines within the environment; lower values are tried first."},"is_enabled":{"type":"boolean","title":"Is Enabled","description":"Whether this machine is active in the environment's fleet."},"valid_from":{"type":"string","title":"Valid From","description":"ISO date (YYYY-MM-DD) from which this membership is effective."},"valid_to":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Valid To","description":"ISO date (YYYY-MM-DD) the membership stops being effective; null = open-ended."}},"additionalProperties":true,"type":"object","required":["membership_id","fleet_priority","is_enabled","valid_from"],"title":"EnvMachineRowPublic","description":"A membership row (list / attach / patch).\n\n``machine`` is ``None`` only on the PATCH path when the underlying\ndefinition row can't be re-read; list/attach always populate it."},"EnvironmentCreate":{"properties":{"name":{"type":"string","maxLength":128,"minLength":1,"title":"Name","description":"Human-readable name for the new environment."},"description":{"anyOf":[{"type":"string","maxLength":512},{"type":"null"}],"title":"Description","description":"Optional longer description of the environment."},"region":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Region","description":"Geographic region this environment prices for (e.g. DE, US)."},"currency":{"type":"string","maxLength":3,"minLength":3,"title":"Currency","description":"ISO 4217 currency code the environment's rates are denominated in.","default":"EUR"},"valid_from":{"type":"string","format":"date","title":"Valid From","description":"ISO date (YYYY-MM-DD) from which the environment is effective."},"valid_to":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Valid To","description":"ISO date (YYYY-MM-DD) the environment stops being effective; null = open-ended."},"enabled_extractors":{"items":{"type":"string"},"type":"array","title":"Enabled Extractors","description":"Geometry and enrichment sources enabled for the environment."}},"type":"object","required":["name","valid_from"],"title":"EnvironmentCreate"},"EnvironmentDetail":{"properties":{"id":{"type":"string","title":"Id","description":"Unique identifier of the costing environment."},"name":{"type":"string","title":"Name","description":"Human-readable name of the costing environment."},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Optional longer description of the environment."},"region":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Region","description":"Geographic region this environment prices for (e.g. DE, US)."},"currency":{"type":"string","title":"Currency","description":"ISO 4217 currency code the environment's rates are denominated in."},"valid_from":{"type":"string","title":"Valid From","description":"ISO date (YYYY-MM-DD) from which this environment is effective."},"valid_to":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Valid To","description":"ISO date (YYYY-MM-DD) the environment stops being effective; null = open-ended."},"enabled_extractors":{"items":{"type":"string"},"type":"array","title":"Enabled Extractors","description":"Geometry and enrichment sources enabled for this environment."},"is_baseline":{"type":"boolean","title":"Is Baseline","description":"Whether this is the auto-provisioned default environment for the tenant."},"attributes":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Attributes","description":"Free-form key/value metadata attached to the environment."}},"additionalProperties":true,"type":"object","required":["id","name","currency","valid_from","enabled_extractors","is_baseline"],"title":"EnvironmentDetail","description":"``GET /{env_id}`` — ``_serialise`` plus the free-form ``attributes`` blob."},"EnvironmentExtractorUpdate":{"properties":{"enabled_extractors":{"items":{"type":"string"},"type":"array","minItems":1,"title":"Enabled Extractors","description":"Geometry-extractor slugs to enable for this environment (at least one)."}},"type":"object","required":["enabled_extractors"],"title":"EnvironmentExtractorUpdate","description":"Payload for ``PATCH /parts/environments/{env_id}``.\n\nOnly carries the fields a tenant is allowed to flip from the UI —\ntoday, the geometry-extractor list. Other env fields (region,\ncurrency, valid_from/to, physics_overrides, …) are managed by ops\nand don't belong on this self-service surface."},"EnvironmentIdentityUpdate":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":128,"minLength":1},{"type":"null"}],"title":"Name","description":"New name for the environment; omit to leave unchanged."},"description":{"anyOf":[{"type":"string","maxLength":512},{"type":"null"}],"title":"Description","description":"New description for the environment; omit to leave unchanged."},"region":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Region","description":"New region for the environment; omit to leave unchanged."},"currency":{"anyOf":[{"type":"string","maxLength":3,"minLength":3},{"type":"null"}],"title":"Currency","description":"New ISO 4217 currency code; omit to leave unchanged."},"valid_from":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Valid From","description":"New effective-from ISO date (YYYY-MM-DD); omit to leave unchanged."},"valid_to":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Valid To","description":"New effective-to ISO date (YYYY-MM-DD); omit to leave unchanged."}},"type":"object","title":"EnvironmentIdentityUpdate","description":"Patch only the identity columns — separate from the\nextractor-list patcher so the two surfaces evolve independently\nand a UI typo in `region` can't accidentally drop extractors."},"EnvironmentPublic":{"properties":{"id":{"type":"string","title":"Id","description":"Unique identifier of the costing environment."},"name":{"type":"string","title":"Name","description":"Human-readable name of the costing environment."},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Optional longer description of the environment."},"region":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Region","description":"Geographic region this environment prices for (e.g. DE, US)."},"currency":{"type":"string","title":"Currency","description":"ISO 4217 currency code the environment's rates are denominated in."},"valid_from":{"type":"string","title":"Valid From","description":"ISO date (YYYY-MM-DD) from which this environment is effective."},"valid_to":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Valid To","description":"ISO date (YYYY-MM-DD) the environment stops being effective; null = open-ended."},"enabled_extractors":{"items":{"type":"string"},"type":"array","title":"Enabled Extractors","description":"Geometry and enrichment sources enabled for this environment."},"is_baseline":{"type":"boolean","title":"Is Baseline","description":"Whether this is the auto-provisioned default environment for the tenant."}},"additionalProperties":true,"type":"object","required":["id","name","currency","valid_from","enabled_extractors","is_baseline"],"title":"EnvironmentPublic","description":"Shape returned by ``_serialise`` (list / create / patch / identity)."},"ErpAutoCalibrateRequest":{"properties":{"work_orders":{"items":{"$ref":"#/components/schemas/ErpWorkOrderPayload"},"type":"array","maxItems":20000,"minItems":1,"title":"Work Orders","description":"Up to 20 000 raw ERP work-order lines. Designed for the AI-agent ERP-import use case: pull tenant's last 12 months of WIP_DISCRETE_JOBS rows, POST them once, and the service resolves part numbers, decomposes setup vs variable cost from the lot-size diversity, and returns a calibrated env."},"target_alpha":{"type":"number","maximum":0.5,"minimum":0.01,"title":"Target Alpha","description":"Target miss rate for the prediction interval (0.10 → a 90% interval).","default":0.1},"holdout_pct":{"type":"number","maximum":0.5,"minimum":0.05,"title":"Holdout Pct","description":"Fraction of rows held out to size the prediction interval.","default":0.15}},"type":"object","required":["work_orders"],"title":"ErpAutoCalibrateRequest"},"ErpWorkOrderPayload":{"properties":{"part_number":{"type":"string","maxLength":128,"minLength":1,"title":"Part Number","description":"Tenant's external part identifier. Maps to SAP MARA-MATNR or Oracle ITEM_NUMBER. Resolved to the latest PartRevision for the org."},"work_order_id":{"type":"string","maxLength":128,"minLength":1,"title":"Work Order Id","description":"ERP work-order reference. Used as the idempotency key — re-uploading the same work_order_id is a no-op."},"quantity":{"type":"integer","maximum":1000000.0,"minimum":1.0,"title":"Quantity","description":"Work-order quantity (lot size)."},"total_cost":{"type":"number","exclusiveMinimum":0.0,"title":"Total Cost","description":"Total cost of the work order in the env's currency. Service converts to per-unit cost via total_cost / quantity."},"annual_forecast":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Annual Forecast","description":"Optional planned 12-month volume for tooling amortization."}},"type":"object","required":["part_number","work_order_id","quantity","total_cost"],"title":"ErpWorkOrderPayload"},"FinalizeRequest":{"properties":{"target_alpha":{"type":"number","title":"Target Alpha","description":"Target miss rate for the prediction interval (0.10 → a 90% interval).","default":0.1},"target_metric":{"type":"string","enum":["cycle_time_s","setup_time_s","unit_cost","machine_choice"],"title":"Target Metric","description":"Metric to calibrate the environment for.","default":"cycle_time_s"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes","description":"Optional free-text note recorded with the run."}},"type":"object","title":"FinalizeRequest"},"FixtureClass":{"type":"string","enum":["vise.3jaw","vise.2jaw","chuck.3jaw","chuck.4jaw","collet","vacuum_table","magnetic_table","dedicated_fixture","parallels","indexing_head","tombstone"],"title":"FixtureClass"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ITGrade":{"type":"string","enum":["IT01","IT0","IT1","IT2","IT3","IT4","IT5","IT6","IT7","IT8","IT9","IT10","IT11","IT12"],"title":"ITGrade"},"IsoMachiningGroup":{"type":"string","enum":["P","M","K","N","S","H"],"title":"IsoMachiningGroup","description":"ISO 513 workpiece groups — drives cutting-data lookup and tariffs.\n\n* ``P`` — non-alloyed & low-alloyed steels\n* ``M`` — stainless steels (austenitic, duplex, …)\n* ``K`` — cast iron (grey, nodular, malleable)\n* ``N`` — non-ferrous (aluminium, copper, plastics)\n* ``S`` — heat-resistant super-alloys + titanium\n* ``H`` — hardened steels (45–65 HRC)"},"LearningCurveFitRequest":{"properties":{"part_revision_id":{"type":"string","format":"uuid","title":"Part Revision Id","description":"Identifier of the part revision the lots belong to."},"lots":{"items":{"$ref":"#/components/schemas/LearningCurveLotPayload"},"type":"array","maxItems":1000,"minItems":3,"title":"Lots","description":"Sequence of production-lot actuals to fit; at least three."},"model":{"type":"string","enum":["crawford_unit","wright_cumulative"],"title":"Model","description":"Learning-curve model to fit (per-unit or cumulative).","default":"wright_cumulative"}},"type":"object","required":["part_revision_id","lots"],"title":"LearningCurveFitRequest"},"LearningCurveLotPayload":{"properties":{"lot_index":{"type":"integer","minimum":1.0,"title":"Lot Index","description":"1-based index in the part's history."},"lot_size":{"type":"integer","maximum":1000000.0,"minimum":1.0,"title":"Lot Size","description":"Number of units produced in this lot."},"lot_total_cost":{"type":"number","exclusiveMinimum":0.0,"title":"Lot Total Cost","description":"Total cost of this lot in the environment's currency."}},"type":"object","required":["lot_index","lot_size","lot_total_cost"],"title":"LearningCurveLotPayload"},"MachineCapabilities":{"properties":{"schema_version":{"type":"string","title":"Schema Version","description":"Semantic version of this capabilities schema.","default":"1.0.0"},"klass":{"$ref":"#/components/schemas/MachineClass","description":"Machine class (process family), e.g. milling.5axis_full."},"subclass":{"$ref":"#/components/schemas/MachineSubclass","description":"Size tier of the machine within its class (small/medium/large).","default":"medium"},"axes_simultaneous":{"type":"integer","maximum":9.0,"minimum":0.0,"title":"Axes Simultaneous","description":"Number of CNC axes the machine can interpolate simultaneously."},"axes_indexable":{"type":"integer","maximum":9.0,"minimum":0.0,"title":"Axes Indexable","description":"Total number of axes available, including positioning-only (indexable) axes."},"max_part_envelope_mm":{"prefixItems":[{"type":"number"},{"type":"number"},{"type":"number"}],"type":"array","maxItems":3,"minItems":3,"title":"Max Part Envelope Mm","description":"Maximum machinable part envelope as (X, Y, Z), in millimetres."},"spindle_power_kw":{"type":"number","minimum":0.0,"title":"Spindle Power Kw","description":"Rated spindle power, in kilowatts."},"max_spindle_rpm":{"type":"integer","minimum":0.0,"title":"Max Spindle Rpm","description":"Maximum spindle speed, in revolutions per minute."},"max_table_load_kg":{"type":"number","minimum":0.0,"title":"Max Table Load Kg","description":"Maximum workpiece weight the table can carry, in kilograms.","default":0.0},"max_tool_diameter_mm":{"type":"number","minimum":0.0,"title":"Max Tool Diameter Mm","description":"Maximum cutting-tool diameter the machine accepts, in millimetres.","default":0.0},"max_tool_length_mm":{"type":"number","minimum":0.0,"title":"Max Tool Length Mm","description":"Maximum cutting-tool length the machine accepts, in millimetres.","default":0.0},"max_material_thickness_mm":{"type":"number","minimum":0.0,"title":"Max Material Thickness Mm","description":"Maximum stock thickness the process can cut/form, in millimetres (0 = not applicable).","default":0.0},"workholding":{"items":{"$ref":"#/components/schemas/FixtureClass"},"type":"array","title":"Workholding","description":"Workholding/fixture types the machine supports."},"coolant":{"items":{"$ref":"#/components/schemas/CoolantType"},"type":"array","title":"Coolant","description":"Coolant delivery types the machine supports."},"iso_286_achievable_grade":{"$ref":"#/components/schemas/ITGrade","description":"Tightest ISO 286 tolerance grade (IT grade) the machine can reliably hold.","default":"IT9"},"chatter_stability_lobe":{"anyOf":[{"$ref":"#/components/schemas/StabilityLobeCurve"},{"type":"null"}],"description":"Optional chatter stability-lobe curve mapping spindle speed (rpm) to max axial depth of cut (mm)."},"nominal_tool_change_time_s_by_class":{"additionalProperties":{"type":"number"},"propertyNames":{"$ref":"#/components/schemas/ToolKind"},"type":"object","title":"Nominal Tool Change Time S By Class","description":"Nominal chip-to-chip tool-change time per tool kind, in seconds."},"positioning_accuracy_mm":{"type":"number","minimum":0.0,"title":"Positioning Accuracy Mm","description":"Linear positioning accuracy, in millimetres.","default":0.01},"repeatability_mm":{"type":"number","minimum":0.0,"title":"Repeatability Mm","description":"Positioning repeatability, in millimetres.","default":0.005},"max_setups_per_part":{"type":"integer","minimum":1.0,"title":"Max Setups Per Part","description":"Maximum number of distinct fixturing setups allowed per part.","default":6},"rapid_traverse_m_per_min":{"type":"number","minimum":0.0,"title":"Rapid Traverse M Per Min","description":"Rapid (non-cutting) traverse speed, in metres per minute.","default":24.0},"vdi_3258":{"anyOf":[{"$ref":"#/components/schemas/VDI3258Inputs"},{"type":"null"}],"description":"Optional VDI 3258 machine-hour-rate cost inputs for this machine."},"certifications":{"items":{"type":"string"},"type":"array","uniqueItems":true,"title":"Certifications","description":"Quality/compliance certifications the machine holds (e.g. AS9100, NADCAP, ISO_9001, IATF_16949)."}},"type":"object","required":["klass","axes_simultaneous","axes_indexable","max_part_envelope_mm","spindle_power_kw","max_spindle_rpm"],"title":"MachineCapabilities"},"MachineClass":{"type":"string","enum":["milling.3axis_vmc","milling.5axis_full","milling.indexable_3plus2","turning.2axis_cnc","turning.live_tool","turning.swiss_type","turning.mill_integrex","press_brake","laser_cutter","waterjet","wire_edm","sinter.dmls","fdm_industrial","injection_molding_press","grinder.surface","grinder.cylindrical"],"title":"MachineClass"},"MachineDefinitionCreate":{"properties":{"name":{"type":"string","maxLength":255,"title":"Name","description":"Human-readable name of the machine."},"vendor":{"type":"string","maxLength":128,"title":"Vendor","description":"Machine manufacturer / vendor."},"model_no":{"type":"string","maxLength":128,"title":"Model No","description":"Vendor's model number for the machine."},"klass":{"$ref":"#/components/schemas/MachineClass","description":"Machine class (process family), e.g. milling.5axis_full."},"subclass":{"$ref":"#/components/schemas/MachineSubclass","description":"Size tier of the machine within its class (small/medium/large).","default":"medium"},"hourly_rate_eur":{"type":"number","title":"Hourly Rate Eur","description":"Machine running rate, in EUR per hour.","default":0.0},"burden_rate_eur":{"type":"number","title":"Burden Rate Eur","description":"Overhead burden applied to the machine, in EUR per hour.","default":0.0},"parent_template_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Parent Template Id","description":"Identifier of a template machine this definition inherits from, if any."},"capabilities":{"$ref":"#/components/schemas/MachineCapabilities","description":"Full capability matrix (axes, envelope, spindle, tolerances) for the machine."},"valid_from":{"type":"string","format":"date","title":"Valid From","description":"Date from which this machine definition is effective (ISO 8601)."},"valid_to":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Valid To","description":"Date after which this definition is no longer effective; null if open-ended (ISO 8601)."}},"type":"object","required":["name","vendor","model_no","klass","capabilities","valid_from"],"title":"MachineDefinitionCreate"},"MachinePublic":{"properties":{"id":{"type":"string","title":"Id","description":"Unique identifier of the machine definition."},"name":{"type":"string","title":"Name","description":"Human-readable name of the machine."},"vendor":{"type":"string","title":"Vendor","description":"Manufacturer or vendor of the machine."},"model_no":{"type":"string","title":"Model No","description":"Vendor model number of the machine."},"klass":{"type":"string","title":"Klass","description":"Machine class (e.g. milling, turning, laser_cutter)."},"subclass":{"type":"string","title":"Subclass","description":"Machine subclass refining the class (e.g. small, medium, large)."},"hourly_rate_eur":{"type":"number","title":"Hourly Rate Eur","description":"Machine-hour rate in EUR per hour."},"burden_rate_eur":{"type":"number","title":"Burden Rate Eur","description":"Overhead burden added on top of the machine-hour rate, in EUR per hour."},"capabilities":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Capabilities","description":"Capability matrix (axes, envelope, spindle, tolerances, certifications)."},"valid_from":{"type":"string","title":"Valid From","description":"ISO date (YYYY-MM-DD) from which this machine definition is effective."},"valid_to":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Valid To","description":"ISO date (YYYY-MM-DD) the machine stops being effective; null = open-ended."}},"additionalProperties":true,"type":"object","required":["id","name","vendor","model_no","klass","subclass","hourly_rate_eur","burden_rate_eur","valid_from"],"title":"MachinePublic","description":"Shape returned by ``_serialise_machine``."},"MachineSubclass":{"type":"string","enum":["small","medium","large"],"title":"MachineSubclass"},"MatchedVia":{"type":"string","enum":["urn","legacy_urn","primary_code","alias","org_override","org_private"],"title":"MatchedVia","description":"Resolution path taken by :func:`material_service.resolve`.\n\nSurfaced on :class:`MaterialLookupResult` so callers can tell *how*\na given input string bound to a canonical grade — exact URN vs.\norg-private trade name vs. catalogue alias. Using an enum prevents\ntypo drift between the service layer and the API contract."},"MaterialCategory":{"type":"string","enum":["carbon_steel","alloy_steel","stainless_steel","tool_steel","cast_iron","aluminium","copper_alloy","nickel_alloy","titanium_alloy","magnesium_alloy","zinc_alloy","thermoplastic","thermoset","elastomer","composite","other"],"title":"MaterialCategory","description":"Top-level material family. Drives ISO machining group defaults and\nUI filtering. Values are stable identifiers — adding a new category is\nadditive; renaming is a breaking change."},"MaterialGradeAliasPublic":{"properties":{"id":{"type":"string","format":"uuid","title":"Id","description":"Unique identifier of the alias."},"material_grade_id":{"type":"string","format":"uuid","title":"Material Grade Id","description":"Identifier of the canonical grade this alias points to."},"standard_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Standard Id","description":"Identifier of the standard the alias belongs to; null for a free-form trade name."},"standard_code":{"anyOf":[{"$ref":"#/components/schemas/MaterialStandardCode"},{"type":"null"}],"description":"URN-safe code of the alias standard; null for a free-form trade name."},"code":{"type":"string","title":"Code","description":"Standards-compliant cased form; the same value as `display_code`."},"is_canonical":{"type":"boolean","title":"Is Canonical","description":"Whether this alias is itself a canonical name under its standard.","default":false},"is_preferred_display":{"type":"boolean","title":"Is Preferred Display","description":"Whether this alias is preferred when rendering the grade."}},"type":"object","required":["id","material_grade_id","code","is_preferred_display"],"title":"MaterialGradeAliasPublic"},"MaterialGradePublic":{"properties":{"id":{"type":"string","format":"uuid","title":"Id","description":"Unique identifier of the material grade."},"urn":{"type":"string","title":"Urn","description":"Canonical URN that uniquely and stably identifies this grade across systems."},"category":{"$ref":"#/components/schemas/MaterialCategory","description":"Broad material family the grade belongs to (e.g. steel, aluminium, polymer)."},"primary_standard_id":{"type":"string","format":"uuid","title":"Primary Standard Id","description":"Identifier of the standard that defines this grade's primary code."},"primary_standard_code":{"anyOf":[{"$ref":"#/components/schemas/MaterialStandardCode"},{"type":"null"}],"description":"URN-safe code of the primary standard (``en10027-2``, ``iso1043-1``, …). Hydrated by the routes layer so frontends can render a badge without a second round-trip."},"primary_code":{"type":"string","title":"Primary Code","description":"Standards-compliant cased display code; the same value as `display_code`."},"name":{"type":"string","title":"Name","description":"Human-readable name of the material grade."},"iso_machining_group":{"anyOf":[{"$ref":"#/components/schemas/IsoMachiningGroup"},{"type":"null"}],"description":"ISO 513 machining group (P/M/K/N/S/H) used to gauge machinability."},"density_kg_per_m3":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Density Kg Per M3","description":"Material density in kilograms per cubic metre."},"is_active":{"type":"boolean","title":"Is Active","description":"Whether the grade is currently active and selectable; false when retired."},"successor_grade_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Successor Grade Id","description":"Identifier of the grade that supersedes this one; null when still current."},"attributes":{"additionalProperties":true,"type":"object","title":"Attributes","description":"Free-form key/value metadata for extra mechanical and physical properties."},"aliases":{"items":{"$ref":"#/components/schemas/MaterialGradeAliasPublic"},"type":"array","title":"Aliases","description":"Cross-references mapping this grade's code across other standards and trade names."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"Timestamp when the grade record was created."},"updated_at":{"type":"string","format":"date-time","title":"Updated At","description":"Timestamp when the grade record was last updated."}},"type":"object","required":["id","urn","category","primary_standard_id","primary_code","name","is_active","created_at","updated_at"],"title":"MaterialGradePublic","description":"API projection. ``primary_code`` is the standards-compliant cased\ndisplay form (e.g. ``X5CrNi18-10``, ``PA6-GF30``, ``EN AW-6061``) —\nsafe to render directly. The lowercase lookup form is internal and\nnot exposed."},"MaterialGradesPublic":{"properties":{"data":{"items":{"$ref":"#/components/schemas/MaterialGradePublic"},"type":"array","title":"Data","description":"The material grades on this page."},"count":{"type":"integer","title":"Count","description":"Total number of grades matching the query (not the page size)."}},"type":"object","required":["data","count"],"title":"MaterialGradesPublic"},"MaterialLookupBatchEntry":{"properties":{"query":{"type":"string","title":"Query","description":"The original query string for this slot, echoed back for correlation."},"result":{"anyOf":[{"$ref":"#/components/schemas/MaterialLookupResult"},{"type":"null"}],"description":"The resolved grade, or null when the query did not match."}},"type":"object","required":["query"],"title":"MaterialLookupBatchEntry","description":"One slot in a batch response. ``result`` is null when the query\ndid not resolve — the caller still gets the original input string so\nthey can correlate hits and misses by position."},"MaterialLookupBatchRequest":{"properties":{"queries":{"items":{"type":"string"},"type":"array","maxItems":100,"minItems":1,"title":"Queries","description":"Material query strings to resolve in one round-trip (1–100)."},"standard":{"anyOf":[{"$ref":"#/components/schemas/MaterialStandardCode"},{"type":"null"}],"description":"Optional hint applied to every query in the batch."}},"type":"object","required":["queries"],"title":"MaterialLookupBatchRequest","description":"Batch lookup payload — resolves up to 100 queries in one round-trip.\n\nDrawing extraction emits N candidate strings per part; one batch call\nreplaces N individual ``/lookup`` requests and keeps the API surface\nsmall for the frontend typeahead and the worker."},"MaterialLookupBatchResult":{"properties":{"entries":{"items":{"$ref":"#/components/schemas/MaterialLookupBatchEntry"},"type":"array","title":"Entries","description":"One result slot per query, in the order the queries were supplied."},"matched_count":{"type":"integer","title":"Matched Count","description":"Number of queries in the batch that resolved to a grade."},"miss_count":{"type":"integer","title":"Miss Count","description":"Number of queries in the batch that did not resolve."}},"type":"object","required":["entries","matched_count","miss_count"],"title":"MaterialLookupBatchResult"},"MaterialLookupRequest":{"properties":{"query":{"type":"string","maxLength":255,"minLength":1,"title":"Query","description":"URN, EN/UNS/AISI/JIS code, trade name, or org internal code."},"standard":{"anyOf":[{"$ref":"#/components/schemas/MaterialStandardCode"},{"type":"null"}],"description":"Optional hint — restrict alias search to this standard."}},"type":"object","required":["query"],"title":"MaterialLookupRequest","description":"Fuzzy lookup payload. Resolves any of: URN, primary code, alias code,\ntrade name, org internal_code. Returns the canonical grade."},"MaterialLookupResult":{"properties":{"matched_via":{"$ref":"#/components/schemas/MatchedVia","description":"Path the resolver used: ``urn`` | ``legacy_urn`` | ``primary_code`` | ``alias`` | ``org_override`` | ``org_private``."},"standard_used":{"anyOf":[{"$ref":"#/components/schemas/MaterialStandardCode"},{"type":"null"}],"description":"Material standard the match resolved against; null if not standard-specific."},"grade":{"$ref":"#/components/schemas/MaterialGradePublic","description":"The canonical material grade the query resolved to."}},"type":"object","required":["matched_via","grade"],"title":"MaterialLookupResult"},"MaterialStandardCode":{"type":"string","enum":["en10027-1","en10027-2","en10025","en10083","en10084","en10088","en-iso-4957","en573-1","en573-2","en1412","en1560","en1561","en1563","iso1043-1","iso1043-2","iso18064","uns","aisi-sae","jis","astm","eclass","unspsc"],"title":"MaterialStandardCode","description":"Issuing standard codes used in URNs and the ``MaterialStandard`` table.\n\nValues are URN-safe (lowercase, hyphenated). The human-readable name\nand issuing body are stored in the ``MaterialStandard`` row.\n\nEach code is tagged with a *kind* (designation, numbering, product,\nclassification) in the database — that is what tells the UI whether\na code is a name for a material (``EN 10027-1``), a number for a\nmaterial (``EN 10027-2``), a list of which materials are deliverable\nunder what conditions (``EN 10025``), or a cross-industry taxonomy\n(``ECLASS``)."},"MaterialStandardPublic":{"properties":{"code":{"type":"string","maxLength":32,"title":"Code","description":"URN-safe standard identifier; matches MaterialStandardCode."},"name":{"type":"string","maxLength":255,"title":"Name","description":"Human-readable name of the standard (e.g. 'EN 10088-3')."},"issuing_body":{"type":"string","maxLength":64,"title":"Issuing Body","description":"CEN, ISO, SAE, ASTM, JISC, ECLASS e.V., UNDP, …"},"region":{"type":"string","maxLength":16,"title":"Region","description":"eu | us | jp | global — informational only.","default":"global"},"kind":{"$ref":"#/components/schemas/StandardKind","description":"Role this standard plays — designation, numbering, product, or classification. Lets the UI render the right context (name vs number vs delivery condition vs taxonomy). Stored as VARCHAR(16) to match the migration that created the table; Pydantic validates the value against StandardKind.","default":"designation"},"is_designation":{"type":"boolean","title":"Is Designation","description":"True when the standard identifies a specific grade. False for classification taxonomies (ECLASS, UNSPSC). Derivable from ``kind`` but kept for backwards-compat with existing filters.","default":true},"id":{"type":"string","format":"uuid","title":"Id","description":"Unique identifier of the material standard."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"Timestamp when the standard record was created."}},"type":"object","required":["code","name","issuing_body","id","created_at"],"title":"MaterialStandardPublic"},"MembershipUpdate":{"properties":{"fleet_priority":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Fleet Priority","description":"New ordering within the environment (lower tried first); omit to leave unchanged."},"is_enabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Enabled","description":"Whether the machine is active in the fleet; omit to leave unchanged."},"valid_from":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Valid From","description":"New membership start ISO date (YYYY-MM-DD); omit to leave unchanged."},"valid_to":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Valid To","description":"New membership end ISO date (YYYY-MM-DD); omit to leave unchanged."}},"type":"object","title":"MembershipUpdate"},"MessageResponse":{"properties":{"message":{"type":"string","title":"Message","description":"Human-readable result of the operation."}},"additionalProperties":true,"type":"object","required":["message"],"title":"MessageResponse","description":"DELETE responses — ``{\"message\": \"deleted\"}`` / ``{\"message\": \"detached\"}``."},"OrgMaterialOverrideCreate":{"properties":{"internal_code":{"anyOf":[{"type":"string","maxLength":128},{"type":"null"}],"title":"Internal Code","description":"Org-internal SKU / part code for this material."},"trade_name":{"anyOf":[{"type":"string","maxLength":128},{"type":"null"}],"title":"Trade Name","description":"Vendor trade name (e.g. 'Inconel 718')."},"notes":{"anyOf":[{"type":"string","maxLength":512},{"type":"null"}],"title":"Notes","description":"Free-text notes attached to this material by the organization."},"material_grade_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Material Grade Id","description":"Canonical grade this override extends. NULL → fully org-private material not in the global catalogue (requires ``urn`` populated)."},"urn":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Urn","description":"Canonical or org-private URN (urn:arc:mat:…:…)."},"attributes":{"additionalProperties":true,"type":"object","title":"Attributes","description":"Free-form key/value metadata attached to this material by the organization."}},"type":"object","title":"OrgMaterialOverrideCreate"},"OrgMaterialOverridePublic":{"properties":{"internal_code":{"anyOf":[{"type":"string","maxLength":128},{"type":"null"}],"title":"Internal Code","description":"Org-internal SKU / part code for this material."},"trade_name":{"anyOf":[{"type":"string","maxLength":128},{"type":"null"}],"title":"Trade Name","description":"Vendor trade name (e.g. 'Inconel 718')."},"notes":{"anyOf":[{"type":"string","maxLength":512},{"type":"null"}],"title":"Notes","description":"Free-text notes attached to this material by the organization."},"id":{"type":"string","format":"uuid","title":"Id","description":"Unique identifier of the override."},"org_id":{"type":"string","format":"uuid","title":"Org Id","description":"Identifier of the organization that owns this override."},"material_grade_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Material Grade Id","description":"Identifier of the canonical grade this override extends; null when fully org-private."},"urn":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Urn","description":"Canonical or org-private URN identifying the material."},"attributes":{"additionalProperties":true,"type":"object","title":"Attributes","description":"Free-form key/value metadata attached to this material by the organization."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"Timestamp when the override was created."},"updated_at":{"type":"string","format":"date-time","title":"Updated At","description":"Timestamp when the override was last updated."}},"type":"object","required":["id","org_id","created_at","updated_at"],"title":"OrgMaterialOverridePublic"},"OrgMaterialOverrideUpdate":{"properties":{"internal_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Internal Code","description":"Org-internal SKU or part code for this material."},"trade_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Trade Name","description":"Vendor trade name for this material (e.g. 'Inconel 718')."},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes","description":"Free-text notes attached to this material by the organization."},"material_grade_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Material Grade Id","description":"Identifier of the canonical grade this override extends; null when fully org-private."},"urn":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Urn","description":"Canonical or org-private URN identifying the material."},"attributes":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Attributes","description":"Free-form key/value metadata attached to this material by the organization."}},"type":"object","title":"OrgMaterialOverrideUpdate","description":"Partial-update payload. Only fields present in the request body\nare touched; ``None`` differentiates from \"not provided\" via Pydantic\n``exclude_unset``. Updating ``urn`` re-validates the format; updating\n``material_grade_id`` re-checks existence."},"OutcomeIngestPayload":{"properties":{"scope":{"type":"string","enum":["platform","environment"],"title":"Scope","description":"Scope of the observations; tenant tokens may submit 'environment' only."},"oracle":{"type":"string","title":"Oracle","description":"Source of the observations (e.g. operator report, MES, supplier quote)."},"env_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Env Id","description":"Target environment; required when scope is 'environment'."},"observations":{"items":{"additionalProperties":true,"type":"object"},"type":"array","maxItems":20000,"title":"Observations","description":"Up to 20,000 observations; each carries target_metric, observation_type, predicted, and actual."}},"type":"object","required":["scope","oracle"],"title":"OutcomeIngestPayload"},"PartCreate":{"properties":{"part_number":{"type":"string","maxLength":64,"title":"Part Number","description":"Stable identifier (≈ SAP MATNR). Unique per org."},"description":{"anyOf":[{"type":"string","maxLength":512},{"type":"null"}],"title":"Description","description":"Human-readable description of the part."},"base_uom":{"type":"string","maxLength":16,"title":"Base Uom","description":"Base unit of measure for the part (ISO unit code, e.g. EA, KG, M).","default":"EA"},"make_or_buy":{"type":"string","maxLength":16,"title":"Make Or Buy","description":"Whether the part is manufactured in-house or purchased.","default":"make"},"procurement_type":{"type":"string","maxLength":32,"title":"Procurement Type","description":"How the part is sourced (e.g. in-house production or external supplier).","default":"in_house"},"lead_time_days":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Lead Time Days","description":"Expected lead time to obtain the part, in days."},"default_currency":{"type":"string","maxLength":3,"title":"Default Currency","description":"Default currency for the part's pricing (ISO 4217 code, e.g. EUR, USD).","default":"EUR"},"classification_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Classification Id","description":"ID of the classification category this part belongs to, if any."},"attributes":{"additionalProperties":true,"type":"object","title":"Attributes","description":"Free-form key/value metadata for the part."}},"type":"object","required":["part_number"],"title":"PartCreate"},"PartPreviewUrl":{"properties":{"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url","description":"Presigned URL to the GLB preview; null unless status is 'ok'."},"status":{"type":"string","title":"Status","description":"Preview readiness state (e.g. ok, pending, failed, no_dataset)."},"data_source_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Data Source Id","description":"Identifier of the resolved CAD file; null when no dataset was found."}},"additionalProperties":true,"type":"object","required":["status"],"title":"PartPreviewUrl","description":"Engine-agnostic GLB preview payload for a Part.\n\n``url`` is ``None`` for every status except ``ok``. ``data_source_id`` is\nabsent when no dataset could be resolved (``status=\"no_dataset\"``)."},"PartPublic":{"properties":{"part_number":{"type":"string","maxLength":64,"title":"Part Number","description":"Stable identifier (≈ SAP MATNR). Unique per org."},"description":{"anyOf":[{"type":"string","maxLength":512},{"type":"null"}],"title":"Description","description":"Human-readable description of the part."},"base_uom":{"type":"string","maxLength":16,"title":"Base Uom","description":"Base unit of measure for the part (ISO unit code, e.g. EA, KG, M).","default":"EA"},"make_or_buy":{"type":"string","maxLength":16,"title":"Make Or Buy","description":"Whether the part is manufactured in-house or purchased.","default":"make"},"procurement_type":{"type":"string","maxLength":32,"title":"Procurement Type","description":"How the part is sourced (e.g. in-house production or external supplier).","default":"in_house"},"lead_time_days":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Lead Time Days","description":"Expected lead time to obtain the part, in days."},"default_currency":{"type":"string","maxLength":3,"title":"Default Currency","description":"Default currency for the part's pricing (ISO 4217 code, e.g. EUR, USD).","default":"EUR"},"id":{"type":"string","format":"uuid","title":"Id","description":"Unique identifier of the part."},"org_id":{"type":"string","format":"uuid","title":"Org Id","description":"ID of the organization that owns the part."},"classification_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Classification Id","description":"ID of the classification category this part belongs to, if any."},"attributes":{"additionalProperties":true,"type":"object","title":"Attributes","description":"Free-form key/value metadata for the part."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"Timestamp when the part was created (UTC, ISO 8601)."},"updated_at":{"type":"string","format":"date-time","title":"Updated At","description":"Timestamp when the part was last updated (UTC, ISO 8601)."}},"type":"object","required":["part_number","id","org_id","created_at","updated_at"],"title":"PartPublic"},"PartRevisionCreate":{"properties":{"revision_code":{"type":"string","maxLength":16,"title":"Revision Code","description":"Customer-facing revision label (A, B, 01, 02, …)."},"parent_revision_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Parent Revision Id","description":"ID of the revision this one was derived from, recording its lineage."},"change_request_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Change Request Id","description":"ID of the change request that triggered this revision, if any."},"attributes":{"additionalProperties":true,"type":"object","title":"Attributes","description":"Free-form key/value metadata for the revision."}},"type":"object","required":["revision_code"],"title":"PartRevisionCreate"},"PartRevisionDatasetPublic":{"properties":{"id":{"type":"string","format":"uuid","title":"Id","description":"Unique identifier of the uploaded file attached to the revision."},"part_revision_id":{"type":"string","format":"uuid","title":"Part Revision Id","description":"ID of the revision this file is attached to."},"data_source_id":{"type":"string","format":"uuid","title":"Data Source Id","description":"ID of the underlying stored file this attachment points to."},"role":{"type":"string","title":"Role","description":"The file's role on the revision (e.g. 3D CAD, 2D drawing, spec)."},"is_primary":{"type":"boolean","title":"Is Primary","description":"Whether this is the primary CAD file used for analysis on the revision."},"is_active":{"type":"boolean","title":"Is Active","description":"Whether this is the current file; superseded re-uploads are marked inactive.","default":true},"attributes":{"additionalProperties":true,"type":"object","title":"Attributes","description":"Free-form key/value metadata for the file attachment."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"Timestamp when the file was attached (UTC, ISO 8601)."},"filename":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Filename","description":"Original filename of the uploaded file."},"content_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content Type","description":"MIME type of the uploaded file (e.g. application/pdf)."},"size_bytes":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Size Bytes","description":"Size of the uploaded file in bytes."}},"type":"object","required":["id","part_revision_id","data_source_id","role","is_primary","created_at"],"title":"PartRevisionDatasetPublic"},"PartRevisionDatasetUpdate":{"properties":{"filename":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Filename","description":"New original filename for the uploaded file."},"is_primary":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Primary","description":"Set true to make this the primary CAD file for analysis on the revision."}},"type":"object","title":"PartRevisionDatasetUpdate","description":"PATCH body for editing a dataset link.\n\nAll fields optional — the route applies whichever the caller sends.\nSetting ``is_primary=True`` is exclusive within the parent revision:\nthe route demotes any other primary on the same revision so the\n\"exactly one primary\" invariant holds without race-prone client\ncoordination."},"PartRevisionPublic":{"properties":{"revision_code":{"type":"string","maxLength":16,"title":"Revision Code","description":"Customer-facing revision label (A, B, 01, 02, …)."},"id":{"type":"string","format":"uuid","title":"Id","description":"Unique identifier of the revision."},"part_id":{"type":"string","format":"uuid","title":"Part Id","description":"ID of the part this revision belongs to."},"parent_revision_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Parent Revision Id","description":"ID of the revision this one was derived from, recording its lineage."},"attributes":{"additionalProperties":true,"type":"object","title":"Attributes","description":"Free-form key/value metadata for the revision."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"Timestamp when the revision was created (UTC, ISO 8601)."},"updated_at":{"type":"string","format":"date-time","title":"Updated At","description":"Timestamp when the revision was last updated (UTC, ISO 8601)."}},"type":"object","required":["revision_code","id","part_id","created_at","updated_at"],"title":"PartRevisionPublic"},"PartRevisionUpdate":{"properties":{"attributes":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Attributes","description":"Free-form metadata to merge onto the revision, as a JSON object."}},"type":"object","title":"PartRevisionUpdate"},"PartRevisionsPublic":{"properties":{"data":{"items":{"$ref":"#/components/schemas/PartRevisionPublic"},"type":"array","title":"Data","description":"The page of revisions matching the query."},"count":{"type":"integer","title":"Count","description":"Total number of revisions matching the query."}},"type":"object","required":["data","count"],"title":"PartRevisionsPublic"},"PartUpdate":{"properties":{"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Human-readable description of the part."},"base_uom":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Base Uom","description":"Base unit of measure for the part (ISO unit code, e.g. EA, KG, M)."},"make_or_buy":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Make Or Buy","description":"Whether the part is manufactured in-house or purchased."},"procurement_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Procurement Type","description":"How the part is sourced (e.g. in-house production or external supplier)."},"lead_time_days":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Lead Time Days","description":"Expected lead time to obtain the part, in days."},"default_currency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Currency","description":"Default currency for the part's pricing (ISO 4217 code, e.g. EUR, USD)."},"classification_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Classification Id","description":"ID of the classification category this part belongs to, if any."},"attributes":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Attributes","description":"Free-form key/value metadata for the part."}},"type":"object","title":"PartUpdate"},"PartsPublic":{"properties":{"data":{"items":{"$ref":"#/components/schemas/PartPublic"},"type":"array","title":"Data","description":"The page of parts matching the query."},"count":{"type":"integer","title":"Count","description":"Total number of parts matching the query."}},"type":"object","required":["data","count"],"title":"PartsPublic"},"PolicyCalibrateRequest":{"properties":{"region":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Region","description":"Region whose seed policy to start from (e.g. DE-BY); null for the default."},"history":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"History","description":"Past machine-choice records, each with candidates and the chosen_machine_id."}},"type":"object","required":["history"],"title":"PolicyCalibrateRequest"},"PresignRequest":{"properties":{"name":{"type":"string","title":"Name","description":"Original filename of the file to upload."},"content_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content Type","description":"MIME type of the file (e.g. application/pdf)."},"size_bytes":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Size Bytes","description":"Size of the file in bytes, if known."}},"type":"object","required":["name"],"title":"PresignRequest"},"PresignResponse":{"properties":{"data_source_id":{"type":"string","format":"uuid","title":"Data Source Id","description":"Identifier of the data source record; pass it to /uploads/confirm."},"url":{"type":"string","title":"Url","description":"Presigned URL the client uploads the file bytes to."},"method":{"type":"string","title":"Method","description":"HTTP method to use against ``url`` (typically PUT or POST)."},"headers":{"anyOf":[{"additionalProperties":{"type":"string"},"type":"object"},{"type":"null"}],"title":"Headers","description":"Headers that must be sent with the upload request; null if none."},"fields":{"anyOf":[{"additionalProperties":{"type":"string"},"type":"object"},{"type":"null"}],"title":"Fields","description":"Form fields to include for a multipart POST upload; null if none."},"expires_in":{"type":"integer","title":"Expires In","description":"Seconds until the presigned URL expires."}},"type":"object","required":["data_source_id","url","method","expires_in"],"title":"PresignResponse"},"RateRowPublicOut":{"properties":{"id":{"type":"string","title":"Id","description":"Unique identifier of the rate row."},"env_id":{"type":"string","title":"Env Id","description":"Identifier of the environment this rate belongs to."},"kind":{"type":"string","title":"Kind","description":"Rate kind: labour, overhead, material, or fx."},"valid_from":{"type":"string","title":"Valid From","description":"ISO date (YYYY-MM-DD) from which this rate is effective."},"valid_to":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Valid To","description":"ISO date (YYYY-MM-DD) the rate stops being effective; null = open-ended."},"currency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Currency","description":"ISO 4217 currency code for the rate; null for kinds without a currency."},"created_at":{"type":"string","title":"Created At","description":"ISO 8601 timestamp when the rate row was created."},"fields":{"additionalProperties":true,"type":"object","title":"Fields","description":"Kind-specific rate columns (e.g. hourly_rate, value, price_per_kg, rate)."}},"additionalProperties":true,"type":"object","required":["id","env_id","kind","valid_from","created_at","fields"],"title":"RateRowPublicOut","description":"Shape returned by ``_rate_to_public`` (uniform across rate kinds)."},"RateUpsert":{"properties":{"kind":{"type":"string","title":"Kind","description":"labour|machine|overhead|material|fx"},"fields":{"additionalProperties":true,"type":"object","title":"Fields","description":"Kind-specific columns (category, machine_ref, …)."},"currency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Currency","description":"ISO 4217 currency code for the rate; null to inherit."},"valid_from":{"type":"string","format":"date","title":"Valid From","description":"Date from which the rate is effective (ISO 8601)."},"valid_to":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Valid To","description":"Date after which the rate is no longer effective; null if open-ended (ISO 8601)."}},"type":"object","required":["kind","valid_from"],"title":"RateUpsert","description":"Generic rate-upsert payload — maps to the right table via ``kind``."},"SelectionCandidatePayload":{"properties":{"machine_id":{"type":"string","format":"uuid","title":"Machine Id","description":"Identifier of the candidate machine."},"machine_name":{"type":"string","title":"Machine Name","description":"Human-readable name of the candidate machine."},"feasible":{"type":"boolean","title":"Feasible","description":"Whether the machine can manufacture the part with no blocking violations."},"provisional_unit_cost_eur":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Provisional Unit Cost Eur","description":"Provisional per-unit cost estimate for this machine, in EUR; null if not feasible."},"capability_score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Capability Score","description":"Relative capability/fit score for this machine; higher is better."},"blocking_violations":{"items":{"type":"string"},"type":"array","title":"Blocking Violations","description":"Feasibility violations that prevent this machine from making the part.","default":[]}},"type":"object","required":["machine_id","machine_name","feasible"],"title":"SelectionCandidatePayload"},"SelectionResponse":{"properties":{"calculation_id":{"type":"string","format":"uuid","title":"Calculation Id","description":"Identifier of the calculation the selection was run for."},"chosen_machine_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Chosen Machine Id","description":"Identifier of the selected machine, or null if none is feasible."},"chosen_machine_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Chosen Machine Name","description":"Name of the selected machine, or null if none is feasible."},"rationale_text":{"type":"string","title":"Rationale Text","description":"Human-readable explanation of why the machine was or was not selected."},"candidates":{"items":{"$ref":"#/components/schemas/SelectionCandidatePayload"},"type":"array","title":"Candidates","description":"All machines evaluated, with their feasibility and scoring."}},"type":"object","required":["calculation_id","chosen_machine_id","chosen_machine_name","rationale_text","candidates"],"title":"SelectionResponse"},"StabilityLobeCurve":{"properties":{"rpm_to_max_axial_depth_mm":{"items":{"$ref":"#/components/schemas/StabilityLobePoint"},"type":"array","title":"Rpm To Max Axial Depth Mm","description":"Stability-lobe points mapping spindle speed to maximum stable axial depth of cut."}},"type":"object","title":"StabilityLobeCurve"},"StabilityLobePoint":{"properties":{"rpm":{"type":"number","minimum":0.0,"title":"Rpm","description":"Spindle speed, in revolutions per minute."},"max_axial_depth_mm":{"type":"number","minimum":0.0,"title":"Max Axial Depth Mm","description":"Maximum stable axial depth of cut at this speed, in millimetres."}},"type":"object","required":["rpm","max_axial_depth_mm"],"title":"StabilityLobePoint"},"StandardKind":{"type":"string","enum":["designation","numbering","product","classification"],"title":"StandardKind","description":"Role a standard plays in the material world.\n\n* ``designation`` — gives a material its *name* (EN 10027-1,\n  EN 573-2, ISO 1043-1, ISO 18064).\n* ``numbering`` — gives a material a *number* (EN 10027-2\n  Werkstoffnummer, EN 573-1 4-digit, EN 1412 CW-number, EN 1560\n  cast-iron number, UNS, AISI/SAE, JIS).\n* ``product`` — lists *which* grades are deliverable in what\n  shapes / heat-treatment / delivery conditions (EN 10025, EN 10083,\n  EN 10088, EN 1561, EN 1563, EN ISO 4957, ASTM A36 …). Not itself a\n  naming system; references grades named under a designation standard.\n* ``classification`` — cross-industry product taxonomy (ECLASS,\n  UNSPSC). Used for integration / procurement catalogues, not for\n  identifying a specific grade."},"TeachRequest":{"properties":{"rows":{"items":{"$ref":"#/components/schemas/TeachRow"},"type":"array","maxItems":20000,"minItems":1,"title":"Rows","description":"Between 1 and 20,000 (predicted, actual) rows to calibrate from."},"target_alpha":{"type":"number","maximum":0.5,"minimum":0.01,"title":"Target Alpha","description":"Target miss rate for the prediction interval (0.10 → a 90% interval).","default":0.1},"holdout_pct":{"type":"number","maximum":0.5,"minimum":0.05,"title":"Holdout Pct","description":"Fraction (0.05–0.5) of rows held out to size the prediction interval.","default":0.15}},"type":"object","required":["rows"],"title":"TeachRequest"},"TeachRow":{"properties":{"part_revision_id":{"type":"string","format":"uuid","title":"Part Revision Id","description":"Part revision this (predicted, actual) pair was observed on."},"predicted":{"type":"number","exclusiveMinimum":0.0,"title":"Predicted","description":"Quoted value for the part; must be greater than 0."},"actual":{"type":"number","exclusiveMinimum":0.0,"title":"Actual","description":"Observed actual value for the part; must be greater than 0."},"target_metric":{"type":"string","enum":["cycle_time_s","unit_cost","setup_time_s"],"title":"Target Metric","description":"Metric the predicted/actual pair refers to.","default":"unit_cost"},"bin":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bin","description":"Optional bin label grouping like parts; null if unset."}},"type":"object","required":["part_revision_id","predicted","actual"],"title":"TeachRow"},"ToolKind":{"type":"string","enum":["end_mill","face_mill","drill","tap","reamer","boring_bar","thread_mill","insert_holder_turn","grooving_tool","grinding_wheel","chamfer_mill"],"title":"ToolKind"},"UploadInputsResponse":{"properties":{"calculation_id":{"type":"string","title":"Calculation Id","description":"UUID of the calculation the file was attached to."},"data_source_id":{"type":"string","title":"Data Source Id","description":"UUID of the stored data source created for the uploaded file."},"role":{"type":"string","title":"Role","description":"Role the file was attached under (e.g. drawing_2d, mesh, rfq_text)."},"sha256":{"type":"string","title":"Sha256","description":"Hex-encoded SHA-256 digest of the uploaded bytes."},"size_bytes":{"type":"integer","title":"Size Bytes","description":"Size of the uploaded file in bytes."},"billing":{"additionalProperties":true,"type":"object","title":"Billing","description":"Free-form billing object describing the upload charge; its internal keys may evolve."}},"additionalProperties":true,"type":"object","required":["calculation_id","data_source_id","role","sha256","size_bytes","billing"],"title":"UploadInputsResponse","description":"Body for ``POST /parts/calculations/{id}/inputs``.\n\n``billing`` is the heterogeneous pricing breakdown from\n``charge_upload_bytes`` — its keys differ by branch (charged /\nskipped_* / insufficient_funds), so it stays an open dict."},"VDI3258Inputs":{"properties":{"acquisition_cost_eur":{"type":"number","exclusiveMinimum":0.0,"title":"Acquisition Cost Eur","description":"Machine acquisition (replacement) cost, in EUR."},"depreciation_life_h":{"type":"number","exclusiveMinimum":0.0,"title":"Depreciation Life H","description":"Depreciation life of the machine, in operating hours."},"annual_hours_T_G":{"type":"number","exclusiveMinimum":0.0,"title":"Annual Hours T G","description":"VDI 3258 total annual attendance hours (T_G), in hours per year."},"annual_hours_T_ST":{"type":"number","minimum":0.0,"title":"Annual Hours T St","description":"VDI 3258 annual standstill (idle) hours (T_ST), in hours per year."},"annual_hours_T_IH":{"type":"number","minimum":0.0,"title":"Annual Hours T Ih","description":"VDI 3258 annual maintenance/repair hours (T_IH), in hours per year."},"capital_interest_rate":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Capital Interest Rate","description":"Imputed annual interest rate on tied-up capital (0–1, e.g. 0.06 = 6%)."},"space_eur_per_m2_y":{"type":"number","minimum":0.0,"title":"Space Eur Per M2 Y","description":"Annual floor-space cost rate, in EUR per square metre per year."},"floor_space_m2":{"type":"number","minimum":0.0,"title":"Floor Space M2","description":"Floor space occupied by the machine, in square metres."},"energy_kw":{"type":"number","minimum":0.0,"title":"Energy Kw","description":"Average electrical power draw while running, in kilowatts."},"energy_eur_per_kwh":{"type":"number","minimum":0.0,"title":"Energy Eur Per Kwh","description":"Electricity price, in EUR per kilowatt-hour."},"operator_hourly_eur":{"type":"number","minimum":0.0,"title":"Operator Hourly Eur","description":"Fully-loaded operator labour cost, in EUR per hour."},"operator_share":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Operator Share","description":"Fraction of an operator's time allocated to this machine (0–1)."},"maintenance_eur_per_year":{"type":"number","minimum":0.0,"title":"Maintenance Eur Per Year","description":"Annual maintenance spend for the machine, in EUR per year."},"tooling_eur_per_year":{"type":"number","minimum":0.0,"title":"Tooling Eur Per Year","description":"Annual perishable-tooling spend for the machine, in EUR per year."}},"type":"object","required":["acquisition_cost_eur","depreciation_life_h","annual_hours_T_G","annual_hours_T_ST","annual_hours_T_IH","capital_interest_rate","space_eur_per_m2_y","floor_space_m2","energy_kw","energy_eur_per_kwh","operator_hourly_eur","operator_share","maintenance_eur_per_year","tooling_eur_per_year"],"title":"VDI3258Inputs"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"app__modules__parts__routes__materials__DeleteMessage":{"properties":{"message":{"type":"string","title":"Message","description":"Human-readable confirmation that the resource was deleted."}},"additionalProperties":true,"type":"object","required":["message"],"title":"DeleteMessage"},"app__modules__parts__routes__parts__DeleteMessage":{"properties":{"message":{"type":"string","title":"Message","description":"Human-readable confirmation that the resource was deleted."}},"additionalProperties":true,"type":"object","required":["message"],"title":"DeleteMessage","description":"``{\"message\": \"...\"}`` envelope for delete endpoints."}},"securitySchemes":{"OAuth2PasswordBearer":{"type":"oauth2","flows":{"password":{"scopes":{},"tokenUrl":"/api/v1/sessions/login"}}},"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key","description":"Server-to-server API key in the ``X-API-Key`` header, e.g. ``ak_live_…``. See the Authentication guide. Do not send it as ``Authorization: Bearer`` — that header is reserved for session / MCP JWTs."}}},"security":[{"ApiKeyAuth":[]},{"OAuth2PasswordBearer":[]}]}